From 4c8f48ed4f3db0e3ba376e6b7a261d26b41d8dd0 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Thu, 29 Apr 2021 15:38:56 +1000 Subject: [PATCH 001/940] syscall: do not change stdio handle inheritance Before the CL 288297 all Go process handles had to be made non-inheritable - otherwise they would escape into the child process. But now this is not necessary. This CL stops changing inheritance flag of stdint, stdout and stderr handles. Fixes #44876 Change-Id: Ib8fcf8066c30282293d96c34486b01b4c04f7116 Reviewed-on: https://go-review.googlesource.com/c/go/+/316269 Trust: Alex Brainman Trust: Jason A. Donenfeld Run-TryBot: Alex Brainman TryBot-Result: Go Bot Reviewed-by: Jason A. Donenfeld --- src/syscall/syscall_windows.go | 1 - src/syscall/syscall_windows_test.go | 65 +++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go index f9f78bd2b30..fa0b5d959af 100644 --- a/src/syscall/syscall_windows.go +++ b/src/syscall/syscall_windows.go @@ -472,7 +472,6 @@ var ( func getStdHandle(h int) (fd Handle) { r, _ := GetStdHandle(h) - CloseOnExec(r) return r } diff --git a/src/syscall/syscall_windows_test.go b/src/syscall/syscall_windows_test.go index b8ec6bee39b..ea8fa191dcb 100644 --- a/src/syscall/syscall_windows_test.go +++ b/src/syscall/syscall_windows_test.go @@ -5,8 +5,12 @@ package syscall_test import ( + "fmt" + "internal/testenv" "os" + "os/exec" "path/filepath" + "strings" "syscall" "testing" ) @@ -71,3 +75,64 @@ func TestTOKEN_ALL_ACCESS(t *testing.T) { t.Errorf("TOKEN_ALL_ACCESS = %x, want 0xF01FF", syscall.TOKEN_ALL_ACCESS) } } + +func TestStdioAreInheritable(t *testing.T) { + testenv.MustHaveGoBuild(t) + testenv.MustHaveExecPath(t, "gcc") + + tmpdir := t.TempDir() + + // build go dll + const dlltext = ` +package main + +import "C" +import ( + "fmt" +) + +//export HelloWorld +func HelloWorld() { + fmt.Println("Hello World") +} + +func main() {} +` + dllsrc := filepath.Join(tmpdir, "helloworld.go") + err := os.WriteFile(dllsrc, []byte(dlltext), 0644) + if err != nil { + t.Fatal(err) + } + dll := filepath.Join(tmpdir, "helloworld.dll") + cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", dll, "-buildmode", "c-shared", dllsrc) + out, err := testenv.CleanCmdEnv(cmd).CombinedOutput() + if err != nil { + t.Fatalf("failed to build go library: %s\n%s", err, out) + } + + // run powershell script + psscript := fmt.Sprintf(` +hostname; +$signature = " [DllImport("%q")] public static extern void HelloWorld(); "; +Add-Type -MemberDefinition $signature -Name World -Namespace Hello; +[Hello.World]::HelloWorld(); +hostname; +`, dll) + psscript = strings.ReplaceAll(psscript, "\n", "") + out, err = exec.Command("powershell", "-Command", psscript).CombinedOutput() + if err != nil { + t.Fatalf("Powershell command failed: %v: %v", err, string(out)) + } + + hostname, err := os.Hostname() + if err != nil { + t.Fatal(err) + } + + have := strings.ReplaceAll(string(out), "\n", "") + have = strings.ReplaceAll(have, "\r", "") + want := fmt.Sprintf("%sHello World%s", hostname, hostname) + if have != want { + t.Fatalf("Powershell command output is wrong: got %q, want %q", have, want) + } +} From 68327e1aa11457cd570bc7eaf03a0260950f27d9 Mon Sep 17 00:00:00 2001 From: Alberto Donizetti Date: Fri, 7 May 2021 19:10:28 +0200 Subject: [PATCH 002/940] cmd/vendor: upgrade pprof to latest This change upgrades the vendored pprof to pick up the fix for a serious issue that made the source view in browser mode blank (tracked upstream as google/pprof#621). I also had to patch pprof.go, since one of the upstream commit we included introduced a breaking change in the file interface (the Base method is now called ObjAddr and has a different signature). I've manually verified that the upgrade fixes the aforementioned issues with the source view. Fixes #45786 Change-Id: I00659ae539a2ad603758e1f06572374d483b9ddc Reviewed-on: https://go-review.googlesource.com/c/go/+/318049 Trust: Alberto Donizetti Reviewed-by: Cherry Mui --- src/cmd/go.mod | 2 +- src/cmd/go.sum | 4 +- src/cmd/pprof/pprof.go | 4 +- .../github.com/google/pprof/driver/driver.go | 4 +- .../pprof/internal/binutils/binutils.go | 188 +++++++++++--- .../google/pprof/internal/elfexec/elfexec.go | 96 +++---- .../google/pprof/internal/plugin/plugin.go | 5 +- .../google/pprof/internal/report/report.go | 15 +- .../google/pprof/internal/report/source.go | 243 ++++++++++++------ .../pprof/internal/report/source_html.go | 7 - .../google/pprof/internal/report/synth.go | 39 +++ .../github.com/google/pprof/profile/encode.go | 2 +- .../github.com/google/pprof/profile/merge.go | 1 - src/cmd/vendor/modules.txt | 2 +- 14 files changed, 416 insertions(+), 196 deletions(-) create mode 100644 src/cmd/vendor/github.com/google/pprof/internal/report/synth.go diff --git a/src/cmd/go.mod b/src/cmd/go.mod index a15cbe070ad..7a96bc64095 100644 --- a/src/cmd/go.mod +++ b/src/cmd/go.mod @@ -3,7 +3,7 @@ module cmd go 1.17 require ( - github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5 + github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 // indirect golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e // indirect diff --git a/src/cmd/go.sum b/src/cmd/go.sum index 8a7ad4290ab..1c6e2248208 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -1,8 +1,8 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5 h1:zIaiqGYDQwa4HVx5wGRTXbx38Pqxjemn4BP98wpzpXo= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a h1:jmAp/2PZAScNd62lTD3Mcb0Ey9FvIIJtLohPhtxZJ+Q= +github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 h1:mV02weKRL81bEnm8A0HT1/CAelMQDBuQIfLw8n+d6xI= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e h1:pv3V0NlNSh5Q6AX/StwGLBjcLS7UN4m4Gq+V+uSecqM= diff --git a/src/cmd/pprof/pprof.go b/src/cmd/pprof/pprof.go index 11f91cbedb9..1d10a7b41f3 100644 --- a/src/cmd/pprof/pprof.go +++ b/src/cmd/pprof/pprof.go @@ -232,9 +232,9 @@ func (f *file) Name() string { return f.name } -func (f *file) Base() uint64 { +func (f *file) ObjAddr(addr uint64) (uint64, error) { // No support for shared libraries. - return 0 + return 0, nil } func (f *file) BuildID() string { diff --git a/src/cmd/vendor/github.com/google/pprof/driver/driver.go b/src/cmd/vendor/github.com/google/pprof/driver/driver.go index e65bc2f417d..fc05f919baf 100644 --- a/src/cmd/vendor/github.com/google/pprof/driver/driver.go +++ b/src/cmd/vendor/github.com/google/pprof/driver/driver.go @@ -159,8 +159,8 @@ type ObjFile interface { // Name returns the underlying file name, if available. Name() string - // Base returns the base address to use when looking up symbols in the file. - Base() uint64 + // ObjAddr returns the objdump address corresponding to a runtime address. + ObjAddr(addr uint64) (uint64, error) // BuildID returns the GNU build ID of the file, or an empty string. BuildID() string diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go b/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go index 576a6ee66a1..5ed8a1f9f1e 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go @@ -42,7 +42,12 @@ type Binutils struct { rep *binrep } -var objdumpLLVMVerRE = regexp.MustCompile(`LLVM version (?:(\d*)\.(\d*)\.(\d*)|.*(trunk).*)`) +var ( + objdumpLLVMVerRE = regexp.MustCompile(`LLVM version (?:(\d*)\.(\d*)\.(\d*)|.*(trunk).*)`) + + // Defined for testing + elfOpen = elf.Open +) // binrep is an immutable representation for Binutils. It is atomically // replaced on every mutation to provide thread-safe access. @@ -421,14 +426,23 @@ func (b *binrep) openMachO(name string, start, limit, offset uint64) (plugin.Obj } func (b *binrep) openELF(name string, start, limit, offset uint64) (plugin.ObjFile, error) { - ef, err := elf.Open(name) + ef, err := elfOpen(name) if err != nil { return nil, fmt.Errorf("error parsing %s: %v", name, err) } defer ef.Close() - var stextOffset *uint64 - var pageAligned = func(addr uint64) bool { return addr%4096 == 0 } + buildID := "" + if f, err := os.Open(name); err == nil { + if id, err := elfexec.GetBuildID(f); err == nil { + buildID = fmt.Sprintf("%x", id) + } + } + + var ( + stextOffset *uint64 + pageAligned = func(addr uint64) bool { return addr%4096 == 0 } + ) if strings.Contains(name, "vmlinux") || !pageAligned(start) || !pageAligned(limit) || !pageAligned(offset) { // Reading all Symbols is expensive, and we only rarely need it so // we don't want to do it every time. But if _stext happens to be @@ -450,38 +464,29 @@ func (b *binrep) openELF(name string, start, limit, offset uint64) (plugin.ObjFi } } - var ph *elf.ProgHeader - // For user space executables, find the actual program segment that is - // associated with the given mapping. Skip this search if limit <= start. - // We cannot use just a check on the start address of the mapping to tell if - // it's a kernel / .ko module mapping, because with quipper address remapping - // enabled, the address would be in the lower half of the address space. - if stextOffset == nil && start < limit && limit < (uint64(1)<<63) { - ph, err = elfexec.FindProgHeaderForMapping(ef, offset, limit-start) - if err != nil { - return nil, fmt.Errorf("failed to find program header for file %q, mapping pgoff %x, memsz=%x: %v", name, offset, limit-start, err) - } - } else { - // For the kernel, find the program segment that includes the .text section. - ph = elfexec.FindTextProgHeader(ef) - } - - base, err := elfexec.GetBase(&ef.FileHeader, ph, stextOffset, start, limit, offset) - if err != nil { + // Check that we can compute a base for the binary. This may not be the + // correct base value, so we don't save it. We delay computing the actual base + // value until we have a sample address for this mapping, so that we can + // correctly identify the associated program segment that is needed to compute + // the base. + if _, err := elfexec.GetBase(&ef.FileHeader, elfexec.FindTextProgHeader(ef), stextOffset, start, limit, offset); err != nil { return nil, fmt.Errorf("could not identify base for %s: %v", name, err) } - buildID := "" - if f, err := os.Open(name); err == nil { - if id, err := elfexec.GetBuildID(f); err == nil { - buildID = fmt.Sprintf("%x", id) - } - } - isData := ph != nil && ph.Flags&elf.PF_X == 0 if b.fast || (!b.addr2lineFound && !b.llvmSymbolizerFound) { - return &fileNM{file: file{b, name, base, buildID, isData}}, nil + return &fileNM{file: file{ + b: b, + name: name, + buildID: buildID, + m: &elfMapping{start: start, limit: limit, offset: offset, stextOffset: stextOffset}, + }}, nil } - return &fileAddr2Line{file: file{b, name, base, buildID, isData}}, nil + return &fileAddr2Line{file: file{ + b: b, + name: name, + buildID: buildID, + m: &elfMapping{start: start, limit: limit, offset: offset, stextOffset: stextOffset}, + }}, nil } func (b *binrep) openPE(name string, start, limit, offset uint64) (plugin.ObjFile, error) { @@ -511,21 +516,119 @@ func (b *binrep) openPE(name string, start, limit, offset uint64) (plugin.ObjFil return &fileAddr2Line{file: file{b: b, name: name, base: base}}, nil } +// elfMapping stores the parameters of a runtime mapping that are needed to +// identify the ELF segment associated with a mapping. +type elfMapping struct { + // Runtime mapping parameters. + start, limit, offset uint64 + // Offset of _stext symbol. Only defined for kernel images, nil otherwise. + stextOffset *uint64 +} + // file implements the binutils.ObjFile interface. type file struct { b *binrep name string - base uint64 buildID string - isData bool + + baseOnce sync.Once // Ensures the base, baseErr and isData are computed once. + base uint64 + baseErr error // Any eventual error while computing the base. + isData bool + // Mapping information. Relevant only for ELF files, nil otherwise. + m *elfMapping +} + +// computeBase computes the relocation base for the given binary file only if +// the elfMapping field is set. It populates the base and isData fields and +// returns an error. +func (f *file) computeBase(addr uint64) error { + if f == nil || f.m == nil { + return nil + } + if addr < f.m.start || addr >= f.m.limit { + return fmt.Errorf("specified address %x is outside the mapping range [%x, %x] for file %q", addr, f.m.start, f.m.limit, f.name) + } + ef, err := elfOpen(f.name) + if err != nil { + return fmt.Errorf("error parsing %s: %v", f.name, err) + } + defer ef.Close() + + var ph *elf.ProgHeader + // For user space executables, find the actual program segment that is + // associated with the given mapping. Skip this search if limit <= start. + // We cannot use just a check on the start address of the mapping to tell if + // it's a kernel / .ko module mapping, because with quipper address remapping + // enabled, the address would be in the lower half of the address space. + if f.m.stextOffset == nil && f.m.start < f.m.limit && f.m.limit < (uint64(1)<<63) { + // Get all program headers associated with the mapping. + headers, hasLoadables := elfexec.ProgramHeadersForMapping(ef, f.m.offset, f.m.limit-f.m.start) + + // Some ELF files don't contain any loadable program segments, e.g. .ko + // kernel modules. It's not an error to have no header in such cases. + if hasLoadables { + ph, err = matchUniqueHeader(headers, addr-f.m.start+f.m.offset) + if err != nil { + return fmt.Errorf("failed to find program header for file %q, ELF mapping %#v, address %x: %v", f.name, *f.m, addr, err) + } + } + } else { + // For the kernel, find the program segment that includes the .text section. + ph = elfexec.FindTextProgHeader(ef) + } + + base, err := elfexec.GetBase(&ef.FileHeader, ph, f.m.stextOffset, f.m.start, f.m.limit, f.m.offset) + if err != nil { + return err + } + f.base = base + f.isData = ph != nil && ph.Flags&elf.PF_X == 0 + return nil +} + +// matchUniqueHeader attempts to identify a unique header from the given list, +// using the given file offset to disambiguate between multiple segments. It +// returns an error if the header list is empty or if it cannot identify a +// unique header. +func matchUniqueHeader(headers []*elf.ProgHeader, fileOffset uint64) (*elf.ProgHeader, error) { + if len(headers) == 0 { + return nil, errors.New("no program header matches mapping info") + } + if len(headers) == 1 { + // Don't use the file offset if we already have a single header. + return headers[0], nil + } + // We have multiple input segments. Attempt to identify a unique one + // based on the given file offset. + var ph *elf.ProgHeader + for _, h := range headers { + if fileOffset >= h.Off && fileOffset < h.Off+h.Memsz { + if ph != nil { + // Assuming no other bugs, this can only happen if we have two or + // more small program segments that fit on the same page, and a + // segment other than the last one includes uninitialized data. + return nil, fmt.Errorf("found second program header (%#v) that matches file offset %x, first program header is %#v. Does first program segment contain uninitialized data?", *h, fileOffset, *ph) + } + ph = h + } + } + if ph == nil { + return nil, fmt.Errorf("no program header matches file offset %x", fileOffset) + } + return ph, nil } func (f *file) Name() string { return f.name } -func (f *file) Base() uint64 { - return f.base +func (f *file) ObjAddr(addr uint64) (uint64, error) { + f.baseOnce.Do(func() { f.baseErr = f.computeBase(addr) }) + if f.baseErr != nil { + return 0, f.baseErr + } + return addr - f.base, nil } func (f *file) BuildID() string { @@ -533,7 +636,11 @@ func (f *file) BuildID() string { } func (f *file) SourceLine(addr uint64) ([]plugin.Frame, error) { - return []plugin.Frame{}, nil + f.baseOnce.Do(func() { f.baseErr = f.computeBase(addr) }) + if f.baseErr != nil { + return nil, f.baseErr + } + return nil, nil } func (f *file) Close() error { @@ -560,6 +667,10 @@ type fileNM struct { } func (f *fileNM) SourceLine(addr uint64) ([]plugin.Frame, error) { + f.baseOnce.Do(func() { f.baseErr = f.computeBase(addr) }) + if f.baseErr != nil { + return nil, f.baseErr + } if f.addr2linernm == nil { addr2liner, err := newAddr2LinerNM(f.b.nm, f.name, f.base) if err != nil { @@ -579,9 +690,14 @@ type fileAddr2Line struct { file addr2liner *addr2Liner llvmSymbolizer *llvmSymbolizer + isData bool } func (f *fileAddr2Line) SourceLine(addr uint64) ([]plugin.Frame, error) { + f.baseOnce.Do(func() { f.baseErr = f.computeBase(addr) }) + if f.baseErr != nil { + return nil, f.baseErr + } f.once.Do(f.init) if f.llvmSymbolizer != nil { return f.llvmSymbolizer.addrInfo(addr) diff --git a/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go b/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go index 3b3c6ee89ff..2638b2db2d9 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go @@ -284,83 +284,71 @@ func FindTextProgHeader(f *elf.File) *elf.ProgHeader { return nil } -// FindProgHeaderForMapping returns the loadable program segment header that is -// fully contained in the runtime mapping with file offset pgoff and memory size -// memsz, or an error if the segment cannot be determined. The function returns -// a nil program header and no error if the ELF binary has no loadable segments. -func FindProgHeaderForMapping(f *elf.File, pgoff, memsz uint64) (*elf.ProgHeader, error) { +// ProgramHeadersForMapping returns the loadable program segment headers that +// are fully contained in the runtime mapping with file offset pgoff and memory +// size memsz, and if the binary includes any loadable segments. +func ProgramHeadersForMapping(f *elf.File, pgoff, memsz uint64) ([]*elf.ProgHeader, bool) { + const ( + // pageSize defines the virtual memory page size used by the loader. This + // value is dependent on the memory management unit of the CPU. The page + // size is 4KB virtually on all the architectures that we care about, so we + // define this metric as a constant. If we encounter architectures where + // page sie is not 4KB, we must try to guess the page size on the system + // where the profile was collected, possibly using the architecture + // specified in the ELF file header. + pageSize = 4096 + pageOffsetMask = pageSize - 1 + pageMask = ^uint64(pageOffsetMask) + ) var headers []*elf.ProgHeader - loadables := 0 + hasLoadables := false for _, p := range f.Progs { + // The segment must be fully included in the mapping. if p.Type == elf.PT_LOAD && pgoff <= p.Off && p.Off+p.Memsz <= pgoff+memsz { - headers = append(headers, &p.ProgHeader) + alignedOffset := uint64(0) + if p.Off > (p.Vaddr & pageOffsetMask) { + alignedOffset = p.Off - (p.Vaddr & pageOffsetMask) + } + if alignedOffset <= pgoff { + headers = append(headers, &p.ProgHeader) + } } if p.Type == elf.PT_LOAD { - loadables++ + hasLoadables = true } } - if len(headers) == 1 { - return headers[0], nil - } - // Some ELF files don't contain any program segments, e.g. .ko loadable kernel - // modules. Don't return an error in such cases. - if loadables == 0 { - return nil, nil - } - if len(headers) == 0 { - return nil, fmt.Errorf("no program header matches file offset %x and memory size %x", pgoff, memsz) + if len(headers) < 2 { + return headers, hasLoadables } - // Segments are mapped page aligned. In some cases, segments may be smaller - // than a page, which causes the next segment to start at a file offset that - // is logically on the same page if we were to align file offsets by page. - // Example: - // LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 - // 0x00000000000006fc 0x00000000000006fc R E 0x200000 - // LOAD 0x0000000000000e10 0x0000000000600e10 0x0000000000600e10 - // 0x0000000000000230 0x0000000000000238 RW 0x200000 - // - // In this case, perf records the following mappings for this executable: - // 0 0 [0xc0]: PERF_RECORD_MMAP2 87867/87867: [0x400000(0x1000) @ 0 00:3c 512041 0]: r-xp exename - // 0 0 [0xc0]: PERF_RECORD_MMAP2 87867/87867: [0x600000(0x2000) @ 0 00:3c 512041 0]: rw-p exename - // - // Both mappings have file offset 0. The first mapping is one page length and - // it can include only the first loadable segment. Due to page alignment, the - // second mapping starts also at file offset 0, and it spans two pages. It can - // include both the first and the second loadable segments. We must return the - // correct program header to compute the correct base offset. - // - // We cannot use the mapping protections to distinguish between segments, - // because protections are not passed through to this function. - // We cannot use the start address to differentiate between segments, because - // with ASLR, the mapping start address can be any value. - // - // We use a heuristic to compute the minimum mapping size required for a - // segment, assuming mappings are 4k page aligned, and return the segment that - // matches the given mapping size. - const pageSize = 4096 - + // If we have more than one matching segments, try a strict check on the + // segment memory size. We use a heuristic to compute the minimum mapping size + // required for a segment, assuming mappings are page aligned. // The memory size based heuristic makes sense only if the mapping size is a - // multiple of 4k page size. + // multiple of page size. if memsz%pageSize != 0 { - return nil, fmt.Errorf("mapping size = %x and %d segments match the passed in mapping", memsz, len(headers)) + return headers, hasLoadables } - // Return an error if no segment, or multiple segments match the size, so we can debug. + // Return all found headers if we cannot narrow the selection to a single + // program segment. var ph *elf.ProgHeader - pageMask := ^uint64(pageSize - 1) for _, h := range headers { wantSize := (h.Vaddr+h.Memsz+pageSize-1)&pageMask - (h.Vaddr & pageMask) if wantSize != memsz { continue } if ph != nil { - return nil, fmt.Errorf("found second program header (%#v) that matches memsz %x, first program header is %#v", *h, memsz, *ph) + // Found a second program header matching, so return all previously + // identified headers. + return headers, hasLoadables } ph = h } if ph == nil { - return nil, fmt.Errorf("found %d matching program headers, but none matches mapping size %x", len(headers), memsz) + // No matching header for the strict check. Return all previously identified + // headers. + return headers, hasLoadables } - return ph, nil + return []*elf.ProgHeader{ph}, hasLoadables } diff --git a/src/cmd/vendor/github.com/google/pprof/internal/plugin/plugin.go b/src/cmd/vendor/github.com/google/pprof/internal/plugin/plugin.go index 3a8d0af7305..a57a0b20a96 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/plugin/plugin.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/plugin/plugin.go @@ -131,8 +131,9 @@ type ObjFile interface { // Name returns the underlyinf file name, if available Name() string - // Base returns the base address to use when looking up symbols in the file. - Base() uint64 + // ObjAddr returns the objdump (linker) address corresponding to a runtime + // address, and an error. + ObjAddr(addr uint64) (uint64, error) // BuildID returns the GNU build ID of the file, or an empty string. BuildID() string diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/report.go b/src/cmd/vendor/github.com/google/pprof/internal/report/report.go index bc5685d61e1..4a865548801 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/report/report.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/report/report.go @@ -445,7 +445,7 @@ func PrintAssembly(w io.Writer, rpt *Report, obj plugin.ObjTool, maxFuncs int) e return err } - ns := annotateAssembly(insts, sns, s.base) + ns := annotateAssembly(insts, sns, s.file) fmt.Fprintf(w, "ROUTINE ======================== %s\n", s.sym.Name[0]) for _, name := range s.sym.Name[1:] { @@ -534,7 +534,6 @@ func symbolsFromBinaries(prof *profile.Profile, g *graph.Graph, rx *regexp.Regex addr = *address } msyms, err := f.Symbols(rx, addr) - base := f.Base() f.Close() if err != nil { continue @@ -543,7 +542,6 @@ func symbolsFromBinaries(prof *profile.Profile, g *graph.Graph, rx *regexp.Regex objSyms = append(objSyms, &objSymbol{ sym: ms, - base: base, file: f, }, ) @@ -558,7 +556,6 @@ func symbolsFromBinaries(prof *profile.Profile, g *graph.Graph, rx *regexp.Regex // added to correspond to sample addresses type objSymbol struct { sym *plugin.Sym - base uint64 file plugin.ObjFile } @@ -578,8 +575,7 @@ func nodesPerSymbol(ns graph.Nodes, symbols []*objSymbol) map[*objSymbol]graph.N for _, s := range symbols { // Gather samples for this symbol. for _, n := range ns { - address := n.Info.Address - s.base - if address >= s.sym.Start && address < s.sym.End { + if address, err := s.file.ObjAddr(n.Info.Address); err == nil && address >= s.sym.Start && address < s.sym.End { symNodes[s] = append(symNodes[s], n) } } @@ -621,7 +617,7 @@ func (a *assemblyInstruction) cumValue() int64 { // annotateAssembly annotates a set of assembly instructions with a // set of samples. It returns a set of nodes to display. base is an // offset to adjust the sample addresses. -func annotateAssembly(insts []plugin.Inst, samples graph.Nodes, base uint64) []assemblyInstruction { +func annotateAssembly(insts []plugin.Inst, samples graph.Nodes, file plugin.ObjFile) []assemblyInstruction { // Add end marker to simplify printing loop. insts = append(insts, plugin.Inst{ Addr: ^uint64(0), @@ -645,7 +641,10 @@ func annotateAssembly(insts []plugin.Inst, samples graph.Nodes, base uint64) []a // Sum all the samples until the next instruction (to account // for samples attributed to the middle of an instruction). - for next := insts[ix+1].Addr; s < len(samples) && samples[s].Info.Address-base < next; s++ { + for next := insts[ix+1].Addr; s < len(samples); s++ { + if addr, err := file.ObjAddr(samples[s].Info.Address); err != nil || addr >= next { + break + } sample := samples[s] n.flatDiv += sample.FlatDiv n.flat += sample.Flat diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/source.go b/src/cmd/vendor/github.com/google/pprof/internal/report/source.go index 4f841eff5dc..54245e5f9ea 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/report/source.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/report/source.go @@ -132,6 +132,7 @@ func printWebSource(w io.Writer, rpt *Report, obj plugin.ObjTool) error { // sourcePrinter holds state needed for generating source+asm HTML listing. type sourcePrinter struct { reader *sourceReader + synth *synthCode objectTool plugin.ObjTool objects map[string]plugin.ObjFile // Opened object files sym *regexp.Regexp // May be nil @@ -146,6 +147,12 @@ type sourcePrinter struct { prettyNames map[string]string } +// addrInfo holds information for an address we are interested in. +type addrInfo struct { + loc *profile.Location // Always non-nil + obj plugin.ObjFile // May be nil +} + // instructionInfo holds collected information for an instruction. type instructionInfo struct { objAddr uint64 // Address in object file (with base subtracted out) @@ -207,6 +214,7 @@ func PrintWebList(w io.Writer, rpt *Report, obj plugin.ObjTool, maxFiles int) er func newSourcePrinter(rpt *Report, obj plugin.ObjTool, sourcePath string) *sourcePrinter { sp := &sourcePrinter{ reader: newSourceReader(sourcePath, rpt.options.TrimPath), + synth: newSynthCode(rpt.prof.Mapping), objectTool: obj, objects: map[string]plugin.ObjFile{}, sym: rpt.options.Symbol, @@ -225,19 +233,21 @@ func newSourcePrinter(rpt *Report, obj plugin.ObjTool, sourcePath string) *sourc } } - addrs := map[uint64]bool{} + addrs := map[uint64]addrInfo{} flat := map[uint64]int64{} cum := map[uint64]int64{} // Record an interest in the function corresponding to lines[index]. - markInterest := func(addr uint64, lines []profile.Line, index int) { - fn := lines[index] + markInterest := func(addr uint64, loc *profile.Location, index int) { + fn := loc.Line[index] if fn.Function == nil { return } sp.interest[fn.Function.Name] = true sp.interest[fn.Function.SystemName] = true - addrs[addr] = true + if _, ok := addrs[addr]; !ok { + addrs[addr] = addrInfo{loc, sp.objectFile(loc.Mapping)} + } } // See if sp.sym matches line. @@ -270,15 +280,21 @@ func newSourcePrinter(rpt *Report, obj plugin.ObjTool, sourcePath string) *sourc sp.prettyNames[line.Function.SystemName] = line.Function.Name } - cum[loc.Address] += value - if i == 0 { - flat[loc.Address] += value + addr := loc.Address + if addr == 0 { + // Some profiles are missing valid addresses. + addr = sp.synth.address(loc) } - if sp.sym == nil || (address != nil && loc.Address == *address) { + cum[addr] += value + if i == 0 { + flat[addr] += value + } + + if sp.sym == nil || (address != nil && addr == *address) { // Interested in top-level entry of stack. if len(loc.Line) > 0 { - markInterest(loc.Address, loc.Line, len(loc.Line)-1) + markInterest(addr, loc, len(loc.Line)-1) } continue } @@ -287,7 +303,7 @@ func newSourcePrinter(rpt *Report, obj plugin.ObjTool, sourcePath string) *sourc matchFile := (loc.Mapping != nil && sp.sym.MatchString(loc.Mapping.File)) for j, line := range loc.Line { if (j == 0 && matchFile) || matches(line) { - markInterest(loc.Address, loc.Line, j) + markInterest(addr, loc, j) } } } @@ -306,10 +322,11 @@ func (sp *sourcePrinter) close() { } } -func (sp *sourcePrinter) expandAddresses(rpt *Report, addrs map[uint64]bool, flat map[uint64]int64) { +func (sp *sourcePrinter) expandAddresses(rpt *Report, addrs map[uint64]addrInfo, flat map[uint64]int64) { // We found interesting addresses (ones with non-zero samples) above. // Get covering address ranges and disassemble the ranges. - ranges := sp.splitIntoRanges(rpt.prof, addrs, flat) + ranges, unprocessed := sp.splitIntoRanges(rpt.prof, addrs, flat) + sp.handleUnprocessed(addrs, unprocessed) // Trim ranges if there are too many. const maxRanges = 25 @@ -321,9 +338,18 @@ func (sp *sourcePrinter) expandAddresses(rpt *Report, addrs map[uint64]bool, fla } for _, r := range ranges { - base := r.obj.Base() - insts, err := sp.objectTool.Disasm(r.mapping.File, r.begin-base, r.end-base, - rpt.options.IntelSyntax) + objBegin, err := r.obj.ObjAddr(r.begin) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to compute objdump address for range start %x: %v\n", r.begin, err) + continue + } + objEnd, err := r.obj.ObjAddr(r.end) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to compute objdump address for range end %x: %v\n", r.end, err) + continue + } + base := r.begin - objBegin + insts, err := sp.objectTool.Disasm(r.mapping.File, objBegin, objEnd, rpt.options.IntelSyntax) if err != nil { // TODO(sanjay): Report that the covered addresses are missing. continue @@ -385,78 +411,115 @@ func (sp *sourcePrinter) expandAddresses(rpt *Report, addrs map[uint64]bool, fla frames = lastFrames } - // See if the stack contains a function we are interested in. - for i, f := range frames { - if !sp.interest[f.Func] { - continue - } - - // Record sub-stack under frame's file/line. - fname := canonicalizeFileName(f.File) - file := sp.files[fname] - if file == nil { - file = &sourceFile{ - fname: fname, - lines: map[int][]sourceInst{}, - funcName: map[int]string{}, - } - sp.files[fname] = file - } - callees := frames[:i] - stack := make([]callID, 0, len(callees)) - for j := len(callees) - 1; j >= 0; j-- { // Reverse so caller is first - stack = append(stack, callID{ - file: callees[j].File, - line: callees[j].Line, - }) - } - file.lines[f.Line] = append(file.lines[f.Line], sourceInst{addr, stack}) - - // Remember the first function name encountered per source line - // and assume that that line belongs to that function. - if _, ok := file.funcName[f.Line]; !ok { - file.funcName[f.Line] = f.Func - } - } + sp.addStack(addr, frames) } } } -// splitIntoRanges converts the set of addresses we are interested in into a set of address -// ranges to disassemble. -func (sp *sourcePrinter) splitIntoRanges(prof *profile.Profile, set map[uint64]bool, flat map[uint64]int64) []addressRange { - // List of mappings so we can stop expanding address ranges at mapping boundaries. - mappings := append([]*profile.Mapping{}, prof.Mapping...) - sort.Slice(mappings, func(i, j int) bool { return mappings[i].Start < mappings[j].Start }) +func (sp *sourcePrinter) addStack(addr uint64, frames []plugin.Frame) { + // See if the stack contains a function we are interested in. + for i, f := range frames { + if !sp.interest[f.Func] { + continue + } - var result []addressRange - addrs := make([]uint64, 0, len(set)) - for addr := range set { - addrs = append(addrs, addr) + // Record sub-stack under frame's file/line. + fname := canonicalizeFileName(f.File) + file := sp.files[fname] + if file == nil { + file = &sourceFile{ + fname: fname, + lines: map[int][]sourceInst{}, + funcName: map[int]string{}, + } + sp.files[fname] = file + } + callees := frames[:i] + stack := make([]callID, 0, len(callees)) + for j := len(callees) - 1; j >= 0; j-- { // Reverse so caller is first + stack = append(stack, callID{ + file: callees[j].File, + line: callees[j].Line, + }) + } + file.lines[f.Line] = append(file.lines[f.Line], sourceInst{addr, stack}) + + // Remember the first function name encountered per source line + // and assume that that line belongs to that function. + if _, ok := file.funcName[f.Line]; !ok { + file.funcName[f.Line] = f.Func + } + } +} + +// synthAsm is the special disassembler value used for instructions without an object file. +const synthAsm = "" + +// handleUnprocessed handles addresses that were skipped by splitIntoRanges because they +// did not belong to a known object file. +func (sp *sourcePrinter) handleUnprocessed(addrs map[uint64]addrInfo, unprocessed []uint64) { + // makeFrames synthesizes a []plugin.Frame list for the specified address. + // The result will typically have length 1, but may be longer if address corresponds + // to inlined calls. + makeFrames := func(addr uint64) []plugin.Frame { + loc := addrs[addr].loc + stack := make([]plugin.Frame, 0, len(loc.Line)) + for _, line := range loc.Line { + fn := line.Function + if fn == nil { + continue + } + stack = append(stack, plugin.Frame{ + Func: fn.Name, + File: fn.Filename, + Line: int(line.Line), + }) + } + return stack + } + + for _, addr := range unprocessed { + frames := makeFrames(addr) + x := instructionInfo{ + objAddr: addr, + length: 1, + disasm: synthAsm, + } + if len(frames) > 0 { + x.file = frames[0].File + x.line = frames[0].Line + } + sp.insts[addr] = x + + sp.addStack(addr, frames) + } +} + +// splitIntoRanges converts the set of addresses we are interested in into a set of address +// ranges to disassemble. It also returns the set of addresses found that did not have an +// associated object file and were therefore not added to an address range. +func (sp *sourcePrinter) splitIntoRanges(prof *profile.Profile, addrMap map[uint64]addrInfo, flat map[uint64]int64) ([]addressRange, []uint64) { + // Partition addresses into two sets: ones with a known object file, and ones without. + var addrs, unprocessed []uint64 + for addr, info := range addrMap { + if info.obj != nil { + addrs = append(addrs, addr) + } else { + unprocessed = append(unprocessed, addr) + } } sort.Slice(addrs, func(i, j int) bool { return addrs[i] < addrs[j] }) - mappingIndex := 0 const expand = 500 // How much to expand range to pick up nearby addresses. + var result []addressRange for i, n := 0, len(addrs); i < n; { begin, end := addrs[i], addrs[i] sum := flat[begin] i++ - // Advance to mapping containing addrs[i] - for mappingIndex < len(mappings) && mappings[mappingIndex].Limit <= begin { - mappingIndex++ - } - if mappingIndex >= len(mappings) { - // TODO(sanjay): Report missed address and its samples. - break - } - m := mappings[mappingIndex] - obj := sp.objectFile(m) - if obj == nil { - // TODO(sanjay): Report missed address and its samples. - continue - } + info := addrMap[begin] + m := info.loc.Mapping + obj := info.obj // Non-nil because of the partitioning done above. // Find following addresses that are close enough to addrs[i]. for i < n && addrs[i] <= end+2*expand && addrs[i] < m.Limit { @@ -479,7 +542,7 @@ func (sp *sourcePrinter) splitIntoRanges(prof *profile.Profile, set map[uint64]b result = append(result, addressRange{begin, end, obj, m, sum}) } - return result + return result, unprocessed } func (sp *sourcePrinter) initSamples(flat, cum map[uint64]int64) { @@ -665,9 +728,12 @@ func (sp *sourcePrinter) functions(f *sourceFile) []sourceFunction { return funcs } -// objectFile return the object for the named file, opening it if necessary. +// objectFile return the object for the specified mapping, opening it if necessary. // It returns nil on error. func (sp *sourcePrinter) objectFile(m *profile.Mapping) plugin.ObjFile { + if m == nil { + return nil + } if object, ok := sp.objects[m.File]; ok { return object // May be nil if we detected an error earlier. } @@ -725,12 +791,28 @@ func printFunctionSourceLine(w io.Writer, lineNo int, flat, cum int64, lineConte return } + nestedInfo := false + cl := "deadsrc" + for _, an := range assembly { + if len(an.inlineCalls) > 0 || an.instruction != synthAsm { + nestedInfo = true + cl = "livesrc" + } + } + fmt.Fprintf(w, - " %6d %10s %10s %8s %s ", - lineNo, + " %6d %10s %10s %8s %s ", + lineNo, cl, valueOrDot(flat, rpt), valueOrDot(cum, rpt), "", template.HTMLEscapeString(lineContents)) - srcIndent := indentation(lineContents) + if nestedInfo { + srcIndent := indentation(lineContents) + printNested(w, srcIndent, assembly, reader, rpt) + } + fmt.Fprintln(w) +} + +func printNested(w io.Writer, srcIndent int, assembly []assemblyInstruction, reader *sourceReader, rpt *Report) { fmt.Fprint(w, "") var curCalls []callID for i, an := range assembly { @@ -763,6 +845,9 @@ func printFunctionSourceLine(w io.Writer, lineNo int, flat, cum int64, lineConte template.HTMLEscapeString(filepath.Base(c.file)), c.line) } curCalls = an.inlineCalls + if an.instruction == synthAsm { + continue + } text := strings.Repeat(" ", srcIndent+4+4*len(curCalls)) + an.instruction fmt.Fprintf(w, " %8s %10s %10s %8x: %s %s\n", "", valueOrDot(flat, rpt), valueOrDot(cum, rpt), an.address, @@ -772,7 +857,7 @@ func printFunctionSourceLine(w io.Writer, lineNo int, flat, cum int64, lineConte // would cause double-escaping of file name. fileline) } - fmt.Fprintln(w, "") + fmt.Fprint(w, "") } // printFunctionClosing prints the end of a function in a weblist report. diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/source_html.go b/src/cmd/vendor/github.com/google/pprof/internal/report/source_html.go index 26e8bdbba8a..17c9f6eb947 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/report/source_html.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/report/source_html.go @@ -40,14 +40,7 @@ h1 { .inlinesrc { color: #000066; } -.deadsrc { -cursor: pointer; -} -.deadsrc:hover { -background-color: #eeeeee; -} .livesrc { -color: #0000ff; cursor: pointer; } .livesrc:hover { diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/synth.go b/src/cmd/vendor/github.com/google/pprof/internal/report/synth.go new file mode 100644 index 00000000000..7a35bbcda8f --- /dev/null +++ b/src/cmd/vendor/github.com/google/pprof/internal/report/synth.go @@ -0,0 +1,39 @@ +package report + +import ( + "github.com/google/pprof/profile" +) + +// synthCode assigns addresses to locations without an address. +type synthCode struct { + next uint64 + addr map[*profile.Location]uint64 // Synthesized address assigned to a location +} + +func newSynthCode(mappings []*profile.Mapping) *synthCode { + // Find a larger address than any mapping. + s := &synthCode{next: 1} + for _, m := range mappings { + if s.next < m.Limit { + s.next = m.Limit + } + } + return s +} + +// address returns the synthetic address for loc, creating one if needed. +func (s *synthCode) address(loc *profile.Location) uint64 { + if loc.Address != 0 { + panic("can only synthesize addresses for locations without an address") + } + if addr, ok := s.addr[loc]; ok { + return addr + } + if s.addr == nil { + s.addr = map[*profile.Location]uint64{} + } + addr := s.next + s.next++ + s.addr[loc] = addr + return addr +} diff --git a/src/cmd/vendor/github.com/google/pprof/profile/encode.go b/src/cmd/vendor/github.com/google/pprof/profile/encode.go index 1e84c72d43d..ab7f03ae267 100644 --- a/src/cmd/vendor/github.com/google/pprof/profile/encode.go +++ b/src/cmd/vendor/github.com/google/pprof/profile/encode.go @@ -308,7 +308,7 @@ func (p *Profile) postDecode() error { if l.strX != 0 { value, err = getString(p.stringTable, &l.strX, err) labels[key] = append(labels[key], value) - } else if l.numX != 0 { + } else if l.numX != 0 || l.unitX != 0 { numValues := numLabels[key] units := numUnits[key] if l.unitX != 0 { diff --git a/src/cmd/vendor/github.com/google/pprof/profile/merge.go b/src/cmd/vendor/github.com/google/pprof/profile/merge.go index 5ab6e9b9b08..9978e7330e6 100644 --- a/src/cmd/vendor/github.com/google/pprof/profile/merge.go +++ b/src/cmd/vendor/github.com/google/pprof/profile/merge.go @@ -231,7 +231,6 @@ func (pm *profileMerger) mapLocation(src *Location) *Location { } if l, ok := pm.locationsByID[src.ID]; ok { - pm.locationsByID[src.ID] = l return l } diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt index 6b19ec3aea1..5fb1c25acee 100644 --- a/src/cmd/vendor/modules.txt +++ b/src/cmd/vendor/modules.txt @@ -1,4 +1,4 @@ -# github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5 +# github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a ## explicit; go 1.14 github.com/google/pprof/driver github.com/google/pprof/internal/binutils From b38b1b2f9ae710ee2c16a103bb21644f1adbc5d3 Mon Sep 17 00:00:00 2001 From: David Chase Date: Wed, 21 Apr 2021 10:55:42 -0400 Subject: [PATCH 003/940] cmd/compile: manage Slot array better steals idea from CL 312093 further investigation revealed additional duplicate slots (equivalent, but not equal), so delete those too. Rearranged Func.Names to be addresses of slots, create canonical addresses so that split slots (which use those addresses to refer to their parent, and split slots can be further split) will preserve "equivalent slots are equal". Removes duplicates, improves metrics for "args at entry". Change-Id: I5bbdcb50bd33655abcab3d27ad8cdce25499faaf Reviewed-on: https://go-review.googlesource.com/c/go/+/312292 Trust: David Chase Run-TryBot: David Chase TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/cmd/compile/internal/ssa/config.go | 7 - src/cmd/compile/internal/ssa/copyelim.go | 2 +- src/cmd/compile/internal/ssa/deadcode.go | 8 +- src/cmd/compile/internal/ssa/debug.go | 6 +- src/cmd/compile/internal/ssa/decompose.go | 140 ++++++++++++------- src/cmd/compile/internal/ssa/expand_calls.go | 40 +++--- src/cmd/compile/internal/ssa/export_test.go | 30 ---- src/cmd/compile/internal/ssa/func.go | 110 ++++++++++++++- src/cmd/compile/internal/ssa/layout.go | 22 +-- src/cmd/compile/internal/ssa/print.go | 2 +- src/cmd/compile/internal/ssa/stackalloc.go | 11 +- src/cmd/compile/internal/ssagen/ssa.go | 80 +---------- 12 files changed, 238 insertions(+), 220 deletions(-) diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index 4ffa047096b..a8393a19995 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -147,13 +147,6 @@ type Frontend interface { // Given the name for a compound type, returns the name we should use // for the parts of that compound type. - SplitString(LocalSlot) (LocalSlot, LocalSlot) - SplitInterface(LocalSlot) (LocalSlot, LocalSlot) - SplitSlice(LocalSlot) (LocalSlot, LocalSlot, LocalSlot) - SplitComplex(LocalSlot) (LocalSlot, LocalSlot) - SplitStruct(LocalSlot, int) LocalSlot - SplitArray(LocalSlot) LocalSlot // array must be length 1 - SplitInt64(LocalSlot) (LocalSlot, LocalSlot) // returns (hi, lo) SplitSlot(parent *LocalSlot, suffix string, offset int64, t *types.Type) LocalSlot // DerefItab dereferences an itab function diff --git a/src/cmd/compile/internal/ssa/copyelim.go b/src/cmd/compile/internal/ssa/copyelim.go index 5954d3bec8e..17f65127ee0 100644 --- a/src/cmd/compile/internal/ssa/copyelim.go +++ b/src/cmd/compile/internal/ssa/copyelim.go @@ -26,7 +26,7 @@ func copyelim(f *Func) { // Update named values. for _, name := range f.Names { - values := f.NamedValues[name] + values := f.NamedValues[*name] for i, v := range values { if v.Op == OpCopy { values[i] = v.Args[0] diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index 96b552ecf3b..5d10dfe025e 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -223,7 +223,7 @@ func deadcode(f *Func) { for _, name := range f.Names { j := 0 s.clear() - values := f.NamedValues[name] + values := f.NamedValues[*name] for _, v := range values { if live[v.ID] && !s.contains(v.ID) { values[j] = v @@ -232,19 +232,19 @@ func deadcode(f *Func) { } } if j == 0 { - delete(f.NamedValues, name) + delete(f.NamedValues, *name) } else { f.Names[i] = name i++ for k := len(values) - 1; k >= j; k-- { values[k] = nil } - f.NamedValues[name] = values[:j] + f.NamedValues[*name] = values[:j] } } clearNames := f.Names[i:] for j := range clearNames { - clearNames[j] = LocalSlot{} + clearNames[j] = nil } f.Names = f.Names[:i] diff --git a/src/cmd/compile/internal/ssa/debug.go b/src/cmd/compile/internal/ssa/debug.go index 0ca435e5157..a2c2a2d98e8 100644 --- a/src/cmd/compile/internal/ssa/debug.go +++ b/src/cmd/compile/internal/ssa/debug.go @@ -367,12 +367,12 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu state.slots = state.slots[:0] state.vars = state.vars[:0] for i, slot := range f.Names { - state.slots = append(state.slots, slot) + state.slots = append(state.slots, *slot) if ir.IsSynthetic(slot.N) { continue } - topSlot := &slot + topSlot := slot for topSlot.SplitOf != nil { topSlot = topSlot.SplitOf } @@ -436,7 +436,7 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu if ir.IsSynthetic(slot.N) { continue } - for _, value := range f.NamedValues[slot] { + for _, value := range f.NamedValues[*slot] { state.valueNames[value.ID] = append(state.valueNames[value.ID], SlotID(i)) } } diff --git a/src/cmd/compile/internal/ssa/decompose.go b/src/cmd/compile/internal/ssa/decompose.go index ba48b6b3b96..753d69cebcd 100644 --- a/src/cmd/compile/internal/ssa/decompose.go +++ b/src/cmd/compile/internal/ssa/decompose.go @@ -36,64 +36,65 @@ func decomposeBuiltIn(f *Func) { // accumulate new LocalSlots in newNames for addition after the iteration. This decomposition is for // builtin types with leaf components, and thus there is no need to reprocess the newly create LocalSlots. var toDelete []namedVal - var newNames []LocalSlot + var newNames []*LocalSlot for i, name := range f.Names { t := name.Type switch { case t.IsInteger() && t.Size() > f.Config.RegSize: - hiName, loName := f.fe.SplitInt64(name) - newNames = append(newNames, hiName, loName) - for j, v := range f.NamedValues[name] { + hiName, loName := f.SplitInt64(name) + newNames = maybeAppend2(f, newNames, hiName, loName) + for j, v := range f.NamedValues[*name] { if v.Op != OpInt64Make { continue } - f.NamedValues[hiName] = append(f.NamedValues[hiName], v.Args[0]) - f.NamedValues[loName] = append(f.NamedValues[loName], v.Args[1]) + f.NamedValues[*hiName] = append(f.NamedValues[*hiName], v.Args[0]) + f.NamedValues[*loName] = append(f.NamedValues[*loName], v.Args[1]) toDelete = append(toDelete, namedVal{i, j}) } case t.IsComplex(): - rName, iName := f.fe.SplitComplex(name) - newNames = append(newNames, rName, iName) - for j, v := range f.NamedValues[name] { + rName, iName := f.SplitComplex(name) + newNames = maybeAppend2(f, newNames, rName, iName) + for j, v := range f.NamedValues[*name] { if v.Op != OpComplexMake { continue } - f.NamedValues[rName] = append(f.NamedValues[rName], v.Args[0]) - f.NamedValues[iName] = append(f.NamedValues[iName], v.Args[1]) + f.NamedValues[*rName] = append(f.NamedValues[*rName], v.Args[0]) + f.NamedValues[*iName] = append(f.NamedValues[*iName], v.Args[1]) toDelete = append(toDelete, namedVal{i, j}) } case t.IsString(): - ptrName, lenName := f.fe.SplitString(name) - newNames = append(newNames, ptrName, lenName) - for j, v := range f.NamedValues[name] { + ptrName, lenName := f.SplitString(name) + newNames = maybeAppend2(f, newNames, ptrName, lenName) + for j, v := range f.NamedValues[*name] { if v.Op != OpStringMake { continue } - f.NamedValues[ptrName] = append(f.NamedValues[ptrName], v.Args[0]) - f.NamedValues[lenName] = append(f.NamedValues[lenName], v.Args[1]) + f.NamedValues[*ptrName] = append(f.NamedValues[*ptrName], v.Args[0]) + f.NamedValues[*lenName] = append(f.NamedValues[*lenName], v.Args[1]) toDelete = append(toDelete, namedVal{i, j}) } case t.IsSlice(): - ptrName, lenName, capName := f.fe.SplitSlice(name) - newNames = append(newNames, ptrName, lenName, capName) - for j, v := range f.NamedValues[name] { + ptrName, lenName, capName := f.SplitSlice(name) + newNames = maybeAppend2(f, newNames, ptrName, lenName) + newNames = maybeAppend(f, newNames, capName) + for j, v := range f.NamedValues[*name] { if v.Op != OpSliceMake { continue } - f.NamedValues[ptrName] = append(f.NamedValues[ptrName], v.Args[0]) - f.NamedValues[lenName] = append(f.NamedValues[lenName], v.Args[1]) - f.NamedValues[capName] = append(f.NamedValues[capName], v.Args[2]) + f.NamedValues[*ptrName] = append(f.NamedValues[*ptrName], v.Args[0]) + f.NamedValues[*lenName] = append(f.NamedValues[*lenName], v.Args[1]) + f.NamedValues[*capName] = append(f.NamedValues[*capName], v.Args[2]) toDelete = append(toDelete, namedVal{i, j}) } case t.IsInterface(): - typeName, dataName := f.fe.SplitInterface(name) - newNames = append(newNames, typeName, dataName) - for j, v := range f.NamedValues[name] { + typeName, dataName := f.SplitInterface(name) + newNames = maybeAppend2(f, newNames, typeName, dataName) + for j, v := range f.NamedValues[*name] { if v.Op != OpIMake { continue } - f.NamedValues[typeName] = append(f.NamedValues[typeName], v.Args[0]) - f.NamedValues[dataName] = append(f.NamedValues[dataName], v.Args[1]) + f.NamedValues[*typeName] = append(f.NamedValues[*typeName], v.Args[0]) + f.NamedValues[*dataName] = append(f.NamedValues[*dataName], v.Args[1]) toDelete = append(toDelete, namedVal{i, j}) } case t.IsFloat(): @@ -107,6 +108,18 @@ func decomposeBuiltIn(f *Func) { f.Names = append(f.Names, newNames...) } +func maybeAppend(f *Func, ss []*LocalSlot, s *LocalSlot) []*LocalSlot { + if _, ok := f.NamedValues[*s]; !ok { + f.NamedValues[*s] = nil + return append(ss, s) + } + return ss +} + +func maybeAppend2(f *Func, ss []*LocalSlot, s1, s2 *LocalSlot) []*LocalSlot { + return maybeAppend(f, maybeAppend(f, ss, s1), s2) +} + func decomposeBuiltInPhi(v *Value) { switch { case v.Type.IsInteger() && v.Type.Size() > v.Block.Func.Config.RegSize: @@ -230,7 +243,7 @@ func decomposeUser(f *Func) { } // Split up named values into their components. i := 0 - var newNames []LocalSlot + var newNames []*LocalSlot for _, name := range f.Names { t := name.Type switch { @@ -250,7 +263,7 @@ func decomposeUser(f *Func) { // decomposeUserArrayInto creates names for the element(s) of arrays referenced // by name where possible, and appends those new names to slots, which is then // returned. -func decomposeUserArrayInto(f *Func, name LocalSlot, slots []LocalSlot) []LocalSlot { +func decomposeUserArrayInto(f *Func, name *LocalSlot, slots []*LocalSlot) []*LocalSlot { t := name.Type if t.NumElem() == 0 { // TODO(khr): Not sure what to do here. Probably nothing. @@ -261,20 +274,20 @@ func decomposeUserArrayInto(f *Func, name LocalSlot, slots []LocalSlot) []LocalS // shouldn't get here due to CanSSA f.Fatalf("array not of size 1") } - elemName := f.fe.SplitArray(name) + elemName := f.SplitArray(name) var keep []*Value - for _, v := range f.NamedValues[name] { + for _, v := range f.NamedValues[*name] { if v.Op != OpArrayMake1 { keep = append(keep, v) continue } - f.NamedValues[elemName] = append(f.NamedValues[elemName], v.Args[0]) + f.NamedValues[*elemName] = append(f.NamedValues[*elemName], v.Args[0]) } if len(keep) == 0 { // delete the name for the array as a whole - delete(f.NamedValues, name) + delete(f.NamedValues, *name) } else { - f.NamedValues[name] = keep + f.NamedValues[*name] = keep } if t.Elem().IsArray() { @@ -289,38 +302,38 @@ func decomposeUserArrayInto(f *Func, name LocalSlot, slots []LocalSlot) []LocalS // decomposeUserStructInto creates names for the fields(s) of structs referenced // by name where possible, and appends those new names to slots, which is then // returned. -func decomposeUserStructInto(f *Func, name LocalSlot, slots []LocalSlot) []LocalSlot { - fnames := []LocalSlot{} // slots for struct in name +func decomposeUserStructInto(f *Func, name *LocalSlot, slots []*LocalSlot) []*LocalSlot { + fnames := []*LocalSlot{} // slots for struct in name t := name.Type n := t.NumFields() for i := 0; i < n; i++ { - fs := f.fe.SplitStruct(name, i) + fs := f.SplitStruct(name, i) fnames = append(fnames, fs) // arrays and structs will be decomposed further, so // there's no need to record a name if !fs.Type.IsArray() && !fs.Type.IsStruct() { - slots = append(slots, fs) + slots = maybeAppend(f, slots, fs) } } makeOp := StructMakeOp(n) var keep []*Value // create named values for each struct field - for _, v := range f.NamedValues[name] { + for _, v := range f.NamedValues[*name] { if v.Op != makeOp { keep = append(keep, v) continue } for i := 0; i < len(fnames); i++ { - f.NamedValues[fnames[i]] = append(f.NamedValues[fnames[i]], v.Args[i]) + f.NamedValues[*fnames[i]] = append(f.NamedValues[*fnames[i]], v.Args[i]) } } if len(keep) == 0 { // delete the name for the struct as a whole - delete(f.NamedValues, name) + delete(f.NamedValues, *name) } else { - f.NamedValues[name] = keep + f.NamedValues[*name] = keep } // now that this f.NamedValues contains values for the struct @@ -328,10 +341,10 @@ func decomposeUserStructInto(f *Func, name LocalSlot, slots []LocalSlot) []Local for i := 0; i < n; i++ { if name.Type.FieldType(i).IsStruct() { slots = decomposeUserStructInto(f, fnames[i], slots) - delete(f.NamedValues, fnames[i]) + delete(f.NamedValues, *fnames[i]) } else if name.Type.FieldType(i).IsArray() { slots = decomposeUserArrayInto(f, fnames[i], slots) - delete(f.NamedValues, fnames[i]) + delete(f.NamedValues, *fnames[i]) } } return slots @@ -416,9 +429,10 @@ type namedVal struct { locIndex, valIndex int // f.NamedValues[f.Names[locIndex]][valIndex] = key } -// deleteNamedVals removes particular values with debugger names from f's naming data structures +// deleteNamedVals removes particular values with debugger names from f's naming data structures, +// removes all values with OpInvalid, and re-sorts the list of Names. func deleteNamedVals(f *Func, toDelete []namedVal) { - // Arrange to delete from larger indices to smaller, to ensure swap-with-end deletion does not invalid pending indices. + // Arrange to delete from larger indices to smaller, to ensure swap-with-end deletion does not invalidate pending indices. sort.Slice(toDelete, func(i, j int) bool { if toDelete[i].locIndex != toDelete[j].locIndex { return toDelete[i].locIndex > toDelete[j].locIndex @@ -430,16 +444,36 @@ func deleteNamedVals(f *Func, toDelete []namedVal) { // Get rid of obsolete names for _, d := range toDelete { loc := f.Names[d.locIndex] - vals := f.NamedValues[loc] + vals := f.NamedValues[*loc] l := len(vals) - 1 if l > 0 { vals[d.valIndex] = vals[l] - f.NamedValues[loc] = vals[:l] - } else { - delete(f.NamedValues, loc) - l = len(f.Names) - 1 - f.Names[d.locIndex] = f.Names[l] - f.Names = f.Names[:l] + } + vals[l] = nil + f.NamedValues[*loc] = vals[:l] + } + // Delete locations with no values attached. + end := len(f.Names) + for i := len(f.Names) - 1; i >= 0; i-- { + loc := f.Names[i] + vals := f.NamedValues[*loc] + last := len(vals) + for j := len(vals) - 1; j >= 0; j-- { + if vals[j].Op == OpInvalid { + last-- + vals[j] = vals[last] + vals[last] = nil + } + } + if last < len(vals) { + f.NamedValues[*loc] = vals[:last] + } + if len(vals) == 0 { + delete(f.NamedValues, *loc) + end-- + f.Names[i] = f.Names[end] + f.Names[end] = nil } } + f.Names = f.Names[:end] } diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index 2852753beeb..d37d06f8e71 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -243,10 +243,10 @@ func (x *expandState) offsetFrom(b *Block, from *Value, offset int64, pt *types. } // splitSlots splits one "field" (specified by sfx, offset, and ty) out of the LocalSlots in ls and returns the new LocalSlots this generates. -func (x *expandState) splitSlots(ls []LocalSlot, sfx string, offset int64, ty *types.Type) []LocalSlot { - var locs []LocalSlot +func (x *expandState) splitSlots(ls []*LocalSlot, sfx string, offset int64, ty *types.Type) []*LocalSlot { + var locs []*LocalSlot for i := range ls { - locs = append(locs, x.f.fe.SplitSlot(&ls[i], sfx, offset, ty)) + locs = append(locs, x.f.SplitSlot(ls[i], sfx, offset, ty)) } return locs } @@ -301,13 +301,13 @@ func (x *expandState) Printf(format string, a ...interface{}) (n int, err error) // It emits the code necessary to implement the leaf select operation that leads to the root. // // TODO when registers really arrive, must also decompose anything split across two registers or registers and memory. -func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, regOffset Abi1RO) []LocalSlot { +func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, regOffset Abi1RO) []*LocalSlot { if x.debug { x.indent(3) defer x.indent(-3) x.Printf("rewriteSelect(%s; %s; memOff=%d; regOff=%d)\n", leaf.LongString(), selector.LongString(), offset, regOffset) } - var locs []LocalSlot + var locs []*LocalSlot leafType := leaf.Type if len(selector.Args) > 0 { w := selector.Args[0] @@ -477,7 +477,7 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, case OpStructSelect: w := selector.Args[0] - var ls []LocalSlot + var ls []*LocalSlot if w.Type.Kind() != types.TSTRUCT { // IData artifact ls = x.rewriteSelect(leaf, w, offset, regOffset) } else { @@ -485,7 +485,7 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, ls = x.rewriteSelect(leaf, w, offset+w.Type.FieldOff(fldi), regOffset+x.regOffset(w.Type, fldi)) if w.Op != OpIData { for _, l := range ls { - locs = append(locs, x.f.fe.SplitStruct(l, int(selector.AuxInt))) + locs = append(locs, x.f.SplitStruct(l, int(selector.AuxInt))) } } } @@ -662,7 +662,7 @@ outer: func (x *expandState) decomposeArg(pos src.XPos, b *Block, source, mem *Value, t *types.Type, storeOffset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { pa := x.prAssignForArg(source) - var locs []LocalSlot + var locs []*LocalSlot for _, s := range x.namedSelects[source] { locs = append(locs, x.f.Names[s.locIndex]) } @@ -756,12 +756,15 @@ func (x *expandState) decomposeArg(pos src.XPos, b *Block, source, mem *Value, t return nil } -func (x *expandState) splitSlotsIntoNames(locs []LocalSlot, suffix string, off int64, rt *types.Type, w *Value) { +func (x *expandState) splitSlotsIntoNames(locs []*LocalSlot, suffix string, off int64, rt *types.Type, w *Value) { wlocs := x.splitSlots(locs, suffix, off, rt) for _, l := range wlocs { - x.f.NamedValues[l] = append(x.f.NamedValues[l], w) + old, ok := x.f.NamedValues[*l] + x.f.NamedValues[*l] = append(old, w) + if !ok { + x.f.Names = append(x.f.Names, l) + } } - x.f.Names = append(x.f.Names, wlocs...) } // decomposeLoad is a helper for storeArgOrLoad. @@ -826,7 +829,7 @@ func (x *expandState) decomposeLoad(pos src.XPos, b *Block, source, mem *Value, // storeOneArg creates a decomposed (one step) arg that is then stored. // pos and b locate the store instruction, source is the "base" of the value input, // mem is the input mem, t is the type in question, and offArg and offStore are the offsets from the respective bases. -func storeOneArg(x *expandState, pos src.XPos, b *Block, locs []LocalSlot, suffix string, source, mem *Value, t *types.Type, argOffset, storeOffset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { +func storeOneArg(x *expandState, pos src.XPos, b *Block, locs []*LocalSlot, suffix string, source, mem *Value, t *types.Type, argOffset, storeOffset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { if x.debug { x.indent(3) defer x.indent(-3) @@ -848,7 +851,7 @@ func storeOneLoad(x *expandState, pos src.XPos, b *Block, source, mem *Value, t return x.storeArgOrLoad(pos, b, w, mem, t, offStore, loadRegOffset, storeRc) } -func storeTwoArg(x *expandState, pos src.XPos, b *Block, locs []LocalSlot, suffix1 string, suffix2 string, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { +func storeTwoArg(x *expandState, pos src.XPos, b *Block, locs []*LocalSlot, suffix1 string, suffix2 string, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { mem = storeOneArg(x, pos, b, locs, suffix1, source, mem, t1, offArg, offStore, loadRegOffset, storeRc.next(t1)) pos = pos.WithNotStmt() t1Size := t1.Size() @@ -1168,7 +1171,7 @@ func expandCalls(f *Func) { for i, name := range f.Names { t := name.Type if x.isAlreadyExpandedAggregateType(t) { - for j, v := range f.NamedValues[name] { + for j, v := range f.NamedValues[*name] { if v.Op == OpSelectN || v.Op == OpArg && x.isAlreadyExpandedAggregateType(v.Type) { ns := x.namedSelects[v] x.namedSelects[v] = append(ns, namedVal{locIndex: i, valIndex: j}) @@ -1477,10 +1480,10 @@ func expandCalls(f *Func) { // Leaf types may have debug locations if !x.isAlreadyExpandedAggregateType(v.Type) { for _, l := range locs { - if _, ok := f.NamedValues[l]; !ok { + if _, ok := f.NamedValues[*l]; !ok { f.Names = append(f.Names, l) } - f.NamedValues[l] = append(f.NamedValues[l], v) + f.NamedValues[*l] = append(f.NamedValues[*l], v) } continue } @@ -1553,7 +1556,7 @@ func expandCalls(f *Func) { // Step 6: elide any copies introduced. // Update named values. for _, name := range f.Names { - values := f.NamedValues[name] + values := f.NamedValues[*name] for i, v := range values { if v.Op == OpCopy { a := v.Args[0] @@ -1725,7 +1728,8 @@ func (x *expandState) newArgToMemOrRegs(baseArg, toReplace *Value, offset int64, loc := LocalSlot{N: aux.Name, Type: t, Off: 0} values, ok := x.f.NamedValues[loc] if !ok { - x.f.Names = append(x.f.Names, loc) + ploc := x.f.localSlotAddr(loc) + x.f.Names = append(x.f.Names, ploc) } x.f.NamedValues[loc] = append(values, w) } diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go index 32e6d09d1bc..8ed8a0c4a6e 100644 --- a/src/cmd/compile/internal/ssa/export_test.go +++ b/src/cmd/compile/internal/ssa/export_test.go @@ -73,36 +73,6 @@ func (TestFrontend) Auto(pos src.XPos, t *types.Type) *ir.Name { n.Class = ir.PAUTO return n } -func (d TestFrontend) SplitString(s LocalSlot) (LocalSlot, LocalSlot) { - return LocalSlot{N: s.N, Type: testTypes.BytePtr, Off: s.Off}, LocalSlot{N: s.N, Type: testTypes.Int, Off: s.Off + 8} -} -func (d TestFrontend) SplitInterface(s LocalSlot) (LocalSlot, LocalSlot) { - return LocalSlot{N: s.N, Type: testTypes.BytePtr, Off: s.Off}, LocalSlot{N: s.N, Type: testTypes.BytePtr, Off: s.Off + 8} -} -func (d TestFrontend) SplitSlice(s LocalSlot) (LocalSlot, LocalSlot, LocalSlot) { - return LocalSlot{N: s.N, Type: s.Type.Elem().PtrTo(), Off: s.Off}, - LocalSlot{N: s.N, Type: testTypes.Int, Off: s.Off + 8}, - LocalSlot{N: s.N, Type: testTypes.Int, Off: s.Off + 16} -} -func (d TestFrontend) SplitComplex(s LocalSlot) (LocalSlot, LocalSlot) { - if s.Type.Size() == 16 { - return LocalSlot{N: s.N, Type: testTypes.Float64, Off: s.Off}, LocalSlot{N: s.N, Type: testTypes.Float64, Off: s.Off + 8} - } - return LocalSlot{N: s.N, Type: testTypes.Float32, Off: s.Off}, LocalSlot{N: s.N, Type: testTypes.Float32, Off: s.Off + 4} -} -func (d TestFrontend) SplitInt64(s LocalSlot) (LocalSlot, LocalSlot) { - if s.Type.IsSigned() { - return LocalSlot{N: s.N, Type: testTypes.Int32, Off: s.Off + 4}, LocalSlot{N: s.N, Type: testTypes.UInt32, Off: s.Off} - } - return LocalSlot{N: s.N, Type: testTypes.UInt32, Off: s.Off + 4}, LocalSlot{N: s.N, Type: testTypes.UInt32, Off: s.Off} -} -func (d TestFrontend) SplitStruct(s LocalSlot, i int) LocalSlot { - return LocalSlot{N: s.N, Type: s.Type.FieldType(i), Off: s.Off + s.Type.FieldOff(i)} -} -func (d TestFrontend) SplitArray(s LocalSlot) LocalSlot { - return LocalSlot{N: s.N, Type: s.Type.Elem(), Off: s.Off} -} - func (d TestFrontend) SplitSlot(parent *LocalSlot, suffix string, offset int64, t *types.Type) LocalSlot { return LocalSlot{N: parent.N, Type: t, Off: offset} } diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index 378a73a95ac..fac876c23eb 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -6,6 +6,7 @@ package ssa import ( "cmd/compile/internal/abi" + "cmd/compile/internal/base" "cmd/compile/internal/types" "cmd/internal/src" "crypto/sha1" @@ -61,7 +62,11 @@ type Func struct { NamedValues map[LocalSlot][]*Value // Names is a copy of NamedValues.Keys. We keep a separate list // of keys to make iteration order deterministic. - Names []LocalSlot + Names []*LocalSlot + // Canonicalize root/top-level local slots, and canonicalize their pieces. + // Because LocalSlot pieces refer to their parents with a pointer, this ensures that equivalent slots really are equal. + CanonicalLocalSlots map[LocalSlot]*LocalSlot + CanonicalLocalSplits map[LocalSlotSplitKey]*LocalSlot // RegArgs is a slice of register-memory pairs that must be spilled and unspilled in the uncommon path of function entry. RegArgs []Spill @@ -87,10 +92,16 @@ type Func struct { constants map[int64][]*Value // constants cache, keyed by constant value; users must check value's Op and Type } +type LocalSlotSplitKey struct { + parent *LocalSlot + Off int64 // offset of slot in N + Type *types.Type // type of slot +} + // NewFunc returns a new, empty function object. // Caller must set f.Config and f.Cache before using f. func NewFunc(fe Frontend) *Func { - return &Func{fe: fe, NamedValues: make(map[LocalSlot][]*Value)} + return &Func{fe: fe, NamedValues: make(map[LocalSlot][]*Value), CanonicalLocalSlots: make(map[LocalSlot]*LocalSlot), CanonicalLocalSplits: make(map[LocalSlotSplitKey]*LocalSlot)} } // NumBlocks returns an integer larger than the id of any Block in the Func. @@ -193,6 +204,101 @@ func (f *Func) retDeadcodeLiveOrderStmts(liveOrderStmts []*Value) { f.Cache.deadcode.liveOrderStmts = liveOrderStmts } +func (f *Func) localSlotAddr(slot LocalSlot) *LocalSlot { + a, ok := f.CanonicalLocalSlots[slot] + if !ok { + a = new(LocalSlot) + *a = slot // don't escape slot + f.CanonicalLocalSlots[slot] = a + } + return a +} + +func (f *Func) SplitString(name *LocalSlot) (*LocalSlot, *LocalSlot) { + ptrType := types.NewPtr(types.Types[types.TUINT8]) + lenType := types.Types[types.TINT] + // Split this string up into two separate variables. + p := f.SplitSlot(name, ".ptr", 0, ptrType) + l := f.SplitSlot(name, ".len", ptrType.Size(), lenType) + return p, l +} + +func (f *Func) SplitInterface(name *LocalSlot) (*LocalSlot, *LocalSlot) { + n := name.N + u := types.Types[types.TUINTPTR] + t := types.NewPtr(types.Types[types.TUINT8]) + // Split this interface up into two separate variables. + sfx := ".itab" + if n.Type().IsEmptyInterface() { + sfx = ".type" + } + c := f.SplitSlot(name, sfx, 0, u) // see comment in typebits.Set + d := f.SplitSlot(name, ".data", u.Size(), t) + return c, d +} + +func (f *Func) SplitSlice(name *LocalSlot) (*LocalSlot, *LocalSlot, *LocalSlot) { + ptrType := types.NewPtr(name.Type.Elem()) + lenType := types.Types[types.TINT] + p := f.SplitSlot(name, ".ptr", 0, ptrType) + l := f.SplitSlot(name, ".len", ptrType.Size(), lenType) + c := f.SplitSlot(name, ".cap", ptrType.Size()+lenType.Size(), lenType) + return p, l, c +} + +func (f *Func) SplitComplex(name *LocalSlot) (*LocalSlot, *LocalSlot) { + s := name.Type.Size() / 2 + var t *types.Type + if s == 8 { + t = types.Types[types.TFLOAT64] + } else { + t = types.Types[types.TFLOAT32] + } + r := f.SplitSlot(name, ".real", 0, t) + i := f.SplitSlot(name, ".imag", t.Size(), t) + return r, i +} + +func (f *Func) SplitInt64(name *LocalSlot) (*LocalSlot, *LocalSlot) { + var t *types.Type + if name.Type.IsSigned() { + t = types.Types[types.TINT32] + } else { + t = types.Types[types.TUINT32] + } + if f.Config.BigEndian { + return f.SplitSlot(name, ".hi", 0, t), f.SplitSlot(name, ".lo", t.Size(), types.Types[types.TUINT32]) + } + return f.SplitSlot(name, ".hi", t.Size(), t), f.SplitSlot(name, ".lo", 0, types.Types[types.TUINT32]) +} + +func (f *Func) SplitStruct(name *LocalSlot, i int) *LocalSlot { + st := name.Type + return f.SplitSlot(name, st.FieldName(i), st.FieldOff(i), st.FieldType(i)) +} +func (f *Func) SplitArray(name *LocalSlot) *LocalSlot { + n := name.N + at := name.Type + if at.NumElem() != 1 { + base.FatalfAt(n.Pos(), "bad array size") + } + et := at.Elem() + return f.SplitSlot(name, "[0]", 0, et) +} + +func (f *Func) SplitSlot(name *LocalSlot, sfx string, offset int64, t *types.Type) *LocalSlot { + lssk := LocalSlotSplitKey{name, offset, t} + if als, ok := f.CanonicalLocalSplits[lssk]; ok { + return als + } + // Note: the _ field may appear several times. But + // have no fear, identically-named but distinct Autos are + // ok, albeit maybe confusing for a debugger. + ls := f.fe.SplitSlot(name, sfx, offset, t) + f.CanonicalLocalSplits[lssk] = &ls + return &ls +} + // newValue allocates a new Value with the given fields and places it at the end of b.Values. func (f *Func) newValue(op Op, t *types.Type, b *Block, pos src.XPos) *Value { var v *Value diff --git a/src/cmd/compile/internal/ssa/layout.go b/src/cmd/compile/internal/ssa/layout.go index a7fd73aead1..6abdb0d0c92 100644 --- a/src/cmd/compile/internal/ssa/layout.go +++ b/src/cmd/compile/internal/ssa/layout.go @@ -12,26 +12,10 @@ func layout(f *Func) { } // Register allocation may use a different order which has constraints -// imposed by the linear-scan algorithm. Note that f.pass here is -// regalloc, so the switch is conditional on -d=ssa/regalloc/test=N +// imposed by the linear-scan algorithm. func layoutRegallocOrder(f *Func) []*Block { - - switch f.pass.test { - case 0: // layout order - return layoutOrder(f) - case 1: // existing block order - return f.Blocks - case 2: // reverse of postorder; legal, but usually not good. - po := f.postorder() - visitOrder := make([]*Block, len(po)) - for i, b := range po { - j := len(po) - i - 1 - visitOrder[j] = b - } - return visitOrder - } - - return nil + // remnant of an experiment; perhaps there will be another. + return layoutOrder(f) } func layoutOrder(f *Func) []*Block { diff --git a/src/cmd/compile/internal/ssa/print.go b/src/cmd/compile/internal/ssa/print.go index 36f09c3ad97..d917183c70f 100644 --- a/src/cmd/compile/internal/ssa/print.go +++ b/src/cmd/compile/internal/ssa/print.go @@ -154,6 +154,6 @@ func fprintFunc(p funcPrinter, f *Func) { p.endBlock(b) } for _, name := range f.Names { - p.named(name, f.NamedValues[name]) + p.named(*name, f.NamedValues[*name]) } } diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go index d9625791226..d41f3996af7 100644 --- a/src/cmd/compile/internal/ssa/stackalloc.go +++ b/src/cmd/compile/internal/ssa/stackalloc.go @@ -141,10 +141,11 @@ func (s *stackAllocState) stackalloc() { s.names = make([]LocalSlot, n) } names := s.names + empty := LocalSlot{} for _, name := range f.Names { // Note: not "range f.NamedValues" above, because // that would be nondeterministic. - for _, v := range f.NamedValues[name] { + for _, v := range f.NamedValues[*name] { if v.Op == OpArgIntReg || v.Op == OpArgFloatReg { aux := v.Aux.(*AuxNameOffset) // Never let an arg be bound to a differently named thing. @@ -162,10 +163,12 @@ func (s *stackAllocState) stackalloc() { continue } - if f.pass.debug > stackDebug { - fmt.Printf("stackalloc value %s to name %s\n", v, name) + if names[v.ID] == empty { + if f.pass.debug > stackDebug { + fmt.Printf("stackalloc value %s to name %s\n", v, *name) + } + names[v.ID] = *name } - names[v.ID] = name } } diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 2abd70169e6..004e084f728 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -8,7 +8,6 @@ import ( "bufio" "bytes" "cmd/compile/internal/abi" - "encoding/binary" "fmt" "go/constant" "html" @@ -6463,7 +6462,8 @@ func (s *state) addNamedValue(n *ir.Name, v *ssa.Value) { loc := ssa.LocalSlot{N: n, Type: n.Type(), Off: 0} values, ok := s.f.NamedValues[loc] if !ok { - s.f.Names = append(s.f.Names, loc) + s.f.Names = append(s.f.Names, &loc) + s.f.CanonicalLocalSlots[loc] = &loc } s.f.NamedValues[loc] = append(values, v) } @@ -7552,82 +7552,6 @@ func (e *ssafn) Auto(pos src.XPos, t *types.Type) *ir.Name { return typecheck.TempAt(pos, e.curfn, t) // Note: adds new auto to e.curfn.Func.Dcl list } -func (e *ssafn) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) { - ptrType := types.NewPtr(types.Types[types.TUINT8]) - lenType := types.Types[types.TINT] - // Split this string up into two separate variables. - p := e.SplitSlot(&name, ".ptr", 0, ptrType) - l := e.SplitSlot(&name, ".len", ptrType.Size(), lenType) - return p, l -} - -func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) { - n := name.N - u := types.Types[types.TUINTPTR] - t := types.NewPtr(types.Types[types.TUINT8]) - // Split this interface up into two separate variables. - f := ".itab" - if n.Type().IsEmptyInterface() { - f = ".type" - } - c := e.SplitSlot(&name, f, 0, u) // see comment in typebits.Set - d := e.SplitSlot(&name, ".data", u.Size(), t) - return c, d -} - -func (e *ssafn) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ssa.LocalSlot) { - ptrType := types.NewPtr(name.Type.Elem()) - lenType := types.Types[types.TINT] - p := e.SplitSlot(&name, ".ptr", 0, ptrType) - l := e.SplitSlot(&name, ".len", ptrType.Size(), lenType) - c := e.SplitSlot(&name, ".cap", ptrType.Size()+lenType.Size(), lenType) - return p, l, c -} - -func (e *ssafn) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) { - s := name.Type.Size() / 2 - var t *types.Type - if s == 8 { - t = types.Types[types.TFLOAT64] - } else { - t = types.Types[types.TFLOAT32] - } - r := e.SplitSlot(&name, ".real", 0, t) - i := e.SplitSlot(&name, ".imag", t.Size(), t) - return r, i -} - -func (e *ssafn) SplitInt64(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) { - var t *types.Type - if name.Type.IsSigned() { - t = types.Types[types.TINT32] - } else { - t = types.Types[types.TUINT32] - } - if Arch.LinkArch.ByteOrder == binary.BigEndian { - return e.SplitSlot(&name, ".hi", 0, t), e.SplitSlot(&name, ".lo", t.Size(), types.Types[types.TUINT32]) - } - return e.SplitSlot(&name, ".hi", t.Size(), t), e.SplitSlot(&name, ".lo", 0, types.Types[types.TUINT32]) -} - -func (e *ssafn) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot { - st := name.Type - // Note: the _ field may appear several times. But - // have no fear, identically-named but distinct Autos are - // ok, albeit maybe confusing for a debugger. - return e.SplitSlot(&name, "."+st.FieldName(i), st.FieldOff(i), st.FieldType(i)) -} - -func (e *ssafn) SplitArray(name ssa.LocalSlot) ssa.LocalSlot { - n := name.N - at := name.Type - if at.NumElem() != 1 { - e.Fatalf(n.Pos(), "bad array size") - } - et := at.Elem() - return e.SplitSlot(&name, "[0]", 0, et) -} - func (e *ssafn) DerefItab(it *obj.LSym, offset int64) *obj.LSym { return reflectdata.ITabSym(it, offset) } From ec4efa42089415b0427a4d30b317cfd7e4a0fe75 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Thu, 19 Mar 2020 17:59:45 -0400 Subject: [PATCH 004/940] crypto/x509: check the private key passed to CreateCertificate Unfortunately, we can't improve the function signature to refer to crypto.PrivateKey and crypto.PublicKey, even if they are both interface{}, because it would break assignments to function types. Fixes #37845 Change-Id: I627f2ac1e1ba98b128dac5382f9cc2524eaef378 Reviewed-on: https://go-review.googlesource.com/c/go/+/224157 Run-TryBot: Filippo Valsorda TryBot-Result: Go Bot Trust: Filippo Valsorda Reviewed-by: Katie Hockman --- src/crypto/x509/x509.go | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go index ff37b361d75..4304ab54e1a 100644 --- a/src/crypto/x509/x509.go +++ b/src/crypto/x509/x509.go @@ -1413,8 +1413,8 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgori // just an empty SEQUENCE. var emptyASN1Subject = []byte{0x30, 0} -// CreateCertificate creates a new X.509v3 certificate based on a template. -// The following members of template are used: +// CreateCertificate creates a new X.509 v3 certificate based on a template. +// The following members of template are currently used: // // - AuthorityKeyId // - BasicConstraintsValid @@ -1451,7 +1451,7 @@ var emptyASN1Subject = []byte{0x30, 0} // // The certificate is signed by parent. If parent is equal to template then the // certificate is self-signed. The parameter pub is the public key of the -// signee and priv is the private key of the signer. +// certificate to be generated and priv is the private key of the signer. // // The returned slice is the certificate in DER encoding. // @@ -1465,7 +1465,7 @@ var emptyASN1Subject = []byte{0x30, 0} // // If SubjectKeyId from template is empty and the template is a CA, SubjectKeyId // will be generated from the hash of the public key. -func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv interface{}) (cert []byte, err error) { +func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv interface{}) ([]byte, error) { key, ok := priv.(crypto.Signer) if !ok { return nil, errors.New("x509: certificate private key does not implement crypto.Signer") @@ -1491,12 +1491,12 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv asn1Issuer, err := subjectBytes(parent) if err != nil { - return + return nil, err } asn1Subject, err := subjectBytes(template) if err != nil { - return + return nil, err } authorityKeyId := template.AuthorityKeyId @@ -1514,9 +1514,19 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv subjectKeyId = h[:] } + // Check that the signer's public key matches the private key, if available. + type privateKey interface { + Equal(crypto.PublicKey) bool + } + if privPub, ok := key.Public().(privateKey); !ok { + return nil, errors.New("x509: internal error: supported public key does not implement Equal") + } else if parent.PublicKey != nil && !privPub.Equal(parent.PublicKey) { + return nil, errors.New("x509: provided PrivateKey doesn't match parent's PublicKey") + } + extensions, err := buildCertExtensions(template, bytes.Equal(asn1Subject, emptyASN1Subject), authorityKeyId, subjectKeyId) if err != nil { - return + return nil, err } encodedPublicKey := asn1.BitString{BitLength: len(publicKeyBytes) * 8, Bytes: publicKeyBytes} @@ -1533,7 +1543,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv tbsCertContents, err := asn1.Marshal(c) if err != nil { - return + return nil, err } c.Raw = tbsCertContents @@ -1555,7 +1565,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv var signature []byte signature, err = key.Sign(rand, signed, signerOpts) if err != nil { - return + return nil, err } signedCert, err := asn1.Marshal(certificate{ From 14c3d2aa596147bd90da298a4b2a70660786c682 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Fri, 30 Apr 2021 17:05:54 -0400 Subject: [PATCH 005/940] crypto/elliptic: import fiat-crypto P-521 field implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fiat Cryptography (https://github.com/mit-plv/fiat-crypto) is a project that produces prime order field implementations (the code that does arithmetic modulo a prime number) based on a formally verified model. The formal verification covers some of the most subtle and hard to test parts of an elliptic curve implementation, like carry chains. It would probably have prevented #20040 and #43786. This CL imports a 64-bit implementation of the P-521 base field, replacing the horribly slow and catastrophically variable time big.Int CurveParams implementation. The code in p521_fiat64.go is generated reproducibly by fiat-crypto, building and running the Dockerfile according to the README. The code in fiat/p521.go is a thin and idiomatic wrapper around the fiat-crypto code. It includes an Invert method generated with the help of github.com/mmcloughlin/addchain. The code in elliptic/p521.go is a line-by-line port of the CurveParams implementation. Lsh(x, N) was replaced with repeated Add(x, x) calls. Mul(x, x) was replaced with Square(x). Mod calls were removed, as all operations are modulo P. Likewise, Add calls to bring values back to positive were removed. The ScalarMult ladder implementation is now constant time, copied from p224ScalarMult. Only other notable changes are adding a p512Point type to keep (x, y, z) together, and making addJacobian and doubleJacobian methods on that type, with the usual receiver semantics to save 4 allocations per step. This amounts to a proof of concept, and is far from a mature elliptic curve implementation. Here's a non-exhaustive list of things that need improvement, most of which are pre-existing issues with crypto/elliptic. Some of these can be fixed without API change, so can't. - Marshal and Unmarshal still use the slow, variable time big.Int arithmetic. The Curve interface does not expose field operations, so we'll have to make our own abstraction. - Point addition uses an incomplete Jacobian formula, which has variable time behaviors for points at infinity and equal points. There are better, complete formulae these days, but I wanted to keep this CL reviewable against the existing code. - The scalar multiplication ladder is still heavily variable time. This is easy to fix and I'll do it in a follow-up CL, but I wanted to keep this one easier to review. - Fundamentally, values have to go in and out of big.Int representation when they pass through the Curve interface, which is both slow and slightly variable-time. - There is no scalar field implementation, so crypto/ecdsa ends up using big.Int for signing. - Extending this to P-384 would involve either duplicating all P-521 code, or coming up with some lower-level interfaces for the base field. Even better, generics, which would maybe let us save heap allocations due to virtual calls. - The readability and idiomaticity of the autogenerated code can improve, although we have a clear abstraction and well-enforced contract, which makes it unlikely we'll have to resort to manually modifying the code. See mit-plv/fiat-crypto#949. - We could also have a 32-bit implementation, since it's almost free to have fiat-crypto generate one. Anyway, it's definitely better than CurveParams, and definitely faster. name old time/op new time/op delta pkg:crypto/elliptic goos:darwin goarch:arm64 ScalarBaseMult/P521-8 4.18ms ± 3% 0.86ms ± 2% -79.50% (p=0.000 n=10+9) ScalarMult/P521-8 4.17ms ± 2% 0.85ms ± 6% -79.68% (p=0.000 n=10+10) pkg:crypto/ecdsa goos:darwin goarch:arm64 Sign/P521-8 4.23ms ± 1% 0.94ms ± 0% -77.70% (p=0.000 n=9+8) Verify/P521-8 8.31ms ± 2% 1.75ms ± 4% -78.99% (p=0.000 n=9+10) GenerateKey/P521-8 4.15ms ± 2% 0.85ms ± 2% -79.49% (p=0.000 n=10+9) name old alloc/op new alloc/op delta pkg:crypto/elliptic goos:darwin goarch:arm64 ScalarBaseMult/P521-8 3.06MB ± 3% 0.00MB ± 0% -99.97% (p=0.000 n=10+10) ScalarMult/P521-8 3.05MB ± 1% 0.00MB ± 0% -99.97% (p=0.000 n=9+10) pkg:crypto/ecdsa goos:darwin goarch:arm64 Sign/P521-8 3.03MB ± 0% 0.01MB ± 0% -99.74% (p=0.000 n=10+8) Verify/P521-8 6.06MB ± 1% 0.00MB ± 0% -99.93% (p=0.000 n=9+9) GenerateKey/P521-8 3.02MB ± 0% 0.00MB ± 0% -99.96% (p=0.000 n=9+10) name old allocs/op new allocs/op delta pkg:crypto/elliptic goos:darwin goarch:arm64 ScalarBaseMult/P521-8 19.8k ± 3% 0.0k ± 0% -99.95% (p=0.000 n=10+10) ScalarMult/P521-8 19.7k ± 1% 0.0k ± 0% -99.95% (p=0.000 n=9+10) pkg:crypto/ecdsa goos:darwin goarch:arm64 Sign/P521-8 19.6k ± 0% 0.1k ± 0% -99.63% (p=0.000 n=10+10) Verify/P521-8 39.2k ± 1% 0.1k ± 0% -99.84% (p=0.000 n=9+10) GenerateKey/P521-8 19.5k ± 0% 0.0k ± 0% -99.91% (p=0.000 n=9+10) Updates #40171 Change-Id: Ic898b09a2388382bf51ec007d9a79d72d44efe10 Reviewed-on: https://go-review.googlesource.com/c/go/+/315271 Run-TryBot: Filippo Valsorda TryBot-Result: Go Bot Reviewed-by: Katie Hockman Trust: Katie Hockman Trust: Filippo Valsorda --- src/crypto/elliptic/elliptic.go | 12 - src/crypto/elliptic/internal/fiat/Dockerfile | 12 + src/crypto/elliptic/internal/fiat/README | 39 + src/crypto/elliptic/internal/fiat/p521.go | 197 ++ .../elliptic/internal/fiat/p521_fiat64.go | 1856 +++++++++++++++++ .../elliptic/internal/fiat/p521_test.go | 37 + src/crypto/elliptic/p521.go | 254 +++ src/go/build/deps_test.go | 1 + 8 files changed, 2396 insertions(+), 12 deletions(-) create mode 100644 src/crypto/elliptic/internal/fiat/Dockerfile create mode 100644 src/crypto/elliptic/internal/fiat/README create mode 100644 src/crypto/elliptic/internal/fiat/p521.go create mode 100644 src/crypto/elliptic/internal/fiat/p521_fiat64.go create mode 100644 src/crypto/elliptic/internal/fiat/p521_test.go create mode 100644 src/crypto/elliptic/p521.go diff --git a/src/crypto/elliptic/elliptic.go b/src/crypto/elliptic/elliptic.go index f93dc16419f..85d105419b4 100644 --- a/src/crypto/elliptic/elliptic.go +++ b/src/crypto/elliptic/elliptic.go @@ -390,7 +390,6 @@ func UnmarshalCompressed(curve Curve, data []byte) (x, y *big.Int) { var initonce sync.Once var p384 *CurveParams -var p521 *CurveParams func initAll() { initP224() @@ -410,17 +409,6 @@ func initP384() { p384.BitSize = 384 } -func initP521() { - // See FIPS 186-3, section D.2.5 - p521 = &CurveParams{Name: "P-521"} - p521.P, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", 10) - p521.N, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449", 10) - p521.B, _ = new(big.Int).SetString("051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", 16) - p521.Gx, _ = new(big.Int).SetString("c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", 16) - p521.Gy, _ = new(big.Int).SetString("11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650", 16) - p521.BitSize = 521 -} - // P256 returns a Curve which implements NIST P-256 (FIPS 186-3, section D.2.3), // also known as secp256r1 or prime256v1. The CurveParams.Name of this Curve is // "P-256". diff --git a/src/crypto/elliptic/internal/fiat/Dockerfile b/src/crypto/elliptic/internal/fiat/Dockerfile new file mode 100644 index 00000000000..7b5ece0e30f --- /dev/null +++ b/src/crypto/elliptic/internal/fiat/Dockerfile @@ -0,0 +1,12 @@ +# Copyright 2021 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. + +FROM coqorg/coq:8.13.2 + +RUN git clone https://github.com/mit-plv/fiat-crypto +RUN cd fiat-crypto && git checkout c076f3550bea2bb7f4cb5766a32594b9e67694f2 +RUN cd fiat-crypto && git submodule update --init --recursive +RUN cd fiat-crypto && eval $(opam env) && make -j4 standalone-ocaml SKIP_BEDROCK2=1 + +ENTRYPOINT ["fiat-crypto/src/ExtractionOCaml/unsaturated_solinas"] diff --git a/src/crypto/elliptic/internal/fiat/README b/src/crypto/elliptic/internal/fiat/README new file mode 100644 index 00000000000..171f57a3274 --- /dev/null +++ b/src/crypto/elliptic/internal/fiat/README @@ -0,0 +1,39 @@ +The code in this package was autogenerated by the fiat-crypto project +at commit c076f3550 from a formally verified model. + + docker build -t fiat-crypto:c076f3550 . + docker run fiat-crypto:c076f3550 --lang Go --no-wide-int --cmovznz-by-mul \ + --internal-static --public-function-case camelCase --public-type-case camelCase \ + --private-function-case camelCase --private-type-case camelCase \ + --no-prefix-fiat --package-name fiat --doc-text-before-function-name '' \ + --doc-prepend-header 'Code generated by Fiat Cryptography. DO NOT EDIT.' \ + --doc-newline-before-package-declaration p521 64 9 '2^521 - 1' \ + carry_mul carry_square carry add sub to_bytes from_bytes selectznz \ + > p521_fiat64.go + +It comes under the following license. + + Copyright (c) 2015-2020 The fiat-crypto Authors. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, + Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The authors are listed at + + https://github.com/mit-plv/fiat-crypto/blob/master/AUTHORS diff --git a/src/crypto/elliptic/internal/fiat/p521.go b/src/crypto/elliptic/internal/fiat/p521.go new file mode 100644 index 00000000000..dc677327e6d --- /dev/null +++ b/src/crypto/elliptic/internal/fiat/p521.go @@ -0,0 +1,197 @@ +// Copyright 2021 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 fiat implements prime order fields using formally verified algorithms +// from the Fiat Cryptography project. +package fiat + +import ( + "crypto/subtle" + "errors" +) + +// P521Element is an integer modulo 2^521 - 1. +// +// The zero value is a valid zero element. +type P521Element struct { + // This element has the following bounds, which are tighter than + // the output bounds of some operations. Those operations must be + // followed by a carry. + // + // [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], + // [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], + // [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x200000000000000] + x [9]uint64 +} + +// One sets e = 1, and returns e. +func (e *P521Element) One() *P521Element { + *e = P521Element{} + e.x[0] = 1 + return e +} + +// Equal returns 1 if e == t, and zero otherwise. +func (e *P521Element) Equal(t *P521Element) int { + eBytes := e.Bytes() + tBytes := t.Bytes() + return subtle.ConstantTimeCompare(eBytes, tBytes) +} + +var p521ZeroEncoding = new(P521Element).Bytes() + +// IsZero returns 1 if e == 0, and zero otherwise. +func (e *P521Element) IsZero() int { + eBytes := e.Bytes() + return subtle.ConstantTimeCompare(eBytes, p521ZeroEncoding) +} + +// Set sets e = t, and returns e. +func (e *P521Element) Set(t *P521Element) *P521Element { + e.x = t.x + return e +} + +// Bytes returns the 66-byte little-endian encoding of e. +func (e *P521Element) Bytes() []byte { + // This function must be inlined to move the allocation to the parent and + // save it from escaping to the heap. + var out [66]byte + p521ToBytes(&out, &e.x) + return out[:] +} + +// SetBytes sets e = v, where v is a little-endian 66-byte encoding, and returns +// e. If v is not 66 bytes or it encodes a value higher than 2^521 - 1, SetBytes +// returns nil and an error, and e is unchanged. +func (e *P521Element) SetBytes(v []byte) (*P521Element, error) { + if len(v) != 66 || v[65] > 1 { + return nil, errors.New("invalid P-521 field encoding") + } + var in [66]byte + copy(in[:], v) + p521FromBytes(&e.x, &in) + return e, nil +} + +// Add sets e = t1 + t2, and returns e. +func (e *P521Element) Add(t1, t2 *P521Element) *P521Element { + p521Add(&e.x, &t1.x, &t2.x) + p521Carry(&e.x, &e.x) + return e +} + +// Sub sets e = t1 - t2, and returns e. +func (e *P521Element) Sub(t1, t2 *P521Element) *P521Element { + p521Sub(&e.x, &t1.x, &t2.x) + p521Carry(&e.x, &e.x) + return e +} + +// Mul sets e = t1 * t2, and returns e. +func (e *P521Element) Mul(t1, t2 *P521Element) *P521Element { + p521CarryMul(&e.x, &t1.x, &t2.x) + return e +} + +// Square sets e = t * t, and returns e. +func (e *P521Element) Square(t *P521Element) *P521Element { + p521CarrySquare(&e.x, &t.x) + return e +} + +// Select sets e to a if cond == 1, and to b if cond == 0. +func (v *P521Element) Select(a, b *P521Element, cond int) *P521Element { + p521Selectznz(&v.x, p521Uint1(cond), &b.x, &a.x) + return v +} + +// Invert sets e = 1/t, and returns e. +// +// If t == 0, Invert returns e = 0. +func (e *P521Element) Invert(t *P521Element) *P521Element { + // Inversion is implemented as exponentiation with exponent p − 2. + // The sequence of multiplications and squarings was generated with + // github.com/mmcloughlin/addchain v0.2.0. + + var t1, t2 = new(P521Element), new(P521Element) + + // _10 = 2 * 1 + t1.Square(t) + + // _11 = 1 + _10 + t1.Mul(t, t1) + + // _1100 = _11 << 2 + t2.Square(t1) + t2.Square(t2) + + // _1111 = _11 + _1100 + t1.Mul(t1, t2) + + // _11110000 = _1111 << 4 + t2.Square(t1) + for i := 0; i < 3; i++ { + t2.Square(t2) + } + + // _11111111 = _1111 + _11110000 + t1.Mul(t1, t2) + + // x16 = _11111111<<8 + _11111111 + t2.Square(t1) + for i := 0; i < 7; i++ { + t2.Square(t2) + } + t1.Mul(t1, t2) + + // x32 = x16<<16 + x16 + t2.Square(t1) + for i := 0; i < 15; i++ { + t2.Square(t2) + } + t1.Mul(t1, t2) + + // x64 = x32<<32 + x32 + t2.Square(t1) + for i := 0; i < 31; i++ { + t2.Square(t2) + } + t1.Mul(t1, t2) + + // x65 = 2*x64 + 1 + t2.Square(t1) + t2.Mul(t2, t) + + // x129 = x65<<64 + x64 + for i := 0; i < 64; i++ { + t2.Square(t2) + } + t1.Mul(t1, t2) + + // x130 = 2*x129 + 1 + t2.Square(t1) + t2.Mul(t2, t) + + // x259 = x130<<129 + x129 + for i := 0; i < 129; i++ { + t2.Square(t2) + } + t1.Mul(t1, t2) + + // x260 = 2*x259 + 1 + t2.Square(t1) + t2.Mul(t2, t) + + // x519 = x260<<259 + x259 + for i := 0; i < 259; i++ { + t2.Square(t2) + } + t1.Mul(t1, t2) + + // return x519<<2 + 1 + t1.Square(t1) + t1.Square(t1) + return e.Mul(t1, t) +} diff --git a/src/crypto/elliptic/internal/fiat/p521_fiat64.go b/src/crypto/elliptic/internal/fiat/p521_fiat64.go new file mode 100644 index 00000000000..f86283b587e --- /dev/null +++ b/src/crypto/elliptic/internal/fiat/p521_fiat64.go @@ -0,0 +1,1856 @@ +// Code generated by Fiat Cryptography. DO NOT EDIT. +// +// Autogenerated: 'fiat-crypto/src/ExtractionOCaml/unsaturated_solinas' --lang Go --no-wide-int --cmovznz-by-mul --internal-static --public-function-case camelCase --public-type-case camelCase --private-function-case camelCase --private-type-case camelCase --no-prefix-fiat --package-name fiat --doc-text-before-function-name '' --doc-prepend-header 'Code generated by Fiat Cryptography. DO NOT EDIT.' --doc-newline-before-package-declaration p521 64 9 '2^521 - 1' carry_mul carry_square carry add sub to_bytes from_bytes selectznz +// +// curve description: p521 +// +// machine_wordsize = 64 (from "64") +// +// requested operations: carry_mul, carry_square, carry, add, sub, to_bytes, from_bytes, selectznz +// +// n = 9 (from "9") +// +// s-c = 2^521 - [(1, 1)] (from "2^521 - 1") +// +// tight_bounds_multiplier = 1 (from "") +// +// +// +// Computed values: +// +// carry_chain = [0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1] +// +// eval z = z[0] + (z[1] << 58) + (z[2] << 116) + (z[3] << 174) + (z[4] << 232) + (z[5] << 0x122) + (z[6] << 0x15c) + (z[7] << 0x196) + (z[8] << 0x1d0) +// +// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248) + (z[32] << 256) + (z[33] << 0x108) + (z[34] << 0x110) + (z[35] << 0x118) + (z[36] << 0x120) + (z[37] << 0x128) + (z[38] << 0x130) + (z[39] << 0x138) + (z[40] << 0x140) + (z[41] << 0x148) + (z[42] << 0x150) + (z[43] << 0x158) + (z[44] << 0x160) + (z[45] << 0x168) + (z[46] << 0x170) + (z[47] << 0x178) + (z[48] << 0x180) + (z[49] << 0x188) + (z[50] << 0x190) + (z[51] << 0x198) + (z[52] << 0x1a0) + (z[53] << 0x1a8) + (z[54] << 0x1b0) + (z[55] << 0x1b8) + (z[56] << 0x1c0) + (z[57] << 0x1c8) + (z[58] << 0x1d0) + (z[59] << 0x1d8) + (z[60] << 0x1e0) + (z[61] << 0x1e8) + (z[62] << 0x1f0) + (z[63] << 0x1f8) + (z[64] << 2^9) + (z[65] << 0x208) +// +// balance = [0x7fffffffffffffe, 0x7fffffffffffffe, 0x7fffffffffffffe, 0x7fffffffffffffe, 0x7fffffffffffffe, 0x7fffffffffffffe, 0x7fffffffffffffe, 0x7fffffffffffffe, 0x3fffffffffffffe] + +package fiat + +import "math/bits" + +type p521Uint1 uint8 +type p521Int1 int8 + +// p521AddcarryxU64 is a thin wrapper around bits.Add64 that uses p521Uint1 rather than uint64 +func p521AddcarryxU64(x uint64, y uint64, carry p521Uint1) (uint64, p521Uint1) { + sum, carryOut := bits.Add64(x, y, uint64(carry)) + return sum, p521Uint1(carryOut) +} + +// p521SubborrowxU64 is a thin wrapper around bits.Sub64 that uses p521Uint1 rather than uint64 +func p521SubborrowxU64(x uint64, y uint64, carry p521Uint1) (uint64, p521Uint1) { + sum, carryOut := bits.Sub64(x, y, uint64(carry)) + return sum, p521Uint1(carryOut) +} + +// p521AddcarryxU58 is an addition with carry. +// +// Postconditions: +// out1 = (arg1 + arg2 + arg3) mod 2^58 +// out2 = ⌊(arg1 + arg2 + arg3) / 2^58⌋ +// +// Input Bounds: +// arg1: [0x0 ~> 0x1] +// arg2: [0x0 ~> 0x3ffffffffffffff] +// arg3: [0x0 ~> 0x3ffffffffffffff] +// Output Bounds: +// out1: [0x0 ~> 0x3ffffffffffffff] +// out2: [0x0 ~> 0x1] +func p521AddcarryxU58(out1 *uint64, out2 *p521Uint1, arg1 p521Uint1, arg2 uint64, arg3 uint64) { + x1 := ((uint64(arg1) + arg2) + arg3) + x2 := (x1 & 0x3ffffffffffffff) + x3 := p521Uint1((x1 >> 58)) + *out1 = x2 + *out2 = x3 +} + +// p521SubborrowxU58 is a subtraction with borrow. +// +// Postconditions: +// out1 = (-arg1 + arg2 + -arg3) mod 2^58 +// out2 = -⌊(-arg1 + arg2 + -arg3) / 2^58⌋ +// +// Input Bounds: +// arg1: [0x0 ~> 0x1] +// arg2: [0x0 ~> 0x3ffffffffffffff] +// arg3: [0x0 ~> 0x3ffffffffffffff] +// Output Bounds: +// out1: [0x0 ~> 0x3ffffffffffffff] +// out2: [0x0 ~> 0x1] +func p521SubborrowxU58(out1 *uint64, out2 *p521Uint1, arg1 p521Uint1, arg2 uint64, arg3 uint64) { + x1 := ((int64(arg2) - int64(arg1)) - int64(arg3)) + x2 := p521Int1((x1 >> 58)) + x3 := (uint64(x1) & 0x3ffffffffffffff) + *out1 = x3 + *out2 = (0x0 - p521Uint1(x2)) +} + +// p521AddcarryxU57 is an addition with carry. +// +// Postconditions: +// out1 = (arg1 + arg2 + arg3) mod 2^57 +// out2 = ⌊(arg1 + arg2 + arg3) / 2^57⌋ +// +// Input Bounds: +// arg1: [0x0 ~> 0x1] +// arg2: [0x0 ~> 0x1ffffffffffffff] +// arg3: [0x0 ~> 0x1ffffffffffffff] +// Output Bounds: +// out1: [0x0 ~> 0x1ffffffffffffff] +// out2: [0x0 ~> 0x1] +func p521AddcarryxU57(out1 *uint64, out2 *p521Uint1, arg1 p521Uint1, arg2 uint64, arg3 uint64) { + x1 := ((uint64(arg1) + arg2) + arg3) + x2 := (x1 & 0x1ffffffffffffff) + x3 := p521Uint1((x1 >> 57)) + *out1 = x2 + *out2 = x3 +} + +// p521SubborrowxU57 is a subtraction with borrow. +// +// Postconditions: +// out1 = (-arg1 + arg2 + -arg3) mod 2^57 +// out2 = -⌊(-arg1 + arg2 + -arg3) / 2^57⌋ +// +// Input Bounds: +// arg1: [0x0 ~> 0x1] +// arg2: [0x0 ~> 0x1ffffffffffffff] +// arg3: [0x0 ~> 0x1ffffffffffffff] +// Output Bounds: +// out1: [0x0 ~> 0x1ffffffffffffff] +// out2: [0x0 ~> 0x1] +func p521SubborrowxU57(out1 *uint64, out2 *p521Uint1, arg1 p521Uint1, arg2 uint64, arg3 uint64) { + x1 := ((int64(arg2) - int64(arg1)) - int64(arg3)) + x2 := p521Int1((x1 >> 57)) + x3 := (uint64(x1) & 0x1ffffffffffffff) + *out1 = x3 + *out2 = (0x0 - p521Uint1(x2)) +} + +// p521CmovznzU64 is a single-word conditional move. +// +// Postconditions: +// out1 = (if arg1 = 0 then arg2 else arg3) +// +// Input Bounds: +// arg1: [0x0 ~> 0x1] +// arg2: [0x0 ~> 0xffffffffffffffff] +// arg3: [0x0 ~> 0xffffffffffffffff] +// Output Bounds: +// out1: [0x0 ~> 0xffffffffffffffff] +func p521CmovznzU64(out1 *uint64, arg1 p521Uint1, arg2 uint64, arg3 uint64) { + x1 := (uint64(arg1) * 0xffffffffffffffff) + x2 := ((x1 & arg3) | ((^x1) & arg2)) + *out1 = x2 +} + +// p521CarryMul multiplies two field elements and reduces the result. +// +// Postconditions: +// eval out1 mod m = (eval arg1 * eval arg2) mod m +// +// Input Bounds: +// arg1: [[0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0x600000000000000]] +// arg2: [[0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0x600000000000000]] +// Output Bounds: +// out1: [[0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x200000000000000]] +func p521CarryMul(out1 *[9]uint64, arg1 *[9]uint64, arg2 *[9]uint64) { + var x1 uint64 + var x2 uint64 + x2, x1 = bits.Mul64(arg1[8], (arg2[8] * 0x2)) + var x3 uint64 + var x4 uint64 + x4, x3 = bits.Mul64(arg1[8], (arg2[7] * 0x2)) + var x5 uint64 + var x6 uint64 + x6, x5 = bits.Mul64(arg1[8], (arg2[6] * 0x2)) + var x7 uint64 + var x8 uint64 + x8, x7 = bits.Mul64(arg1[8], (arg2[5] * 0x2)) + var x9 uint64 + var x10 uint64 + x10, x9 = bits.Mul64(arg1[8], (arg2[4] * 0x2)) + var x11 uint64 + var x12 uint64 + x12, x11 = bits.Mul64(arg1[8], (arg2[3] * 0x2)) + var x13 uint64 + var x14 uint64 + x14, x13 = bits.Mul64(arg1[8], (arg2[2] * 0x2)) + var x15 uint64 + var x16 uint64 + x16, x15 = bits.Mul64(arg1[8], (arg2[1] * 0x2)) + var x17 uint64 + var x18 uint64 + x18, x17 = bits.Mul64(arg1[7], (arg2[8] * 0x2)) + var x19 uint64 + var x20 uint64 + x20, x19 = bits.Mul64(arg1[7], (arg2[7] * 0x2)) + var x21 uint64 + var x22 uint64 + x22, x21 = bits.Mul64(arg1[7], (arg2[6] * 0x2)) + var x23 uint64 + var x24 uint64 + x24, x23 = bits.Mul64(arg1[7], (arg2[5] * 0x2)) + var x25 uint64 + var x26 uint64 + x26, x25 = bits.Mul64(arg1[7], (arg2[4] * 0x2)) + var x27 uint64 + var x28 uint64 + x28, x27 = bits.Mul64(arg1[7], (arg2[3] * 0x2)) + var x29 uint64 + var x30 uint64 + x30, x29 = bits.Mul64(arg1[7], (arg2[2] * 0x2)) + var x31 uint64 + var x32 uint64 + x32, x31 = bits.Mul64(arg1[6], (arg2[8] * 0x2)) + var x33 uint64 + var x34 uint64 + x34, x33 = bits.Mul64(arg1[6], (arg2[7] * 0x2)) + var x35 uint64 + var x36 uint64 + x36, x35 = bits.Mul64(arg1[6], (arg2[6] * 0x2)) + var x37 uint64 + var x38 uint64 + x38, x37 = bits.Mul64(arg1[6], (arg2[5] * 0x2)) + var x39 uint64 + var x40 uint64 + x40, x39 = bits.Mul64(arg1[6], (arg2[4] * 0x2)) + var x41 uint64 + var x42 uint64 + x42, x41 = bits.Mul64(arg1[6], (arg2[3] * 0x2)) + var x43 uint64 + var x44 uint64 + x44, x43 = bits.Mul64(arg1[5], (arg2[8] * 0x2)) + var x45 uint64 + var x46 uint64 + x46, x45 = bits.Mul64(arg1[5], (arg2[7] * 0x2)) + var x47 uint64 + var x48 uint64 + x48, x47 = bits.Mul64(arg1[5], (arg2[6] * 0x2)) + var x49 uint64 + var x50 uint64 + x50, x49 = bits.Mul64(arg1[5], (arg2[5] * 0x2)) + var x51 uint64 + var x52 uint64 + x52, x51 = bits.Mul64(arg1[5], (arg2[4] * 0x2)) + var x53 uint64 + var x54 uint64 + x54, x53 = bits.Mul64(arg1[4], (arg2[8] * 0x2)) + var x55 uint64 + var x56 uint64 + x56, x55 = bits.Mul64(arg1[4], (arg2[7] * 0x2)) + var x57 uint64 + var x58 uint64 + x58, x57 = bits.Mul64(arg1[4], (arg2[6] * 0x2)) + var x59 uint64 + var x60 uint64 + x60, x59 = bits.Mul64(arg1[4], (arg2[5] * 0x2)) + var x61 uint64 + var x62 uint64 + x62, x61 = bits.Mul64(arg1[3], (arg2[8] * 0x2)) + var x63 uint64 + var x64 uint64 + x64, x63 = bits.Mul64(arg1[3], (arg2[7] * 0x2)) + var x65 uint64 + var x66 uint64 + x66, x65 = bits.Mul64(arg1[3], (arg2[6] * 0x2)) + var x67 uint64 + var x68 uint64 + x68, x67 = bits.Mul64(arg1[2], (arg2[8] * 0x2)) + var x69 uint64 + var x70 uint64 + x70, x69 = bits.Mul64(arg1[2], (arg2[7] * 0x2)) + var x71 uint64 + var x72 uint64 + x72, x71 = bits.Mul64(arg1[1], (arg2[8] * 0x2)) + var x73 uint64 + var x74 uint64 + x74, x73 = bits.Mul64(arg1[8], arg2[0]) + var x75 uint64 + var x76 uint64 + x76, x75 = bits.Mul64(arg1[7], arg2[1]) + var x77 uint64 + var x78 uint64 + x78, x77 = bits.Mul64(arg1[7], arg2[0]) + var x79 uint64 + var x80 uint64 + x80, x79 = bits.Mul64(arg1[6], arg2[2]) + var x81 uint64 + var x82 uint64 + x82, x81 = bits.Mul64(arg1[6], arg2[1]) + var x83 uint64 + var x84 uint64 + x84, x83 = bits.Mul64(arg1[6], arg2[0]) + var x85 uint64 + var x86 uint64 + x86, x85 = bits.Mul64(arg1[5], arg2[3]) + var x87 uint64 + var x88 uint64 + x88, x87 = bits.Mul64(arg1[5], arg2[2]) + var x89 uint64 + var x90 uint64 + x90, x89 = bits.Mul64(arg1[5], arg2[1]) + var x91 uint64 + var x92 uint64 + x92, x91 = bits.Mul64(arg1[5], arg2[0]) + var x93 uint64 + var x94 uint64 + x94, x93 = bits.Mul64(arg1[4], arg2[4]) + var x95 uint64 + var x96 uint64 + x96, x95 = bits.Mul64(arg1[4], arg2[3]) + var x97 uint64 + var x98 uint64 + x98, x97 = bits.Mul64(arg1[4], arg2[2]) + var x99 uint64 + var x100 uint64 + x100, x99 = bits.Mul64(arg1[4], arg2[1]) + var x101 uint64 + var x102 uint64 + x102, x101 = bits.Mul64(arg1[4], arg2[0]) + var x103 uint64 + var x104 uint64 + x104, x103 = bits.Mul64(arg1[3], arg2[5]) + var x105 uint64 + var x106 uint64 + x106, x105 = bits.Mul64(arg1[3], arg2[4]) + var x107 uint64 + var x108 uint64 + x108, x107 = bits.Mul64(arg1[3], arg2[3]) + var x109 uint64 + var x110 uint64 + x110, x109 = bits.Mul64(arg1[3], arg2[2]) + var x111 uint64 + var x112 uint64 + x112, x111 = bits.Mul64(arg1[3], arg2[1]) + var x113 uint64 + var x114 uint64 + x114, x113 = bits.Mul64(arg1[3], arg2[0]) + var x115 uint64 + var x116 uint64 + x116, x115 = bits.Mul64(arg1[2], arg2[6]) + var x117 uint64 + var x118 uint64 + x118, x117 = bits.Mul64(arg1[2], arg2[5]) + var x119 uint64 + var x120 uint64 + x120, x119 = bits.Mul64(arg1[2], arg2[4]) + var x121 uint64 + var x122 uint64 + x122, x121 = bits.Mul64(arg1[2], arg2[3]) + var x123 uint64 + var x124 uint64 + x124, x123 = bits.Mul64(arg1[2], arg2[2]) + var x125 uint64 + var x126 uint64 + x126, x125 = bits.Mul64(arg1[2], arg2[1]) + var x127 uint64 + var x128 uint64 + x128, x127 = bits.Mul64(arg1[2], arg2[0]) + var x129 uint64 + var x130 uint64 + x130, x129 = bits.Mul64(arg1[1], arg2[7]) + var x131 uint64 + var x132 uint64 + x132, x131 = bits.Mul64(arg1[1], arg2[6]) + var x133 uint64 + var x134 uint64 + x134, x133 = bits.Mul64(arg1[1], arg2[5]) + var x135 uint64 + var x136 uint64 + x136, x135 = bits.Mul64(arg1[1], arg2[4]) + var x137 uint64 + var x138 uint64 + x138, x137 = bits.Mul64(arg1[1], arg2[3]) + var x139 uint64 + var x140 uint64 + x140, x139 = bits.Mul64(arg1[1], arg2[2]) + var x141 uint64 + var x142 uint64 + x142, x141 = bits.Mul64(arg1[1], arg2[1]) + var x143 uint64 + var x144 uint64 + x144, x143 = bits.Mul64(arg1[1], arg2[0]) + var x145 uint64 + var x146 uint64 + x146, x145 = bits.Mul64(arg1[0], arg2[8]) + var x147 uint64 + var x148 uint64 + x148, x147 = bits.Mul64(arg1[0], arg2[7]) + var x149 uint64 + var x150 uint64 + x150, x149 = bits.Mul64(arg1[0], arg2[6]) + var x151 uint64 + var x152 uint64 + x152, x151 = bits.Mul64(arg1[0], arg2[5]) + var x153 uint64 + var x154 uint64 + x154, x153 = bits.Mul64(arg1[0], arg2[4]) + var x155 uint64 + var x156 uint64 + x156, x155 = bits.Mul64(arg1[0], arg2[3]) + var x157 uint64 + var x158 uint64 + x158, x157 = bits.Mul64(arg1[0], arg2[2]) + var x159 uint64 + var x160 uint64 + x160, x159 = bits.Mul64(arg1[0], arg2[1]) + var x161 uint64 + var x162 uint64 + x162, x161 = bits.Mul64(arg1[0], arg2[0]) + var x163 uint64 + var x164 p521Uint1 + x163, x164 = p521AddcarryxU64(x29, x15, 0x0) + var x165 uint64 + x165, _ = p521AddcarryxU64(x30, x16, x164) + var x167 uint64 + var x168 p521Uint1 + x167, x168 = p521AddcarryxU64(x41, x163, 0x0) + var x169 uint64 + x169, _ = p521AddcarryxU64(x42, x165, x168) + var x171 uint64 + var x172 p521Uint1 + x171, x172 = p521AddcarryxU64(x51, x167, 0x0) + var x173 uint64 + x173, _ = p521AddcarryxU64(x52, x169, x172) + var x175 uint64 + var x176 p521Uint1 + x175, x176 = p521AddcarryxU64(x59, x171, 0x0) + var x177 uint64 + x177, _ = p521AddcarryxU64(x60, x173, x176) + var x179 uint64 + var x180 p521Uint1 + x179, x180 = p521AddcarryxU64(x65, x175, 0x0) + var x181 uint64 + x181, _ = p521AddcarryxU64(x66, x177, x180) + var x183 uint64 + var x184 p521Uint1 + x183, x184 = p521AddcarryxU64(x69, x179, 0x0) + var x185 uint64 + x185, _ = p521AddcarryxU64(x70, x181, x184) + var x187 uint64 + var x188 p521Uint1 + x187, x188 = p521AddcarryxU64(x71, x183, 0x0) + var x189 uint64 + x189, _ = p521AddcarryxU64(x72, x185, x188) + var x191 uint64 + var x192 p521Uint1 + x191, x192 = p521AddcarryxU64(x161, x187, 0x0) + var x193 uint64 + x193, _ = p521AddcarryxU64(x162, x189, x192) + x195 := ((x191 >> 58) | ((x193 << 6) & 0xffffffffffffffff)) + x196 := (x193 >> 58) + x197 := (x191 & 0x3ffffffffffffff) + var x198 uint64 + var x199 p521Uint1 + x198, x199 = p521AddcarryxU64(x75, x73, 0x0) + var x200 uint64 + x200, _ = p521AddcarryxU64(x76, x74, x199) + var x202 uint64 + var x203 p521Uint1 + x202, x203 = p521AddcarryxU64(x79, x198, 0x0) + var x204 uint64 + x204, _ = p521AddcarryxU64(x80, x200, x203) + var x206 uint64 + var x207 p521Uint1 + x206, x207 = p521AddcarryxU64(x85, x202, 0x0) + var x208 uint64 + x208, _ = p521AddcarryxU64(x86, x204, x207) + var x210 uint64 + var x211 p521Uint1 + x210, x211 = p521AddcarryxU64(x93, x206, 0x0) + var x212 uint64 + x212, _ = p521AddcarryxU64(x94, x208, x211) + var x214 uint64 + var x215 p521Uint1 + x214, x215 = p521AddcarryxU64(x103, x210, 0x0) + var x216 uint64 + x216, _ = p521AddcarryxU64(x104, x212, x215) + var x218 uint64 + var x219 p521Uint1 + x218, x219 = p521AddcarryxU64(x115, x214, 0x0) + var x220 uint64 + x220, _ = p521AddcarryxU64(x116, x216, x219) + var x222 uint64 + var x223 p521Uint1 + x222, x223 = p521AddcarryxU64(x129, x218, 0x0) + var x224 uint64 + x224, _ = p521AddcarryxU64(x130, x220, x223) + var x226 uint64 + var x227 p521Uint1 + x226, x227 = p521AddcarryxU64(x145, x222, 0x0) + var x228 uint64 + x228, _ = p521AddcarryxU64(x146, x224, x227) + var x230 uint64 + var x231 p521Uint1 + x230, x231 = p521AddcarryxU64(x77, x1, 0x0) + var x232 uint64 + x232, _ = p521AddcarryxU64(x78, x2, x231) + var x234 uint64 + var x235 p521Uint1 + x234, x235 = p521AddcarryxU64(x81, x230, 0x0) + var x236 uint64 + x236, _ = p521AddcarryxU64(x82, x232, x235) + var x238 uint64 + var x239 p521Uint1 + x238, x239 = p521AddcarryxU64(x87, x234, 0x0) + var x240 uint64 + x240, _ = p521AddcarryxU64(x88, x236, x239) + var x242 uint64 + var x243 p521Uint1 + x242, x243 = p521AddcarryxU64(x95, x238, 0x0) + var x244 uint64 + x244, _ = p521AddcarryxU64(x96, x240, x243) + var x246 uint64 + var x247 p521Uint1 + x246, x247 = p521AddcarryxU64(x105, x242, 0x0) + var x248 uint64 + x248, _ = p521AddcarryxU64(x106, x244, x247) + var x250 uint64 + var x251 p521Uint1 + x250, x251 = p521AddcarryxU64(x117, x246, 0x0) + var x252 uint64 + x252, _ = p521AddcarryxU64(x118, x248, x251) + var x254 uint64 + var x255 p521Uint1 + x254, x255 = p521AddcarryxU64(x131, x250, 0x0) + var x256 uint64 + x256, _ = p521AddcarryxU64(x132, x252, x255) + var x258 uint64 + var x259 p521Uint1 + x258, x259 = p521AddcarryxU64(x147, x254, 0x0) + var x260 uint64 + x260, _ = p521AddcarryxU64(x148, x256, x259) + var x262 uint64 + var x263 p521Uint1 + x262, x263 = p521AddcarryxU64(x17, x3, 0x0) + var x264 uint64 + x264, _ = p521AddcarryxU64(x18, x4, x263) + var x266 uint64 + var x267 p521Uint1 + x266, x267 = p521AddcarryxU64(x83, x262, 0x0) + var x268 uint64 + x268, _ = p521AddcarryxU64(x84, x264, x267) + var x270 uint64 + var x271 p521Uint1 + x270, x271 = p521AddcarryxU64(x89, x266, 0x0) + var x272 uint64 + x272, _ = p521AddcarryxU64(x90, x268, x271) + var x274 uint64 + var x275 p521Uint1 + x274, x275 = p521AddcarryxU64(x97, x270, 0x0) + var x276 uint64 + x276, _ = p521AddcarryxU64(x98, x272, x275) + var x278 uint64 + var x279 p521Uint1 + x278, x279 = p521AddcarryxU64(x107, x274, 0x0) + var x280 uint64 + x280, _ = p521AddcarryxU64(x108, x276, x279) + var x282 uint64 + var x283 p521Uint1 + x282, x283 = p521AddcarryxU64(x119, x278, 0x0) + var x284 uint64 + x284, _ = p521AddcarryxU64(x120, x280, x283) + var x286 uint64 + var x287 p521Uint1 + x286, x287 = p521AddcarryxU64(x133, x282, 0x0) + var x288 uint64 + x288, _ = p521AddcarryxU64(x134, x284, x287) + var x290 uint64 + var x291 p521Uint1 + x290, x291 = p521AddcarryxU64(x149, x286, 0x0) + var x292 uint64 + x292, _ = p521AddcarryxU64(x150, x288, x291) + var x294 uint64 + var x295 p521Uint1 + x294, x295 = p521AddcarryxU64(x19, x5, 0x0) + var x296 uint64 + x296, _ = p521AddcarryxU64(x20, x6, x295) + var x298 uint64 + var x299 p521Uint1 + x298, x299 = p521AddcarryxU64(x31, x294, 0x0) + var x300 uint64 + x300, _ = p521AddcarryxU64(x32, x296, x299) + var x302 uint64 + var x303 p521Uint1 + x302, x303 = p521AddcarryxU64(x91, x298, 0x0) + var x304 uint64 + x304, _ = p521AddcarryxU64(x92, x300, x303) + var x306 uint64 + var x307 p521Uint1 + x306, x307 = p521AddcarryxU64(x99, x302, 0x0) + var x308 uint64 + x308, _ = p521AddcarryxU64(x100, x304, x307) + var x310 uint64 + var x311 p521Uint1 + x310, x311 = p521AddcarryxU64(x109, x306, 0x0) + var x312 uint64 + x312, _ = p521AddcarryxU64(x110, x308, x311) + var x314 uint64 + var x315 p521Uint1 + x314, x315 = p521AddcarryxU64(x121, x310, 0x0) + var x316 uint64 + x316, _ = p521AddcarryxU64(x122, x312, x315) + var x318 uint64 + var x319 p521Uint1 + x318, x319 = p521AddcarryxU64(x135, x314, 0x0) + var x320 uint64 + x320, _ = p521AddcarryxU64(x136, x316, x319) + var x322 uint64 + var x323 p521Uint1 + x322, x323 = p521AddcarryxU64(x151, x318, 0x0) + var x324 uint64 + x324, _ = p521AddcarryxU64(x152, x320, x323) + var x326 uint64 + var x327 p521Uint1 + x326, x327 = p521AddcarryxU64(x21, x7, 0x0) + var x328 uint64 + x328, _ = p521AddcarryxU64(x22, x8, x327) + var x330 uint64 + var x331 p521Uint1 + x330, x331 = p521AddcarryxU64(x33, x326, 0x0) + var x332 uint64 + x332, _ = p521AddcarryxU64(x34, x328, x331) + var x334 uint64 + var x335 p521Uint1 + x334, x335 = p521AddcarryxU64(x43, x330, 0x0) + var x336 uint64 + x336, _ = p521AddcarryxU64(x44, x332, x335) + var x338 uint64 + var x339 p521Uint1 + x338, x339 = p521AddcarryxU64(x101, x334, 0x0) + var x340 uint64 + x340, _ = p521AddcarryxU64(x102, x336, x339) + var x342 uint64 + var x343 p521Uint1 + x342, x343 = p521AddcarryxU64(x111, x338, 0x0) + var x344 uint64 + x344, _ = p521AddcarryxU64(x112, x340, x343) + var x346 uint64 + var x347 p521Uint1 + x346, x347 = p521AddcarryxU64(x123, x342, 0x0) + var x348 uint64 + x348, _ = p521AddcarryxU64(x124, x344, x347) + var x350 uint64 + var x351 p521Uint1 + x350, x351 = p521AddcarryxU64(x137, x346, 0x0) + var x352 uint64 + x352, _ = p521AddcarryxU64(x138, x348, x351) + var x354 uint64 + var x355 p521Uint1 + x354, x355 = p521AddcarryxU64(x153, x350, 0x0) + var x356 uint64 + x356, _ = p521AddcarryxU64(x154, x352, x355) + var x358 uint64 + var x359 p521Uint1 + x358, x359 = p521AddcarryxU64(x23, x9, 0x0) + var x360 uint64 + x360, _ = p521AddcarryxU64(x24, x10, x359) + var x362 uint64 + var x363 p521Uint1 + x362, x363 = p521AddcarryxU64(x35, x358, 0x0) + var x364 uint64 + x364, _ = p521AddcarryxU64(x36, x360, x363) + var x366 uint64 + var x367 p521Uint1 + x366, x367 = p521AddcarryxU64(x45, x362, 0x0) + var x368 uint64 + x368, _ = p521AddcarryxU64(x46, x364, x367) + var x370 uint64 + var x371 p521Uint1 + x370, x371 = p521AddcarryxU64(x53, x366, 0x0) + var x372 uint64 + x372, _ = p521AddcarryxU64(x54, x368, x371) + var x374 uint64 + var x375 p521Uint1 + x374, x375 = p521AddcarryxU64(x113, x370, 0x0) + var x376 uint64 + x376, _ = p521AddcarryxU64(x114, x372, x375) + var x378 uint64 + var x379 p521Uint1 + x378, x379 = p521AddcarryxU64(x125, x374, 0x0) + var x380 uint64 + x380, _ = p521AddcarryxU64(x126, x376, x379) + var x382 uint64 + var x383 p521Uint1 + x382, x383 = p521AddcarryxU64(x139, x378, 0x0) + var x384 uint64 + x384, _ = p521AddcarryxU64(x140, x380, x383) + var x386 uint64 + var x387 p521Uint1 + x386, x387 = p521AddcarryxU64(x155, x382, 0x0) + var x388 uint64 + x388, _ = p521AddcarryxU64(x156, x384, x387) + var x390 uint64 + var x391 p521Uint1 + x390, x391 = p521AddcarryxU64(x25, x11, 0x0) + var x392 uint64 + x392, _ = p521AddcarryxU64(x26, x12, x391) + var x394 uint64 + var x395 p521Uint1 + x394, x395 = p521AddcarryxU64(x37, x390, 0x0) + var x396 uint64 + x396, _ = p521AddcarryxU64(x38, x392, x395) + var x398 uint64 + var x399 p521Uint1 + x398, x399 = p521AddcarryxU64(x47, x394, 0x0) + var x400 uint64 + x400, _ = p521AddcarryxU64(x48, x396, x399) + var x402 uint64 + var x403 p521Uint1 + x402, x403 = p521AddcarryxU64(x55, x398, 0x0) + var x404 uint64 + x404, _ = p521AddcarryxU64(x56, x400, x403) + var x406 uint64 + var x407 p521Uint1 + x406, x407 = p521AddcarryxU64(x61, x402, 0x0) + var x408 uint64 + x408, _ = p521AddcarryxU64(x62, x404, x407) + var x410 uint64 + var x411 p521Uint1 + x410, x411 = p521AddcarryxU64(x127, x406, 0x0) + var x412 uint64 + x412, _ = p521AddcarryxU64(x128, x408, x411) + var x414 uint64 + var x415 p521Uint1 + x414, x415 = p521AddcarryxU64(x141, x410, 0x0) + var x416 uint64 + x416, _ = p521AddcarryxU64(x142, x412, x415) + var x418 uint64 + var x419 p521Uint1 + x418, x419 = p521AddcarryxU64(x157, x414, 0x0) + var x420 uint64 + x420, _ = p521AddcarryxU64(x158, x416, x419) + var x422 uint64 + var x423 p521Uint1 + x422, x423 = p521AddcarryxU64(x27, x13, 0x0) + var x424 uint64 + x424, _ = p521AddcarryxU64(x28, x14, x423) + var x426 uint64 + var x427 p521Uint1 + x426, x427 = p521AddcarryxU64(x39, x422, 0x0) + var x428 uint64 + x428, _ = p521AddcarryxU64(x40, x424, x427) + var x430 uint64 + var x431 p521Uint1 + x430, x431 = p521AddcarryxU64(x49, x426, 0x0) + var x432 uint64 + x432, _ = p521AddcarryxU64(x50, x428, x431) + var x434 uint64 + var x435 p521Uint1 + x434, x435 = p521AddcarryxU64(x57, x430, 0x0) + var x436 uint64 + x436, _ = p521AddcarryxU64(x58, x432, x435) + var x438 uint64 + var x439 p521Uint1 + x438, x439 = p521AddcarryxU64(x63, x434, 0x0) + var x440 uint64 + x440, _ = p521AddcarryxU64(x64, x436, x439) + var x442 uint64 + var x443 p521Uint1 + x442, x443 = p521AddcarryxU64(x67, x438, 0x0) + var x444 uint64 + x444, _ = p521AddcarryxU64(x68, x440, x443) + var x446 uint64 + var x447 p521Uint1 + x446, x447 = p521AddcarryxU64(x143, x442, 0x0) + var x448 uint64 + x448, _ = p521AddcarryxU64(x144, x444, x447) + var x450 uint64 + var x451 p521Uint1 + x450, x451 = p521AddcarryxU64(x159, x446, 0x0) + var x452 uint64 + x452, _ = p521AddcarryxU64(x160, x448, x451) + var x454 uint64 + var x455 p521Uint1 + x454, x455 = p521AddcarryxU64(x195, x450, 0x0) + var x456 uint64 + x456, _ = p521AddcarryxU64(x196, x452, x455) + x458 := ((x454 >> 58) | ((x456 << 6) & 0xffffffffffffffff)) + x459 := (x456 >> 58) + x460 := (x454 & 0x3ffffffffffffff) + var x461 uint64 + var x462 p521Uint1 + x461, x462 = p521AddcarryxU64(x458, x418, 0x0) + var x463 uint64 + x463, _ = p521AddcarryxU64(x459, x420, x462) + x465 := ((x461 >> 58) | ((x463 << 6) & 0xffffffffffffffff)) + x466 := (x463 >> 58) + x467 := (x461 & 0x3ffffffffffffff) + var x468 uint64 + var x469 p521Uint1 + x468, x469 = p521AddcarryxU64(x465, x386, 0x0) + var x470 uint64 + x470, _ = p521AddcarryxU64(x466, x388, x469) + x472 := ((x468 >> 58) | ((x470 << 6) & 0xffffffffffffffff)) + x473 := (x470 >> 58) + x474 := (x468 & 0x3ffffffffffffff) + var x475 uint64 + var x476 p521Uint1 + x475, x476 = p521AddcarryxU64(x472, x354, 0x0) + var x477 uint64 + x477, _ = p521AddcarryxU64(x473, x356, x476) + x479 := ((x475 >> 58) | ((x477 << 6) & 0xffffffffffffffff)) + x480 := (x477 >> 58) + x481 := (x475 & 0x3ffffffffffffff) + var x482 uint64 + var x483 p521Uint1 + x482, x483 = p521AddcarryxU64(x479, x322, 0x0) + var x484 uint64 + x484, _ = p521AddcarryxU64(x480, x324, x483) + x486 := ((x482 >> 58) | ((x484 << 6) & 0xffffffffffffffff)) + x487 := (x484 >> 58) + x488 := (x482 & 0x3ffffffffffffff) + var x489 uint64 + var x490 p521Uint1 + x489, x490 = p521AddcarryxU64(x486, x290, 0x0) + var x491 uint64 + x491, _ = p521AddcarryxU64(x487, x292, x490) + x493 := ((x489 >> 58) | ((x491 << 6) & 0xffffffffffffffff)) + x494 := (x491 >> 58) + x495 := (x489 & 0x3ffffffffffffff) + var x496 uint64 + var x497 p521Uint1 + x496, x497 = p521AddcarryxU64(x493, x258, 0x0) + var x498 uint64 + x498, _ = p521AddcarryxU64(x494, x260, x497) + x500 := ((x496 >> 58) | ((x498 << 6) & 0xffffffffffffffff)) + x501 := (x498 >> 58) + x502 := (x496 & 0x3ffffffffffffff) + var x503 uint64 + var x504 p521Uint1 + x503, x504 = p521AddcarryxU64(x500, x226, 0x0) + var x505 uint64 + x505, _ = p521AddcarryxU64(x501, x228, x504) + x507 := ((x503 >> 57) | ((x505 << 7) & 0xffffffffffffffff)) + x508 := (x505 >> 57) + x509 := (x503 & 0x1ffffffffffffff) + var x510 uint64 + var x511 p521Uint1 + x510, x511 = p521AddcarryxU64(x197, x507, 0x0) + x512 := (uint64(x511) + x508) + x513 := ((x510 >> 58) | ((x512 << 6) & 0xffffffffffffffff)) + x514 := (x510 & 0x3ffffffffffffff) + x515 := (x513 + x460) + x516 := p521Uint1((x515 >> 58)) + x517 := (x515 & 0x3ffffffffffffff) + x518 := (uint64(x516) + x467) + out1[0] = x514 + out1[1] = x517 + out1[2] = x518 + out1[3] = x474 + out1[4] = x481 + out1[5] = x488 + out1[6] = x495 + out1[7] = x502 + out1[8] = x509 +} + +// p521CarrySquare squares a field element and reduces the result. +// +// Postconditions: +// eval out1 mod m = (eval arg1 * eval arg1) mod m +// +// Input Bounds: +// arg1: [[0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0x600000000000000]] +// Output Bounds: +// out1: [[0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x200000000000000]] +func p521CarrySquare(out1 *[9]uint64, arg1 *[9]uint64) { + x1 := arg1[8] + x2 := (x1 * 0x2) + x3 := (arg1[8] * 0x2) + x4 := arg1[7] + x5 := (x4 * 0x2) + x6 := (arg1[7] * 0x2) + x7 := arg1[6] + x8 := (x7 * 0x2) + x9 := (arg1[6] * 0x2) + x10 := arg1[5] + x11 := (x10 * 0x2) + x12 := (arg1[5] * 0x2) + x13 := (arg1[4] * 0x2) + x14 := (arg1[3] * 0x2) + x15 := (arg1[2] * 0x2) + x16 := (arg1[1] * 0x2) + var x17 uint64 + var x18 uint64 + x18, x17 = bits.Mul64(arg1[8], (x1 * 0x2)) + var x19 uint64 + var x20 uint64 + x20, x19 = bits.Mul64(arg1[7], (x2 * 0x2)) + var x21 uint64 + var x22 uint64 + x22, x21 = bits.Mul64(arg1[7], (x4 * 0x2)) + var x23 uint64 + var x24 uint64 + x24, x23 = bits.Mul64(arg1[6], (x2 * 0x2)) + var x25 uint64 + var x26 uint64 + x26, x25 = bits.Mul64(arg1[6], (x5 * 0x2)) + var x27 uint64 + var x28 uint64 + x28, x27 = bits.Mul64(arg1[6], (x7 * 0x2)) + var x29 uint64 + var x30 uint64 + x30, x29 = bits.Mul64(arg1[5], (x2 * 0x2)) + var x31 uint64 + var x32 uint64 + x32, x31 = bits.Mul64(arg1[5], (x5 * 0x2)) + var x33 uint64 + var x34 uint64 + x34, x33 = bits.Mul64(arg1[5], (x8 * 0x2)) + var x35 uint64 + var x36 uint64 + x36, x35 = bits.Mul64(arg1[5], (x10 * 0x2)) + var x37 uint64 + var x38 uint64 + x38, x37 = bits.Mul64(arg1[4], (x2 * 0x2)) + var x39 uint64 + var x40 uint64 + x40, x39 = bits.Mul64(arg1[4], (x5 * 0x2)) + var x41 uint64 + var x42 uint64 + x42, x41 = bits.Mul64(arg1[4], (x8 * 0x2)) + var x43 uint64 + var x44 uint64 + x44, x43 = bits.Mul64(arg1[4], (x11 * 0x2)) + var x45 uint64 + var x46 uint64 + x46, x45 = bits.Mul64(arg1[4], arg1[4]) + var x47 uint64 + var x48 uint64 + x48, x47 = bits.Mul64(arg1[3], (x2 * 0x2)) + var x49 uint64 + var x50 uint64 + x50, x49 = bits.Mul64(arg1[3], (x5 * 0x2)) + var x51 uint64 + var x52 uint64 + x52, x51 = bits.Mul64(arg1[3], (x8 * 0x2)) + var x53 uint64 + var x54 uint64 + x54, x53 = bits.Mul64(arg1[3], x12) + var x55 uint64 + var x56 uint64 + x56, x55 = bits.Mul64(arg1[3], x13) + var x57 uint64 + var x58 uint64 + x58, x57 = bits.Mul64(arg1[3], arg1[3]) + var x59 uint64 + var x60 uint64 + x60, x59 = bits.Mul64(arg1[2], (x2 * 0x2)) + var x61 uint64 + var x62 uint64 + x62, x61 = bits.Mul64(arg1[2], (x5 * 0x2)) + var x63 uint64 + var x64 uint64 + x64, x63 = bits.Mul64(arg1[2], x9) + var x65 uint64 + var x66 uint64 + x66, x65 = bits.Mul64(arg1[2], x12) + var x67 uint64 + var x68 uint64 + x68, x67 = bits.Mul64(arg1[2], x13) + var x69 uint64 + var x70 uint64 + x70, x69 = bits.Mul64(arg1[2], x14) + var x71 uint64 + var x72 uint64 + x72, x71 = bits.Mul64(arg1[2], arg1[2]) + var x73 uint64 + var x74 uint64 + x74, x73 = bits.Mul64(arg1[1], (x2 * 0x2)) + var x75 uint64 + var x76 uint64 + x76, x75 = bits.Mul64(arg1[1], x6) + var x77 uint64 + var x78 uint64 + x78, x77 = bits.Mul64(arg1[1], x9) + var x79 uint64 + var x80 uint64 + x80, x79 = bits.Mul64(arg1[1], x12) + var x81 uint64 + var x82 uint64 + x82, x81 = bits.Mul64(arg1[1], x13) + var x83 uint64 + var x84 uint64 + x84, x83 = bits.Mul64(arg1[1], x14) + var x85 uint64 + var x86 uint64 + x86, x85 = bits.Mul64(arg1[1], x15) + var x87 uint64 + var x88 uint64 + x88, x87 = bits.Mul64(arg1[1], arg1[1]) + var x89 uint64 + var x90 uint64 + x90, x89 = bits.Mul64(arg1[0], x3) + var x91 uint64 + var x92 uint64 + x92, x91 = bits.Mul64(arg1[0], x6) + var x93 uint64 + var x94 uint64 + x94, x93 = bits.Mul64(arg1[0], x9) + var x95 uint64 + var x96 uint64 + x96, x95 = bits.Mul64(arg1[0], x12) + var x97 uint64 + var x98 uint64 + x98, x97 = bits.Mul64(arg1[0], x13) + var x99 uint64 + var x100 uint64 + x100, x99 = bits.Mul64(arg1[0], x14) + var x101 uint64 + var x102 uint64 + x102, x101 = bits.Mul64(arg1[0], x15) + var x103 uint64 + var x104 uint64 + x104, x103 = bits.Mul64(arg1[0], x16) + var x105 uint64 + var x106 uint64 + x106, x105 = bits.Mul64(arg1[0], arg1[0]) + var x107 uint64 + var x108 p521Uint1 + x107, x108 = p521AddcarryxU64(x51, x43, 0x0) + var x109 uint64 + x109, _ = p521AddcarryxU64(x52, x44, x108) + var x111 uint64 + var x112 p521Uint1 + x111, x112 = p521AddcarryxU64(x61, x107, 0x0) + var x113 uint64 + x113, _ = p521AddcarryxU64(x62, x109, x112) + var x115 uint64 + var x116 p521Uint1 + x115, x116 = p521AddcarryxU64(x73, x111, 0x0) + var x117 uint64 + x117, _ = p521AddcarryxU64(x74, x113, x116) + var x119 uint64 + var x120 p521Uint1 + x119, x120 = p521AddcarryxU64(x105, x115, 0x0) + var x121 uint64 + x121, _ = p521AddcarryxU64(x106, x117, x120) + x123 := ((x119 >> 58) | ((x121 << 6) & 0xffffffffffffffff)) + x124 := (x121 >> 58) + x125 := (x119 & 0x3ffffffffffffff) + var x126 uint64 + var x127 p521Uint1 + x126, x127 = p521AddcarryxU64(x53, x45, 0x0) + var x128 uint64 + x128, _ = p521AddcarryxU64(x54, x46, x127) + var x130 uint64 + var x131 p521Uint1 + x130, x131 = p521AddcarryxU64(x63, x126, 0x0) + var x132 uint64 + x132, _ = p521AddcarryxU64(x64, x128, x131) + var x134 uint64 + var x135 p521Uint1 + x134, x135 = p521AddcarryxU64(x75, x130, 0x0) + var x136 uint64 + x136, _ = p521AddcarryxU64(x76, x132, x135) + var x138 uint64 + var x139 p521Uint1 + x138, x139 = p521AddcarryxU64(x89, x134, 0x0) + var x140 uint64 + x140, _ = p521AddcarryxU64(x90, x136, x139) + var x142 uint64 + var x143 p521Uint1 + x142, x143 = p521AddcarryxU64(x55, x17, 0x0) + var x144 uint64 + x144, _ = p521AddcarryxU64(x56, x18, x143) + var x146 uint64 + var x147 p521Uint1 + x146, x147 = p521AddcarryxU64(x65, x142, 0x0) + var x148 uint64 + x148, _ = p521AddcarryxU64(x66, x144, x147) + var x150 uint64 + var x151 p521Uint1 + x150, x151 = p521AddcarryxU64(x77, x146, 0x0) + var x152 uint64 + x152, _ = p521AddcarryxU64(x78, x148, x151) + var x154 uint64 + var x155 p521Uint1 + x154, x155 = p521AddcarryxU64(x91, x150, 0x0) + var x156 uint64 + x156, _ = p521AddcarryxU64(x92, x152, x155) + var x158 uint64 + var x159 p521Uint1 + x158, x159 = p521AddcarryxU64(x57, x19, 0x0) + var x160 uint64 + x160, _ = p521AddcarryxU64(x58, x20, x159) + var x162 uint64 + var x163 p521Uint1 + x162, x163 = p521AddcarryxU64(x67, x158, 0x0) + var x164 uint64 + x164, _ = p521AddcarryxU64(x68, x160, x163) + var x166 uint64 + var x167 p521Uint1 + x166, x167 = p521AddcarryxU64(x79, x162, 0x0) + var x168 uint64 + x168, _ = p521AddcarryxU64(x80, x164, x167) + var x170 uint64 + var x171 p521Uint1 + x170, x171 = p521AddcarryxU64(x93, x166, 0x0) + var x172 uint64 + x172, _ = p521AddcarryxU64(x94, x168, x171) + var x174 uint64 + var x175 p521Uint1 + x174, x175 = p521AddcarryxU64(x23, x21, 0x0) + var x176 uint64 + x176, _ = p521AddcarryxU64(x24, x22, x175) + var x178 uint64 + var x179 p521Uint1 + x178, x179 = p521AddcarryxU64(x69, x174, 0x0) + var x180 uint64 + x180, _ = p521AddcarryxU64(x70, x176, x179) + var x182 uint64 + var x183 p521Uint1 + x182, x183 = p521AddcarryxU64(x81, x178, 0x0) + var x184 uint64 + x184, _ = p521AddcarryxU64(x82, x180, x183) + var x186 uint64 + var x187 p521Uint1 + x186, x187 = p521AddcarryxU64(x95, x182, 0x0) + var x188 uint64 + x188, _ = p521AddcarryxU64(x96, x184, x187) + var x190 uint64 + var x191 p521Uint1 + x190, x191 = p521AddcarryxU64(x29, x25, 0x0) + var x192 uint64 + x192, _ = p521AddcarryxU64(x30, x26, x191) + var x194 uint64 + var x195 p521Uint1 + x194, x195 = p521AddcarryxU64(x71, x190, 0x0) + var x196 uint64 + x196, _ = p521AddcarryxU64(x72, x192, x195) + var x198 uint64 + var x199 p521Uint1 + x198, x199 = p521AddcarryxU64(x83, x194, 0x0) + var x200 uint64 + x200, _ = p521AddcarryxU64(x84, x196, x199) + var x202 uint64 + var x203 p521Uint1 + x202, x203 = p521AddcarryxU64(x97, x198, 0x0) + var x204 uint64 + x204, _ = p521AddcarryxU64(x98, x200, x203) + var x206 uint64 + var x207 p521Uint1 + x206, x207 = p521AddcarryxU64(x31, x27, 0x0) + var x208 uint64 + x208, _ = p521AddcarryxU64(x32, x28, x207) + var x210 uint64 + var x211 p521Uint1 + x210, x211 = p521AddcarryxU64(x37, x206, 0x0) + var x212 uint64 + x212, _ = p521AddcarryxU64(x38, x208, x211) + var x214 uint64 + var x215 p521Uint1 + x214, x215 = p521AddcarryxU64(x85, x210, 0x0) + var x216 uint64 + x216, _ = p521AddcarryxU64(x86, x212, x215) + var x218 uint64 + var x219 p521Uint1 + x218, x219 = p521AddcarryxU64(x99, x214, 0x0) + var x220 uint64 + x220, _ = p521AddcarryxU64(x100, x216, x219) + var x222 uint64 + var x223 p521Uint1 + x222, x223 = p521AddcarryxU64(x39, x33, 0x0) + var x224 uint64 + x224, _ = p521AddcarryxU64(x40, x34, x223) + var x226 uint64 + var x227 p521Uint1 + x226, x227 = p521AddcarryxU64(x47, x222, 0x0) + var x228 uint64 + x228, _ = p521AddcarryxU64(x48, x224, x227) + var x230 uint64 + var x231 p521Uint1 + x230, x231 = p521AddcarryxU64(x87, x226, 0x0) + var x232 uint64 + x232, _ = p521AddcarryxU64(x88, x228, x231) + var x234 uint64 + var x235 p521Uint1 + x234, x235 = p521AddcarryxU64(x101, x230, 0x0) + var x236 uint64 + x236, _ = p521AddcarryxU64(x102, x232, x235) + var x238 uint64 + var x239 p521Uint1 + x238, x239 = p521AddcarryxU64(x41, x35, 0x0) + var x240 uint64 + x240, _ = p521AddcarryxU64(x42, x36, x239) + var x242 uint64 + var x243 p521Uint1 + x242, x243 = p521AddcarryxU64(x49, x238, 0x0) + var x244 uint64 + x244, _ = p521AddcarryxU64(x50, x240, x243) + var x246 uint64 + var x247 p521Uint1 + x246, x247 = p521AddcarryxU64(x59, x242, 0x0) + var x248 uint64 + x248, _ = p521AddcarryxU64(x60, x244, x247) + var x250 uint64 + var x251 p521Uint1 + x250, x251 = p521AddcarryxU64(x103, x246, 0x0) + var x252 uint64 + x252, _ = p521AddcarryxU64(x104, x248, x251) + var x254 uint64 + var x255 p521Uint1 + x254, x255 = p521AddcarryxU64(x123, x250, 0x0) + var x256 uint64 + x256, _ = p521AddcarryxU64(x124, x252, x255) + x258 := ((x254 >> 58) | ((x256 << 6) & 0xffffffffffffffff)) + x259 := (x256 >> 58) + x260 := (x254 & 0x3ffffffffffffff) + var x261 uint64 + var x262 p521Uint1 + x261, x262 = p521AddcarryxU64(x258, x234, 0x0) + var x263 uint64 + x263, _ = p521AddcarryxU64(x259, x236, x262) + x265 := ((x261 >> 58) | ((x263 << 6) & 0xffffffffffffffff)) + x266 := (x263 >> 58) + x267 := (x261 & 0x3ffffffffffffff) + var x268 uint64 + var x269 p521Uint1 + x268, x269 = p521AddcarryxU64(x265, x218, 0x0) + var x270 uint64 + x270, _ = p521AddcarryxU64(x266, x220, x269) + x272 := ((x268 >> 58) | ((x270 << 6) & 0xffffffffffffffff)) + x273 := (x270 >> 58) + x274 := (x268 & 0x3ffffffffffffff) + var x275 uint64 + var x276 p521Uint1 + x275, x276 = p521AddcarryxU64(x272, x202, 0x0) + var x277 uint64 + x277, _ = p521AddcarryxU64(x273, x204, x276) + x279 := ((x275 >> 58) | ((x277 << 6) & 0xffffffffffffffff)) + x280 := (x277 >> 58) + x281 := (x275 & 0x3ffffffffffffff) + var x282 uint64 + var x283 p521Uint1 + x282, x283 = p521AddcarryxU64(x279, x186, 0x0) + var x284 uint64 + x284, _ = p521AddcarryxU64(x280, x188, x283) + x286 := ((x282 >> 58) | ((x284 << 6) & 0xffffffffffffffff)) + x287 := (x284 >> 58) + x288 := (x282 & 0x3ffffffffffffff) + var x289 uint64 + var x290 p521Uint1 + x289, x290 = p521AddcarryxU64(x286, x170, 0x0) + var x291 uint64 + x291, _ = p521AddcarryxU64(x287, x172, x290) + x293 := ((x289 >> 58) | ((x291 << 6) & 0xffffffffffffffff)) + x294 := (x291 >> 58) + x295 := (x289 & 0x3ffffffffffffff) + var x296 uint64 + var x297 p521Uint1 + x296, x297 = p521AddcarryxU64(x293, x154, 0x0) + var x298 uint64 + x298, _ = p521AddcarryxU64(x294, x156, x297) + x300 := ((x296 >> 58) | ((x298 << 6) & 0xffffffffffffffff)) + x301 := (x298 >> 58) + x302 := (x296 & 0x3ffffffffffffff) + var x303 uint64 + var x304 p521Uint1 + x303, x304 = p521AddcarryxU64(x300, x138, 0x0) + var x305 uint64 + x305, _ = p521AddcarryxU64(x301, x140, x304) + x307 := ((x303 >> 57) | ((x305 << 7) & 0xffffffffffffffff)) + x308 := (x305 >> 57) + x309 := (x303 & 0x1ffffffffffffff) + var x310 uint64 + var x311 p521Uint1 + x310, x311 = p521AddcarryxU64(x125, x307, 0x0) + x312 := (uint64(x311) + x308) + x313 := ((x310 >> 58) | ((x312 << 6) & 0xffffffffffffffff)) + x314 := (x310 & 0x3ffffffffffffff) + x315 := (x313 + x260) + x316 := p521Uint1((x315 >> 58)) + x317 := (x315 & 0x3ffffffffffffff) + x318 := (uint64(x316) + x267) + out1[0] = x314 + out1[1] = x317 + out1[2] = x318 + out1[3] = x274 + out1[4] = x281 + out1[5] = x288 + out1[6] = x295 + out1[7] = x302 + out1[8] = x309 +} + +// p521Carry reduces a field element. +// +// Postconditions: +// eval out1 mod m = eval arg1 mod m +// +// Input Bounds: +// arg1: [[0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0x600000000000000]] +// Output Bounds: +// out1: [[0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x200000000000000]] +func p521Carry(out1 *[9]uint64, arg1 *[9]uint64) { + x1 := arg1[0] + x2 := ((x1 >> 58) + arg1[1]) + x3 := ((x2 >> 58) + arg1[2]) + x4 := ((x3 >> 58) + arg1[3]) + x5 := ((x4 >> 58) + arg1[4]) + x6 := ((x5 >> 58) + arg1[5]) + x7 := ((x6 >> 58) + arg1[6]) + x8 := ((x7 >> 58) + arg1[7]) + x9 := ((x8 >> 58) + arg1[8]) + x10 := ((x1 & 0x3ffffffffffffff) + (x9 >> 57)) + x11 := (uint64(p521Uint1((x10 >> 58))) + (x2 & 0x3ffffffffffffff)) + x12 := (x10 & 0x3ffffffffffffff) + x13 := (x11 & 0x3ffffffffffffff) + x14 := (uint64(p521Uint1((x11 >> 58))) + (x3 & 0x3ffffffffffffff)) + x15 := (x4 & 0x3ffffffffffffff) + x16 := (x5 & 0x3ffffffffffffff) + x17 := (x6 & 0x3ffffffffffffff) + x18 := (x7 & 0x3ffffffffffffff) + x19 := (x8 & 0x3ffffffffffffff) + x20 := (x9 & 0x1ffffffffffffff) + out1[0] = x12 + out1[1] = x13 + out1[2] = x14 + out1[3] = x15 + out1[4] = x16 + out1[5] = x17 + out1[6] = x18 + out1[7] = x19 + out1[8] = x20 +} + +// p521Add adds two field elements. +// +// Postconditions: +// eval out1 mod m = (eval arg1 + eval arg2) mod m +// +// Input Bounds: +// arg1: [[0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x200000000000000]] +// arg2: [[0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x200000000000000]] +// Output Bounds: +// out1: [[0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0x600000000000000]] +func p521Add(out1 *[9]uint64, arg1 *[9]uint64, arg2 *[9]uint64) { + x1 := (arg1[0] + arg2[0]) + x2 := (arg1[1] + arg2[1]) + x3 := (arg1[2] + arg2[2]) + x4 := (arg1[3] + arg2[3]) + x5 := (arg1[4] + arg2[4]) + x6 := (arg1[5] + arg2[5]) + x7 := (arg1[6] + arg2[6]) + x8 := (arg1[7] + arg2[7]) + x9 := (arg1[8] + arg2[8]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 + out1[4] = x5 + out1[5] = x6 + out1[6] = x7 + out1[7] = x8 + out1[8] = x9 +} + +// p521Sub subtracts two field elements. +// +// Postconditions: +// eval out1 mod m = (eval arg1 - eval arg2) mod m +// +// Input Bounds: +// arg1: [[0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x200000000000000]] +// arg2: [[0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x200000000000000]] +// Output Bounds: +// out1: [[0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0xc00000000000000], [0x0 ~> 0x600000000000000]] +func p521Sub(out1 *[9]uint64, arg1 *[9]uint64, arg2 *[9]uint64) { + x1 := ((0x7fffffffffffffe + arg1[0]) - arg2[0]) + x2 := ((0x7fffffffffffffe + arg1[1]) - arg2[1]) + x3 := ((0x7fffffffffffffe + arg1[2]) - arg2[2]) + x4 := ((0x7fffffffffffffe + arg1[3]) - arg2[3]) + x5 := ((0x7fffffffffffffe + arg1[4]) - arg2[4]) + x6 := ((0x7fffffffffffffe + arg1[5]) - arg2[5]) + x7 := ((0x7fffffffffffffe + arg1[6]) - arg2[6]) + x8 := ((0x7fffffffffffffe + arg1[7]) - arg2[7]) + x9 := ((0x3fffffffffffffe + arg1[8]) - arg2[8]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 + out1[4] = x5 + out1[5] = x6 + out1[6] = x7 + out1[7] = x8 + out1[8] = x9 +} + +// p521ToBytes serializes a field element to bytes in little-endian order. +// +// Postconditions: +// out1 = map (λ x, ⌊((eval arg1 mod m) mod 2^(8 * (x + 1))) / 2^(8 * x)⌋) [0..65] +// +// Input Bounds: +// arg1: [[0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x200000000000000]] +// Output Bounds: +// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0x1]] +func p521ToBytes(out1 *[66]uint8, arg1 *[9]uint64) { + var x1 uint64 + var x2 p521Uint1 + p521SubborrowxU58(&x1, &x2, 0x0, arg1[0], 0x3ffffffffffffff) + var x3 uint64 + var x4 p521Uint1 + p521SubborrowxU58(&x3, &x4, x2, arg1[1], 0x3ffffffffffffff) + var x5 uint64 + var x6 p521Uint1 + p521SubborrowxU58(&x5, &x6, x4, arg1[2], 0x3ffffffffffffff) + var x7 uint64 + var x8 p521Uint1 + p521SubborrowxU58(&x7, &x8, x6, arg1[3], 0x3ffffffffffffff) + var x9 uint64 + var x10 p521Uint1 + p521SubborrowxU58(&x9, &x10, x8, arg1[4], 0x3ffffffffffffff) + var x11 uint64 + var x12 p521Uint1 + p521SubborrowxU58(&x11, &x12, x10, arg1[5], 0x3ffffffffffffff) + var x13 uint64 + var x14 p521Uint1 + p521SubborrowxU58(&x13, &x14, x12, arg1[6], 0x3ffffffffffffff) + var x15 uint64 + var x16 p521Uint1 + p521SubborrowxU58(&x15, &x16, x14, arg1[7], 0x3ffffffffffffff) + var x17 uint64 + var x18 p521Uint1 + p521SubborrowxU57(&x17, &x18, x16, arg1[8], 0x1ffffffffffffff) + var x19 uint64 + p521CmovznzU64(&x19, x18, uint64(0x0), 0xffffffffffffffff) + var x20 uint64 + var x21 p521Uint1 + p521AddcarryxU58(&x20, &x21, 0x0, x1, (x19 & 0x3ffffffffffffff)) + var x22 uint64 + var x23 p521Uint1 + p521AddcarryxU58(&x22, &x23, x21, x3, (x19 & 0x3ffffffffffffff)) + var x24 uint64 + var x25 p521Uint1 + p521AddcarryxU58(&x24, &x25, x23, x5, (x19 & 0x3ffffffffffffff)) + var x26 uint64 + var x27 p521Uint1 + p521AddcarryxU58(&x26, &x27, x25, x7, (x19 & 0x3ffffffffffffff)) + var x28 uint64 + var x29 p521Uint1 + p521AddcarryxU58(&x28, &x29, x27, x9, (x19 & 0x3ffffffffffffff)) + var x30 uint64 + var x31 p521Uint1 + p521AddcarryxU58(&x30, &x31, x29, x11, (x19 & 0x3ffffffffffffff)) + var x32 uint64 + var x33 p521Uint1 + p521AddcarryxU58(&x32, &x33, x31, x13, (x19 & 0x3ffffffffffffff)) + var x34 uint64 + var x35 p521Uint1 + p521AddcarryxU58(&x34, &x35, x33, x15, (x19 & 0x3ffffffffffffff)) + var x36 uint64 + var x37 p521Uint1 + p521AddcarryxU57(&x36, &x37, x35, x17, (x19 & 0x1ffffffffffffff)) + x38 := (x34 << 6) + x39 := (x32 << 4) + x40 := (x30 << 2) + x41 := (x26 << 6) + x42 := (x24 << 4) + x43 := (x22 << 2) + x44 := (uint8(x20) & 0xff) + x45 := (x20 >> 8) + x46 := (uint8(x45) & 0xff) + x47 := (x45 >> 8) + x48 := (uint8(x47) & 0xff) + x49 := (x47 >> 8) + x50 := (uint8(x49) & 0xff) + x51 := (x49 >> 8) + x52 := (uint8(x51) & 0xff) + x53 := (x51 >> 8) + x54 := (uint8(x53) & 0xff) + x55 := (x53 >> 8) + x56 := (uint8(x55) & 0xff) + x57 := uint8((x55 >> 8)) + x58 := (x43 + uint64(x57)) + x59 := (uint8(x58) & 0xff) + x60 := (x58 >> 8) + x61 := (uint8(x60) & 0xff) + x62 := (x60 >> 8) + x63 := (uint8(x62) & 0xff) + x64 := (x62 >> 8) + x65 := (uint8(x64) & 0xff) + x66 := (x64 >> 8) + x67 := (uint8(x66) & 0xff) + x68 := (x66 >> 8) + x69 := (uint8(x68) & 0xff) + x70 := (x68 >> 8) + x71 := (uint8(x70) & 0xff) + x72 := uint8((x70 >> 8)) + x73 := (x42 + uint64(x72)) + x74 := (uint8(x73) & 0xff) + x75 := (x73 >> 8) + x76 := (uint8(x75) & 0xff) + x77 := (x75 >> 8) + x78 := (uint8(x77) & 0xff) + x79 := (x77 >> 8) + x80 := (uint8(x79) & 0xff) + x81 := (x79 >> 8) + x82 := (uint8(x81) & 0xff) + x83 := (x81 >> 8) + x84 := (uint8(x83) & 0xff) + x85 := (x83 >> 8) + x86 := (uint8(x85) & 0xff) + x87 := uint8((x85 >> 8)) + x88 := (x41 + uint64(x87)) + x89 := (uint8(x88) & 0xff) + x90 := (x88 >> 8) + x91 := (uint8(x90) & 0xff) + x92 := (x90 >> 8) + x93 := (uint8(x92) & 0xff) + x94 := (x92 >> 8) + x95 := (uint8(x94) & 0xff) + x96 := (x94 >> 8) + x97 := (uint8(x96) & 0xff) + x98 := (x96 >> 8) + x99 := (uint8(x98) & 0xff) + x100 := (x98 >> 8) + x101 := (uint8(x100) & 0xff) + x102 := uint8((x100 >> 8)) + x103 := (uint8(x28) & 0xff) + x104 := (x28 >> 8) + x105 := (uint8(x104) & 0xff) + x106 := (x104 >> 8) + x107 := (uint8(x106) & 0xff) + x108 := (x106 >> 8) + x109 := (uint8(x108) & 0xff) + x110 := (x108 >> 8) + x111 := (uint8(x110) & 0xff) + x112 := (x110 >> 8) + x113 := (uint8(x112) & 0xff) + x114 := (x112 >> 8) + x115 := (uint8(x114) & 0xff) + x116 := uint8((x114 >> 8)) + x117 := (x40 + uint64(x116)) + x118 := (uint8(x117) & 0xff) + x119 := (x117 >> 8) + x120 := (uint8(x119) & 0xff) + x121 := (x119 >> 8) + x122 := (uint8(x121) & 0xff) + x123 := (x121 >> 8) + x124 := (uint8(x123) & 0xff) + x125 := (x123 >> 8) + x126 := (uint8(x125) & 0xff) + x127 := (x125 >> 8) + x128 := (uint8(x127) & 0xff) + x129 := (x127 >> 8) + x130 := (uint8(x129) & 0xff) + x131 := uint8((x129 >> 8)) + x132 := (x39 + uint64(x131)) + x133 := (uint8(x132) & 0xff) + x134 := (x132 >> 8) + x135 := (uint8(x134) & 0xff) + x136 := (x134 >> 8) + x137 := (uint8(x136) & 0xff) + x138 := (x136 >> 8) + x139 := (uint8(x138) & 0xff) + x140 := (x138 >> 8) + x141 := (uint8(x140) & 0xff) + x142 := (x140 >> 8) + x143 := (uint8(x142) & 0xff) + x144 := (x142 >> 8) + x145 := (uint8(x144) & 0xff) + x146 := uint8((x144 >> 8)) + x147 := (x38 + uint64(x146)) + x148 := (uint8(x147) & 0xff) + x149 := (x147 >> 8) + x150 := (uint8(x149) & 0xff) + x151 := (x149 >> 8) + x152 := (uint8(x151) & 0xff) + x153 := (x151 >> 8) + x154 := (uint8(x153) & 0xff) + x155 := (x153 >> 8) + x156 := (uint8(x155) & 0xff) + x157 := (x155 >> 8) + x158 := (uint8(x157) & 0xff) + x159 := (x157 >> 8) + x160 := (uint8(x159) & 0xff) + x161 := uint8((x159 >> 8)) + x162 := (uint8(x36) & 0xff) + x163 := (x36 >> 8) + x164 := (uint8(x163) & 0xff) + x165 := (x163 >> 8) + x166 := (uint8(x165) & 0xff) + x167 := (x165 >> 8) + x168 := (uint8(x167) & 0xff) + x169 := (x167 >> 8) + x170 := (uint8(x169) & 0xff) + x171 := (x169 >> 8) + x172 := (uint8(x171) & 0xff) + x173 := (x171 >> 8) + x174 := (uint8(x173) & 0xff) + x175 := p521Uint1((x173 >> 8)) + out1[0] = x44 + out1[1] = x46 + out1[2] = x48 + out1[3] = x50 + out1[4] = x52 + out1[5] = x54 + out1[6] = x56 + out1[7] = x59 + out1[8] = x61 + out1[9] = x63 + out1[10] = x65 + out1[11] = x67 + out1[12] = x69 + out1[13] = x71 + out1[14] = x74 + out1[15] = x76 + out1[16] = x78 + out1[17] = x80 + out1[18] = x82 + out1[19] = x84 + out1[20] = x86 + out1[21] = x89 + out1[22] = x91 + out1[23] = x93 + out1[24] = x95 + out1[25] = x97 + out1[26] = x99 + out1[27] = x101 + out1[28] = x102 + out1[29] = x103 + out1[30] = x105 + out1[31] = x107 + out1[32] = x109 + out1[33] = x111 + out1[34] = x113 + out1[35] = x115 + out1[36] = x118 + out1[37] = x120 + out1[38] = x122 + out1[39] = x124 + out1[40] = x126 + out1[41] = x128 + out1[42] = x130 + out1[43] = x133 + out1[44] = x135 + out1[45] = x137 + out1[46] = x139 + out1[47] = x141 + out1[48] = x143 + out1[49] = x145 + out1[50] = x148 + out1[51] = x150 + out1[52] = x152 + out1[53] = x154 + out1[54] = x156 + out1[55] = x158 + out1[56] = x160 + out1[57] = x161 + out1[58] = x162 + out1[59] = x164 + out1[60] = x166 + out1[61] = x168 + out1[62] = x170 + out1[63] = x172 + out1[64] = x174 + out1[65] = uint8(x175) +} + +// p521FromBytes deserializes a field element from bytes in little-endian order. +// +// Postconditions: +// eval out1 mod m = bytes_eval arg1 mod m +// +// Input Bounds: +// arg1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0x1]] +// Output Bounds: +// out1: [[0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x400000000000000], [0x0 ~> 0x200000000000000]] +func p521FromBytes(out1 *[9]uint64, arg1 *[66]uint8) { + x1 := (uint64(p521Uint1(arg1[65])) << 56) + x2 := (uint64(arg1[64]) << 48) + x3 := (uint64(arg1[63]) << 40) + x4 := (uint64(arg1[62]) << 32) + x5 := (uint64(arg1[61]) << 24) + x6 := (uint64(arg1[60]) << 16) + x7 := (uint64(arg1[59]) << 8) + x8 := arg1[58] + x9 := (uint64(arg1[57]) << 50) + x10 := (uint64(arg1[56]) << 42) + x11 := (uint64(arg1[55]) << 34) + x12 := (uint64(arg1[54]) << 26) + x13 := (uint64(arg1[53]) << 18) + x14 := (uint64(arg1[52]) << 10) + x15 := (uint64(arg1[51]) << 2) + x16 := (uint64(arg1[50]) << 52) + x17 := (uint64(arg1[49]) << 44) + x18 := (uint64(arg1[48]) << 36) + x19 := (uint64(arg1[47]) << 28) + x20 := (uint64(arg1[46]) << 20) + x21 := (uint64(arg1[45]) << 12) + x22 := (uint64(arg1[44]) << 4) + x23 := (uint64(arg1[43]) << 54) + x24 := (uint64(arg1[42]) << 46) + x25 := (uint64(arg1[41]) << 38) + x26 := (uint64(arg1[40]) << 30) + x27 := (uint64(arg1[39]) << 22) + x28 := (uint64(arg1[38]) << 14) + x29 := (uint64(arg1[37]) << 6) + x30 := (uint64(arg1[36]) << 56) + x31 := (uint64(arg1[35]) << 48) + x32 := (uint64(arg1[34]) << 40) + x33 := (uint64(arg1[33]) << 32) + x34 := (uint64(arg1[32]) << 24) + x35 := (uint64(arg1[31]) << 16) + x36 := (uint64(arg1[30]) << 8) + x37 := arg1[29] + x38 := (uint64(arg1[28]) << 50) + x39 := (uint64(arg1[27]) << 42) + x40 := (uint64(arg1[26]) << 34) + x41 := (uint64(arg1[25]) << 26) + x42 := (uint64(arg1[24]) << 18) + x43 := (uint64(arg1[23]) << 10) + x44 := (uint64(arg1[22]) << 2) + x45 := (uint64(arg1[21]) << 52) + x46 := (uint64(arg1[20]) << 44) + x47 := (uint64(arg1[19]) << 36) + x48 := (uint64(arg1[18]) << 28) + x49 := (uint64(arg1[17]) << 20) + x50 := (uint64(arg1[16]) << 12) + x51 := (uint64(arg1[15]) << 4) + x52 := (uint64(arg1[14]) << 54) + x53 := (uint64(arg1[13]) << 46) + x54 := (uint64(arg1[12]) << 38) + x55 := (uint64(arg1[11]) << 30) + x56 := (uint64(arg1[10]) << 22) + x57 := (uint64(arg1[9]) << 14) + x58 := (uint64(arg1[8]) << 6) + x59 := (uint64(arg1[7]) << 56) + x60 := (uint64(arg1[6]) << 48) + x61 := (uint64(arg1[5]) << 40) + x62 := (uint64(arg1[4]) << 32) + x63 := (uint64(arg1[3]) << 24) + x64 := (uint64(arg1[2]) << 16) + x65 := (uint64(arg1[1]) << 8) + x66 := arg1[0] + x67 := (x65 + uint64(x66)) + x68 := (x64 + x67) + x69 := (x63 + x68) + x70 := (x62 + x69) + x71 := (x61 + x70) + x72 := (x60 + x71) + x73 := (x59 + x72) + x74 := (x73 & 0x3ffffffffffffff) + x75 := uint8((x73 >> 58)) + x76 := (x58 + uint64(x75)) + x77 := (x57 + x76) + x78 := (x56 + x77) + x79 := (x55 + x78) + x80 := (x54 + x79) + x81 := (x53 + x80) + x82 := (x52 + x81) + x83 := (x82 & 0x3ffffffffffffff) + x84 := uint8((x82 >> 58)) + x85 := (x51 + uint64(x84)) + x86 := (x50 + x85) + x87 := (x49 + x86) + x88 := (x48 + x87) + x89 := (x47 + x88) + x90 := (x46 + x89) + x91 := (x45 + x90) + x92 := (x91 & 0x3ffffffffffffff) + x93 := uint8((x91 >> 58)) + x94 := (x44 + uint64(x93)) + x95 := (x43 + x94) + x96 := (x42 + x95) + x97 := (x41 + x96) + x98 := (x40 + x97) + x99 := (x39 + x98) + x100 := (x38 + x99) + x101 := (x36 + uint64(x37)) + x102 := (x35 + x101) + x103 := (x34 + x102) + x104 := (x33 + x103) + x105 := (x32 + x104) + x106 := (x31 + x105) + x107 := (x30 + x106) + x108 := (x107 & 0x3ffffffffffffff) + x109 := uint8((x107 >> 58)) + x110 := (x29 + uint64(x109)) + x111 := (x28 + x110) + x112 := (x27 + x111) + x113 := (x26 + x112) + x114 := (x25 + x113) + x115 := (x24 + x114) + x116 := (x23 + x115) + x117 := (x116 & 0x3ffffffffffffff) + x118 := uint8((x116 >> 58)) + x119 := (x22 + uint64(x118)) + x120 := (x21 + x119) + x121 := (x20 + x120) + x122 := (x19 + x121) + x123 := (x18 + x122) + x124 := (x17 + x123) + x125 := (x16 + x124) + x126 := (x125 & 0x3ffffffffffffff) + x127 := uint8((x125 >> 58)) + x128 := (x15 + uint64(x127)) + x129 := (x14 + x128) + x130 := (x13 + x129) + x131 := (x12 + x130) + x132 := (x11 + x131) + x133 := (x10 + x132) + x134 := (x9 + x133) + x135 := (x7 + uint64(x8)) + x136 := (x6 + x135) + x137 := (x5 + x136) + x138 := (x4 + x137) + x139 := (x3 + x138) + x140 := (x2 + x139) + x141 := (x1 + x140) + out1[0] = x74 + out1[1] = x83 + out1[2] = x92 + out1[3] = x100 + out1[4] = x108 + out1[5] = x117 + out1[6] = x126 + out1[7] = x134 + out1[8] = x141 +} + +// p521Selectznz is a multi-limb conditional select. +// +// Postconditions: +// eval out1 = (if arg1 = 0 then eval arg2 else eval arg3) +// +// Input Bounds: +// arg1: [0x0 ~> 0x1] +// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// arg3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// Output Bounds: +// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +func p521Selectznz(out1 *[9]uint64, arg1 p521Uint1, arg2 *[9]uint64, arg3 *[9]uint64) { + var x1 uint64 + p521CmovznzU64(&x1, arg1, arg2[0], arg3[0]) + var x2 uint64 + p521CmovznzU64(&x2, arg1, arg2[1], arg3[1]) + var x3 uint64 + p521CmovznzU64(&x3, arg1, arg2[2], arg3[2]) + var x4 uint64 + p521CmovznzU64(&x4, arg1, arg2[3], arg3[3]) + var x5 uint64 + p521CmovznzU64(&x5, arg1, arg2[4], arg3[4]) + var x6 uint64 + p521CmovznzU64(&x6, arg1, arg2[5], arg3[5]) + var x7 uint64 + p521CmovznzU64(&x7, arg1, arg2[6], arg3[6]) + var x8 uint64 + p521CmovznzU64(&x8, arg1, arg2[7], arg3[7]) + var x9 uint64 + p521CmovznzU64(&x9, arg1, arg2[8], arg3[8]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 + out1[4] = x5 + out1[5] = x6 + out1[6] = x7 + out1[7] = x8 + out1[8] = x9 +} diff --git a/src/crypto/elliptic/internal/fiat/p521_test.go b/src/crypto/elliptic/internal/fiat/p521_test.go new file mode 100644 index 00000000000..661bde397e4 --- /dev/null +++ b/src/crypto/elliptic/internal/fiat/p521_test.go @@ -0,0 +1,37 @@ +// Copyright 2021 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 fiat_test + +import ( + "crypto/elliptic/internal/fiat" + "crypto/rand" + "testing" +) + +func p521Random(t *testing.T) *fiat.P521Element { + buf := make([]byte, 66) + if _, err := rand.Read(buf); err != nil { + t.Fatal(err) + } + buf[65] &= 1 + e, err := new(fiat.P521Element).SetBytes(buf) + if err != nil { + t.Fatal(err) + } + return e +} + +func TestP521Invert(t *testing.T) { + a := p521Random(t) + inv := new(fiat.P521Element).Invert(a) + one := new(fiat.P521Element).Mul(a, inv) + if new(fiat.P521Element).One().Equal(one) != 1 { + t.Errorf("a * 1/a != 1; got %x for %x", one.Bytes(), a.Bytes()) + } + inv.Invert(new(fiat.P521Element)) + if new(fiat.P521Element).Equal(inv) != 1 { + t.Errorf("1/0 != 0; got %x", inv.Bytes()) + } +} diff --git a/src/crypto/elliptic/p521.go b/src/crypto/elliptic/p521.go new file mode 100644 index 00000000000..ac9de637025 --- /dev/null +++ b/src/crypto/elliptic/p521.go @@ -0,0 +1,254 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package elliptic + +import ( + "crypto/elliptic/internal/fiat" + "math/big" +) + +type p521Curve struct { + *CurveParams +} + +var p521 p521Curve +var p521Params *CurveParams + +func initP521() { + // See FIPS 186-3, section D.2.5 + p521.CurveParams = &CurveParams{Name: "P-521"} + p521.P, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", 10) + p521.N, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449", 10) + p521.B, _ = new(big.Int).SetString("051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", 16) + p521.Gx, _ = new(big.Int).SetString("c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", 16) + p521.Gy, _ = new(big.Int).SetString("11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650", 16) + p521.BitSize = 521 +} + +func (curve p521Curve) Params() *CurveParams { + return curve.CurveParams +} + +func (curve p521Curve) IsOnCurve(x, y *big.Int) bool { + x1 := bigIntToFiatP521(x) + y1 := bigIntToFiatP521(y) + b := bigIntToFiatP521(curve.B) // TODO: precompute this value. + + // x³ - 3x + b. + x3 := new(fiat.P521Element).Square(x1) + x3.Mul(x3, x1) + + threeX := new(fiat.P521Element).Add(x1, x1) + threeX.Add(threeX, x1) + + x3.Sub(x3, threeX) + x3.Add(x3, b) + + // y² = x³ - 3x + b + y2 := new(fiat.P521Element).Square(y1) + + return x3.Equal(y2) == 1 +} + +type p512Point struct { + x, y, z *fiat.P521Element +} + +func fiatP521ToBigInt(x *fiat.P521Element) *big.Int { + xBytes := x.Bytes() + for i := range xBytes[:len(xBytes)/2] { + xBytes[i], xBytes[len(xBytes)-i-1] = xBytes[len(xBytes)-i-1], xBytes[i] + } + return new(big.Int).SetBytes(xBytes) +} + +// affineFromJacobian brings a point in Jacobian coordinates back to affine +// coordinates, with (0, 0) representing infinity by convention. It also goes +// back to big.Int values to match the exposed API. +func (curve p521Curve) affineFromJacobian(p *p512Point) (x, y *big.Int) { + if p.z.IsZero() == 1 { + return new(big.Int), new(big.Int) + } + + zinv := new(fiat.P521Element).Invert(p.z) + zinvsq := new(fiat.P521Element).Mul(zinv, zinv) + + xx := new(fiat.P521Element).Mul(p.x, zinvsq) + zinvsq.Mul(zinvsq, zinv) + yy := new(fiat.P521Element).Mul(p.y, zinvsq) + + return fiatP521ToBigInt(xx), fiatP521ToBigInt(yy) +} + +func bigIntToFiatP521(x *big.Int) *fiat.P521Element { + xBytes := new(big.Int).Mod(x, p521.P).FillBytes(make([]byte, 66)) + for i := range xBytes[:len(xBytes)/2] { + xBytes[i], xBytes[len(xBytes)-i-1] = xBytes[len(xBytes)-i-1], xBytes[i] + } + x1, err := new(fiat.P521Element).SetBytes(xBytes) + if err != nil { + // The input is reduced modulo P and encoded in a fixed size bytes + // slice, this should be impossible. + panic("internal error: bigIntToFiatP521") + } + return x1 +} + +// jacobianFromAffine converts (x, y) affine coordinates into (x, y, z) Jacobian +// coordinates. It also converts from big.Int to fiat, which is necessarily a +// messy and variable-time operation, which we can't avoid due to the exposed API. +func (curve p521Curve) jacobianFromAffine(x, y *big.Int) *p512Point { + // (0, 0) is by convention the point at infinity, which can't be represented + // in affine coordinates, but is (0, 0, 0) in Jacobian. + if x.Sign() == 0 && y.Sign() == 0 { + return &p512Point{ + x: new(fiat.P521Element), + y: new(fiat.P521Element), + z: new(fiat.P521Element), + } + } + return &p512Point{ + x: bigIntToFiatP521(x), + y: bigIntToFiatP521(y), + z: new(fiat.P521Element).One(), + } +} + +func (curve p521Curve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { + p1 := curve.jacobianFromAffine(x1, y1) + p2 := curve.jacobianFromAffine(x2, y2) + return curve.affineFromJacobian(p1.addJacobian(p1, p2)) +} + +// addJacobian sets q = p1 + p2, and returns q. The points may overlap. +func (q *p512Point) addJacobian(p1, p2 *p512Point) *p512Point { + // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl + if p1.z.IsZero() == 1 { + q.x.Set(p2.x) + q.y.Set(p2.y) + q.z.Set(p2.z) + return q + } + if p2.z.IsZero() == 1 { + q.x.Set(p1.x) + q.y.Set(p1.y) + q.z.Set(p1.z) + return q + } + + z1z1 := new(fiat.P521Element).Square(p1.z) + z2z2 := new(fiat.P521Element).Square(p2.z) + + u1 := new(fiat.P521Element).Mul(p1.x, z2z2) + u2 := new(fiat.P521Element).Mul(p2.x, z1z1) + h := new(fiat.P521Element).Sub(u2, u1) + xEqual := h.IsZero() == 1 + i := new(fiat.P521Element).Add(h, h) + i.Square(i) + j := new(fiat.P521Element).Mul(h, i) + + s1 := new(fiat.P521Element).Mul(p1.y, p2.z) + s1.Mul(s1, z2z2) + s2 := new(fiat.P521Element).Mul(p2.y, p1.z) + s2.Mul(s2, z1z1) + r := new(fiat.P521Element).Sub(s2, s1) + yEqual := r.IsZero() == 1 + if xEqual && yEqual { + return q.doubleJacobian(p1) + } + r.Add(r, r) + v := new(fiat.P521Element).Mul(u1, i) + + q.x.Set(r) + q.x.Square(q.x) + q.x.Sub(q.x, j) + q.x.Sub(q.x, v) + q.x.Sub(q.x, v) + + q.y.Set(r) + v.Sub(v, q.x) + q.y.Mul(q.y, v) + s1.Mul(s1, j) + s1.Add(s1, s1) + q.y.Sub(q.y, s1) + + q.z.Add(p1.z, p2.z) + q.z.Square(q.z) + q.z.Sub(q.z, z1z1) + q.z.Sub(q.z, z2z2) + q.z.Mul(q.z, h) + + return q +} + +func (curve p521Curve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { + p := curve.jacobianFromAffine(x1, y1) + return curve.affineFromJacobian(p.doubleJacobian(p)) +} + +// doubleJacobian sets q = p + p, and returns q. The points may overlap. +func (q *p512Point) doubleJacobian(p *p512Point) *p512Point { + // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b + delta := new(fiat.P521Element).Square(p.z) + gamma := new(fiat.P521Element).Square(p.y) + alpha := new(fiat.P521Element).Sub(p.x, delta) + alpha2 := new(fiat.P521Element).Add(p.x, delta) + alpha.Mul(alpha, alpha2) + alpha2.Set(alpha) + alpha.Add(alpha, alpha) + alpha.Add(alpha, alpha2) + + beta := alpha2.Mul(p.x, gamma) + + q.x.Square(alpha) + beta8 := new(fiat.P521Element).Add(beta, beta) + beta8.Add(beta8, beta8) + beta8.Add(beta8, beta8) + q.x.Sub(q.x, beta8) + + q.z.Add(p.y, p.z) + q.z.Square(q.z) + q.z.Sub(q.z, gamma) + q.z.Sub(q.z, delta) + + beta.Add(beta, beta) + beta.Add(beta, beta) + beta.Sub(beta, q.x) + q.y.Mul(alpha, beta) + + gamma.Square(gamma) + gamma.Add(gamma, gamma) + gamma.Add(gamma, gamma) + gamma.Add(gamma, gamma) + + q.y.Sub(q.y, gamma) + + return q +} + +func (curve p521Curve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) { + B := curve.jacobianFromAffine(Bx, By) + p := &p512Point{ + x: new(fiat.P521Element), + y: new(fiat.P521Element), + z: new(fiat.P521Element), + } + + for _, byte := range k { + for bitNum := 0; bitNum < 8; bitNum++ { + p.doubleJacobian(p) + if byte&0x80 == 0x80 { + p.addJacobian(B, p) + } + byte <<= 1 + } + } + + return curve.affineFromJacobian(p) +} + +func (curve p521Curve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { + return curve.ScalarMult(curve.Gx, curve.Gy, k) +} diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index bb6d92f89ac..3a0e769284d 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -392,6 +392,7 @@ var depsRules = ` < crypto < crypto/subtle < crypto/internal/subtle + < crypto/elliptic/internal/fiat < crypto/ed25519/internal/edwards25519/field < crypto/ed25519/internal/edwards25519 < crypto/cipher From ea93e6885847b50bf4e6d3f263843f9c4e8d15f8 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Sat, 1 May 2021 01:28:16 -0400 Subject: [PATCH 006/940] crypto/elliptic: make P-521 scalar multiplication constant time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Like for P-224, we do the constant time selects to hide the point-at-infinity special cases of addition, but not the P = Q case, which presumably doesn't happen in normal operations. Runtime increases by about 50%, as expected, since on average we were able to skip half the additions, and the additions reasonably amounted to half the runtime. Still, the Fiat code is so much faster than big.Int that we're still more than three time faster overall than pre-CL 315271. name old time/op new time/op delta pkg:crypto/elliptic goos:darwin goarch:arm64 ScalarBaseMult/P521-8 4.18ms ± 3% 1.35ms ± 1% -67.64% (p=0.000 n=10+10) ScalarMult/P521-8 4.17ms ± 2% 1.36ms ± 1% -67.45% (p=0.000 n=10+10) pkg:crypto/ecdsa goos:darwin goarch:arm64 Sign/P521-8 4.23ms ± 1% 1.44ms ± 1% -66.02% (p=0.000 n=9+10) Verify/P521-8 8.31ms ± 2% 2.73ms ± 2% -67.08% (p=0.000 n=9+9) GenerateKey/P521-8 4.15ms ± 2% 1.35ms ± 2% -67.41% (p=0.000 n=10+10) Updates #40171 Change-Id: I782f2b7f33dd60af9b3b75e46d920d4cb47f719f Reviewed-on: https://go-review.googlesource.com/c/go/+/315274 Run-TryBot: Filippo Valsorda TryBot-Result: Go Bot Trust: Filippo Valsorda Trust: Katie Hockman Reviewed-by: Katie Hockman --- src/crypto/elliptic/p521.go | 73 ++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/src/crypto/elliptic/p521.go b/src/crypto/elliptic/p521.go index ac9de637025..ce74e0539c9 100644 --- a/src/crypto/elliptic/p521.go +++ b/src/crypto/elliptic/p521.go @@ -125,18 +125,8 @@ func (curve p521Curve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { // addJacobian sets q = p1 + p2, and returns q. The points may overlap. func (q *p512Point) addJacobian(p1, p2 *p512Point) *p512Point { // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl - if p1.z.IsZero() == 1 { - q.x.Set(p2.x) - q.y.Set(p2.y) - q.z.Set(p2.z) - return q - } - if p2.z.IsZero() == 1 { - q.x.Set(p1.x) - q.y.Set(p1.y) - q.z.Set(p1.z) - return q - } + z1IsZero := p1.z.IsZero() + z2IsZero := p2.z.IsZero() z1z1 := new(fiat.P521Element).Square(p1.z) z2z2 := new(fiat.P521Element).Square(p2.z) @@ -155,31 +145,41 @@ func (q *p512Point) addJacobian(p1, p2 *p512Point) *p512Point { s2.Mul(s2, z1z1) r := new(fiat.P521Element).Sub(s2, s1) yEqual := r.IsZero() == 1 - if xEqual && yEqual { + if xEqual && yEqual && z1IsZero == 0 && z2IsZero == 0 { return q.doubleJacobian(p1) } r.Add(r, r) v := new(fiat.P521Element).Mul(u1, i) - q.x.Set(r) - q.x.Square(q.x) - q.x.Sub(q.x, j) - q.x.Sub(q.x, v) - q.x.Sub(q.x, v) + x := new(fiat.P521Element).Set(r) + x.Square(x) + x.Sub(x, j) + x.Sub(x, v) + x.Sub(x, v) - q.y.Set(r) - v.Sub(v, q.x) - q.y.Mul(q.y, v) + y := new(fiat.P521Element).Set(r) + v.Sub(v, x) + y.Mul(y, v) s1.Mul(s1, j) s1.Add(s1, s1) - q.y.Sub(q.y, s1) + y.Sub(y, s1) - q.z.Add(p1.z, p2.z) - q.z.Square(q.z) - q.z.Sub(q.z, z1z1) - q.z.Sub(q.z, z2z2) - q.z.Mul(q.z, h) + z := new(fiat.P521Element).Add(p1.z, p2.z) + z.Square(z) + z.Sub(z, z1z1) + z.Sub(z, z2z2) + z.Mul(z, h) + x.Select(p2.x, x, z1IsZero) + x.Select(p1.x, x, z2IsZero) + y.Select(p2.y, y, z1IsZero) + y.Select(p1.y, y, z2IsZero) + z.Select(p2.z, z, z1IsZero) + z.Select(p1.z, z, z2IsZero) + + q.x.Set(x) + q.y.Set(y) + q.z.Set(z) return q } @@ -228,21 +228,26 @@ func (q *p512Point) doubleJacobian(p *p512Point) *p512Point { return q } -func (curve p521Curve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) { +func (curve p521Curve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) { B := curve.jacobianFromAffine(Bx, By) - p := &p512Point{ + p, t := &p512Point{ + x: new(fiat.P521Element), + y: new(fiat.P521Element), + z: new(fiat.P521Element), + }, &p512Point{ x: new(fiat.P521Element), y: new(fiat.P521Element), z: new(fiat.P521Element), } - for _, byte := range k { + for _, byte := range scalar { for bitNum := 0; bitNum < 8; bitNum++ { p.doubleJacobian(p) - if byte&0x80 == 0x80 { - p.addJacobian(B, p) - } - byte <<= 1 + bit := (byte >> (7 - bitNum)) & 1 + t.addJacobian(p, B) + p.x.Select(t.x, p.x, int(bit)) + p.y.Select(t.y, p.y, int(bit)) + p.z.Select(t.z, p.z, int(bit)) } } From 5203357ebacf9f41ca5e194d953c164049172e96 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 7 May 2021 22:51:29 -0700 Subject: [PATCH 007/940] cmd/compile: make non-concurrent compiles deterministic again Spreading function compilation across multiple goroutines results in non-deterministic output. This is how cmd/compile has historically behaved for concurrent builds, but is troublesome for non-concurrent builds, particularly because it interferes with "toolstash -cmp". I spent some time trying to think of a simple, unified algorithm that can concurrently schedule work but gracefully degrades to a deterministic build for single-worker builds, but I couldn't come up with any. The simplest idea I found was to simply abstract away the operation of scheduling work so that we can have alternative deterministic vs concurrent modes. Change-Id: I08afa00527ce1844432412f4f8553781c4e323df Reviewed-on: https://go-review.googlesource.com/c/go/+/318229 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/gc/compile.go | 59 ++++++++++++++++---------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/src/cmd/compile/internal/gc/compile.go b/src/cmd/compile/internal/gc/compile.go index a7380510d12..00504451a88 100644 --- a/src/cmd/compile/internal/gc/compile.go +++ b/src/cmd/compile/internal/gc/compile.go @@ -119,38 +119,51 @@ func compileFunctions() { }) } - // We queue up a goroutine per function that needs to be - // compiled, but require them to grab an available worker ID - // before doing any substantial work to limit parallelism. - workerIDs := make(chan int, base.Flag.LowerC) - for i := 0; i < base.Flag.LowerC; i++ { - workerIDs <- i + // By default, we perform work right away on the current goroutine + // as the solo worker. + queue := func(work func(int)) { + work(0) + } + + if nWorkers := base.Flag.LowerC; nWorkers > 1 { + // For concurrent builds, we create a goroutine per task, but + // require them to hold a unique worker ID while performing work + // to limit parallelism. + workerIDs := make(chan int, nWorkers) + for i := 0; i < nWorkers; i++ { + workerIDs <- i + } + + queue = func(work func(int)) { + go func() { + worker := <-workerIDs + work(worker) + workerIDs <- worker + }() + } } var wg sync.WaitGroup - var asyncCompile func(*ir.Func) - asyncCompile = func(fn *ir.Func) { - wg.Add(1) - go func() { - worker := <-workerIDs - ssagen.Compile(fn, worker) - workerIDs <- worker - - // Done compiling fn. Schedule it's closures for compilation. - for _, closure := range fn.Closures { - asyncCompile(closure) - } - wg.Done() - }() + var compile func([]*ir.Func) + compile = func(fns []*ir.Func) { + wg.Add(len(fns)) + for _, fn := range fns { + fn := fn + queue(func(worker int) { + ssagen.Compile(fn, worker) + compile(fn.Closures) + wg.Done() + }) + } } types.CalcSizeDisabled = true // not safe to calculate sizes concurrently base.Ctxt.InParallel = true - for _, fn := range compilequeue { - asyncCompile(fn) - } + + compile(compilequeue) compilequeue = nil wg.Wait() + base.Ctxt.InParallel = false types.CalcSizeDisabled = false } From 8ec8f6aa87569a6bc567d4a7039fc22a473b37ec Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Sun, 31 Jan 2021 04:21:47 +1100 Subject: [PATCH 008/940] runtime: switch openbsd/arm to pthreads This switches openbsd/arm to thread creation via pthreads, rather than doing direct system calls. Update #36435 Change-Id: Ia8749e3723a9967905c33b6d93dfd9be797a486c Reviewed-on: https://go-review.googlesource.com/c/go/+/315790 Trust: Joel Sing Reviewed-by: Cherry Mui --- src/runtime/asm_arm.s | 13 ++ src/runtime/defs_openbsd_arm.go | 9 ++ src/runtime/os_openbsd_libc.go | 4 +- src/runtime/os_openbsd_syscall.go | 4 +- src/runtime/proc.go | 2 +- src/runtime/sys_libc.go | 4 +- src/runtime/sys_openbsd.go | 4 +- src/runtime/sys_openbsd_arm.s | 207 ++++++++++++++++++------------ 8 files changed, 153 insertions(+), 94 deletions(-) diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index e779fc8f844..6d3573d68fb 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -142,6 +142,11 @@ TEXT runtime·rt0_go(SB),NOSPLIT|NOFRAME|TOPFRAME,$0 BL runtime·emptyfunc(SB) // fault if stack check is wrong +#ifdef GOOS_openbsd + // Save g to TLS so that it is available from signal trampoline. + BL runtime·save_g(SB) +#endif + BL runtime·_initcgo(SB) // will clobber R0-R3 // update stackguard after _cgo_init @@ -633,9 +638,13 @@ TEXT ·cgocallback(SB),NOSPLIT,$12-12 NO_LOCAL_POINTERS // Load m and g from thread-local storage. +#ifdef GOOS_openbsd + BL runtime·load_g(SB) +#else MOVB runtime·iscgo(SB), R0 CMP $0, R0 BL.NE runtime·load_g(SB) +#endif // If g is nil, Go did not create the current thread. // Call needm to obtain one for temporary use. @@ -744,6 +753,9 @@ TEXT setg<>(SB),NOSPLIT|NOFRAME,$0-0 // Save g to thread-local storage. #ifdef GOOS_windows B runtime·save_g(SB) +#else +#ifdef GOOS_openbsd + B runtime·save_g(SB) #else MOVB runtime·iscgo(SB), R0 CMP $0, R0 @@ -753,6 +765,7 @@ TEXT setg<>(SB),NOSPLIT|NOFRAME,$0-0 MOVW g, R0 RET #endif +#endif TEXT runtime·emptyfunc(SB),0,$0-0 RET diff --git a/src/runtime/defs_openbsd_arm.go b/src/runtime/defs_openbsd_arm.go index 170bb3876c4..9b84b5a3a3e 100644 --- a/src/runtime/defs_openbsd_arm.go +++ b/src/runtime/defs_openbsd_arm.go @@ -30,6 +30,8 @@ const ( _SA_RESTART = 0x2 _SA_ONSTACK = 0x1 + _PTHREAD_CREATE_DETACHED = 0x1 + _SIGHUP = 0x1 _SIGINT = 0x2 _SIGQUIT = 0x3 @@ -174,3 +176,10 @@ type keventt struct { udata *byte pad_cgo_1 [4]byte } + +type pthread uintptr +type pthreadattr uintptr +type pthreadcond uintptr +type pthreadcondattr uintptr +type pthreadmutex uintptr +type pthreadmutexattr uintptr diff --git a/src/runtime/os_openbsd_libc.go b/src/runtime/os_openbsd_libc.go index cff5a092d7c..8150753796b 100644 --- a/src/runtime/os_openbsd_libc.go +++ b/src/runtime/os_openbsd_libc.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (openbsd && 386) || (openbsd && amd64) || (openbsd && arm64) -// +build openbsd,386 openbsd,amd64 openbsd,arm64 +//go:build (openbsd && 386) || (openbsd && amd64) || (openbsd && arm) || (openbsd && arm64) +// +build openbsd,386 openbsd,amd64 openbsd,arm openbsd,arm64 package runtime diff --git a/src/runtime/os_openbsd_syscall.go b/src/runtime/os_openbsd_syscall.go index 53154879618..94e851cde8d 100644 --- a/src/runtime/os_openbsd_syscall.go +++ b/src/runtime/os_openbsd_syscall.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build openbsd && !386 && openbsd && !amd64 && openbsd && !arm64 -// +build openbsd,!386,openbsd,!amd64,openbsd,!arm64 +//go:build openbsd && !386 && openbsd && !amd64 && openbsd && !arm && openbsd && !arm64 +// +build openbsd,!386,openbsd,!amd64,openbsd,!arm,openbsd,!arm64 package runtime diff --git a/src/runtime/proc.go b/src/runtime/proc.go index d9f8c65530c..650ab6a1eee 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -1316,7 +1316,7 @@ func mStackIsSystemAllocated() bool { return true case "openbsd": switch GOARCH { - case "386", "amd64", "arm64": + case "386", "amd64", "arm", "arm64": return true } } diff --git a/src/runtime/sys_libc.go b/src/runtime/sys_libc.go index 91195eb3c01..346b1ab2850 100644 --- a/src/runtime/sys_libc.go +++ b/src/runtime/sys_libc.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build darwin || (openbsd && 386) || (openbsd && amd64) || (openbsd && arm64) -// +build darwin openbsd,386 openbsd,amd64 openbsd,arm64 +//go:build darwin || (openbsd && 386) || (openbsd && amd64) || (openbsd && arm) || (openbsd && arm64) +// +build darwin openbsd,386 openbsd,amd64 openbsd,arm openbsd,arm64 package runtime diff --git a/src/runtime/sys_openbsd.go b/src/runtime/sys_openbsd.go index f6146c2e1d1..89203bf85f4 100644 --- a/src/runtime/sys_openbsd.go +++ b/src/runtime/sys_openbsd.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (openbsd && 386) || (openbsd && amd64) || (openbsd && arm64) -// +build openbsd,386 openbsd,amd64 openbsd,arm64 +//go:build (openbsd && 386) || (openbsd && amd64) || (openbsd && arm) || (openbsd && arm64) +// +build openbsd,386 openbsd,amd64 openbsd,arm openbsd,arm64 package runtime diff --git a/src/runtime/sys_openbsd_arm.s b/src/runtime/sys_openbsd_arm.s index 45d69a312a8..65d29415b06 100644 --- a/src/runtime/sys_openbsd_arm.s +++ b/src/runtime/sys_openbsd_arm.s @@ -10,7 +10,7 @@ #include "go_tls.h" #include "textflag.h" -#define CLOCK_REALTIME $0 +#define CLOCK_REALTIME $0 #define CLOCK_MONOTONIC $3 // With OpenBSD 6.7 onwards, an armv7 syscall returns two instructions @@ -25,6 +25,127 @@ NOOP; \ NOOP +// mstart_stub is the first function executed on a new thread started by pthread_create. +// It just does some low-level setup and then calls mstart. +// Note: called with the C calling convention. +TEXT runtime·mstart_stub(SB),NOSPLIT,$0 + // R0 points to the m. + // We are already on m's g0 stack. + + // Save callee-save registers. + MOVM.DB.W [R4-R11], (R13) + + MOVW m_g0(R0), g + BL runtime·save_g(SB) + + BL runtime·mstart(SB) + + // Restore callee-save registers. + MOVM.IA.W (R13), [R4-R11] + + // Go is all done with this OS thread. + // Tell pthread everything is ok (we never join with this thread, so + // the value here doesn't really matter). + MOVW $0, R0 + RET + +TEXT runtime·sigfwd(SB),NOSPLIT,$0-16 + MOVW sig+4(FP), R0 + MOVW info+8(FP), R1 + MOVW ctx+12(FP), R2 + MOVW fn+0(FP), R3 + MOVW R13, R9 + SUB $24, R13 + BIC $0x7, R13 // alignment for ELF ABI + BL (R3) + MOVW R9, R13 + RET + +TEXT runtime·sigtramp(SB),NOSPLIT,$0 + // Reserve space for callee-save registers and arguments. + MOVM.DB.W [R4-R11], (R13) + SUB $16, R13 + + // If called from an external code context, g will not be set. + // Save R0, since runtime·load_g will clobber it. + MOVW R0, 4(R13) // signum + BL runtime·load_g(SB) + + MOVW R1, 8(R13) + MOVW R2, 12(R13) + BL runtime·sigtrampgo(SB) + + // Restore callee-save registers. + ADD $16, R13 + MOVM.IA.W (R13), [R4-R11] + + RET + +TEXT ·publicationBarrier(SB),NOSPLIT|NOFRAME,$0-0 + B runtime·armPublicationBarrier(SB) + +// TODO(jsing): OpenBSD only supports GOARM=7 machines... this +// should not be needed, however the linker still allows GOARM=5 +// on this platform. +TEXT runtime·read_tls_fallback(SB),NOSPLIT|NOFRAME,$0 + MOVM.WP [R1, R2, R3, R12], (R13) + MOVW $330, R12 // sys___get_tcb + INVOKE_SYSCALL + MOVM.IAW (R13), [R1, R2, R3, R12] + RET + +// These trampolines help convert from Go calling convention to C calling convention. +// They should be called with asmcgocall - note that while asmcgocall does +// stack alignment, creation of a frame undoes it again. +// A pointer to the arguments is passed in R0. +// A single int32 result is returned in R0. +// (For more results, make an args/results structure.) +TEXT runtime·pthread_attr_init_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + BIC $0x7, R13 // align for ELF ABI + MOVW 0(R0), R0 // arg 1 attr + BL libc_pthread_attr_init(SB) + MOVW R9, R13 + RET + +TEXT runtime·pthread_attr_destroy_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + BIC $0x7, R13 // align for ELF ABI + MOVW 0(R0), R0 // arg 1 attr + BL libc_pthread_attr_destroy(SB) + MOVW R9, R13 + RET + +TEXT runtime·pthread_attr_getstacksize_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + BIC $0x7, R13 // align for ELF ABI + MOVW 4(R0), R1 // arg 2 size + MOVW 0(R0), R0 // arg 1 attr + BL libc_pthread_attr_getstacksize(SB) + MOVW R9, R13 + RET + +TEXT runtime·pthread_attr_setdetachstate_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + BIC $0x7, R13 // align for ELF ABI + MOVW 4(R0), R1 // arg 2 state + MOVW 0(R0), R0 // arg 1 attr + BL libc_pthread_attr_setdetachstate(SB) + MOVW R9, R13 + RET + +TEXT runtime·pthread_create_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + SUB $16, R13 + BIC $0x7, R13 // align for ELF ABI + MOVW 0(R0), R1 // arg 2 attr + MOVW 4(R0), R2 // arg 3 start + MOVW 8(R0), R3 // arg 4 arg + MOVW R13, R0 // arg 1 &threadid (discarded) + BL libc_pthread_create(SB) + MOVW R9, R13 + RET + // Exit the entire program (like C exit) TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0 MOVW code+0(FP), R0 // arg 1 - status @@ -247,80 +368,6 @@ TEXT runtime·obsdsigprocmask(SB),NOSPLIT,$0 MOVW R0, ret+8(FP) RET -TEXT runtime·sigfwd(SB),NOSPLIT,$0-16 - MOVW sig+4(FP), R0 - MOVW info+8(FP), R1 - MOVW ctx+12(FP), R2 - MOVW fn+0(FP), R11 - MOVW R13, R4 - SUB $24, R13 - BIC $0x7, R13 // alignment for ELF ABI - BL (R11) - MOVW R4, R13 - RET - -TEXT runtime·sigtramp(SB),NOSPLIT,$0 - // Reserve space for callee-save registers and arguments. - MOVM.DB.W [R4-R11], (R13) - SUB $16, R13 - - // If called from an external code context, g will not be set. - // Save R0, since runtime·load_g will clobber it. - MOVW R0, 4(R13) // signum - MOVB runtime·iscgo(SB), R0 - CMP $0, R0 - BL.NE runtime·load_g(SB) - - MOVW R1, 8(R13) - MOVW R2, 12(R13) - BL runtime·sigtrampgo(SB) - - // Restore callee-save registers. - ADD $16, R13 - MOVM.IA.W (R13), [R4-R11] - - RET - -// int32 tfork(void *param, uintptr psize, M *mp, G *gp, void (*fn)(void)); -TEXT runtime·tfork(SB),NOSPLIT,$0 - - // Copy mp, gp and fn off parent stack for use by child. - MOVW mm+8(FP), R4 - MOVW gg+12(FP), R5 - MOVW fn+16(FP), R6 - - MOVW param+0(FP), R0 // arg 1 - param - MOVW psize+4(FP), R1 // arg 2 - psize - MOVW $8, R12 // sys___tfork - INVOKE_SYSCALL - - // Return if syscall failed. - B.CC 4(PC) - RSB $0, R0 - MOVW R0, ret+20(FP) - RET - - // In parent, return. - CMP $0, R0 - BEQ 3(PC) - MOVW R0, ret+20(FP) - RET - - // Initialise m, g. - MOVW R5, g - MOVW R4, g_m(g) - - // Paranoia; check that stack splitting code works. - BL runtime·emptyfunc(SB) - - // Call fn. - BL (R6) - - // fn should never return. - MOVW $2, R8 // crash if reached - MOVW R8, (R8) - RET - TEXT runtime·sigaltstack(SB),NOSPLIT,$0 MOVW new+0(FP), R0 // arg 1 - new sigaltstack MOVW old+4(FP), R1 // arg 2 - old sigaltstack @@ -423,13 +470,3 @@ TEXT runtime·setNonblock(SB),NOSPLIT,$0-4 MOVW $92, R12 INVOKE_SYSCALL RET - -TEXT ·publicationBarrier(SB),NOSPLIT|NOFRAME,$0-0 - B runtime·armPublicationBarrier(SB) - -TEXT runtime·read_tls_fallback(SB),NOSPLIT|NOFRAME,$0 - MOVM.WP [R1, R2, R3, R12], (R13) - MOVW $330, R12 // sys___get_tcb - INVOKE_SYSCALL - MOVM.IAW (R13), [R1, R2, R3, R12] - RET From 83df4a590bbd259b82db37e0c6e721ddc267614b Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Mon, 1 Feb 2021 03:51:02 +1100 Subject: [PATCH 009/940] runtime: switch openbsd/arm locking to libc Switch openbsd/arm to locking via libc, rather than performing direct system calls. Update #36435 Change-Id: I190abb1aa544d2cb406fe412960ec106c9716f87 Reviewed-on: https://go-review.googlesource.com/c/go/+/315791 Trust: Joel Sing Reviewed-by: Cherry Mui --- src/runtime/os_openbsd_syscall1.go | 4 +- src/runtime/sys_openbsd1.go | 4 +- src/runtime/sys_openbsd_arm.s | 67 ++++++++++++++++-------------- 3 files changed, 39 insertions(+), 36 deletions(-) diff --git a/src/runtime/os_openbsd_syscall1.go b/src/runtime/os_openbsd_syscall1.go index ecae67aa2fc..f8f666890aa 100644 --- a/src/runtime/os_openbsd_syscall1.go +++ b/src/runtime/os_openbsd_syscall1.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build openbsd && !386 && !amd64 && !arm64 -// +build openbsd,!386,!amd64,!arm64 +//go:build openbsd && !386 && !amd64 && !arm && !arm64 +// +build openbsd,!386,!amd64,!arm,!arm64 package runtime diff --git a/src/runtime/sys_openbsd1.go b/src/runtime/sys_openbsd1.go index b007b6d3f59..1af48539faa 100644 --- a/src/runtime/sys_openbsd1.go +++ b/src/runtime/sys_openbsd1.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (openbsd && 386) || (openbsd && amd64) || (openbsd && arm64) -// +build openbsd,386 openbsd,amd64 openbsd,arm64 +//go:build (openbsd && 386) || (openbsd && amd64) || (openbsd && arm) || (openbsd && arm64) +// +build openbsd,386 openbsd,amd64 openbsd,arm openbsd,arm64 package runtime diff --git a/src/runtime/sys_openbsd_arm.s b/src/runtime/sys_openbsd_arm.s index 65d29415b06..1402402de3c 100644 --- a/src/runtime/sys_openbsd_arm.s +++ b/src/runtime/sys_openbsd_arm.s @@ -104,7 +104,7 @@ TEXT runtime·pthread_attr_init_trampoline(SB),NOSPLIT,$0 MOVW R13, R9 BIC $0x7, R13 // align for ELF ABI MOVW 0(R0), R0 // arg 1 attr - BL libc_pthread_attr_init(SB) + CALL libc_pthread_attr_init(SB) MOVW R9, R13 RET @@ -112,7 +112,7 @@ TEXT runtime·pthread_attr_destroy_trampoline(SB),NOSPLIT,$0 MOVW R13, R9 BIC $0x7, R13 // align for ELF ABI MOVW 0(R0), R0 // arg 1 attr - BL libc_pthread_attr_destroy(SB) + CALL libc_pthread_attr_destroy(SB) MOVW R9, R13 RET @@ -121,7 +121,7 @@ TEXT runtime·pthread_attr_getstacksize_trampoline(SB),NOSPLIT,$0 BIC $0x7, R13 // align for ELF ABI MOVW 4(R0), R1 // arg 2 size MOVW 0(R0), R0 // arg 1 attr - BL libc_pthread_attr_getstacksize(SB) + CALL libc_pthread_attr_getstacksize(SB) MOVW R9, R13 RET @@ -130,7 +130,7 @@ TEXT runtime·pthread_attr_setdetachstate_trampoline(SB),NOSPLIT,$0 BIC $0x7, R13 // align for ELF ABI MOVW 4(R0), R1 // arg 2 state MOVW 0(R0), R0 // arg 1 attr - BL libc_pthread_attr_setdetachstate(SB) + CALL libc_pthread_attr_setdetachstate(SB) MOVW R9, R13 RET @@ -142,7 +142,37 @@ TEXT runtime·pthread_create_trampoline(SB),NOSPLIT,$0 MOVW 4(R0), R2 // arg 3 start MOVW 8(R0), R3 // arg 4 arg MOVW R13, R0 // arg 1 &threadid (discarded) - BL libc_pthread_create(SB) + CALL libc_pthread_create(SB) + MOVW R9, R13 + RET + +TEXT runtime·thrsleep_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + SUB $16, R13 + BIC $0x7, R13 // align for ELF ABI + MOVW 4(R0), R1 // arg 2 - clock_id + MOVW 8(R0), R2 // arg 3 - abstime + MOVW 12(R0), R3 // arg 4 - lock + MOVW 16(R0), R4 // arg 5 - abort (on stack) + MOVW R4, 0(R13) + MOVW 0(R0), R0 // arg 1 - id + CALL libc_thrsleep(SB) + MOVW R9, R13 + RET + +TEXT runtime·thrwakeup_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + BIC $0x7, R13 // align for ELF ABI + MOVW 4(R0), R1 // arg 2 - count + MOVW 0(R0), R0 // arg 1 - id + CALL libc_thrwakeup(SB) + MOVW R9, R13 + RET + +TEXT runtime·sched_yield_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + BIC $0x7, R13 // align for ELF ABI + CALL libc_sched_yield(SB) MOVW R9, R13 RET @@ -377,33 +407,6 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$0 MOVW.CS R8, (R8) RET -TEXT runtime·osyield(SB),NOSPLIT,$0 - MOVW $298, R12 // sys_sched_yield - INVOKE_SYSCALL - RET - -TEXT runtime·thrsleep(SB),NOSPLIT,$4 - MOVW ident+0(FP), R0 // arg 1 - ident - MOVW clock_id+4(FP), R1 // arg 2 - clock_id - MOVW tsp+8(FP), R2 // arg 3 - tsp - MOVW lock+12(FP), R3 // arg 4 - lock - MOVW abort+16(FP), R4 // arg 5 - abort (on stack) - MOVW R4, 4(R13) - ADD $4, R13 - MOVW $94, R12 // sys___thrsleep - INVOKE_SYSCALL - SUB $4, R13 - MOVW R0, ret+20(FP) - RET - -TEXT runtime·thrwakeup(SB),NOSPLIT,$0 - MOVW ident+0(FP), R0 // arg 1 - ident - MOVW n+4(FP), R1 // arg 2 - n - MOVW $301, R12 // sys___thrwakeup - INVOKE_SYSCALL - MOVW R0, ret+8(FP) - RET - TEXT runtime·sysctl(SB),NOSPLIT,$8 MOVW mib+0(FP), R0 // arg 1 - mib MOVW miblen+4(FP), R1 // arg 2 - miblen From 603f43cbae1f29c9c167b2b331dc31c8486c888b Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Wed, 3 Feb 2021 18:17:35 +1100 Subject: [PATCH 010/940] runtime: switch runtime to libc for openbsd/arm Use libc rather than performing direct system calls for the runtime on openbsd/arm. Updates #36435 Change-Id: If64a96a61c80b9748792f8a85a8f16ed6ebca91f Reviewed-on: https://go-review.googlesource.com/c/go/+/315792 Trust: Joel Sing Reviewed-by: Cherry Mui --- src/runtime/defs_openbsd_arm.go | 5 + src/runtime/os_openbsd_syscall2.go | 4 +- src/runtime/proc.go | 2 +- src/runtime/sys_openbsd2.go | 4 +- src/runtime/sys_openbsd_arm.s | 522 ++++++++++++++--------------- 5 files changed, 267 insertions(+), 270 deletions(-) diff --git a/src/runtime/defs_openbsd_arm.go b/src/runtime/defs_openbsd_arm.go index 9b84b5a3a3e..6f128c4284b 100644 --- a/src/runtime/defs_openbsd_arm.go +++ b/src/runtime/defs_openbsd_arm.go @@ -32,6 +32,11 @@ const ( _PTHREAD_CREATE_DETACHED = 0x1 + _F_SETFD = 0x2 + _F_GETFL = 0x3 + _F_SETFL = 0x4 + _FD_CLOEXEC = 0x1 + _SIGHUP = 0x1 _SIGINT = 0x2 _SIGQUIT = 0x3 diff --git a/src/runtime/os_openbsd_syscall2.go b/src/runtime/os_openbsd_syscall2.go index 6aa57a99da1..84543acec4a 100644 --- a/src/runtime/os_openbsd_syscall2.go +++ b/src/runtime/os_openbsd_syscall2.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build openbsd && !386 && !amd64 && !arm64 -// +build openbsd,!386,!amd64,!arm64 +//go:build openbsd && !386 && !amd64 && !arm && !arm64 +// +build openbsd,!386,!amd64,!arm,!arm64 package runtime diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 650ab6a1eee..ba02b149952 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -1303,7 +1303,7 @@ func usesLibcall() bool { case "aix", "darwin", "illumos", "ios", "solaris", "windows": return true case "openbsd": - return GOARCH == "386" || GOARCH == "amd64" || GOARCH == "arm64" + return GOARCH == "386" || GOARCH == "amd64" || GOARCH == "arm" || GOARCH == "arm64" } return false } diff --git a/src/runtime/sys_openbsd2.go b/src/runtime/sys_openbsd2.go index 91ed04fb486..2d53f67a616 100644 --- a/src/runtime/sys_openbsd2.go +++ b/src/runtime/sys_openbsd2.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (openbsd && 386) || (openbsd && amd64) || (openbsd && arm64) -// +build openbsd,386 openbsd,amd64 openbsd,arm64 +//go:build (openbsd && 386) || (openbsd && amd64) || (openbsd && arm) || (openbsd && arm64) +// +build openbsd,386 openbsd,amd64 openbsd,arm openbsd,arm64 package runtime diff --git a/src/runtime/sys_openbsd_arm.s b/src/runtime/sys_openbsd_arm.s index 1402402de3c..49cb19bbff9 100644 --- a/src/runtime/sys_openbsd_arm.s +++ b/src/runtime/sys_openbsd_arm.s @@ -146,6 +146,16 @@ TEXT runtime·pthread_create_trampoline(SB),NOSPLIT,$0 MOVW R9, R13 RET +TEXT runtime·thrkill_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + BIC $0x7, R13 // align for ELF ABI + MOVW 4(R0), R1 // arg 2 - signal + MOVW $0, R2 // arg 3 - tcb + MOVW 0(R0), R0 // arg 1 - tid + CALL libc_thrkill(SB) + MOVW R9, R13 + RET + TEXT runtime·thrsleep_trampoline(SB),NOSPLIT,$0 MOVW R13, R9 SUB $16, R13 @@ -169,307 +179,289 @@ TEXT runtime·thrwakeup_trampoline(SB),NOSPLIT,$0 MOVW R9, R13 RET -TEXT runtime·sched_yield_trampoline(SB),NOSPLIT,$0 +TEXT runtime·exit_trampoline(SB),NOSPLIT,$0 MOVW R13, R9 BIC $0x7, R13 // align for ELF ABI - CALL libc_sched_yield(SB) + MOVW 0(R0), R0 // arg 1 exit status + BL libc_exit(SB) + MOVW $0, R8 // crash on failure + MOVW R8, (R8) MOVW R9, R13 RET -// Exit the entire program (like C exit) -TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0 - MOVW code+0(FP), R0 // arg 1 - status - MOVW $1, R12 // sys_exit - INVOKE_SYSCALL - MOVW.CS $0, R8 // crash on syscall failure - MOVW.CS R8, (R8) +TEXT runtime·getthrid_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + MOVW R0, R8 + BIC $0x7, R13 // align for ELF ABI + BL libc_getthrid(SB) + MOVW R0, 0(R8) + MOVW R9, R13 RET -// func exitThread(wait *uint32) -TEXT runtime·exitThread(SB),NOSPLIT,$0-4 - MOVW wait+0(FP), R0 // arg 1 - notdead - MOVW $302, R12 // sys___threxit - INVOKE_SYSCALL - MOVW.CS $1, R8 // crash on syscall failure - MOVW.CS R8, (R8) - JMP 0(PC) - -TEXT runtime·open(SB),NOSPLIT|NOFRAME,$0 - MOVW name+0(FP), R0 // arg 1 - path - MOVW mode+4(FP), R1 // arg 2 - mode - MOVW perm+8(FP), R2 // arg 3 - perm - MOVW $5, R12 // sys_open - INVOKE_SYSCALL - MOVW.CS $-1, R0 - MOVW R0, ret+12(FP) +TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + BIC $0x7, R13 // align for ELF ABI + MOVW R0, R4 + BL libc_getpid(SB) // arg 1 pid + MOVW R4, R1 // arg 2 signal + BL libc_kill(SB) + MOVW R9, R13 RET -TEXT runtime·closefd(SB),NOSPLIT|NOFRAME,$0 - MOVW fd+0(FP), R0 // arg 1 - fd - MOVW $6, R12 // sys_close - INVOKE_SYSCALL - MOVW.CS $-1, R0 - MOVW R0, ret+4(FP) +TEXT runtime·sched_yield_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + BIC $0x7, R13 // align for ELF ABI + BL libc_sched_yield(SB) + MOVW R9, R13 RET -TEXT runtime·read(SB),NOSPLIT|NOFRAME,$0 - MOVW fd+0(FP), R0 // arg 1 - fd - MOVW p+4(FP), R1 // arg 2 - buf - MOVW n+8(FP), R2 // arg 3 - nbyte - MOVW $3, R12 // sys_read - INVOKE_SYSCALL - RSB.CS $0, R0 // caller expects negative errno - MOVW R0, ret+12(FP) - RET - -// func pipe() (r, w int32, errno int32) -TEXT runtime·pipe(SB),NOSPLIT,$0-12 - MOVW $r+0(FP), R0 - MOVW $263, R12 - INVOKE_SYSCALL - MOVW R0, errno+8(FP) - RET - -// func pipe2(flags int32) (r, w int32, errno int32) -TEXT runtime·pipe2(SB),NOSPLIT,$0-16 - MOVW $r+4(FP), R0 - MOVW flags+0(FP), R1 - MOVW $101, R12 - INVOKE_SYSCALL - MOVW R0, errno+12(FP) - RET - -TEXT runtime·write1(SB),NOSPLIT|NOFRAME,$0 - MOVW fd+0(FP), R0 // arg 1 - fd - MOVW p+4(FP), R1 // arg 2 - buf - MOVW n+8(FP), R2 // arg 3 - nbyte - MOVW $4, R12 // sys_write - INVOKE_SYSCALL - RSB.CS $0, R0 // caller expects negative errno - MOVW R0, ret+12(FP) - RET - -TEXT runtime·usleep(SB),NOSPLIT,$16 - MOVW usec+0(FP), R0 - CALL runtime·usplitR0(SB) - MOVW R0, 4(R13) // tv_sec - l32 - MOVW $0, R0 - MOVW R0, 8(R13) // tv_sec - h32 - MOVW $1000, R2 - MUL R1, R2 - MOVW R2, 12(R13) // tv_nsec - - MOVW $4(R13), R0 // arg 1 - rqtp - MOVW $0, R1 // arg 2 - rmtp - MOVW $91, R12 // sys_nanosleep - INVOKE_SYSCALL - RET - -TEXT runtime·getthrid(SB),NOSPLIT,$0-4 - MOVW $299, R12 // sys_getthrid - INVOKE_SYSCALL - MOVW R0, ret+0(FP) - RET - -TEXT runtime·thrkill(SB),NOSPLIT,$0-8 - MOVW tid+0(FP), R0 // arg 1 - tid - MOVW sig+4(FP), R1 // arg 2 - signum - MOVW $0, R2 // arg 3 - tcb - MOVW $119, R12 // sys_thrkill - INVOKE_SYSCALL - RET - -TEXT runtime·raiseproc(SB),NOSPLIT,$12 - MOVW $20, R12 // sys_getpid - INVOKE_SYSCALL - // arg 1 - pid, already in R0 - MOVW sig+0(FP), R1 // arg 2 - signum - MOVW $122, R12 // sys_kill - INVOKE_SYSCALL - RET - -TEXT runtime·mmap(SB),NOSPLIT,$16 - MOVW addr+0(FP), R0 // arg 1 - addr - MOVW n+4(FP), R1 // arg 2 - len - MOVW prot+8(FP), R2 // arg 3 - prot - MOVW flags+12(FP), R3 // arg 4 - flags - MOVW fd+16(FP), R4 // arg 5 - fd (on stack) - MOVW R4, 4(R13) - MOVW $0, R5 // arg 6 - pad (on stack) - MOVW R5, 8(R13) - MOVW off+20(FP), R6 // arg 7 - offset (on stack) - MOVW R6, 12(R13) // lower 32 bits (from Go runtime) - MOVW $0, R7 - MOVW R7, 16(R13) // high 32 bits - ADD $4, R13 - MOVW $197, R12 // sys_mmap - INVOKE_SYSCALL - SUB $4, R13 +TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + SUB $16, R13 + BIC $0x7, R13 // align for ELF ABI + MOVW R0, R8 + MOVW 4(R0), R1 // arg 2 len + MOVW 8(R0), R2 // arg 3 prot + MOVW 12(R0), R3 // arg 4 flags + MOVW 16(R0), R4 // arg 5 fid (on stack) + MOVW R4, 0(R13) + MOVW $0, R5 // pad (on stack) + MOVW R5, 4(R13) + MOVW 20(R0), R6 // arg 6 offset (on stack) + MOVW R6, 8(R13) // low 32 bits + MOVW $0, R7 + MOVW R7, 12(R13) // high 32 bits + MOVW 0(R0), R0 // arg 1 addr + BL libc_mmap(SB) MOVW $0, R1 - MOVW.CS R0, R1 // if error, move to R1 - MOVW.CS $0, R0 - MOVW R0, p+24(FP) - MOVW R1, err+28(FP) + CMP $-1, R0 + BNE ok + BL libc_errno(SB) + MOVW (R0), R1 // errno + MOVW $0, R0 +ok: + MOVW R0, 24(R8) + MOVW R1, 28(R8) + MOVW R9, R13 RET -TEXT runtime·munmap(SB),NOSPLIT,$0 - MOVW addr+0(FP), R0 // arg 1 - addr - MOVW n+4(FP), R1 // arg 2 - len - MOVW $73, R12 // sys_munmap - INVOKE_SYSCALL - MOVW.CS $0, R8 // crash on syscall failure - MOVW.CS R8, (R8) +TEXT runtime·munmap_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + BIC $0x7, R13 // align for ELF ABI + MOVW 4(R0), R1 // arg 2 len + MOVW 0(R0), R0 // arg 1 addr + BL libc_munmap(SB) + CMP $-1, R0 + BNE 3(PC) + MOVW $0, R8 // crash on failure + MOVW R8, (R8) + MOVW R9, R13 RET -TEXT runtime·madvise(SB),NOSPLIT,$0 - MOVW addr+0(FP), R0 // arg 1 - addr - MOVW n+4(FP), R1 // arg 2 - len - MOVW flags+8(FP), R2 // arg 2 - flags - MOVW $75, R12 // sys_madvise - INVOKE_SYSCALL - MOVW.CS $-1, R0 - MOVW R0, ret+12(FP) +TEXT runtime·madvise_trampoline(SB), NOSPLIT, $0 + MOVW R13, R9 + BIC $0x7, R13 // align for ELF ABI + MOVW 4(R0), R1 // arg 2 len + MOVW 8(R0), R2 // arg 3 advice + MOVW 0(R0), R0 // arg 1 addr + BL libc_madvise(SB) + // ignore failure - maybe pages are locked + MOVW R9, R13 RET -TEXT runtime·setitimer(SB),NOSPLIT,$0 - MOVW mode+0(FP), R0 // arg 1 - mode - MOVW new+4(FP), R1 // arg 2 - new value - MOVW old+8(FP), R2 // arg 3 - old value - MOVW $69, R12 // sys_setitimer - INVOKE_SYSCALL +TEXT runtime·open_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + SUB $8, R13 + BIC $0x7, R13 // align for ELF ABI + MOVW 4(R0), R1 // arg 2 - flags + MOVW 8(R0), R2 // arg 3 - mode (vararg, on stack) + MOVW R2, 0(R13) + MOVW 0(R0), R0 // arg 1 - path + MOVW R13, R4 + BIC $0x7, R13 // align for ELF ABI + BL libc_open(SB) + MOVW R9, R13 RET -// func walltime() (sec int64, nsec int32) -TEXT runtime·walltime(SB), NOSPLIT, $32 - MOVW CLOCK_REALTIME, R0 // arg 1 - clock_id - MOVW $8(R13), R1 // arg 2 - tp - MOVW $87, R12 // sys_clock_gettime - INVOKE_SYSCALL - - MOVW 8(R13), R0 // sec - l32 - MOVW 12(R13), R1 // sec - h32 - MOVW 16(R13), R2 // nsec - - MOVW R0, sec_lo+0(FP) - MOVW R1, sec_hi+4(FP) - MOVW R2, nsec+8(FP) - +TEXT runtime·close_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + BIC $0x7, R13 // align for ELF ABI + MOVW 0(R0), R0 // arg 1 - fd + BL libc_close(SB) + MOVW R9, R13 RET -// int64 nanotime1(void) so really -// void nanotime1(int64 *nsec) -TEXT runtime·nanotime1(SB),NOSPLIT,$32 - MOVW CLOCK_MONOTONIC, R0 // arg 1 - clock_id - MOVW $8(R13), R1 // arg 2 - tp - MOVW $87, R12 // sys_clock_gettime - INVOKE_SYSCALL - - MOVW 8(R13), R0 // sec - l32 - MOVW 12(R13), R4 // sec - h32 - MOVW 16(R13), R2 // nsec - - MOVW $1000000000, R3 - MULLU R0, R3, (R1, R0) - MUL R3, R4 - ADD.S R2, R0 - ADC R4, R1 - - MOVW R0, ret_lo+0(FP) - MOVW R1, ret_hi+4(FP) +TEXT runtime·read_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + BIC $0x7, R13 // align for ELF ABI + MOVW 4(R0), R1 // arg 2 - buf + MOVW 8(R0), R2 // arg 3 - count + MOVW 0(R0), R0 // arg 1 - fd + BL libc_read(SB) + CMP $-1, R0 + BNE noerr + BL libc_errno(SB) + MOVW (R0), R0 // errno + RSB.CS $0, R0 // caller expects negative errno +noerr: + MOVW R9, R13 RET -TEXT runtime·sigaction(SB),NOSPLIT,$0 - MOVW sig+0(FP), R0 // arg 1 - signum - MOVW new+4(FP), R1 // arg 2 - new sigaction - MOVW old+8(FP), R2 // arg 3 - old sigaction - MOVW $46, R12 // sys_sigaction - INVOKE_SYSCALL - MOVW.CS $3, R8 // crash on syscall failure - MOVW.CS R8, (R8) +TEXT runtime·write_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + BIC $0x7, R13 // align for ELF ABI + MOVW 4(R0), R1 // arg 2 buf + MOVW 8(R0), R2 // arg 3 count + MOVW 0(R0), R0 // arg 1 fd + BL libc_write(SB) + CMP $-1, R0 + BNE noerr + BL libc_errno(SB) + MOVW (R0), R0 // errno + RSB.CS $0, R0 // caller expects negative errno +noerr: + MOVW R9, R13 RET -TEXT runtime·obsdsigprocmask(SB),NOSPLIT,$0 - MOVW how+0(FP), R0 // arg 1 - mode - MOVW new+4(FP), R1 // arg 2 - new - MOVW $48, R12 // sys_sigprocmask - INVOKE_SYSCALL - MOVW.CS $3, R8 // crash on syscall failure - MOVW.CS R8, (R8) - MOVW R0, ret+8(FP) +TEXT runtime·pipe2_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + BIC $0x7, R13 // align for ELF ABI + MOVW 4(R0), R1 // arg 2 flags + MOVW 0(R0), R0 // arg 1 filedes + BL libc_pipe2(SB) + CMP $-1, R0 + BNE 3(PC) + BL libc_errno(SB) + MOVW (R0), R0 // errno + RSB.CS $0, R0 // caller expects negative errno + MOVW R9, R13 RET -TEXT runtime·sigaltstack(SB),NOSPLIT,$0 - MOVW new+0(FP), R0 // arg 1 - new sigaltstack - MOVW old+4(FP), R1 // arg 2 - old sigaltstack - MOVW $288, R12 // sys_sigaltstack - INVOKE_SYSCALL - MOVW.CS $0, R8 // crash on syscall failure - MOVW.CS R8, (R8) +TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + BIC $0x7, R13 // align for ELF ABI + MOVW 4(R0), R1 // arg 2 new + MOVW 8(R0), R2 // arg 3 old + MOVW 0(R0), R0 // arg 1 which + BL libc_setitimer(SB) + MOVW R9, R13 RET -TEXT runtime·sysctl(SB),NOSPLIT,$8 - MOVW mib+0(FP), R0 // arg 1 - mib - MOVW miblen+4(FP), R1 // arg 2 - miblen - MOVW out+8(FP), R2 // arg 3 - out - MOVW size+12(FP), R3 // arg 4 - size - MOVW dst+16(FP), R4 // arg 5 - dest (on stack) - MOVW R4, 4(R13) - MOVW ndst+20(FP), R5 // arg 6 - newlen (on stack) - MOVW R5, 8(R13) - ADD $4, R13 - MOVW $202, R12 // sys___sysctl - INVOKE_SYSCALL - SUB $4, R13 - MOVW.CC $0, R0 - RSB.CS $0, R0 - MOVW R0, ret+24(FP) +TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + BIC $0x7, R13 // align for ELF ABI + MOVW 0(R0), R0 // arg 1 usec + BL libc_usleep(SB) + MOVW R9, R13 RET -// int32 runtime·kqueue(void); -TEXT runtime·kqueue(SB),NOSPLIT,$0 - MOVW $269, R12 // sys_kqueue - INVOKE_SYSCALL - RSB.CS $0, R0 - MOVW R0, ret+0(FP) +TEXT runtime·sysctl_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + SUB $8, R13 + BIC $0x7, R13 // align for ELF ABI + MOVW 4(R0), R1 // arg 2 miblen + MOVW 8(R0), R2 // arg 3 out + MOVW 12(R0), R3 // arg 4 size + MOVW 16(R0), R4 // arg 5 dst (on stack) + MOVW R4, 0(R13) + MOVW 20(R0), R5 // arg 6 ndst (on stack) + MOVW R5, 4(R13) + MOVW 0(R0), R0 // arg 1 mib + BL libc_sysctl(SB) + MOVW R9, R13 RET -// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout); -TEXT runtime·kevent(SB),NOSPLIT,$8 - MOVW kq+0(FP), R0 // arg 1 - kq - MOVW ch+4(FP), R1 // arg 2 - changelist - MOVW nch+8(FP), R2 // arg 3 - nchanges - MOVW ev+12(FP), R3 // arg 4 - eventlist - MOVW nev+16(FP), R4 // arg 5 - nevents (on stack) - MOVW R4, 4(R13) - MOVW ts+20(FP), R5 // arg 6 - timeout (on stack) - MOVW R5, 8(R13) - ADD $4, R13 - MOVW $72, R12 // sys_kevent - INVOKE_SYSCALL - RSB.CS $0, R0 - SUB $4, R13 - MOVW R0, ret+24(FP) +TEXT runtime·kqueue_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + BIC $0x7, R13 // align for ELF ABI + BL libc_kqueue(SB) + MOVW R9, R13 RET -// func closeonexec(fd int32) -TEXT runtime·closeonexec(SB),NOSPLIT,$0 - MOVW fd+0(FP), R0 // arg 1 - fd - MOVW $2, R1 // arg 2 - cmd (F_SETFD) - MOVW $1, R2 // arg 3 - arg (FD_CLOEXEC) - MOVW $92, R12 // sys_fcntl - INVOKE_SYSCALL +TEXT runtime·kevent_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + SUB $8, R13 + BIC $0x7, R13 // align for ELF ABI + MOVW 4(R0), R1 // arg 2 keventt + MOVW 8(R0), R2 // arg 3 nch + MOVW 12(R0), R3 // arg 4 ev + MOVW 16(R0), R4 // arg 5 nev (on stack) + MOVW R4, 0(R13) + MOVW 20(R0), R5 // arg 6 ts (on stack) + MOVW R5, 4(R13) + MOVW 0(R0), R0 // arg 1 kq + BL libc_kevent(SB) + CMP $-1, R0 + BNE ok + BL libc_errno(SB) + MOVW (R0), R0 // errno + RSB.CS $0, R0 // caller expects negative errno +ok: + MOVW R9, R13 RET -// func runtime·setNonblock(fd int32) -TEXT runtime·setNonblock(SB),NOSPLIT,$0-4 - MOVW fd+0(FP), R0 // fd - MOVW $3, R1 // F_GETFL - MOVW $0, R2 - MOVW $92, R12 - INVOKE_SYSCALL - ORR $0x4, R0, R2 // O_NONBLOCK - MOVW fd+0(FP), R0 // fd - MOVW $4, R1 // F_SETFL - MOVW $92, R12 - INVOKE_SYSCALL +TEXT runtime·clock_gettime_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + BIC $0x7, R13 // align for ELF ABI + MOVW 4(R0), R1 // arg 2 tp + MOVW 0(R0), R0 // arg 1 clock_id + BL libc_clock_gettime(SB) + CMP $-1, R0 + BNE 3(PC) + MOVW $0, R8 // crash on failure + MOVW R8, (R8) + MOVW R9, R13 + RET + +TEXT runtime·fcntl_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + SUB $8, R13 + BIC $0x7, R13 // align for ELF ABI + MOVW 4(R0), R1 // arg 2 cmd + MOVW 8(R0), R2 // arg 3 arg (vararg, on stack) + MOVW R2, 0(R13) + MOVW 0(R0), R0 // arg 1 fd + BL libc_fcntl(SB) + MOVW R9, R13 + RET + +TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + BIC $0x7, R13 // align for ELF ABI + MOVW 4(R0), R1 // arg 2 new + MOVW 8(R0), R2 // arg 3 old + MOVW 0(R0), R0 // arg 1 sig + BL libc_sigaction(SB) + CMP $-1, R0 + BNE 3(PC) + MOVW $0, R8 // crash on failure + MOVW R8, (R8) + MOVW R9, R13 + RET + +TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + BIC $0x7, R13 // align for ELF ABI + MOVW 4(R0), R1 // arg 2 new + MOVW 8(R0), R2 // arg 3 old + MOVW 0(R0), R0 // arg 1 how + BL libc_pthread_sigmask(SB) + CMP $-1, R0 + BNE 3(PC) + MOVW $0, R8 // crash on failure + MOVW R8, (R8) + MOVW R9, R13 + RET + +TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0 + MOVW R13, R9 + BIC $0x7, R13 // align for ELF ABI + MOVW 4(R0), R1 // arg 2 old + MOVW 0(R0), R0 // arg 1 new + BL libc_sigaltstack(SB) + CMP $-1, R0 + BNE 3(PC) + MOVW $0, R8 // crash on failure + MOVW R8, (R8) + MOVW R9, R13 RET From bedf2c488630bd8253598b78088bc27fc36fbd29 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Fri, 5 Feb 2021 04:22:18 +1100 Subject: [PATCH 011/940] runtime,syscall: convert syscall on openbsd/arm to libc Convert the syscall package on openbsd/arm to use libc rather than performing direct system calls. Updates #36435 Change-Id: Iff3a91c959292cbf4e0a09c7fd34efc8e88ff83f Reviewed-on: https://go-review.googlesource.com/c/go/+/315793 Trust: Joel Sing Reviewed-by: Cherry Mui --- src/runtime/sys_openbsd3.go | 4 +- src/runtime/sys_openbsd_arm.s | 339 +++++++++++ src/syscall/asm_openbsd_arm.s | 135 +---- src/syscall/exec_bsd.go | 4 +- src/syscall/exec_libc2.go | 4 +- src/syscall/exec_unix.go | 2 +- src/syscall/mkall.sh | 5 +- src/syscall/mksyscall.pl | 4 + src/syscall/syscall_openbsd1.go | 4 +- src/syscall/syscall_openbsd_libc.go | 4 +- src/syscall/zsyscall_openbsd_arm.go | 867 +++++++++++++++++++++++----- src/syscall/zsyscall_openbsd_arm.s | 233 ++++++++ 12 files changed, 1336 insertions(+), 269 deletions(-) create mode 100644 src/syscall/zsyscall_openbsd_arm.s diff --git a/src/runtime/sys_openbsd3.go b/src/runtime/sys_openbsd3.go index 8fdee05733c..4ef0bdcf77f 100644 --- a/src/runtime/sys_openbsd3.go +++ b/src/runtime/sys_openbsd3.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (openbsd && 386) || (openbsd && amd64) || (openbsd && arm64) -// +build openbsd,386 openbsd,amd64 openbsd,arm64 +//go:build (openbsd && 386) || (openbsd && amd64) || (openbsd && arm) || (openbsd && arm64) +// +build openbsd,386 openbsd,amd64 openbsd,arm openbsd,arm64 package runtime diff --git a/src/runtime/sys_openbsd_arm.s b/src/runtime/sys_openbsd_arm.s index 49cb19bbff9..143fcf05184 100644 --- a/src/runtime/sys_openbsd_arm.s +++ b/src/runtime/sys_openbsd_arm.s @@ -465,3 +465,342 @@ TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0 MOVW R8, (R8) MOVW R9, R13 RET + +// syscall calls a function in libc on behalf of the syscall package. +// syscall takes a pointer to a struct like: +// struct { +// fn uintptr +// a1 uintptr +// a2 uintptr +// a3 uintptr +// r1 uintptr +// r2 uintptr +// err uintptr +// } +// syscall must be called on the g0 stack with the +// C calling convention (use libcCall). +// +// syscall expects a 32-bit result and tests for 32-bit -1 +// to decide there was an error. +TEXT runtime·syscall(SB),NOSPLIT,$0 + MOVW R13, R9 + BIC $0x7, R13 // align for ELF ABI + + MOVW R0, R8 + + MOVW (0*4)(R8), R7 // fn + MOVW (1*4)(R8), R0 // a1 + MOVW (2*4)(R8), R1 // a2 + MOVW (3*4)(R8), R2 // a3 + + BL (R7) + + MOVW R0, (4*4)(R8) // r1 + MOVW R1, (5*4)(R8) // r2 + + // Standard libc functions return -1 on error and set errno. + CMP $-1, R0 + BNE ok + + // Get error code from libc. + BL libc_errno(SB) + MOVW (R0), R1 + MOVW R1, (6*4)(R8) // err + +ok: + MOVW $0, R0 // no error (it's ignored anyway) + MOVW R9, R13 + RET + +// syscallX calls a function in libc on behalf of the syscall package. +// syscallX takes a pointer to a struct like: +// struct { +// fn uintptr +// a1 uintptr +// a2 uintptr +// a3 uintptr +// r1 uintptr +// r2 uintptr +// err uintptr +// } +// syscallX must be called on the g0 stack with the +// C calling convention (use libcCall). +// +// syscallX is like syscall but expects a 64-bit result +// and tests for 64-bit -1 to decide there was an error. +TEXT runtime·syscallX(SB),NOSPLIT,$0 + MOVW R13, R9 + BIC $0x7, R13 // align for ELF ABI + + MOVW R0, R8 + + MOVW (0*4)(R8), R7 // fn + MOVW (1*4)(R8), R0 // a1 + MOVW (2*4)(R8), R1 // a2 + MOVW (3*4)(R8), R2 // a3 + + BL (R7) + + MOVW R0, (4*4)(R8) // r1 + MOVW R1, (5*4)(R8) // r2 + + // Standard libc functions return -1 on error and set errno. + CMP $-1, R0 + BNE ok + CMP $-1, R1 + BNE ok + + // Get error code from libc. + BL libc_errno(SB) + MOVW (R0), R1 + MOVW R1, (6*4)(R8) // err + +ok: + MOVW $0, R0 // no error (it's ignored anyway) + MOVW R9, R13 + RET + +// syscall6 calls a function in libc on behalf of the syscall package. +// syscall6 takes a pointer to a struct like: +// struct { +// fn uintptr +// a1 uintptr +// a2 uintptr +// a3 uintptr +// a4 uintptr +// a5 uintptr +// a6 uintptr +// r1 uintptr +// r2 uintptr +// err uintptr +// } +// syscall6 must be called on the g0 stack with the +// C calling convention (use libcCall). +// +// syscall6 expects a 32-bit result and tests for 32-bit -1 +// to decide there was an error. +TEXT runtime·syscall6(SB),NOSPLIT,$0 + MOVW R13, R9 + SUB $8, R13 + BIC $0x7, R13 // align for ELF ABI + + MOVW R0, R8 + + MOVW (0*4)(R8), R7 // fn + MOVW (1*4)(R8), R0 // a1 + MOVW (2*4)(R8), R1 // a2 + MOVW (3*4)(R8), R2 // a3 + MOVW (4*4)(R8), R3 // a4 + MOVW (5*4)(R8), R4 // a5 + MOVW R4, 0(R13) + MOVW (6*4)(R8), R5 // a6 + MOVW R5, 4(R13) + + BL (R7) + + MOVW R0, (7*4)(R8) // r1 + MOVW R1, (8*4)(R8) // r2 + + // Standard libc functions return -1 on error and set errno. + CMP $-1, R0 + BNE ok + + // Get error code from libc. + BL libc_errno(SB) + MOVW (R0), R1 + MOVW R1, (9*4)(R8) // err + +ok: + MOVW $0, R0 // no error (it's ignored anyway) + MOVW R9, R13 + RET + +// syscall6X calls a function in libc on behalf of the syscall package. +// syscall6X takes a pointer to a struct like: +// struct { +// fn uintptr +// a1 uintptr +// a2 uintptr +// a3 uintptr +// a4 uintptr +// a5 uintptr +// a6 uintptr +// r1 uintptr +// r2 uintptr +// err uintptr +// } +// syscall6X must be called on the g0 stack with the +// C calling convention (use libcCall). +// +// syscall6X is like syscall6 but expects a 64-bit result +// and tests for 64-bit -1 to decide there was an error. +TEXT runtime·syscall6X(SB),NOSPLIT,$0 + MOVW R13, R9 + SUB $8, R13 + BIC $0x7, R13 // align for ELF ABI + + MOVW R0, R8 + + MOVW (0*4)(R8), R7 // fn + MOVW (1*4)(R8), R0 // a1 + MOVW (2*4)(R8), R1 // a2 + MOVW (3*4)(R8), R2 // a3 + MOVW (4*4)(R8), R3 // a4 + MOVW (5*4)(R8), R4 // a5 + MOVW R4, 0(R13) + MOVW (6*4)(R8), R5 // a6 + MOVW R5, 4(R13) + + BL (R7) + + MOVW R0, (7*4)(R8) // r1 + MOVW R1, (8*4)(R8) // r2 + + // Standard libc functions return -1 on error and set errno. + CMP $-1, R0 + BNE ok + CMP $-1, R1 + BNE ok + + // Get error code from libc. + BL libc_errno(SB) + MOVW (R0), R1 + MOVW R1, (9*4)(R8) // err + +ok: + MOVW $0, R0 // no error (it's ignored anyway) + MOVW R9, R13 + RET + +// syscall10 calls a function in libc on behalf of the syscall package. +// syscall10 takes a pointer to a struct like: +// struct { +// fn uintptr +// a1 uintptr +// a2 uintptr +// a3 uintptr +// a4 uintptr +// a5 uintptr +// a6 uintptr +// a7 uintptr +// a8 uintptr +// a9 uintptr +// a10 uintptr +// r1 uintptr +// r2 uintptr +// err uintptr +// } +// syscall10 must be called on the g0 stack with the +// C calling convention (use libcCall). +TEXT runtime·syscall10(SB),NOSPLIT,$0 + MOVW R13, R9 + SUB $24, R13 + BIC $0x7, R13 // align for ELF ABI + + MOVW R0, R8 + + MOVW (0*4)(R8), R7 // fn + MOVW (1*4)(R8), R0 // a1 + MOVW (2*4)(R8), R1 // a2 + MOVW (3*4)(R8), R2 // a3 + MOVW (4*4)(R8), R3 // a4 + MOVW (5*4)(R8), R4 // a5 + MOVW R4, 0(R13) + MOVW (6*4)(R8), R5 // a6 + MOVW R5, 4(R13) + MOVW (7*4)(R8), R6 // a7 + MOVW R6, 8(R13) + MOVW (8*4)(R8), R4 // a8 + MOVW R4, 12(R13) + MOVW (9*4)(R8), R5 // a9 + MOVW R5, 16(R13) + MOVW (10*4)(R8), R6 // a10 + MOVW R6, 20(R13) + + BL (R7) + + MOVW R0, (11*4)(R8) // r1 + MOVW R1, (12*4)(R8) // r2 + + // Standard libc functions return -1 on error and set errno. + CMP $-1, R0 + BNE ok + + // Get error code from libc. + BL libc_errno(SB) + MOVW (R0), R1 + MOVW R1, (13*4)(R8) // err + +ok: + MOVW $0, R0 // no error (it's ignored anyway) + MOVW R9, R13 + RET + +// syscall10X calls a function in libc on behalf of the syscall package. +// syscall10X takes a pointer to a struct like: +// struct { +// fn uintptr +// a1 uintptr +// a2 uintptr +// a3 uintptr +// a4 uintptr +// a5 uintptr +// a6 uintptr +// a7 uintptr +// a8 uintptr +// a9 uintptr +// a10 uintptr +// r1 uintptr +// r2 uintptr +// err uintptr +// } +// syscall10X must be called on the g0 stack with the +// C calling convention (use libcCall). +// +// syscall10X is like syscall10 but expects a 64-bit result +// and tests for 64-bit -1 to decide there was an error. +TEXT runtime·syscall10X(SB),NOSPLIT,$0 + MOVW R13, R9 + SUB $24, R13 + BIC $0x7, R13 // align for ELF ABI + + MOVW R0, R8 + + MOVW (0*4)(R8), R7 // fn + MOVW (1*4)(R8), R0 // a1 + MOVW (2*4)(R8), R1 // a2 + MOVW (3*4)(R8), R2 // a3 + MOVW (4*4)(R8), R3 // a4 + MOVW (5*4)(R8), R4 // a5 + MOVW R4, 0(R13) + MOVW (6*4)(R8), R5 // a6 + MOVW R5, 4(R13) + MOVW (7*4)(R8), R6 // a7 + MOVW R6, 8(R13) + MOVW (8*4)(R8), R4 // a8 + MOVW R4, 12(R13) + MOVW (9*4)(R8), R5 // a9 + MOVW R5, 16(R13) + MOVW (10*4)(R8), R6 // a10 + MOVW R6, 20(R13) + + BL (R7) + + MOVW R0, (11*4)(R8) // r1 + MOVW R1, (12*4)(R8) // r2 + + // Standard libc functions return -1 on error and set errno. + CMP $-1, R0 + BNE ok + CMP $-1, R1 + BNE ok + + // Get error code from libc. + BL libc_errno(SB) + MOVW (R0), R1 + MOVW R1, (13*4)(R8) // err + +ok: + MOVW $0, R0 // no error (it's ignored anyway) + MOVW R9, R13 + RET diff --git a/src/syscall/asm_openbsd_arm.s b/src/syscall/asm_openbsd_arm.s index 26fd791fdad..520da91bf32 100644 --- a/src/syscall/asm_openbsd_arm.s +++ b/src/syscall/asm_openbsd_arm.s @@ -3,137 +3,30 @@ // license that can be found in the LICENSE file. #include "textflag.h" -#include "funcdata.h" // // System call support for ARM, OpenBSD // -// func Syscall(trap int32, a1, a2, a3 int32) (r1, r2, err int32); -// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32); -// func Syscall9(trap int32, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int32) -// func RawSyscall(trap int32, a1, a2, a3 int32) (r1, r2, err int32); -// func RawSyscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32); - -// See comment in runtime/sys_openbsd_arm.s re this construction. -#define NOOP MOVW R0, R0 -#define INVOKE_SYSCALL \ - SWI $0; \ - NOOP; \ - NOOP +// Provide these function names via assembly so they are provided as ABI0, +// rather than ABIInternal. +// func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) TEXT ·Syscall(SB),NOSPLIT,$0-28 - BL runtime·entersyscall(SB) - MOVW trap+0(FP), R12 // syscall number - MOVW a1+4(FP), R0 // arg 1 - MOVW a2+8(FP), R1 // arg 2 - MOVW a3+12(FP), R2 // arg 3 - INVOKE_SYSCALL - MOVW $0, R2 - BCS error - MOVW R0, r1+16(FP) // ret 1 - MOVW R1, r2+20(FP) // ret 2 - MOVW R2, err+24(FP) // err - BL runtime·exitsyscall(SB) - RET -error: - MOVW $-1, R3 - MOVW R3, r1+16(FP) // ret 1 - MOVW R2, r2+20(FP) // ret 2 - MOVW R0, err+24(FP) // err - BL runtime·exitsyscall(SB) - RET + JMP ·syscallInternal(SB) +// func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) TEXT ·Syscall6(SB),NOSPLIT,$0-40 - BL runtime·entersyscall(SB) - MOVW trap+0(FP), R12 // syscall number - MOVW a1+4(FP), R0 // arg 1 - MOVW a2+8(FP), R1 // arg 2 - MOVW a3+12(FP), R2 // arg 3 - MOVW a4+16(FP), R3 // arg 4 - MOVW R13, R4 - MOVW $a5+20(FP), R13 // arg 5 to arg 6 are passed on stack - INVOKE_SYSCALL - MOVW R4, R13 - MOVW $0, R2 - BCS error6 - MOVW R0, r1+28(FP) // ret 1 - MOVW R1, r2+32(FP) // ret 2 - MOVW R2, err+36(FP) // err - BL runtime·exitsyscall(SB) - RET -error6: - MOVW $-1, R3 - MOVW R3, r1+28(FP) // ret 1 - MOVW R2, r2+32(FP) // ret 2 - MOVW R0, err+36(FP) // err - BL runtime·exitsyscall(SB) - RET - -TEXT ·Syscall9(SB),NOSPLIT,$0-52 - BL runtime·entersyscall(SB) - MOVW num+0(FP), R12 // syscall number - MOVW a1+4(FP), R0 // arg 1 - MOVW a2+8(FP), R1 // arg 2 - MOVW a3+12(FP), R2 // arg 3 - MOVW a4+16(FP), R3 // arg 4 - MOVW R13, R4 - MOVW $a5+20(FP), R13 // arg 5 to arg 9 are passed on stack - INVOKE_SYSCALL - MOVW R4, R13 - MOVW $0, R2 - BCS error9 - MOVW R0, r1+40(FP) // ret 1 - MOVW R1, r2+44(FP) // ret 2 - MOVW R2, err+48(FP) // err - BL runtime·exitsyscall(SB) - RET -error9: - MOVW $-1, R3 - MOVW R3, r1+40(FP) // ret 1 - MOVW R2, r2+44(FP) // ret 2 - MOVW R0, err+48(FP) // err - BL runtime·exitsyscall(SB) - RET + JMP ·syscall6Internal(SB) +// func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) TEXT ·RawSyscall(SB),NOSPLIT,$0-28 - MOVW trap+0(FP), R12 // syscall number - MOVW a1+4(FP), R0 // arg 1 - MOVW a2+8(FP), R1 // arg 2 - MOVW a3+12(FP), R2 // arg 3 - INVOKE_SYSCALL - MOVW $0, R2 - BCS errorr - MOVW R0, r1+16(FP) // ret 1 - MOVW R1, r2+20(FP) // ret 2 - MOVW R2, err+24(FP) // err - RET -errorr: - MOVW $-1, R3 - MOVW R3, r1+16(FP) // ret 1 - MOVW R2, r2+20(FP) // ret 2 - MOVW R0, err+24(FP) // err - RET + JMP ·rawSyscallInternal(SB) +// func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 - MOVW trap+0(FP), R12 // syscall number - MOVW a1+4(FP), R0 // arg 1 - MOVW a2+8(FP), R1 // arg 2 - MOVW a3+12(FP), R2 // arg 3 - MOVW a4+16(FP), R3 // arg 4 - MOVW R13, R4 - MOVW $a5+20(FP), R13 // arg 5 to arg 6 are passed on stack - INVOKE_SYSCALL - MOVW R4, R13 - MOVW $0, R2 - BCS errorr6 - MOVW R0, r1+28(FP) // ret 1 - MOVW R1, r2+32(FP) // ret 2 - MOVW R2, err+36(FP) // err - RET -errorr6: - MOVW $-1, R3 - MOVW R3, r1+28(FP) // ret 1 - MOVW R2, r2+32(FP) // ret 2 - MOVW R0, err+36(FP) // err - RET + JMP ·rawSyscall6Internal(SB) + +// func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) +TEXT ·Syscall9(SB),NOSPLIT,$0-52 + JMP ·syscall9Internal(SB) diff --git a/src/syscall/exec_bsd.go b/src/syscall/exec_bsd.go index 41d1f693b2b..569dd675ed2 100644 --- a/src/syscall/exec_bsd.go +++ b/src/syscall/exec_bsd.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build dragonfly || freebsd || netbsd || (openbsd && !386 && !amd64 && !arm64) -// +build dragonfly freebsd netbsd openbsd,!386,!amd64,!arm64 +//go:build dragonfly || freebsd || netbsd || (openbsd && !386 && !amd64 && !arm && !arm64) +// +build dragonfly freebsd netbsd openbsd,!386,!amd64,!arm,!arm64 package syscall diff --git a/src/syscall/exec_libc2.go b/src/syscall/exec_libc2.go index 8e957b3d4a0..7442d59affc 100644 --- a/src/syscall/exec_libc2.go +++ b/src/syscall/exec_libc2.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build darwin || (openbsd && 386) || (openbsd && amd64) || (openbsd && arm64) -// +build darwin openbsd,386 openbsd,amd64 openbsd,arm64 +//go:build darwin || (openbsd && 386) || (openbsd && amd64) || (openbsd && arm) || (openbsd && arm64) +// +build darwin openbsd,386 openbsd,amd64 openbsd,arm openbsd,arm64 package syscall diff --git a/src/syscall/exec_unix.go b/src/syscall/exec_unix.go index 206a1e17d67..54b18dccd73 100644 --- a/src/syscall/exec_unix.go +++ b/src/syscall/exec_unix.go @@ -301,7 +301,7 @@ func Exec(argv0 string, argv []string, envv []string) (err error) { } else if runtime.GOOS == "darwin" || runtime.GOOS == "ios" { // Similarly on Darwin. err1 = execveDarwin(argv0p, &argvp[0], &envvp[0]) - } else if runtime.GOOS == "openbsd" && (runtime.GOARCH == "386" || runtime.GOARCH == "amd64" || runtime.GOARCH == "arm64") { + } else if runtime.GOOS == "openbsd" && (runtime.GOARCH == "386" || runtime.GOARCH == "amd64" || runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { // Similarly on OpenBSD. err1 = execveOpenBSD(argv0p, &argvp[0], &envvp[0]) } else { diff --git a/src/syscall/mkall.sh b/src/syscall/mkall.sh index 7739147310c..dffb52864ba 100755 --- a/src/syscall/mkall.sh +++ b/src/syscall/mkall.sh @@ -303,15 +303,16 @@ openbsd_amd64) mkasm="go run mkasm.go" ;; openbsd_arm) - GOOSARCH_in="syscall_openbsd1.go syscall_openbsd_$GOARCH.go" + GOOSARCH_in="syscall_openbsd_libc.go syscall_openbsd_$GOARCH.go" mkerrors="$mkerrors" - mksyscall="./mksyscall.pl -l32 -openbsd -arm" + mksyscall="./mksyscall.pl -l32 -openbsd -arm -libc" mksysctl="./mksysctl_openbsd.pl" zsysctl="zsysctl_openbsd.go" mksysnum="curl -s 'http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl" # Let the type of C char be signed to make the bare syscall # API consistent between platforms. mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char" + mkasm="go run mkasm.go" ;; openbsd_arm64) GOOSARCH_in="syscall_openbsd_libc.go syscall_openbsd_$GOARCH.go" diff --git a/src/syscall/mksyscall.pl b/src/syscall/mksyscall.pl index 5ca3b465d80..758948bc53f 100755 --- a/src/syscall/mksyscall.pl +++ b/src/syscall/mksyscall.pl @@ -191,6 +191,10 @@ while(<>) { if (!$libc) { push @args, "0"; } + if($libc && $arm && @args % 2) { + # arm abi specifies 64 bit argument must be 64 bit aligned. + push @args, "0" + } if($_32bit eq "big-endian") { push @args, "uintptr($name>>32)", "uintptr($name)"; } elsif($_32bit eq "little-endian") { diff --git a/src/syscall/syscall_openbsd1.go b/src/syscall/syscall_openbsd1.go index c446768aab6..450f3848319 100644 --- a/src/syscall/syscall_openbsd1.go +++ b/src/syscall/syscall_openbsd1.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build openbsd && !386 && !amd64 && !arm64 -// +build openbsd,!386,!amd64,!arm64 +//go:build openbsd && !386 && !amd64 && !arm && !arm64 +// +build openbsd,!386,!amd64,!arm,!arm64 package syscall diff --git a/src/syscall/syscall_openbsd_libc.go b/src/syscall/syscall_openbsd_libc.go index 750be6f7078..2390912b0f5 100644 --- a/src/syscall/syscall_openbsd_libc.go +++ b/src/syscall/syscall_openbsd_libc.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (openbsd && 386) || (openbsd && amd64) || (openbsd && arm64) -// +build openbsd,386 openbsd,amd64 openbsd,arm64 +//go:build (openbsd && 386) || (openbsd && amd64) || (openbsd && arm) || (openbsd && arm64) +// +build openbsd,386 openbsd,amd64 openbsd,arm openbsd,arm64 package syscall diff --git a/src/syscall/zsyscall_openbsd_arm.go b/src/syscall/zsyscall_openbsd_arm.go index 31425b35588..04a2fadccdd 100644 --- a/src/syscall/zsyscall_openbsd_arm.go +++ b/src/syscall/zsyscall_openbsd_arm.go @@ -1,4 +1,4 @@ -// mksyscall.pl -l32 -openbsd -arm -tags openbsd,arm syscall_bsd.go syscall_openbsd.go syscall_openbsd_arm.go +// mksyscall.pl -l32 -openbsd -arm -libc -tags openbsd,arm syscall_bsd.go syscall_openbsd.go syscall_openbsd_libc.go syscall_openbsd_arm.go // Code generated by the command above; DO NOT EDIT. //go:build openbsd && arm @@ -7,11 +7,12 @@ package syscall import "unsafe" +import "internal/abi" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getgroups(ngid int, gid *_Gid_t) (n int, err error) { - r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + r0, _, e1 := rawSyscall(abi.FuncPCABI0(libc_getgroups_trampoline), uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -19,20 +20,28 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) { return } +func libc_getgroups_trampoline() + +//go:cgo_import_dynamic libc_getgroups getgroups "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func setgroups(ngid int, gid *_Gid_t) (err error) { - _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_setgroups_trampoline), uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setgroups_trampoline() + +//go:cgo_import_dynamic libc_setgroups setgroups "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) { - r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) + r0, _, e1 := syscall6(abi.FuncPCABI0(libc_wait4_trampoline), uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) wpid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -40,10 +49,14 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err return } +func libc_wait4_trampoline() + +//go:cgo_import_dynamic libc_wait4 wait4 "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { - r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + r0, _, e1 := syscall(abi.FuncPCABI0(libc_accept_trampoline), uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -51,30 +64,42 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { return } +func libc_accept_trampoline() + +//go:cgo_import_dynamic libc_accept accept "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { - _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen)) + _, _, e1 := syscall(abi.FuncPCABI0(libc_bind_trampoline), uintptr(s), uintptr(addr), uintptr(addrlen)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_bind_trampoline() + +//go:cgo_import_dynamic libc_bind bind "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { - _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen)) + _, _, e1 := syscall(abi.FuncPCABI0(libc_connect_trampoline), uintptr(s), uintptr(addr), uintptr(addrlen)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_connect_trampoline() + +//go:cgo_import_dynamic libc_connect connect "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func socket(domain int, typ int, proto int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto)) + r0, _, e1 := rawSyscall(abi.FuncPCABI0(libc_socket_trampoline), uintptr(domain), uintptr(typ), uintptr(proto)) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -82,66 +107,94 @@ func socket(domain int, typ int, proto int) (fd int, err error) { return } +func libc_socket_trampoline() + +//go:cgo_import_dynamic libc_socket socket "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) { - _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) + _, _, e1 := syscall6(abi.FuncPCABI0(libc_getsockopt_trampoline), uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getsockopt_trampoline() + +//go:cgo_import_dynamic libc_getsockopt getsockopt "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { - _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) + _, _, e1 := syscall6(abi.FuncPCABI0(libc_setsockopt_trampoline), uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setsockopt_trampoline() + +//go:cgo_import_dynamic libc_setsockopt setsockopt "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { - _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_getpeername_trampoline), uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getpeername_trampoline() + +//go:cgo_import_dynamic libc_getpeername getpeername "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { - _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_getsockname_trampoline), uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getsockname_trampoline() + +//go:cgo_import_dynamic libc_getsockname getsockname "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Shutdown(s int, how int) (err error) { - _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_shutdown_trampoline), uintptr(s), uintptr(how), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_shutdown_trampoline() + +//go:cgo_import_dynamic libc_shutdown shutdown "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) { - _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) + _, _, e1 := rawSyscall6(abi.FuncPCABI0(libc_socketpair_trampoline), uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_socketpair_trampoline() + +//go:cgo_import_dynamic libc_socketpair socketpair "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) { @@ -151,7 +204,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) + r0, _, e1 := syscall6(abi.FuncPCABI0(libc_recvfrom_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -159,6 +212,10 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl return } +func libc_recvfrom_trampoline() + +//go:cgo_import_dynamic libc_recvfrom recvfrom "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) { @@ -168,17 +225,21 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) ( } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) + _, _, e1 := syscall6(abi.FuncPCABI0(libc_sendto_trampoline), uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_sendto_trampoline() + +//go:cgo_import_dynamic libc_sendto sendto "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { - r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + r0, _, e1 := syscall(abi.FuncPCABI0(libc_recvmsg_trampoline), uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -186,10 +247,14 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { return } +func libc_recvmsg_trampoline() + +//go:cgo_import_dynamic libc_recvmsg recvmsg "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { - r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + r0, _, e1 := syscall(abi.FuncPCABI0(libc_sendmsg_trampoline), uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -197,10 +262,14 @@ func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { return } +func libc_sendmsg_trampoline() + +//go:cgo_import_dynamic libc_sendmsg sendmsg "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) { - r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))) + r0, _, e1 := syscall6(abi.FuncPCABI0(libc_kevent_trampoline), uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -208,21 +277,9 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne return } -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func libc_kevent_trampoline() -func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { - var _p0 unsafe.Pointer - if len(mib) > 0 { - _p0 = unsafe.Pointer(&mib[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} +//go:cgo_import_dynamic libc_kevent kevent "libc.so" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT @@ -232,27 +289,35 @@ func utimes(path string, timeval *[2]Timeval) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_utimes_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_utimes_trampoline() + +//go:cgo_import_dynamic libc_utimes utimes "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func futimes(fd int, timeval *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_futimes_trampoline), uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_futimes_trampoline() + +//go:cgo_import_dynamic libc_futimes futimes "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func fcntl(fd int, cmd int, arg int) (val int, err error) { - r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg)) + r0, _, e1 := syscall(abi.FuncPCABI0(libc_fcntl_trampoline), uintptr(fd), uintptr(cmd), uintptr(arg)) val = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -260,20 +325,28 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) { return } +func libc_fcntl_trampoline() + +//go:cgo_import_dynamic libc_fcntl fcntl "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func pipe2(p *[2]_C_int, flags int) (err error) { - _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0) + _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_pipe2_trampoline), uintptr(unsafe.Pointer(p)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_pipe2_trampoline() + +//go:cgo_import_dynamic libc_pipe2 pipe2 "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int, err error) { - r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0) + r0, _, e1 := syscall6(abi.FuncPCABI0(libc_accept4_trampoline), uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0) nfd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -281,6 +354,10 @@ func accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int return } +func libc_accept4_trampoline() + +//go:cgo_import_dynamic libc_accept4 accept4 "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getdents(fd int, buf []byte) (n int, err error) { @@ -290,7 +367,7 @@ func getdents(fd int, buf []byte) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf))) + r0, _, e1 := syscall(abi.FuncPCABI0(libc_getdents_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(buf))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -298,6 +375,10 @@ func getdents(fd int, buf []byte) (n int, err error) { return } +func libc_getdents_trampoline() + +//go:cgo_import_dynamic libc_getdents getdents "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Access(path string, mode uint32) (err error) { @@ -306,23 +387,31 @@ func Access(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_access_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_access_trampoline() + +//go:cgo_import_dynamic libc_access access "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Adjtime(delta *Timeval, olddelta *Timeval) (err error) { - _, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_adjtime_trampoline), uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_adjtime_trampoline() + +//go:cgo_import_dynamic libc_adjtime adjtime "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chdir(path string) (err error) { @@ -331,13 +420,17 @@ func Chdir(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_chdir_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chdir_trampoline() + +//go:cgo_import_dynamic libc_chdir chdir "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chflags(path string, flags int) (err error) { @@ -346,13 +439,17 @@ func Chflags(path string, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_chflags_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chflags_trampoline() + +//go:cgo_import_dynamic libc_chflags chflags "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chmod(path string, mode uint32) (err error) { @@ -361,13 +458,17 @@ func Chmod(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_chmod_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chmod_trampoline() + +//go:cgo_import_dynamic libc_chmod chmod "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chown(path string, uid int, gid int) (err error) { @@ -376,13 +477,17 @@ func Chown(path string, uid int, gid int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + _, _, e1 := syscall(abi.FuncPCABI0(libc_chown_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chown_trampoline() + +//go:cgo_import_dynamic libc_chown chown "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chroot(path string) (err error) { @@ -391,27 +496,35 @@ func Chroot(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_chroot_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chroot_trampoline() + +//go:cgo_import_dynamic libc_chroot chroot "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Close(fd int) (err error) { - _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_close_trampoline), uintptr(fd), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_close_trampoline() + +//go:cgo_import_dynamic libc_close close "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Dup(fd int) (nfd int, err error) { - r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0) + r0, _, e1 := syscall(abi.FuncPCABI0(libc_dup_trampoline), uintptr(fd), 0, 0) nfd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -419,70 +532,98 @@ func Dup(fd int) (nfd int, err error) { return } +func libc_dup_trampoline() + +//go:cgo_import_dynamic libc_dup dup "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Dup2(from int, to int) (err error) { - _, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_dup2_trampoline), uintptr(from), uintptr(to), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_dup2_trampoline() + +//go:cgo_import_dynamic libc_dup2 dup2 "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchdir(fd int) (err error) { - _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_fchdir_trampoline), uintptr(fd), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchdir_trampoline() + +//go:cgo_import_dynamic libc_fchdir fchdir "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchflags(fd int, flags int) (err error) { - _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_fchflags_trampoline), uintptr(fd), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchflags_trampoline() + +//go:cgo_import_dynamic libc_fchflags fchflags "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchmod(fd int, mode uint32) (err error) { - _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_fchmod_trampoline), uintptr(fd), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchmod_trampoline() + +//go:cgo_import_dynamic libc_fchmod fchmod "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchown(fd int, uid int, gid int) (err error) { - _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) + _, _, e1 := syscall(abi.FuncPCABI0(libc_fchown_trampoline), uintptr(fd), uintptr(uid), uintptr(gid)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchown_trampoline() + +//go:cgo_import_dynamic libc_fchown fchown "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Flock(fd int, how int) (err error) { - _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_flock_trampoline), uintptr(fd), uintptr(how), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_flock_trampoline() + +//go:cgo_import_dynamic libc_flock flock "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fpathconf(fd int, name int) (val int, err error) { - r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0) + r0, _, e1 := syscall(abi.FuncPCABI0(libc_fpathconf_trampoline), uintptr(fd), uintptr(name), 0) val = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -490,74 +631,106 @@ func Fpathconf(fd int, name int) (val int, err error) { return } +func libc_fpathconf_trampoline() + +//go:cgo_import_dynamic libc_fpathconf fpathconf "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fstat(fd int, stat *Stat_t) (err error) { - _, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_fstat_trampoline), uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fstat_trampoline() + +//go:cgo_import_dynamic libc_fstat fstat "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fstatfs(fd int, stat *Statfs_t) (err error) { - _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_fstatfs_trampoline), uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fstatfs_trampoline() + +//go:cgo_import_dynamic libc_fstatfs fstatfs "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fsync(fd int) (err error) { - _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_fsync_trampoline), uintptr(fd), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fsync_trampoline() + +//go:cgo_import_dynamic libc_fsync fsync "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Ftruncate(fd int, length int64) (err error) { - _, _, e1 := Syscall6(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0) + _, _, e1 := syscall6(abi.FuncPCABI0(libc_ftruncate_trampoline), uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_ftruncate_trampoline() + +//go:cgo_import_dynamic libc_ftruncate ftruncate "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getegid() (egid int) { - r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + r0, _, _ := rawSyscall(abi.FuncPCABI0(libc_getegid_trampoline), 0, 0, 0) egid = int(r0) return } +func libc_getegid_trampoline() + +//go:cgo_import_dynamic libc_getegid getegid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + r0, _, _ := rawSyscall(abi.FuncPCABI0(libc_geteuid_trampoline), 0, 0, 0) uid = int(r0) return } +func libc_geteuid_trampoline() + +//go:cgo_import_dynamic libc_geteuid geteuid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + r0, _, _ := rawSyscall(abi.FuncPCABI0(libc_getgid_trampoline), 0, 0, 0) gid = int(r0) return } +func libc_getgid_trampoline() + +//go:cgo_import_dynamic libc_getgid getgid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpgid(pid int) (pgid int, err error) { - r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0) + r0, _, e1 := rawSyscall(abi.FuncPCABI0(libc_getpgid_trampoline), uintptr(pid), 0, 0) pgid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -565,34 +738,50 @@ func Getpgid(pid int) (pgid int, err error) { return } +func libc_getpgid_trampoline() + +//go:cgo_import_dynamic libc_getpgid getpgid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpgrp() (pgrp int) { - r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0) + r0, _, _ := rawSyscall(abi.FuncPCABI0(libc_getpgrp_trampoline), 0, 0, 0) pgrp = int(r0) return } +func libc_getpgrp_trampoline() + +//go:cgo_import_dynamic libc_getpgrp getpgrp "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + r0, _, _ := rawSyscall(abi.FuncPCABI0(libc_getpid_trampoline), 0, 0, 0) pid = int(r0) return } +func libc_getpid_trampoline() + +//go:cgo_import_dynamic libc_getpid getpid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + r0, _, _ := rawSyscall(abi.FuncPCABI0(libc_getppid_trampoline), 0, 0, 0) ppid = int(r0) return } +func libc_getppid_trampoline() + +//go:cgo_import_dynamic libc_getppid getppid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpriority(which int, who int) (prio int, err error) { - r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0) + r0, _, e1 := syscall(abi.FuncPCABI0(libc_getpriority_trampoline), uintptr(which), uintptr(who), 0) prio = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -600,30 +789,42 @@ func Getpriority(which int, who int) (prio int, err error) { return } +func libc_getpriority_trampoline() + +//go:cgo_import_dynamic libc_getpriority getpriority "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getrlimit(which int, lim *Rlimit) (err error) { - _, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_getrlimit_trampoline), uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getrlimit_trampoline() + +//go:cgo_import_dynamic libc_getrlimit getrlimit "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getrusage(who int, rusage *Rusage) (err error) { - _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) + _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_getrusage_trampoline), uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getrusage_trampoline() + +//go:cgo_import_dynamic libc_getrusage getrusage "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getsid(pid int) (sid int, err error) { - r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + r0, _, e1 := rawSyscall(abi.FuncPCABI0(libc_getsid_trampoline), uintptr(pid), 0, 0) sid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -631,46 +832,66 @@ func Getsid(pid int) (sid int, err error) { return } +func libc_getsid_trampoline() + +//go:cgo_import_dynamic libc_getsid getsid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Gettimeofday(tv *Timeval) (err error) { - _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) + _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_gettimeofday_trampoline), uintptr(unsafe.Pointer(tv)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_gettimeofday_trampoline() + +//go:cgo_import_dynamic libc_gettimeofday gettimeofday "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + r0, _, _ := rawSyscall(abi.FuncPCABI0(libc_getuid_trampoline), 0, 0, 0) uid = int(r0) return } +func libc_getuid_trampoline() + +//go:cgo_import_dynamic libc_getuid getuid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Issetugid() (tainted bool) { - r0, _, _ := Syscall(SYS_ISSETUGID, 0, 0, 0) + r0, _, _ := syscall(abi.FuncPCABI0(libc_issetugid_trampoline), 0, 0, 0) tainted = bool(r0 != 0) return } +func libc_issetugid_trampoline() + +//go:cgo_import_dynamic libc_issetugid issetugid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Kill(pid int, signum Signal) (err error) { - _, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_kill_trampoline), uintptr(pid), uintptr(signum), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_kill_trampoline() + +//go:cgo_import_dynamic libc_kill kill "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Kqueue() (fd int, err error) { - r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0) + r0, _, e1 := syscall(abi.FuncPCABI0(libc_kqueue_trampoline), 0, 0, 0) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -678,6 +899,10 @@ func Kqueue() (fd int, err error) { return } +func libc_kqueue_trampoline() + +//go:cgo_import_dynamic libc_kqueue kqueue "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Lchown(path string, uid int, gid int) (err error) { @@ -686,13 +911,17 @@ func Lchown(path string, uid int, gid int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + _, _, e1 := syscall(abi.FuncPCABI0(libc_lchown_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_lchown_trampoline() + +//go:cgo_import_dynamic libc_lchown lchown "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Link(path string, link string) (err error) { @@ -706,23 +935,31 @@ func Link(path string, link string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_link_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_link_trampoline() + +//go:cgo_import_dynamic libc_link link "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Listen(s int, backlog int) (err error) { - _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_listen_trampoline), uintptr(s), uintptr(backlog), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_listen_trampoline() + +//go:cgo_import_dynamic libc_listen listen "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Lstat(path string, stat *Stat_t) (err error) { @@ -731,13 +968,17 @@ func Lstat(path string, stat *Stat_t) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_lstat_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_lstat_trampoline() + +//go:cgo_import_dynamic libc_lstat lstat "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mkdir(path string, mode uint32) (err error) { @@ -746,13 +987,17 @@ func Mkdir(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_mkdir_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mkdir_trampoline() + +//go:cgo_import_dynamic libc_mkdir mkdir "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mkfifo(path string, mode uint32) (err error) { @@ -761,13 +1006,17 @@ func Mkfifo(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_mkfifo_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mkfifo_trampoline() + +//go:cgo_import_dynamic libc_mkfifo mkfifo "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mknod(path string, mode uint32, dev int) (err error) { @@ -776,23 +1025,31 @@ func Mknod(path string, mode uint32, dev int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + _, _, e1 := syscall(abi.FuncPCABI0(libc_mknod_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mknod_trampoline() + +//go:cgo_import_dynamic libc_mknod mknod "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Nanosleep(time *Timespec, leftover *Timespec) (err error) { - _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_nanosleep_trampoline), uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_nanosleep_trampoline() + +//go:cgo_import_dynamic libc_nanosleep nanosleep "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Open(path string, mode int, perm uint32) (fd int, err error) { @@ -801,7 +1058,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { if err != nil { return } - r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + r0, _, e1 := syscall(abi.FuncPCABI0(libc_open_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -809,6 +1066,10 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { return } +func libc_open_trampoline() + +//go:cgo_import_dynamic libc_open open "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Pathconf(path string, name int) (val int, err error) { @@ -817,7 +1078,7 @@ func Pathconf(path string, name int) (val int, err error) { if err != nil { return } - r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + r0, _, e1 := syscall(abi.FuncPCABI0(libc_pathconf_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) val = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -825,6 +1086,10 @@ func Pathconf(path string, name int) (val int, err error) { return } +func libc_pathconf_trampoline() + +//go:cgo_import_dynamic libc_pathconf pathconf "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Pread(fd int, p []byte, offset int64) (n int, err error) { @@ -834,7 +1099,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32)) + r0, _, e1 := syscall6(abi.FuncPCABI0(libc_pread_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -842,6 +1107,10 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) { return } +func libc_pread_trampoline() + +//go:cgo_import_dynamic libc_pread pread "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Pwrite(fd int, p []byte, offset int64) (n int, err error) { @@ -851,7 +1120,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32)) + r0, _, e1 := syscall6(abi.FuncPCABI0(libc_pwrite_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -859,6 +1128,10 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { return } +func libc_pwrite_trampoline() + +//go:cgo_import_dynamic libc_pwrite pwrite "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func read(fd int, p []byte) (n int, err error) { @@ -868,7 +1141,7 @@ func read(fd int, p []byte) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p))) + r0, _, e1 := syscall(abi.FuncPCABI0(libc_read_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -876,6 +1149,10 @@ func read(fd int, p []byte) (n int, err error) { return } +func libc_read_trampoline() + +//go:cgo_import_dynamic libc_read read "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Readlink(path string, buf []byte) (n int, err error) { @@ -890,7 +1167,7 @@ func Readlink(path string, buf []byte) (n int, err error) { } else { _p1 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + r0, _, e1 := syscall(abi.FuncPCABI0(libc_readlink_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -898,6 +1175,10 @@ func Readlink(path string, buf []byte) (n int, err error) { return } +func libc_readlink_trampoline() + +//go:cgo_import_dynamic libc_readlink readlink "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Rename(from string, to string) (err error) { @@ -911,13 +1192,17 @@ func Rename(from string, to string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_rename_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_rename_trampoline() + +//go:cgo_import_dynamic libc_rename rename "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Revoke(path string) (err error) { @@ -926,13 +1211,17 @@ func Revoke(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_revoke_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_revoke_trampoline() + +//go:cgo_import_dynamic libc_revoke revoke "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Rmdir(path string) (err error) { @@ -941,64 +1230,73 @@ func Rmdir(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_rmdir_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func libc_rmdir_trampoline() -func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { - r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), uintptr(whence), 0) - newoffset = int64(int64(r1)<<32 | int64(r0)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} +//go:cgo_import_dynamic libc_rmdir rmdir "libc.so" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) { - _, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) + _, _, e1 := syscall6(abi.FuncPCABI0(libc_select_trampoline), uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_select_trampoline() + +//go:cgo_import_dynamic libc_select select "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setegid(egid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0) + _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_setegid_trampoline), uintptr(egid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setegid_trampoline() + +//go:cgo_import_dynamic libc_setegid setegid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Seteuid(euid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0) + _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_seteuid_trampoline), uintptr(euid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_seteuid_trampoline() + +//go:cgo_import_dynamic libc_seteuid seteuid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setgid(gid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0) + _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_setgid_trampoline), uintptr(gid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setgid_trampoline() + +//go:cgo_import_dynamic libc_setgid setgid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setlogin(name string) (err error) { @@ -1007,67 +1305,91 @@ func Setlogin(name string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_setlogin_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setlogin_trampoline() + +//go:cgo_import_dynamic libc_setlogin setlogin "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setpgid(pid int, pgid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0) + _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_setpgid_trampoline), uintptr(pid), uintptr(pgid), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setpgid_trampoline() + +//go:cgo_import_dynamic libc_setpgid setpgid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setpriority(which int, who int, prio int) (err error) { - _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio)) + _, _, e1 := syscall(abi.FuncPCABI0(libc_setpriority_trampoline), uintptr(which), uintptr(who), uintptr(prio)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setpriority_trampoline() + +//go:cgo_import_dynamic libc_setpriority setpriority "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setregid(rgid int, egid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0) + _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_setregid_trampoline), uintptr(rgid), uintptr(egid), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setregid_trampoline() + +//go:cgo_import_dynamic libc_setregid setregid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setreuid(ruid int, euid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0) + _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_setreuid_trampoline), uintptr(ruid), uintptr(euid), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setreuid_trampoline() + +//go:cgo_import_dynamic libc_setreuid setreuid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setrlimit(which int, lim *Rlimit) (err error) { - _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_setrlimit_trampoline), uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setrlimit_trampoline() + +//go:cgo_import_dynamic libc_setrlimit setrlimit "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setsid() (pid int, err error) { - r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0) + r0, _, e1 := rawSyscall(abi.FuncPCABI0(libc_setsid_trampoline), 0, 0, 0) pid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1075,26 +1397,38 @@ func Setsid() (pid int, err error) { return } +func libc_setsid_trampoline() + +//go:cgo_import_dynamic libc_setsid setsid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Settimeofday(tp *Timeval) (err error) { - _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0) + _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_settimeofday_trampoline), uintptr(unsafe.Pointer(tp)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_settimeofday_trampoline() + +//go:cgo_import_dynamic libc_settimeofday settimeofday "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setuid(uid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0) + _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_setuid_trampoline), uintptr(uid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setuid_trampoline() + +//go:cgo_import_dynamic libc_setuid setuid "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Stat(path string, stat *Stat_t) (err error) { @@ -1103,13 +1437,17 @@ func Stat(path string, stat *Stat_t) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_stat_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_stat_trampoline() + +//go:cgo_import_dynamic libc_stat stat "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Statfs(path string, stat *Statfs_t) (err error) { @@ -1118,13 +1456,17 @@ func Statfs(path string, stat *Statfs_t) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_statfs_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_statfs_trampoline() + +//go:cgo_import_dynamic libc_statfs statfs "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Symlink(path string, link string) (err error) { @@ -1138,23 +1480,31 @@ func Symlink(path string, link string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_symlink_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_symlink_trampoline() + +//go:cgo_import_dynamic libc_symlink symlink "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Sync() (err error) { - _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_sync_trampoline), 0, 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_sync_trampoline() + +//go:cgo_import_dynamic libc_sync sync "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Truncate(path string, length int64) (err error) { @@ -1163,21 +1513,29 @@ func Truncate(path string, length int64) (err error) { if err != nil { return } - _, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0) + _, _, e1 := syscall6(abi.FuncPCABI0(libc_truncate_trampoline), uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_truncate_trampoline() + +//go:cgo_import_dynamic libc_truncate truncate "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(newmask int) (oldmask int) { - r0, _, _ := Syscall(SYS_UMASK, uintptr(newmask), 0, 0) + r0, _, _ := syscall(abi.FuncPCABI0(libc_umask_trampoline), uintptr(newmask), 0, 0) oldmask = int(r0) return } +func libc_umask_trampoline() + +//go:cgo_import_dynamic libc_umask umask "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Unlink(path string) (err error) { @@ -1186,13 +1544,17 @@ func Unlink(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_unlink_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_unlink_trampoline() + +//go:cgo_import_dynamic libc_unlink unlink "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Unmount(path string, flags int) (err error) { @@ -1201,13 +1563,17 @@ func Unmount(path string, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_unmount_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_unmount_trampoline() + +//go:cgo_import_dynamic libc_unmount unmount "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func write(fd int, p []byte) (n int, err error) { @@ -1217,7 +1583,7 @@ func write(fd int, p []byte) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p))) + r0, _, e1 := syscall(abi.FuncPCABI0(libc_write_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1225,10 +1591,14 @@ func write(fd int, p []byte) (n int, err error) { return } +func libc_write_trampoline() + +//go:cgo_import_dynamic libc_write write "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) { - r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), 0, uintptr(pos), uintptr(pos>>32), 0) + r0, _, e1 := syscall9(abi.FuncPCABI0(libc_mmap_trampoline), uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), 0, uintptr(pos), uintptr(pos>>32), 0) ret = uintptr(r0) if e1 != 0 { err = errnoErr(e1) @@ -1236,20 +1606,62 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) ( return } +func libc_mmap_trampoline() + +//go:cgo_import_dynamic libc_mmap mmap "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func munmap(addr uintptr, length uintptr) (err error) { - _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0) + _, _, e1 := syscall(abi.FuncPCABI0(libc_munmap_trampoline), uintptr(addr), uintptr(length), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_munmap_trampoline() + +//go:cgo_import_dynamic libc_munmap munmap "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func utimensat(dirfd int, path string, times *[2]Timespec, flag int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := syscall6(abi.FuncPCABI0(libc_utimensat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), uintptr(flag), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_utimensat_trampoline() + +//go:cgo_import_dynamic libc_utimensat utimensat "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func directSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr) (ret uintptr, err error) { + r0, _, e1 := syscall6(abi.FuncPCABI0(libc_syscall_trampoline), uintptr(trap), uintptr(a1), uintptr(a2), uintptr(a3), uintptr(a4), uintptr(a5)) + ret = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_syscall_trampoline() + +//go:cgo_import_dynamic libc_syscall syscall "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func readlen(fd int, buf *byte, nbuf int) (n int, err error) { - r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + r0, _, e1 := syscall(abi.FuncPCABI0(libc_read_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1260,7 +1672,7 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func writelen(fd int, buf *byte, nbuf int) (n int, err error) { - r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + r0, _, e1 := syscall(abi.FuncPCABI0(libc_write_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1270,19 +1682,19 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimensat(dirfd int, path string, times *[2]Timespec, flag int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_UTIMENSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), uintptr(flag), 0, 0) +func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { + r0, r1, e1 := syscall6X(abi.FuncPCABI0(libc_lseek_trampoline), uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), uintptr(whence), 0) + newoffset = int64(int64(r1)<<32 | int64(r0)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_lseek_trampoline() + +//go:cgo_import_dynamic libc_lseek lseek "libc.so" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getcwd(buf []byte) (n int, err error) { @@ -1292,10 +1704,195 @@ func getcwd(buf []byte) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall(SYS___GETCWD, uintptr(_p0), uintptr(len(buf)), 0) + r0, _, e1 := syscall(abi.FuncPCABI0(libc_getcwd_trampoline), uintptr(_p0), uintptr(len(buf)), 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) } return } + +func libc_getcwd_trampoline() + +//go:cgo_import_dynamic libc_getcwd getcwd "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { + var _p0 unsafe.Pointer + if len(mib) > 0 { + _p0 = unsafe.Pointer(&mib[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := syscall6(abi.FuncPCABI0(libc_sysctl_trampoline), uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_sysctl_trampoline() + +//go:cgo_import_dynamic libc_sysctl sysctl "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fork() (pid int, err error) { + r0, _, e1 := rawSyscall(abi.FuncPCABI0(libc_fork_trampoline), 0, 0, 0) + pid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fork_trampoline() + +//go:cgo_import_dynamic libc_fork fork "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ioctl(fd int, req int, arg int) (err error) { + _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_ioctl_trampoline), uintptr(fd), uintptr(req), uintptr(arg)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_ioctl_trampoline() + +//go:cgo_import_dynamic libc_ioctl ioctl "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func execve(path *byte, argv **byte, envp **byte) (err error) { + _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_execve_trampoline), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(argv)), uintptr(unsafe.Pointer(envp))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_execve_trampoline() + +//go:cgo_import_dynamic libc_execve execve "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func exit(res int) (err error) { + _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_exit_trampoline), uintptr(res), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_exit_trampoline() + +//go:cgo_import_dynamic libc_exit exit "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +//go:nosplit +func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) { + _, _, e1 := syscall6(abi.FuncPCABI0(libc_ptrace_trampoline), uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_ptrace_trampoline() + +//go:cgo_import_dynamic libc_ptrace ptrace "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getentropy(p []byte) (err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_getentropy_trampoline), uintptr(_p0), uintptr(len(p)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_getentropy_trampoline() + +//go:cgo_import_dynamic libc_getentropy getentropy "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := syscall6(abi.FuncPCABI0(libc_fstatat_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fstatat_trampoline() + +//go:cgo_import_dynamic libc_fstatat fstatat "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fcntlPtr(fd int, cmd int, arg unsafe.Pointer) (val int, err error) { + r0, _, e1 := syscall(abi.FuncPCABI0(libc_fcntl_trampoline), uintptr(fd), uintptr(cmd), uintptr(arg)) + val = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func unlinkat(fd int, path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := syscall(abi.FuncPCABI0(libc_unlinkat_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_unlinkat_trampoline() + +//go:cgo_import_dynamic libc_unlinkat unlinkat "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func openat(fd int, path string, flags int, perm uint32) (fdret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := syscall6(abi.FuncPCABI0(libc_openat_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(perm), 0, 0) + fdret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_openat_trampoline() + +//go:cgo_import_dynamic libc_openat openat "libc.so" diff --git a/src/syscall/zsyscall_openbsd_arm.s b/src/syscall/zsyscall_openbsd_arm.s new file mode 100644 index 00000000000..d33f3aa3e05 --- /dev/null +++ b/src/syscall/zsyscall_openbsd_arm.s @@ -0,0 +1,233 @@ +// go run mkasm.go openbsd arm +// Code generated by the command above; DO NOT EDIT. +#include "textflag.h" +TEXT ·libc_getgroups_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getgroups(SB) +TEXT ·libc_setgroups_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setgroups(SB) +TEXT ·libc_wait4_trampoline(SB),NOSPLIT,$0-0 + JMP libc_wait4(SB) +TEXT ·libc_accept_trampoline(SB),NOSPLIT,$0-0 + JMP libc_accept(SB) +TEXT ·libc_bind_trampoline(SB),NOSPLIT,$0-0 + JMP libc_bind(SB) +TEXT ·libc_connect_trampoline(SB),NOSPLIT,$0-0 + JMP libc_connect(SB) +TEXT ·libc_socket_trampoline(SB),NOSPLIT,$0-0 + JMP libc_socket(SB) +TEXT ·libc_getsockopt_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getsockopt(SB) +TEXT ·libc_setsockopt_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setsockopt(SB) +TEXT ·libc_getpeername_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpeername(SB) +TEXT ·libc_getsockname_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getsockname(SB) +TEXT ·libc_shutdown_trampoline(SB),NOSPLIT,$0-0 + JMP libc_shutdown(SB) +TEXT ·libc_socketpair_trampoline(SB),NOSPLIT,$0-0 + JMP libc_socketpair(SB) +TEXT ·libc_recvfrom_trampoline(SB),NOSPLIT,$0-0 + JMP libc_recvfrom(SB) +TEXT ·libc_sendto_trampoline(SB),NOSPLIT,$0-0 + JMP libc_sendto(SB) +TEXT ·libc_recvmsg_trampoline(SB),NOSPLIT,$0-0 + JMP libc_recvmsg(SB) +TEXT ·libc_sendmsg_trampoline(SB),NOSPLIT,$0-0 + JMP libc_sendmsg(SB) +TEXT ·libc_kevent_trampoline(SB),NOSPLIT,$0-0 + JMP libc_kevent(SB) +TEXT ·libc_utimes_trampoline(SB),NOSPLIT,$0-0 + JMP libc_utimes(SB) +TEXT ·libc_futimes_trampoline(SB),NOSPLIT,$0-0 + JMP libc_futimes(SB) +TEXT ·libc_fcntl_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fcntl(SB) +TEXT ·libc_pipe2_trampoline(SB),NOSPLIT,$0-0 + JMP libc_pipe2(SB) +TEXT ·libc_accept4_trampoline(SB),NOSPLIT,$0-0 + JMP libc_accept4(SB) +TEXT ·libc_getdents_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getdents(SB) +TEXT ·libc_access_trampoline(SB),NOSPLIT,$0-0 + JMP libc_access(SB) +TEXT ·libc_adjtime_trampoline(SB),NOSPLIT,$0-0 + JMP libc_adjtime(SB) +TEXT ·libc_chdir_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chdir(SB) +TEXT ·libc_chflags_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chflags(SB) +TEXT ·libc_chmod_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chmod(SB) +TEXT ·libc_chown_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chown(SB) +TEXT ·libc_chroot_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chroot(SB) +TEXT ·libc_close_trampoline(SB),NOSPLIT,$0-0 + JMP libc_close(SB) +TEXT ·libc_dup_trampoline(SB),NOSPLIT,$0-0 + JMP libc_dup(SB) +TEXT ·libc_dup2_trampoline(SB),NOSPLIT,$0-0 + JMP libc_dup2(SB) +TEXT ·libc_fchdir_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchdir(SB) +TEXT ·libc_fchflags_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchflags(SB) +TEXT ·libc_fchmod_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchmod(SB) +TEXT ·libc_fchown_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchown(SB) +TEXT ·libc_flock_trampoline(SB),NOSPLIT,$0-0 + JMP libc_flock(SB) +TEXT ·libc_fpathconf_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fpathconf(SB) +TEXT ·libc_fstat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fstat(SB) +TEXT ·libc_fstatfs_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fstatfs(SB) +TEXT ·libc_fsync_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fsync(SB) +TEXT ·libc_ftruncate_trampoline(SB),NOSPLIT,$0-0 + JMP libc_ftruncate(SB) +TEXT ·libc_getegid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getegid(SB) +TEXT ·libc_geteuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_geteuid(SB) +TEXT ·libc_getgid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getgid(SB) +TEXT ·libc_getpgid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpgid(SB) +TEXT ·libc_getpgrp_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpgrp(SB) +TEXT ·libc_getpid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpid(SB) +TEXT ·libc_getppid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getppid(SB) +TEXT ·libc_getpriority_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpriority(SB) +TEXT ·libc_getrlimit_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getrlimit(SB) +TEXT ·libc_getrusage_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getrusage(SB) +TEXT ·libc_getsid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getsid(SB) +TEXT ·libc_gettimeofday_trampoline(SB),NOSPLIT,$0-0 + JMP libc_gettimeofday(SB) +TEXT ·libc_getuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getuid(SB) +TEXT ·libc_issetugid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_issetugid(SB) +TEXT ·libc_kill_trampoline(SB),NOSPLIT,$0-0 + JMP libc_kill(SB) +TEXT ·libc_kqueue_trampoline(SB),NOSPLIT,$0-0 + JMP libc_kqueue(SB) +TEXT ·libc_lchown_trampoline(SB),NOSPLIT,$0-0 + JMP libc_lchown(SB) +TEXT ·libc_link_trampoline(SB),NOSPLIT,$0-0 + JMP libc_link(SB) +TEXT ·libc_listen_trampoline(SB),NOSPLIT,$0-0 + JMP libc_listen(SB) +TEXT ·libc_lstat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_lstat(SB) +TEXT ·libc_mkdir_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mkdir(SB) +TEXT ·libc_mkfifo_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mkfifo(SB) +TEXT ·libc_mknod_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mknod(SB) +TEXT ·libc_nanosleep_trampoline(SB),NOSPLIT,$0-0 + JMP libc_nanosleep(SB) +TEXT ·libc_open_trampoline(SB),NOSPLIT,$0-0 + JMP libc_open(SB) +TEXT ·libc_pathconf_trampoline(SB),NOSPLIT,$0-0 + JMP libc_pathconf(SB) +TEXT ·libc_pread_trampoline(SB),NOSPLIT,$0-0 + JMP libc_pread(SB) +TEXT ·libc_pwrite_trampoline(SB),NOSPLIT,$0-0 + JMP libc_pwrite(SB) +TEXT ·libc_read_trampoline(SB),NOSPLIT,$0-0 + JMP libc_read(SB) +TEXT ·libc_readlink_trampoline(SB),NOSPLIT,$0-0 + JMP libc_readlink(SB) +TEXT ·libc_rename_trampoline(SB),NOSPLIT,$0-0 + JMP libc_rename(SB) +TEXT ·libc_revoke_trampoline(SB),NOSPLIT,$0-0 + JMP libc_revoke(SB) +TEXT ·libc_rmdir_trampoline(SB),NOSPLIT,$0-0 + JMP libc_rmdir(SB) +TEXT ·libc_select_trampoline(SB),NOSPLIT,$0-0 + JMP libc_select(SB) +TEXT ·libc_setegid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setegid(SB) +TEXT ·libc_seteuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_seteuid(SB) +TEXT ·libc_setgid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setgid(SB) +TEXT ·libc_setlogin_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setlogin(SB) +TEXT ·libc_setpgid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setpgid(SB) +TEXT ·libc_setpriority_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setpriority(SB) +TEXT ·libc_setregid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setregid(SB) +TEXT ·libc_setreuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setreuid(SB) +TEXT ·libc_setrlimit_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setrlimit(SB) +TEXT ·libc_setsid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setsid(SB) +TEXT ·libc_settimeofday_trampoline(SB),NOSPLIT,$0-0 + JMP libc_settimeofday(SB) +TEXT ·libc_setuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setuid(SB) +TEXT ·libc_stat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_stat(SB) +TEXT ·libc_statfs_trampoline(SB),NOSPLIT,$0-0 + JMP libc_statfs(SB) +TEXT ·libc_symlink_trampoline(SB),NOSPLIT,$0-0 + JMP libc_symlink(SB) +TEXT ·libc_sync_trampoline(SB),NOSPLIT,$0-0 + JMP libc_sync(SB) +TEXT ·libc_truncate_trampoline(SB),NOSPLIT,$0-0 + JMP libc_truncate(SB) +TEXT ·libc_umask_trampoline(SB),NOSPLIT,$0-0 + JMP libc_umask(SB) +TEXT ·libc_unlink_trampoline(SB),NOSPLIT,$0-0 + JMP libc_unlink(SB) +TEXT ·libc_unmount_trampoline(SB),NOSPLIT,$0-0 + JMP libc_unmount(SB) +TEXT ·libc_write_trampoline(SB),NOSPLIT,$0-0 + JMP libc_write(SB) +TEXT ·libc_mmap_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mmap(SB) +TEXT ·libc_munmap_trampoline(SB),NOSPLIT,$0-0 + JMP libc_munmap(SB) +TEXT ·libc_utimensat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_utimensat(SB) +TEXT ·libc_syscall_trampoline(SB),NOSPLIT,$0-0 + JMP libc_syscall(SB) +TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 + JMP libc_lseek(SB) +TEXT ·libc_getcwd_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getcwd(SB) +TEXT ·libc_sysctl_trampoline(SB),NOSPLIT,$0-0 + JMP libc_sysctl(SB) +TEXT ·libc_fork_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fork(SB) +TEXT ·libc_ioctl_trampoline(SB),NOSPLIT,$0-0 + JMP libc_ioctl(SB) +TEXT ·libc_execve_trampoline(SB),NOSPLIT,$0-0 + JMP libc_execve(SB) +TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0 + JMP libc_exit(SB) +TEXT ·libc_ptrace_trampoline(SB),NOSPLIT,$0-0 + JMP libc_ptrace(SB) +TEXT ·libc_getentropy_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getentropy(SB) +TEXT ·libc_fstatat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fstatat(SB) +TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_unlinkat(SB) +TEXT ·libc_openat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_openat(SB) From c14ecaca8182314efd2ef7280feffc2242644887 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Wed, 17 Feb 2021 17:12:03 +1100 Subject: [PATCH 012/940] runtime: skip TestCrashDumpsAllThreads on openbsd/arm This test is also now flakey on this platform. Updates #36435 Updates #42464 Change-Id: Idedb81478178ffffe7a9c125a6e8bbd83458f9ab Reviewed-on: https://go-review.googlesource.com/c/go/+/315794 Trust: Joel Sing Reviewed-by: Cherry Mui --- src/runtime/crash_unix_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/runtime/crash_unix_test.go b/src/runtime/crash_unix_test.go index 9469d5e6a64..694cc3d138b 100644 --- a/src/runtime/crash_unix_test.go +++ b/src/runtime/crash_unix_test.go @@ -69,7 +69,8 @@ func TestCrashDumpsAllThreads(t *testing.T) { t.Skipf("skipping; not supported on %v", runtime.GOOS) } - if runtime.GOOS == "openbsd" && runtime.GOARCH == "mips64" { + if runtime.GOOS == "openbsd" && (runtime.GOARCH == "arm" || runtime.GOARCH == "mips64") { + // This may be ncpu < 2 related... t.Skipf("skipping; test fails on %s/%s - see issue #42464", runtime.GOOS, runtime.GOARCH) } From 287025925f66f90ad9b30aea2e533928026a8376 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Sun, 9 May 2021 11:06:17 -0700 Subject: [PATCH 013/940] cmd/compile,reflect: allow longer type names Encode the length of type names and tags in a varint encoding instead of a fixed 2-byte encoding. This allows lengths longer than 65535 (which can happen for large unnamed structs). Removed the alignment check for #14962, it isn't relevant any more since we're no longer reading pointers directly out of this data (it is encoded as an offset which is copied out bytewise). Fixes #44155 Update #14962 Change-Id: I6084f6027e5955dc16777c87b0dd5ea2baa49629 Reviewed-on: https://go-review.googlesource.com/c/go/+/318249 Trust: Keith Randall Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- .../compile/internal/reflectdata/reflect.go | 29 +++-- src/cmd/link/internal/ld/decodesym.go | 5 +- src/internal/reflectlite/all_test.go | 13 -- src/internal/reflectlite/type.go | 48 ++++---- src/reflect/all_test.go | 13 -- src/reflect/type.go | 111 +++++++++++------- src/runtime/type.go | 53 ++++----- 7 files changed, 141 insertions(+), 131 deletions(-) diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index 01eaf26a0a6..8c0e33f6df1 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -5,6 +5,7 @@ package reflectdata import ( + "encoding/binary" "fmt" "internal/buildcfg" "os" @@ -473,21 +474,25 @@ func dnameField(lsym *obj.LSym, ot int, spkg *types.Pkg, ft *types.Field) int { // dnameData writes the contents of a reflect.name into s at offset ot. func dnameData(s *obj.LSym, ot int, name, tag string, pkg *types.Pkg, exported bool) int { - if len(name) > 1<<16-1 { - base.Fatalf("name too long: %s", name) + if len(name) >= 1<<29 { + base.Fatalf("name too long: %d %s...", len(name), name[:1024]) } - if len(tag) > 1<<16-1 { - base.Fatalf("tag too long: %s", tag) + if len(tag) >= 1<<29 { + base.Fatalf("tag too long: %d %s...", len(tag), tag[:1024]) } + var nameLen [binary.MaxVarintLen64]byte + nameLenLen := binary.PutUvarint(nameLen[:], uint64(len(name))) + var tagLen [binary.MaxVarintLen64]byte + tagLenLen := binary.PutUvarint(tagLen[:], uint64(len(tag))) // Encode name and tag. See reflect/type.go for details. var bits byte - l := 1 + 2 + len(name) + l := 1 + nameLenLen + len(name) if exported { bits |= 1 << 0 } if len(tag) > 0 { - l += 2 + len(tag) + l += tagLenLen + len(tag) bits |= 1 << 1 } if pkg != nil { @@ -495,14 +500,12 @@ func dnameData(s *obj.LSym, ot int, name, tag string, pkg *types.Pkg, exported b } b := make([]byte, l) b[0] = bits - b[1] = uint8(len(name) >> 8) - b[2] = uint8(len(name)) - copy(b[3:], name) + copy(b[1:], nameLen[:nameLenLen]) + copy(b[1+nameLenLen:], name) if len(tag) > 0 { - tb := b[3+len(name):] - tb[0] = uint8(len(tag) >> 8) - tb[1] = uint8(len(tag)) - copy(tb[2:], tag) + tb := b[1+nameLenLen+len(name):] + copy(tb, tagLen[:tagLenLen]) + copy(tb[tagLenLen:], tag) } ot = int(s.WriteBytes(base.Ctxt, int64(ot), b)) diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go index fc179fc6e44..c41d97706ef 100644 --- a/src/cmd/link/internal/ld/decodesym.go +++ b/src/cmd/link/internal/ld/decodesym.go @@ -10,6 +10,7 @@ import ( "cmd/link/internal/loader" "cmd/link/internal/sym" "debug/elf" + "encoding/binary" "log" ) @@ -126,8 +127,8 @@ func decodetypeName(ldr *loader.Loader, symIdx loader.Sym, relocs *loader.Relocs } data := ldr.Data(r) - namelen := int(uint16(data[1])<<8 | uint16(data[2])) - return string(data[3 : 3+namelen]) + nameLen, nameLenLen := binary.Uvarint(data[1:]) + return string(data[1+nameLenLen : 1+nameLenLen+int(nameLen)]) } func decodetypeFuncInType(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs, i int) loader.Sym { diff --git a/src/internal/reflectlite/all_test.go b/src/internal/reflectlite/all_test.go index e2c4f30487b..e15f364fcd3 100644 --- a/src/internal/reflectlite/all_test.go +++ b/src/internal/reflectlite/all_test.go @@ -982,19 +982,6 @@ func TestNames(t *testing.T) { } } -type embed struct { - EmbedWithUnexpMeth -} - -func TestNameBytesAreAligned(t *testing.T) { - typ := TypeOf(embed{}) - b := FirstMethodNameBytes(typ) - v := uintptr(unsafe.Pointer(b)) - if v%unsafe.Alignof((*byte)(nil)) != 0 { - t.Errorf("reflect.name.bytes pointer is not aligned: %x", v) - } -} - // TestUnaddressableField tests that the reflect package will not allow // a type from another package to be used as a named type with an // unexported field. diff --git a/src/internal/reflectlite/type.go b/src/internal/reflectlite/type.go index 15ba30da36c..f529f7c5fcc 100644 --- a/src/internal/reflectlite/type.go +++ b/src/internal/reflectlite/type.go @@ -321,49 +321,55 @@ func (n name) isExported() bool { return (*n.bytes)&(1<<0) != 0 } -func (n name) nameLen() int { - return int(uint16(*n.data(1, "name len field"))<<8 | uint16(*n.data(2, "name len field"))) +func (n name) hasTag() bool { + return (*n.bytes)&(1<<1) != 0 } -func (n name) tagLen() int { - if *n.data(0, "name flag field")&(1<<1) == 0 { - return 0 +// readVarint parses a varint as encoded by encoding/binary. +// It returns the number of encoded bytes and the encoded value. +func (n name) readVarint(off int) (int, int) { + v := 0 + for i := 0; ; i++ { + x := *n.data(off+i, "read varint") + v += int(x&0x7f) << (7 * i) + if x&0x80 == 0 { + return i + 1, v + } } - off := 3 + n.nameLen() - return int(uint16(*n.data(off, "name taglen field"))<<8 | uint16(*n.data(off+1, "name taglen field"))) } func (n name) name() (s string) { if n.bytes == nil { return } - b := (*[4]byte)(unsafe.Pointer(n.bytes)) - + i, l := n.readVarint(1) hdr := (*unsafeheader.String)(unsafe.Pointer(&s)) - hdr.Data = unsafe.Pointer(&b[3]) - hdr.Len = int(b[1])<<8 | int(b[2]) - return s + hdr.Data = unsafe.Pointer(n.data(1+i, "non-empty string")) + hdr.Len = l + return } func (n name) tag() (s string) { - tl := n.tagLen() - if tl == 0 { + if !n.hasTag() { return "" } - nl := n.nameLen() + i, l := n.readVarint(1) + i2, l2 := n.readVarint(1 + i + l) hdr := (*unsafeheader.String)(unsafe.Pointer(&s)) - hdr.Data = unsafe.Pointer(n.data(3+nl+2, "non-empty string")) - hdr.Len = tl - return s + hdr.Data = unsafe.Pointer(n.data(1+i+l+i2, "non-empty string")) + hdr.Len = l2 + return } func (n name) pkgPath() string { if n.bytes == nil || *n.data(0, "name flag field")&(1<<2) == 0 { return "" } - off := 3 + n.nameLen() - if tl := n.tagLen(); tl > 0 { - off += 2 + tl + i, l := n.readVarint(1) + off := 1 + i + l + if n.hasTag() { + i2, l2 := n.readVarint(off) + off += i2 + l2 } var nameOff int32 // Note that this field may not be aligned in memory, diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 065ff046115..17104ad4fab 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -6942,19 +6942,6 @@ func TestExported(t *testing.T) { } } -type embed struct { - EmbedWithUnexpMeth -} - -func TestNameBytesAreAligned(t *testing.T) { - typ := TypeOf(embed{}) - b := FirstMethodNameBytes(typ) - v := uintptr(unsafe.Pointer(b)) - if v%unsafe.Alignof((*byte)(nil)) != 0 { - t.Errorf("reflect.name.bytes pointer is not aligned: %x", v) - } -} - func TestTypeStrings(t *testing.T) { type stringTest struct { typ Type diff --git a/src/reflect/type.go b/src/reflect/type.go index 9727bfe467c..39414fc2a64 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -450,14 +450,11 @@ type structType struct { // 1<<1 tag data follows the name // 1<<2 pkgPath nameOff follows the name and tag // -// The next two bytes are the data length: +// Following that, there is a varint-encoded length of the name, +// followed by the name itself. // -// l := uint16(data[1])<<8 | uint16(data[2]) -// -// Bytes [3:3+l] are the string data. -// -// If tag data follows then bytes 3+l and 3+l+1 are the tag length, -// with the data following. +// If tag data is present, it also has a varint-encoded length +// followed by the tag itself. // // If the import path follows, then 4 bytes at the end of // the data form a nameOff. The import path is only set for concrete @@ -465,6 +462,13 @@ type structType struct { // // If a name starts with "*", then the exported bit represents // whether the pointed to type is exported. +// +// Note: this encoding must match here and in: +// cmd/compile/internal/reflectdata/reflect.go +// runtime/type.go +// internal/reflectlite/type.go +// cmd/link/internal/ld/decodesym.go + type name struct { bytes *byte } @@ -477,49 +481,70 @@ func (n name) isExported() bool { return (*n.bytes)&(1<<0) != 0 } -func (n name) nameLen() int { - return int(uint16(*n.data(1, "name len field"))<<8 | uint16(*n.data(2, "name len field"))) +func (n name) hasTag() bool { + return (*n.bytes)&(1<<1) != 0 } -func (n name) tagLen() int { - if *n.data(0, "name flag field")&(1<<1) == 0 { - return 0 +// readVarint parses a varint as encoded by encoding/binary. +// It returns the number of encoded bytes and the encoded value. +func (n name) readVarint(off int) (int, int) { + v := 0 + for i := 0; ; i++ { + x := *n.data(off+i, "read varint") + v += int(x&0x7f) << (7 * i) + if x&0x80 == 0 { + return i + 1, v + } + } +} + +// writeVarint writes n to buf in varint form. Returns the +// number of bytes written. n must be nonnegative. +// Writes at most 10 bytes. +func writeVarint(buf []byte, n int) int { + for i := 0; ; i++ { + b := byte(n & 0x7f) + n >>= 7 + if n == 0 { + buf[i] = b + return i + 1 + } + buf[i] = b | 0x80 } - off := 3 + n.nameLen() - return int(uint16(*n.data(off, "name taglen field"))<<8 | uint16(*n.data(off+1, "name taglen field"))) } func (n name) name() (s string) { if n.bytes == nil { return } - b := (*[4]byte)(unsafe.Pointer(n.bytes)) - + i, l := n.readVarint(1) hdr := (*unsafeheader.String)(unsafe.Pointer(&s)) - hdr.Data = unsafe.Pointer(&b[3]) - hdr.Len = int(b[1])<<8 | int(b[2]) - return s + hdr.Data = unsafe.Pointer(n.data(1+i, "non-empty string")) + hdr.Len = l + return } func (n name) tag() (s string) { - tl := n.tagLen() - if tl == 0 { + if !n.hasTag() { return "" } - nl := n.nameLen() + i, l := n.readVarint(1) + i2, l2 := n.readVarint(1 + i + l) hdr := (*unsafeheader.String)(unsafe.Pointer(&s)) - hdr.Data = unsafe.Pointer(n.data(3+nl+2, "non-empty string")) - hdr.Len = tl - return s + hdr.Data = unsafe.Pointer(n.data(1+i+l+i2, "non-empty string")) + hdr.Len = l2 + return } func (n name) pkgPath() string { if n.bytes == nil || *n.data(0, "name flag field")&(1<<2) == 0 { return "" } - off := 3 + n.nameLen() - if tl := n.tagLen(); tl > 0 { - off += 2 + tl + i, l := n.readVarint(1) + off := 1 + i + l + if n.hasTag() { + i2, l2 := n.readVarint(off) + off += i2 + l2 } var nameOff int32 // Note that this field may not be aligned in memory, @@ -530,33 +555,35 @@ func (n name) pkgPath() string { } func newName(n, tag string, exported bool) name { - if len(n) > 1<<16-1 { - panic("reflect.nameFrom: name too long: " + n) + if len(n) >= 1<<29 { + panic("reflect.nameFrom: name too long: " + n[:1024] + "...") } - if len(tag) > 1<<16-1 { - panic("reflect.nameFrom: tag too long: " + tag) + if len(tag) >= 1<<29 { + panic("reflect.nameFrom: tag too long: " + tag[:1024] + "...") } + var nameLen [10]byte + var tagLen [10]byte + nameLenLen := writeVarint(nameLen[:], len(n)) + tagLenLen := writeVarint(tagLen[:], len(tag)) var bits byte - l := 1 + 2 + len(n) + l := 1 + nameLenLen + len(n) if exported { bits |= 1 << 0 } if len(tag) > 0 { - l += 2 + len(tag) + l += tagLenLen + len(tag) bits |= 1 << 1 } b := make([]byte, l) b[0] = bits - b[1] = uint8(len(n) >> 8) - b[2] = uint8(len(n)) - copy(b[3:], n) + copy(b[1:], nameLen[:nameLenLen]) + copy(b[1+nameLenLen:], n) if len(tag) > 0 { - tb := b[3+len(n):] - tb[0] = uint8(len(tag) >> 8) - tb[1] = uint8(len(tag)) - copy(tb[2:], tag) + tb := b[1+nameLenLen+len(n):] + copy(tb, tagLen[:tagLenLen]) + copy(tb[tagLenLen:], tag) } return name{bytes: &b[0]} @@ -2570,7 +2597,7 @@ func StructOf(fields []StructField) Type { hash = fnv1(hash, byte(ft.hash>>24), byte(ft.hash>>16), byte(ft.hash>>8), byte(ft.hash)) repr = append(repr, (" " + ft.String())...) - if f.name.tagLen() > 0 { + if f.name.hasTag() { hash = fnv1(hash, []byte(f.name.tag())...) repr = append(repr, (" " + strconv.Quote(f.name.tag()))...) } diff --git a/src/runtime/type.go b/src/runtime/type.go index c0911b1dcb1..335fc57f4b9 100644 --- a/src/runtime/type.go +++ b/src/runtime/type.go @@ -459,51 +459,52 @@ func (n name) isExported() bool { return (*n.bytes)&(1<<0) != 0 } -func (n name) nameLen() int { - return int(uint16(*n.data(1))<<8 | uint16(*n.data(2))) -} - -func (n name) tagLen() int { - if *n.data(0)&(1<<1) == 0 { - return 0 +func (n name) readvarint(off int) (int, int) { + v := 0 + for i := 0; ; i++ { + x := *n.data(off + i) + v += int(x&0x7f) << (7 * i) + if x&0x80 == 0 { + return i + 1, v + } } - off := 3 + n.nameLen() - return int(uint16(*n.data(off))<<8 | uint16(*n.data(off + 1))) } func (n name) name() (s string) { if n.bytes == nil { return "" } - nl := n.nameLen() - if nl == 0 { + i, l := n.readvarint(1) + if l == 0 { return "" } hdr := (*stringStruct)(unsafe.Pointer(&s)) - hdr.str = unsafe.Pointer(n.data(3)) - hdr.len = nl - return s + hdr.str = unsafe.Pointer(n.data(1 + i)) + hdr.len = l + return } func (n name) tag() (s string) { - tl := n.tagLen() - if tl == 0 { + if *n.data(0)&(1<<1) == 0 { return "" } - nl := n.nameLen() + i, l := n.readvarint(1) + i2, l2 := n.readvarint(1 + i + l) hdr := (*stringStruct)(unsafe.Pointer(&s)) - hdr.str = unsafe.Pointer(n.data(3 + nl + 2)) - hdr.len = tl - return s + hdr.str = unsafe.Pointer(n.data(1 + i + l + i2)) + hdr.len = l2 + return } func (n name) pkgPath() string { if n.bytes == nil || *n.data(0)&(1<<2) == 0 { return "" } - off := 3 + n.nameLen() - if tl := n.tagLen(); tl > 0 { - off += 2 + tl + i, l := n.readvarint(1) + off := 1 + i + l + if *n.data(0)&(1<<1) != 0 { + i2, l2 := n.readvarint(off) + off += i2 + l2 } var nameOff nameOff copy((*[4]byte)(unsafe.Pointer(&nameOff))[:], (*[4]byte)(unsafe.Pointer(n.data(off)))[:]) @@ -515,10 +516,8 @@ func (n name) isBlank() bool { if n.bytes == nil { return false } - if n.nameLen() != 1 { - return false - } - return *n.data(3) == '_' + _, l := n.readvarint(1) + return l == 1 && *n.data(2) == '_' } // typelinksinit scans the types from extra modules and builds the From e18a8b4fb27df3ee04f7eb00c4f1ed77e5486ce8 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Wed, 5 May 2021 17:05:51 -0400 Subject: [PATCH 014/940] go/build: avoid duplicates in InvalidGoFiles For #45827 For #39986 Updates #45999 Change-Id: I0c919b6a2e56e7003b90425487eafe0f0eadc609 Reviewed-on: https://go-review.googlesource.com/c/go/+/317299 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Jay Conrod --- src/go/build/build.go | 36 +++++++++++++++++++++--------------- src/go/build/build_test.go | 18 ++++++++++++++++-- 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/src/go/build/build.go b/src/go/build/build.go index 8d1a107c6ea..b85fa96de1f 100644 --- a/src/go/build/build.go +++ b/src/go/build/build.go @@ -810,6 +810,17 @@ Found: } var badGoError error + badFiles := make(map[string]bool) + badFile := func(name string, err error) { + if badGoError == nil { + badGoError = err + } + if !badFiles[name] { + p.InvalidGoFiles = append(p.InvalidGoFiles, name) + badFiles[name] = true + } + } + var Sfiles []string // files with ".S"(capital S)/.sx(capital s equivalent for case insensitive filesystems) var firstFile, firstCommentFile string embedPos := make(map[string][]token.Position) @@ -834,16 +845,9 @@ Found: name := d.Name() ext := nameExt(name) - badFile := func(err error) { - if badGoError == nil { - badGoError = err - } - p.InvalidGoFiles = append(p.InvalidGoFiles, name) - } - info, err := ctxt.matchFile(p.Dir, name, allTags, &p.BinaryOnly, fset) if err != nil { - badFile(err) + badFile(name, err) continue } if info == nil { @@ -874,7 +878,7 @@ Found: } if info.parseErr != nil { - badFile(info.parseErr) + badFile(name, info.parseErr) continue } pf := info.parsed @@ -896,12 +900,14 @@ Found: p.Name = pkg firstFile = name } else if pkg != p.Name { - badFile(&MultiplePackageError{ + // TODO(#45999): The choice of p.Name is arbitrary based on file iteration + // order. Instead of resolving p.Name arbitrarily, we should clear out the + // existing name and mark the existing files as also invalid. + badFile(name, &MultiplePackageError{ Dir: p.Dir, Packages: []string{p.Name, pkg}, Files: []string{firstFile, name}, }) - p.InvalidGoFiles = append(p.InvalidGoFiles, name) } // Grab the first package comment as docs, provided it is not from a test file. if pf.Doc != nil && p.Doc == "" && !isTest && !isXTest { @@ -913,12 +919,12 @@ Found: if line != 0 { com, err := strconv.Unquote(qcom) if err != nil { - badFile(fmt.Errorf("%s:%d: cannot parse import comment", filename, line)) + badFile(name, fmt.Errorf("%s:%d: cannot parse import comment", filename, line)) } else if p.ImportComment == "" { p.ImportComment = com firstCommentFile = name } else if p.ImportComment != com { - badFile(fmt.Errorf("found import comments %q (%s) and %q (%s) in %s", p.ImportComment, firstCommentFile, com, name, p.Dir)) + badFile(name, fmt.Errorf("found import comments %q (%s) and %q (%s) in %s", p.ImportComment, firstCommentFile, com, name, p.Dir)) } } } @@ -928,13 +934,13 @@ Found: for _, imp := range info.imports { if imp.path == "C" { if isTest { - badFile(fmt.Errorf("use of cgo in test %s not supported", filename)) + badFile(name, fmt.Errorf("use of cgo in test %s not supported", filename)) continue } isCgo = true if imp.doc != nil { if err := ctxt.saveCgo(filename, p, imp.doc); err != nil { - badFile(err) + badFile(name, err) } } } diff --git a/src/go/build/build_test.go b/src/go/build/build_test.go index 7e785680831..80f930f3c23 100644 --- a/src/go/build/build_test.go +++ b/src/go/build/build_test.go @@ -104,7 +104,8 @@ func TestEmptyFolderImport(t *testing.T) { } func TestMultiplePackageImport(t *testing.T) { - _, err := Import(".", "testdata/multi", 0) + pkg, err := Import(".", "testdata/multi", 0) + mpe, ok := err.(*MultiplePackageError) if !ok { t.Fatal(`Import("testdata/multi") did not return MultiplePackageError.`) @@ -115,7 +116,20 @@ func TestMultiplePackageImport(t *testing.T) { Files: []string{"file.go", "file_appengine.go"}, } if !reflect.DeepEqual(mpe, want) { - t.Errorf("got %#v; want %#v", mpe, want) + t.Errorf("err = %#v; want %#v", mpe, want) + } + + // TODO(#45999): Since the name is ambiguous, pkg.Name should be left empty. + if wantName := "main"; pkg.Name != wantName { + t.Errorf("pkg.Name = %q; want %q", pkg.Name, wantName) + } + + if wantGoFiles := []string{"file.go", "file_appengine.go"}; !reflect.DeepEqual(pkg.GoFiles, wantGoFiles) { + t.Errorf("pkg.GoFiles = %q; want %q", pkg.GoFiles, wantGoFiles) + } + + if wantInvalidFiles := []string{"file_appengine.go"}; !reflect.DeepEqual(pkg.InvalidGoFiles, wantInvalidFiles) { + t.Errorf("pkg.InvalidGoFiles = %q; want %q", pkg.InvalidGoFiles, wantInvalidFiles) } } From a9edda3788b7ff6a73686874c9b3dcb1e5e18b87 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Mon, 3 May 2021 17:03:01 -0400 Subject: [PATCH 015/940] cmd/go: add a test that reproduces #45827 For #45827 Change-Id: I4d3268d66fb0927161f44b353faef11aa4551e40 Reviewed-on: https://go-review.googlesource.com/c/go/+/317298 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Jay Conrod --- .../go/testdata/script/mod_run_pkgerror.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/cmd/go/testdata/script/mod_run_pkgerror.txt diff --git a/src/cmd/go/testdata/script/mod_run_pkgerror.txt b/src/cmd/go/testdata/script/mod_run_pkgerror.txt new file mode 100644 index 00000000000..fd7060aaa86 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_run_pkgerror.txt @@ -0,0 +1,18 @@ +# https://golang.org/issue/45827: 'go run .' should report the same package +# errors as 'go build'. + +! go build +stderr '^found packages m \(m\.go\) and main \(main\.go\) in '$PWD'$' + +! go run . + # TODO(#45827): This error should match the above. +stderr '^go run: no packages loaded from \.$' + +-- go.mod -- +module m + +go 1.17 +-- m.go -- +package m +-- main.go -- +package main From 031854117f91fbc1265840a04caf2a7a168dd06b Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Wed, 5 May 2021 17:08:39 -0400 Subject: [PATCH 016/940] cmd/go: include packages with InvalidGoFiles when filtering main packages If a package has files with conflicting package names, go/build empirically populates the first name encountered and puts the remaining files in InvalidGoFiles. That foiled our check for packages whose name is either unpopulated or "main", since the "package main" could be found in a source file after the first. Instead, we now treat any package with a nonzero set of InvalidGoFiles as potentially a main package. This biases toward over-reporting errors, but we would rather over-report than under-report. If we fix #45999, we will be able to make these error checks more precise. Updates #42088 Fixes #45827 Fixes #39986 Change-Id: I588314341b17961b38660192c2130678dc03023e Reviewed-on: https://go-review.googlesource.com/c/go/+/317300 Trust: Bryan C. Mills Reviewed-by: Jay Conrod --- src/cmd/go/internal/load/pkg.go | 80 +++++++++++-------- .../script/mod_install_pkg_version.txt | 2 +- .../go/testdata/script/mod_run_nonmain.txt | 18 +++++ .../go/testdata/script/mod_run_pkgerror.txt | 20 ++++- 4 files changed, 84 insertions(+), 36 deletions(-) create mode 100644 src/cmd/go/testdata/script/mod_run_nonmain.txt diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 153399d83e6..3c7cd44ee33 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -87,6 +87,7 @@ type PackagePublic struct { CgoFiles []string `json:",omitempty"` // .go source files that import "C" CompiledGoFiles []string `json:",omitempty"` // .go output from running cgo on CgoFiles IgnoredGoFiles []string `json:",omitempty"` // .go source files ignored due to build constraints + InvalidGoFiles []string `json:",omitempty"` // .go source files with detected problems (parse error, wrong package name, and so on) IgnoredOtherFiles []string `json:",omitempty"` // non-.go source files ignored due to build constraints CFiles []string `json:",omitempty"` // .c source files CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files @@ -144,6 +145,7 @@ func (p *Package) AllFiles() []string { p.CgoFiles, // no p.CompiledGoFiles, because they are from GoFiles or generated by us p.IgnoredGoFiles, + // no p.InvalidGoFiles, because they are from GoFiles p.IgnoredOtherFiles, p.CFiles, p.CXXFiles, @@ -371,6 +373,7 @@ func (p *Package) copyBuild(opts PackageOpts, pp *build.Package) { p.GoFiles = pp.GoFiles p.CgoFiles = pp.CgoFiles p.IgnoredGoFiles = pp.IgnoredGoFiles + p.InvalidGoFiles = pp.InvalidGoFiles p.IgnoredOtherFiles = pp.IgnoredOtherFiles p.CFiles = pp.CFiles p.CXXFiles = pp.CXXFiles @@ -2493,7 +2496,7 @@ func PackagesAndErrors(ctx context.Context, opts PackageOpts, patterns []string) } if opts.MainOnly { - pkgs = mainPackagesOnly(pkgs, patterns) + pkgs = mainPackagesOnly(pkgs, matches) } // Now that CmdlinePkg is set correctly, @@ -2547,50 +2550,63 @@ func CheckPackageErrors(pkgs []*Package) { // mainPackagesOnly filters out non-main packages matched only by arguments // containing "..." and returns the remaining main packages. // +// Packages with missing, invalid, or ambiguous names may be treated as +// possibly-main packages. +// // mainPackagesOnly sets a non-main package's Error field and returns it if it // is named by a literal argument. // // mainPackagesOnly prints warnings for non-literal arguments that only match // non-main packages. -func mainPackagesOnly(pkgs []*Package, patterns []string) []*Package { - matchers := make([]func(string) bool, len(patterns)) - for i, p := range patterns { - if strings.Contains(p, "...") { - matchers[i] = search.MatchPattern(p) +func mainPackagesOnly(pkgs []*Package, matches []*search.Match) []*Package { + treatAsMain := map[string]bool{} + for _, m := range matches { + if m.IsLiteral() { + for _, path := range m.Pkgs { + treatAsMain[path] = true + } } } - matchedPkgs := make([]*Package, 0, len(pkgs)) - mainCount := make([]int, len(patterns)) - nonMainCount := make([]int, len(patterns)) + var mains []*Package for _, pkg := range pkgs { - if pkg.Name == "main" || (pkg.Incomplete && pkg.Name == "") { - matchedPkgs = append(matchedPkgs, pkg) - for i := range patterns { - if matchers[i] != nil && matchers[i](pkg.ImportPath) { - mainCount[i]++ - } - } - } else { - for i := range patterns { - if matchers[i] == nil && patterns[i] == pkg.ImportPath { - if pkg.Error == nil { - pkg.Error = &PackageError{Err: &mainPackageError{importPath: pkg.ImportPath}} - } - matchedPkgs = append(matchedPkgs, pkg) - } else if matchers[i] != nil && matchers[i](pkg.ImportPath) { - nonMainCount[i]++ - } - } + if pkg.Name == "main" { + treatAsMain[pkg.ImportPath] = true + mains = append(mains, pkg) + continue } - } - for i, p := range patterns { - if matchers[i] != nil && mainCount[i] == 0 && nonMainCount[i] > 0 { - fmt.Fprintf(os.Stderr, "go: warning: %q matched no main packages\n", p) + + if len(pkg.InvalidGoFiles) > 0 { // TODO(#45999): && pkg.Name == "", but currently go/build sets pkg.Name arbitrarily if it is ambiguous. + // The package has (or may have) conflicting names, and we can't easily + // tell whether one of them is "main". So assume that it could be, and + // report an error for the package. + treatAsMain[pkg.ImportPath] = true + } + if treatAsMain[pkg.ImportPath] { + if pkg.Error == nil { + pkg.Error = &PackageError{Err: &mainPackageError{importPath: pkg.ImportPath}} + } + mains = append(mains, pkg) } } - return matchedPkgs + for _, m := range matches { + if m.IsLiteral() || len(m.Pkgs) == 0 { + continue + } + foundMain := false + for _, path := range m.Pkgs { + if treatAsMain[path] { + foundMain = true + break + } + } + if !foundMain { + fmt.Fprintf(os.Stderr, "go: warning: %q matched only non-main packages\n", m.Pattern()) + } + } + + return mains } type mainPackageError struct { diff --git a/src/cmd/go/testdata/script/mod_install_pkg_version.txt b/src/cmd/go/testdata/script/mod_install_pkg_version.txt index 2c14ef737b3..fd02392af1b 100644 --- a/src/cmd/go/testdata/script/mod_install_pkg_version.txt +++ b/src/cmd/go/testdata/script/mod_install_pkg_version.txt @@ -143,7 +143,7 @@ stderr '^go: warning: "example.com/cmd/nomatch\.\.\." matched no packages$' # If a wildcard matches only non-main packges, we should see a different warning. go install example.com/cmd/err...@v1.0.0 -stderr '^go: warning: "example.com/cmd/err\.\.\." matched no main packages$' +stderr '^go: warning: "example.com/cmd/err\.\.\." matched only non-main packages$' # 'go install pkg@version' should report errors if the module contains diff --git a/src/cmd/go/testdata/script/mod_run_nonmain.txt b/src/cmd/go/testdata/script/mod_run_nonmain.txt new file mode 100644 index 00000000000..036755d2d1a --- /dev/null +++ b/src/cmd/go/testdata/script/mod_run_nonmain.txt @@ -0,0 +1,18 @@ +! go run $PWD +! stderr 'no packages loaded' +stderr '^package example.net/nonmain is not a main package$' + +! go run . +stderr '^package example.net/nonmain is not a main package$' + +! go run ./... +stderr '^go: warning: "\./\.\.\." matched only non-main packages$' +stderr '^go run: no packages loaded from \./\.\.\.$' + +-- go.mod -- +module example.net/nonmain + +go 1.17 +-- nonmain.go -- +// Package nonmain is not a main package. +package nonmain diff --git a/src/cmd/go/testdata/script/mod_run_pkgerror.txt b/src/cmd/go/testdata/script/mod_run_pkgerror.txt index fd7060aaa86..48f900dd346 100644 --- a/src/cmd/go/testdata/script/mod_run_pkgerror.txt +++ b/src/cmd/go/testdata/script/mod_run_pkgerror.txt @@ -1,12 +1,26 @@ +# https://golang.org/issue/39986: files reported as invalid by go/build should +# be listed in InvalidGoFiles. + +go list -e -f '{{.Incomplete}}{{"\n"}}{{.Error}}{{"\n"}}{{.InvalidGoFiles}}{{"\n"}}' . +stdout '^true\nfound packages m \(m\.go\) and main \(main\.go\) in '$PWD'\n\[main.go\]\n' + + # https://golang.org/issue/45827: 'go run .' should report the same package -# errors as 'go build'. +# errors as 'go build' and 'go list'. ! go build stderr '^found packages m \(m\.go\) and main \(main\.go\) in '$PWD'$' +! go list . +stderr '^found packages m \(m\.go\) and main \(main\.go\) in '$PWD'$' + ! go run . - # TODO(#45827): This error should match the above. -stderr '^go run: no packages loaded from \.$' +! stderr 'no packages loaded' +stderr '^found packages m \(m\.go\) and main \(main\.go\) in '$PWD'$' + +! go run ./... +! stderr 'no packages loaded' +stderr '^found packages m \(m\.go\) and main \(main\.go\) in '$PWD'$' -- go.mod -- module m From 82517acae866d60a9754d44d004bfa159e656c07 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 10 May 2021 14:52:22 +0200 Subject: [PATCH 017/940] net, runtime: drop macOS 10.12 skip conditions in tests Go 1.17 requires macOS 10.13 or later. Thus, drop the special cases for the darwin-amd64-10_12 builder added in CL 202618. Updates #22019 Updates #23011 Updates #32919 Change-Id: Idef11c213dfb25fd002b7cda6d425cf2e26a2e06 Reviewed-on: https://go-review.googlesource.com/c/go/+/318329 Trust: Tobias Klauser Run-TryBot: Tobias Klauser TryBot-Result: Go Bot Reviewed-by: Brad Fitzpatrick Reviewed-by: Bryan C. Mills --- src/net/dial_test.go | 10 +--------- src/net/server_test.go | 7 ------- src/runtime/crash_test.go | 8 -------- 3 files changed, 1 insertion(+), 24 deletions(-) diff --git a/src/net/dial_test.go b/src/net/dial_test.go index 394bdb047e7..f899da10cf8 100644 --- a/src/net/dial_test.go +++ b/src/net/dial_test.go @@ -656,15 +656,7 @@ func TestDialerLocalAddr(t *testing.T) { } c, err := d.Dial(tt.network, addr) if err == nil && tt.error != nil || err != nil && tt.error == nil { - // A suspected kernel bug in macOS 10.12 occasionally results in - // timeout errors when dialing address ::1. The errors have not - // been observed on newer versions of the OS, so we don't plan to work - // around them. See https://golang.org/issue/22019. - if tt.raddr == "::1" && os.Getenv("GO_BUILDER_NAME") == "darwin-amd64-10_12" && os.IsTimeout(err) { - t.Logf("ignoring timeout error on Darwin; see https://golang.org/issue/22019") - } else { - t.Errorf("%s %v->%s: got %v; want %v", tt.network, tt.laddr, tt.raddr, err, tt.error) - } + t.Errorf("%s %v->%s: got %v; want %v", tt.network, tt.laddr, tt.raddr, err, tt.error) } if err != nil { if perr := parseDialError(err); perr != nil { diff --git a/src/net/server_test.go b/src/net/server_test.go index 8d4db7233d1..7cbf1522988 100644 --- a/src/net/server_test.go +++ b/src/net/server_test.go @@ -105,13 +105,6 @@ func TestTCPServer(t *testing.T) { if perr := parseDialError(err); perr != nil { t.Error(perr) } - if tt.taddr == "::1" && os.Getenv("GO_BUILDER_NAME") == "darwin-amd64-10_12" && os.IsTimeout(err) { - // A suspected kernel bug in macOS 10.12 occasionally results in - // "i/o timeout" errors when dialing address ::1. The errors have not - // been observed on newer versions of the OS, so we don't plan to work - // around them. See https://golang.org/issue/32919. - t.Skipf("skipping due to error on known-flaky macOS 10.12 builder: %v", err) - } t.Fatal(err) } defer c.Close() diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go index e5bd7973b70..e0c0bac8926 100644 --- a/src/runtime/crash_test.go +++ b/src/runtime/crash_test.go @@ -470,14 +470,6 @@ func TestRecoverBeforePanicAfterGoexit2(t *testing.T) { } func TestNetpollDeadlock(t *testing.T) { - if os.Getenv("GO_BUILDER_NAME") == "darwin-amd64-10_12" { - // A suspected kernel bug in macOS 10.12 occasionally results in - // an apparent deadlock when dialing localhost. The errors have not - // been observed on newer versions of the OS, so we don't plan to work - // around them. See https://golang.org/issue/22019. - testenv.SkipFlaky(t, 22019) - } - t.Parallel() output := runTestProg(t, "testprognet", "NetpollDeadlock") want := "done\n" From deb3403ff52b8833df6c4e2f82cbdddeb13573dd Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Wed, 8 Jul 2020 16:20:51 -0400 Subject: [PATCH 018/940] go/build: include files with parse errors in GoFiles and other lists go/build.ImportDir returns a *build.Package with various lists of files. If a file is invalid for some reason, for example, because it has a different package name than other files, it's added to InvalidGoFiles in addition to GoFiles, TestGoFiles, or other lists. Previously, files with parse errors or build constraint errors were not included in these lists, which causes problems for tools that use 'go list' since InvalidGoFiles is not printed. With this change, files with any kind of error are added to one of the GoFiles lists. Fixes #39986 Change-Id: Iee007b5092293eb4420c8a39ce731805fe32135f Reviewed-on: https://go-review.googlesource.com/c/go/+/241577 Trust: Jay Conrod Run-TryBot: Jay Conrod TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills --- src/cmd/go/testdata/script/list_load_err.txt | 26 ++++++++++++++++---- src/go/build/build.go | 19 ++++++++------ 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/cmd/go/testdata/script/list_load_err.txt b/src/cmd/go/testdata/script/list_load_err.txt index b3b72713e54..0cfa7fbed2f 100644 --- a/src/cmd/go/testdata/script/list_load_err.txt +++ b/src/cmd/go/testdata/script/list_load_err.txt @@ -2,26 +2,42 @@ # other files in the same package cause go/build.Import to return an error. # Verfifies golang.org/issue/38568 - go list -e -deps ./scan stdout m/want - go list -e -deps ./multi stdout m/want - go list -e -deps ./constraint stdout m/want - [cgo] go list -e -test -deps ./cgotest [cgo] stdout m/want - [cgo] go list -e -deps ./cgoflag [cgo] stdout m/want + +# go list -e should include files with errors in GoFiles, TestGoFiles, and +# other lists, assuming they match constraints. +# Verifies golang.org/issue/39986 +go list -e -f '{{range .GoFiles}}{{.}},{{end}}' ./scan +stdout '^good.go,scan.go,$' + +go list -e -f '{{range .GoFiles}}{{.}},{{end}}' ./multi +stdout '^a.go,b.go,$' + +go list -e -f '{{range .GoFiles}}{{.}},{{end}}' ./constraint +stdout '^good.go,$' +go list -e -f '{{range .IgnoredGoFiles}}{{.}},{{end}}' ./constraint +stdout '^constraint.go,$' + +[cgo] go list -e -f '{{range .XTestGoFiles}}{{.}},{{end}}' ./cgotest +[cgo] stdout '^cgo_test.go,$' + +[cgo] go list -e -f '{{range .GoFiles}}{{.}},{{end}}' ./cgoflag +[cgo] stdout '^cgoflag.go,$' + -- go.mod -- module m diff --git a/src/go/build/build.go b/src/go/build/build.go index b85fa96de1f..8afa9d52404 100644 --- a/src/go/build/build.go +++ b/src/go/build/build.go @@ -879,14 +879,17 @@ Found: if info.parseErr != nil { badFile(name, info.parseErr) - continue + // Fall through: we might still have a partial AST in info.parsed, + // and we want to list files with parse errors anyway. } - pf := info.parsed - pkg := pf.Name.Name - if pkg == "documentation" { - p.IgnoredGoFiles = append(p.IgnoredGoFiles, name) - continue + var pkg string + if info.parsed != nil { + pkg = info.parsed.Name.Name + if pkg == "documentation" { + p.IgnoredGoFiles = append(p.IgnoredGoFiles, name) + continue + } } isTest := strings.HasSuffix(name, "_test.go") @@ -910,8 +913,8 @@ Found: }) } // Grab the first package comment as docs, provided it is not from a test file. - if pf.Doc != nil && p.Doc == "" && !isTest && !isXTest { - p.Doc = doc.Synopsis(pf.Doc.Text()) + if info.parsed != nil && info.parsed.Doc != nil && p.Doc == "" && !isTest && !isXTest { + p.Doc = doc.Synopsis(info.parsed.Doc.Text()) } if mode&ImportComment != 0 { From d9e068d2894ff2fce48a171212171bc3f394b023 Mon Sep 17 00:00:00 2001 From: Lynn Boger Date: Wed, 31 Mar 2021 12:28:47 -0500 Subject: [PATCH 019/940] runtime/cgo,cmd/internal/obj/ppc64: fix signals with cgo Recently some tsan tests were enabled on ppc64le which had not been enabled before. This resulted in failures on systems with tsan available, and while debugging it was determined that there were other issues related to the use of signals with cgo. Signals were not being forwarded within programs linked against libtsan because the nocgo sigaction was being called for ppc64le with or without cgo. Adding callCgoSigaction and calling that allows signals to be registered so that signal forwarding works. For linux-ppc64 and aix-ppc64, this won't change. On linux-ppc64 there is no cgo. I can't test aix-ppc64 so those owners can enable it if they want. In reviewing comments about sigtramp in sys_linux_arm64 it was noted that a previous issue in arm64 due to missing callee save registers could also be a problem on ppc64x, so code was added to save and restore those. Also, the use of R31 as a temp register in some cases caused an issue since it is a nonvolatile register in C and was being clobbered in cases where the C code expected it to be valid. The code sequences to load these addresses were changed to avoid the use of R31 when loading such an address. To get around a vet error, the stubs_ppc64x.go file in runtime was split into stubs_ppc64.go and stubs_ppc64le.go. Updates #45040 Change-Id: Ia4ecff950613cbe1b89471790b1d3819d5b5cfb9 Reviewed-on: https://go-review.googlesource.com/c/go/+/306369 Trust: Lynn Boger Run-TryBot: Lynn Boger TryBot-Result: Go Bot Reviewed-by: Carlos Eduardo Seo --- src/cmd/asm/internal/asm/testdata/ppc64.s | 4 +- src/cmd/internal/obj/ppc64/asm9.go | 33 ++-- src/runtime/cgo/gcc_mmap.c | 2 +- src/runtime/cgo/gcc_sigaction.c | 2 +- src/runtime/cgo/sigaction.go | 8 +- src/runtime/cgo_sigaction.go | 6 +- src/runtime/sigaction.go | 4 +- src/runtime/stubs_ppc64.go | 16 ++ .../{stubs_ppc64x.go => stubs_ppc64le.go} | 3 - src/runtime/sys_linux_ppc64x.s | 176 +++++++++++++++++- 10 files changed, 223 insertions(+), 31 deletions(-) create mode 100644 src/runtime/stubs_ppc64.go rename src/runtime/{stubs_ppc64x.go => stubs_ppc64le.go} (83%) diff --git a/src/cmd/asm/internal/asm/testdata/ppc64.s b/src/cmd/asm/internal/asm/testdata/ppc64.s index 1bd4b1e1c89..b6c0aa5035c 100644 --- a/src/cmd/asm/internal/asm/testdata/ppc64.s +++ b/src/cmd/asm/internal/asm/testdata/ppc64.s @@ -41,8 +41,8 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0 MOVDBR (R3)(R4), R5 // 7ca41c28 MOVWBR (R3)(R4), R5 // 7ca41c2c MOVHBR (R3)(R4), R5 // 7ca41e2c - MOVD $foo+4009806848(FP), R5 // 3fe1ef0138bfcc20 - MOVD $foo(SB), R5 // 3fe0000038bf0000 + MOVD $foo+4009806848(FP), R5 // 3ca1ef0138a5cc20 + MOVD $foo(SB), R5 // 3ca0000038a50000 MOVDU 8(R3), R4 // e8830009 MOVDU (R3)(R4), R5 // 7ca4186a diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go index 69f967acfd4..316959f62d7 100644 --- a/src/cmd/internal/obj/ppc64/asm9.go +++ b/src/cmd/internal/obj/ppc64/asm9.go @@ -2220,7 +2220,7 @@ func (c *ctxt9) opform(insn uint32) int { // Encode instructions and create relocation for accessing s+d according to the // instruction op with source or destination (as appropriate) register reg. -func (c *ctxt9) symbolAccess(s *obj.LSym, d int64, reg int16, op uint32) (o1, o2 uint32) { +func (c *ctxt9) symbolAccess(s *obj.LSym, d int64, reg int16, op uint32, reuse bool) (o1, o2 uint32) { if c.ctxt.Headtype == objabi.Haix { // Every symbol access must be made via a TOC anchor. c.ctxt.Diag("symbolAccess called for %s", s.Name) @@ -2232,8 +2232,15 @@ func (c *ctxt9) symbolAccess(s *obj.LSym, d int64, reg int16, op uint32) (o1, o2 } else { base = REG_R0 } - o1 = AOP_IRR(OP_ADDIS, REGTMP, base, 0) - o2 = AOP_IRR(op, uint32(reg), REGTMP, 0) + // If reg can be reused when computing the symbol address, + // use it instead of REGTMP. + if !reuse { + o1 = AOP_IRR(OP_ADDIS, REGTMP, base, 0) + o2 = AOP_IRR(op, uint32(reg), REGTMP, 0) + } else { + o1 = AOP_IRR(OP_ADDIS, uint32(reg), base, 0) + o2 = AOP_IRR(op, uint32(reg), uint32(reg), 0) + } rel := obj.Addrel(c.cursym) rel.Off = int32(c.pc) rel.Siz = 8 @@ -2877,14 +2884,14 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { switch p.From.Name { case obj.NAME_EXTERN, obj.NAME_STATIC: // Load a 32 bit constant, or relocation depending on if a symbol is attached - o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, OP_ADDI) + o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, OP_ADDI, true) default: if r == 0 { r = c.getimpliedreg(&p.From, p) } // Add a 32 bit offset to a register. - o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(int32(v)))) - o2 = AOP_IRR(OP_ADDI, uint32(p.To.Reg), REGTMP, uint32(v)) + o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), uint32(r), uint32(high16adjusted(int32(v)))) + o2 = AOP_IRR(OP_ADDI, uint32(p.To.Reg), uint32(p.To.Reg), uint32(v)) } case 27: /* subc ra,$simm,rd => subfic rd,ra,$simm */ @@ -3043,10 +3050,10 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { if r == 0 { r = c.getimpliedreg(&p.From, p) } - o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(v))) - o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), REGTMP, uint32(v)) + o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), uint32(r), uint32(high16adjusted(v))) + o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), uint32(p.To.Reg), uint32(v)) - // Sign extend MOVB operations. This is ignored for other cases (o.size == 8). + // Sign extend MOVB if needed o3 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0) case 40: /* word */ @@ -3404,7 +3411,8 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { if c.opform(inst) == DS_FORM && v&0x3 != 0 { log.Fatalf("invalid offset for DS form load/store %v", p) } - o1, o2 = c.symbolAccess(p.To.Sym, v, p.From.Reg, inst) + // Can't reuse base for store instructions. + o1, o2 = c.symbolAccess(p.To.Sym, v, p.From.Reg, inst, false) case 75: // 32 bit offset symbol loads (got/toc/addr) v := p.From.Offset @@ -3432,10 +3440,11 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { rel.Type = objabi.R_ADDRPOWER_TOCREL_DS } default: - o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, inst) + reuseBaseReg := p.As != AFMOVD && p.As != AFMOVS + // Reuse To.Reg as base register if not FP move. + o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, inst, reuseBaseReg) } - // Sign extend MOVB operations. This is ignored for other cases (o.size == 8). o3 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0) case 79: diff --git a/src/runtime/cgo/gcc_mmap.c b/src/runtime/cgo/gcc_mmap.c index e6a621d5a37..698a7e3cd24 100644 --- a/src/runtime/cgo/gcc_mmap.c +++ b/src/runtime/cgo/gcc_mmap.c @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build linux,amd64 linux,arm64 +// +build linux,amd64 linux,arm64 linux,ppc64le #include #include diff --git a/src/runtime/cgo/gcc_sigaction.c b/src/runtime/cgo/gcc_sigaction.c index 890008e327d..dd283151f17 100644 --- a/src/runtime/cgo/gcc_sigaction.c +++ b/src/runtime/cgo/gcc_sigaction.c @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build linux,amd64 linux,arm64 +// +build linux,amd64 linux,arm64 linux,ppc64le #include #include diff --git a/src/runtime/cgo/sigaction.go b/src/runtime/cgo/sigaction.go index ee63ea4c09e..692fd2675f9 100644 --- a/src/runtime/cgo/sigaction.go +++ b/src/runtime/cgo/sigaction.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (linux && amd64) || (freebsd && amd64) || (linux && arm64) -// +build linux,amd64 freebsd,amd64 linux,arm64 +//go:build (linux && amd64) || (freebsd && amd64) || (linux && arm64) || (linux && ppc64le) +// +build linux,amd64 freebsd,amd64 linux,arm64 linux,ppc64le package cgo @@ -11,8 +11,8 @@ package cgo import _ "unsafe" // When using cgo, call the C library for sigaction, so that we call into -// any sanitizer interceptors. This supports using the memory -// sanitizer with Go programs. The memory sanitizer only applies to +// any sanitizer interceptors. This supports using the sanitizers +// with Go programs. The thread and memory sanitizers only apply to // C/C++ code; this permits that code to see the Go runtime's existing signal // handlers when registering new signal handlers for the process. diff --git a/src/runtime/cgo_sigaction.go b/src/runtime/cgo_sigaction.go index 15690ecb0bf..6099d1b746f 100644 --- a/src/runtime/cgo_sigaction.go +++ b/src/runtime/cgo_sigaction.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Support for memory sanitizer. See runtime/cgo/sigaction.go. +// Support for sanitizers. See runtime/cgo/sigaction.go. -//go:build (linux && amd64) || (freebsd && amd64) || (linux && arm64) -// +build linux,amd64 freebsd,amd64 linux,arm64 +//go:build (linux && amd64) || (freebsd && amd64) || (linux && arm64) || (linux && ppc64le) +// +build linux,amd64 freebsd,amd64 linux,arm64 linux,ppc64le package runtime diff --git a/src/runtime/sigaction.go b/src/runtime/sigaction.go index 76f37b1b535..30050efcc78 100644 --- a/src/runtime/sigaction.go +++ b/src/runtime/sigaction.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (linux && !amd64 && !arm64) || (freebsd && !amd64) -// +build linux,!amd64,!arm64 freebsd,!amd64 +//go:build (linux && !amd64 && !arm64 && !ppc64le) || (freebsd && !amd64) +// +build linux,!amd64,!arm64,!ppc64le freebsd,!amd64 package runtime diff --git a/src/runtime/stubs_ppc64.go b/src/runtime/stubs_ppc64.go new file mode 100644 index 00000000000..f692947109a --- /dev/null +++ b/src/runtime/stubs_ppc64.go @@ -0,0 +1,16 @@ +// Copyright 2021 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 linux +// +build linux + +package runtime + +// Called from assembly only; declared for go vet. +func load_g() +func save_g() +func reginit() + +//go:noescape +func callCgoSigaction(sig uintptr, new, old *sigactiont) int32 diff --git a/src/runtime/stubs_ppc64x.go b/src/runtime/stubs_ppc64le.go similarity index 83% rename from src/runtime/stubs_ppc64x.go rename to src/runtime/stubs_ppc64le.go index 0841b413fdb..5b733136e3b 100644 --- a/src/runtime/stubs_ppc64x.go +++ b/src/runtime/stubs_ppc64le.go @@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build ppc64 || ppc64le -// +build ppc64 ppc64le - package runtime // Called from assembly only; declared for go vet. diff --git a/src/runtime/sys_linux_ppc64x.s b/src/runtime/sys_linux_ppc64x.s index 75da130357a..46387288d53 100644 --- a/src/runtime/sys_linux_ppc64x.s +++ b/src/runtime/sys_linux_ppc64x.s @@ -336,6 +336,26 @@ TEXT runtime·rt_sigaction(SB),NOSPLIT|NOFRAME,$0-36 MOVW R3, ret+32(FP) RET +#ifdef GOARCH_ppc64le +// Call the function stored in _cgo_sigaction using the GCC calling convention. +TEXT runtime·callCgoSigaction(SB),NOSPLIT,$0 + MOVD sig+0(FP), R3 + MOVD new+8(FP), R4 + MOVD old+16(FP), R5 + MOVD _cgo_sigaction(SB), R12 + MOVD R12, CTR // R12 should contain the function address + MOVD R1, R15 // Save R1 + MOVD R2, 24(R1) // Save R2 + SUB $48, R1 // reserve 32 (frame) + 16 bytes for sp-8 where fp may be saved. + RLDICR $0, R1, $59, R1 // Align to 16 bytes for C code + BL (CTR) + XOR R0, R0, R0 // Clear R0 as Go expects + MOVD R15, R1 // Restore R1 + MOVD 24(R1), R2 // Restore R2 + MOVW R3, ret+24(FP) // Return result + RET +#endif + TEXT runtime·sigfwd(SB),NOSPLIT,$0-32 MOVW sig+8(FP), R3 MOVD info+16(FP), R4 @@ -351,15 +371,97 @@ TEXT runtime·sigreturn(SB),NOSPLIT,$0-0 #ifdef GOARCH_ppc64le // ppc64le doesn't need function descriptors -TEXT runtime·sigtramp(SB),NOSPLIT,$64 +// Save callee-save registers in the case of signal forwarding. +// Same as on ARM64 https://golang.org/issue/31827 . +TEXT runtime·sigtramp(SB),NOSPLIT|NOFRAME,$0 #else // function descriptor for the real sigtramp TEXT runtime·sigtramp(SB),NOSPLIT|NOFRAME,$0 DWORD $sigtramp<>(SB) DWORD $0 DWORD $0 -TEXT sigtramp<>(SB),NOSPLIT,$64 +TEXT sigtramp<>(SB),NOSPLIT|NOFRAME,$0 #endif + // Start with standard C stack frame layout and linkage. + MOVD LR, R0 + MOVD R0, 16(R1) // Save LR in caller's frame. + MOVW CR, R0 // Save CR in caller's frame + MOVD R0, 8(R1) + // The stack must be acquired here and not + // in the automatic way based on stack size + // since that sequence clobbers R31 before it + // gets saved. + // We are being ultra safe here in saving the + // Vregs. The case where they might need to + // be saved is very unlikely. + MOVDU R1, -544(R1) + MOVD R14, 64(R1) + MOVD R15, 72(R1) + MOVD R16, 80(R1) + MOVD R17, 88(R1) + MOVD R18, 96(R1) + MOVD R19, 104(R1) + MOVD R20, 112(R1) + MOVD R21, 120(R1) + MOVD R22, 128(R1) + MOVD R23, 136(R1) + MOVD R24, 144(R1) + MOVD R25, 152(R1) + MOVD R26, 160(R1) + MOVD R27, 168(R1) + MOVD R28, 176(R1) + MOVD R29, 184(R1) + MOVD g, 192(R1) // R30 + MOVD R31, 200(R1) + FMOVD F14, 208(R1) + FMOVD F15, 216(R1) + FMOVD F16, 224(R1) + FMOVD F17, 232(R1) + FMOVD F18, 240(R1) + FMOVD F19, 248(R1) + FMOVD F20, 256(R1) + FMOVD F21, 264(R1) + FMOVD F22, 272(R1) + FMOVD F23, 280(R1) + FMOVD F24, 288(R1) + FMOVD F25, 296(R1) + FMOVD F26, 304(R1) + FMOVD F27, 312(R1) + FMOVD F28, 320(R1) + FMOVD F29, 328(R1) + FMOVD F30, 336(R1) + FMOVD F31, 344(R1) + // Save V regs + // STXVD2X and LXVD2X used since + // we aren't sure of alignment. + // Endianness doesn't matter + // if we are just loading and + // storing values. + MOVD $352, R7 // V20 + STXVD2X VS52, (R7)(R1) + ADD $16, R7 // V21 368 + STXVD2X VS53, (R7)(R1) + ADD $16, R7 // V22 384 + STXVD2X VS54, (R7)(R1) + ADD $16, R7 // V23 400 + STXVD2X VS55, (R7)(R1) + ADD $16, R7 // V24 416 + STXVD2X VS56, (R7)(R1) + ADD $16, R7 // V25 432 + STXVD2X VS57, (R7)(R1) + ADD $16, R7 // V26 448 + STXVD2X VS58, (R7)(R1) + ADD $16, R7 // V27 464 + STXVD2X VS59, (R7)(R1) + ADD $16, R7 // V28 480 + STXVD2X VS60, (R7)(R1) + ADD $16, R7 // V29 496 + STXVD2X VS61, (R7)(R1) + ADD $16, R7 // V30 512 + STXVD2X VS62, (R7)(R1) + ADD $16, R7 // V31 528 + STXVD2X VS63, (R7)(R1) + // initialize essential registers (just in case) BL runtime·reginit(SB) @@ -376,7 +478,74 @@ TEXT sigtramp<>(SB),NOSPLIT,$64 MOVD $runtime·sigtrampgo(SB), R12 MOVD R12, CTR BL (CTR) - MOVD 24(R1), R2 + MOVD 24(R1), R2 // Should this be here? Where is it saved? + // Starts at 64; FIXED_FRAME is 32 + MOVD 64(R1), R14 + MOVD 72(R1), R15 + MOVD 80(R1), R16 + MOVD 88(R1), R17 + MOVD 96(R1), R18 + MOVD 104(R1), R19 + MOVD 112(R1), R20 + MOVD 120(R1), R21 + MOVD 128(R1), R22 + MOVD 136(R1), R23 + MOVD 144(R1), R24 + MOVD 152(R1), R25 + MOVD 160(R1), R26 + MOVD 168(R1), R27 + MOVD 176(R1), R28 + MOVD 184(R1), R29 + MOVD 192(R1), g // R30 + MOVD 200(R1), R31 + FMOVD 208(R1), F14 + FMOVD 216(R1), F15 + FMOVD 224(R1), F16 + FMOVD 232(R1), F17 + FMOVD 240(R1), F18 + FMOVD 248(R1), F19 + FMOVD 256(R1), F20 + FMOVD 264(R1), F21 + FMOVD 272(R1), F22 + FMOVD 280(R1), F23 + FMOVD 288(R1), F24 + FMOVD 292(R1), F25 + FMOVD 300(R1), F26 + FMOVD 308(R1), F27 + FMOVD 316(R1), F28 + FMOVD 328(R1), F29 + FMOVD 336(R1), F30 + FMOVD 344(R1), F31 + MOVD $352, R7 + LXVD2X (R7)(R1), VS52 + ADD $16, R7 // 368 V21 + LXVD2X (R7)(R1), VS53 + ADD $16, R7 // 384 V22 + LXVD2X (R7)(R1), VS54 + ADD $16, R7 // 400 V23 + LXVD2X (R7)(R1), VS55 + ADD $16, R7 // 416 V24 + LXVD2X (R7)(R1), VS56 + ADD $16, R7 // 432 V25 + LXVD2X (R7)(R1), VS57 + ADD $16, R7 // 448 V26 + LXVD2X (R7)(R1), VS58 + ADD $16, R8 // 464 V27 + LXVD2X (R7)(R1), VS59 + ADD $16, R7 // 480 V28 + LXVD2X (R7)(R1), VS60 + ADD $16, R7 // 496 V29 + LXVD2X (R7)(R1), VS61 + ADD $16, R7 // 512 V30 + LXVD2X (R7)(R1), VS62 + ADD $16, R7 // 528 V31 + LXVD2X (R7)(R1), VS63 + ADD $544, R1 + MOVD 8(R1), R0 + MOVFL R0, $0xff + MOVD 16(R1), R0 + MOVD R0, LR + RET #ifdef GOARCH_ppc64le @@ -406,6 +575,7 @@ TEXT runtime·cgoSigtramp(SB),NOSPLIT|NOFRAME,$0 // Figure out if we are currently in a cgo call. // If not, just do usual sigtramp. + // compared to ARM64 and others. CMP $0, g BEQ sigtrampnog // g == nil MOVD g_m(g), R6 From 73d5aef4d19486d5eb03730791bd21f47c6c7d2b Mon Sep 17 00:00:00 2001 From: Tao Qingyun Date: Sat, 12 Dec 2020 09:45:45 +0000 Subject: [PATCH 020/940] cmd/internal/objfile: add objabi.SNOPTRDATA to "D" Change-Id: I65913534a4a3e2cbc0d4b00454dd3092eb908cb5 GitHub-Last-Rev: 39dc0d21b81eb6aeec4c29d4ea72e6c1ef7fea0d GitHub-Pull-Request: golang/go#43151 Reviewed-on: https://go-review.googlesource.com/c/go/+/277452 Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Cherry Mui Trust: Heschi Kreinick --- src/cmd/internal/objfile/goobj.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/internal/objfile/goobj.go b/src/cmd/internal/objfile/goobj.go index f19bec5dcb2..dd21d223511 100644 --- a/src/cmd/internal/objfile/goobj.go +++ b/src/cmd/internal/objfile/goobj.go @@ -168,7 +168,7 @@ func (f *goobjFile) symbols() ([]Sym, error) { code = 'T' case objabi.SRODATA: code = 'R' - case objabi.SDATA: + case objabi.SNOPTRDATA, objabi.SDATA: code = 'D' case objabi.SBSS, objabi.SNOPTRBSS, objabi.STLSBSS: code = 'B' From dc50683bf7ebdfde726d710131ba05fe97e10a07 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Wed, 13 May 2020 18:24:16 -0700 Subject: [PATCH 021/940] crypto/elliptic: upgrade from generic curve impl to specific if available This change alters the CurveParam methods to upgrade from the generic curve implementation to the specific P224 or P256 implementations when called on the embedded CurveParams. This removes the trap of using elliptic.P224().Params() instead of elliptic.P224(), for example, which results in using the generic implementation instead of the optimized constant time one. For P224 this is done for all of the CurveParams methods, except Params, as the optimized implementation covers all these methods. For P256 this is only done for ScalarMult and ScalarBaseMult, as despite having implementations of addition and doubling they aren't exposed and instead the generic implementation is used. For P256 an additional check that there actually is a specific implementation is added, as unlike the P224 implementation the P256 one is only available on certain platforms. This change takes the simple, fast approach to checking this, it simply compares pointers. This removes the most obvious class of mistakes people make, but still allows edge cases where the embedded CurveParams pointer has been dereferenced (as seen in the unit tests) or when someone has manually constructed their own CurveParams that matches one of the standard curves. A more complex approach could be taken to also address these cases, but it would require directly comparing all of the CurveParam fields which would, in the worst case, require comparing against two standard CurveParam sets in the ScalarMult and ScalarBaseMult paths, which are likely to be the hottest already. Updates #34648 Change-Id: I82d752f979260394632905c15ffe4f65f4ffa376 Reviewed-on: https://go-review.googlesource.com/c/go/+/233939 Trust: Roland Shoemaker Trust: Katie Hockman Run-TryBot: Roland Shoemaker TryBot-Result: Go Bot Reviewed-by: Filippo Valsorda Reviewed-by: Katie Hockman --- src/crypto/elliptic/elliptic.go | 39 ++++++++++++++++++++++++++++ src/crypto/elliptic/elliptic_test.go | 18 ++++++++++--- src/crypto/elliptic/p256_asm.go | 4 +-- src/crypto/elliptic/p256_generic.go | 4 +-- 4 files changed, 55 insertions(+), 10 deletions(-) diff --git a/src/crypto/elliptic/elliptic.go b/src/crypto/elliptic/elliptic.go index 85d105419b4..b8e5a3097d2 100644 --- a/src/crypto/elliptic/elliptic.go +++ b/src/crypto/elliptic/elliptic.go @@ -40,6 +40,15 @@ type Curve interface { ScalarBaseMult(k []byte) (x, y *big.Int) } +func matchesSpecificCurve(params *CurveParams, available ...Curve) (Curve, bool) { + for _, c := range available { + if params == c.Params() { + return c, true + } + } + return nil, false +} + // CurveParams contains the parameters of an elliptic curve and also provides // a generic, non-constant time implementation of Curve. type CurveParams struct { @@ -71,6 +80,12 @@ func (curve *CurveParams) polynomial(x *big.Int) *big.Int { } func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool { + // If there is a dedicated constant-time implementation for this curve operation, + // use that instead of the generic one. + if specific, ok := matchesSpecificCurve(curve, p224, p521); ok { + return specific.IsOnCurve(x, y) + } + // y² = x³ - 3x + b y2 := new(big.Int).Mul(y, y) y2.Mod(y2, curve.P) @@ -108,6 +123,12 @@ func (curve *CurveParams) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big. } func (curve *CurveParams) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { + // If there is a dedicated constant-time implementation for this curve operation, + // use that instead of the generic one. + if specific, ok := matchesSpecificCurve(curve, p224, p521); ok { + return specific.Add(x1, y1, x2, y2) + } + z1 := zForAffine(x1, y1) z2 := zForAffine(x2, y2) return curve.affineFromJacobian(curve.addJacobian(x1, y1, z1, x2, y2, z2)) @@ -192,6 +213,12 @@ func (curve *CurveParams) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int } func (curve *CurveParams) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { + // If there is a dedicated constant-time implementation for this curve operation, + // use that instead of the generic one. + if specific, ok := matchesSpecificCurve(curve, p224, p521); ok { + return specific.Double(x1, y1) + } + z1 := zForAffine(x1, y1) return curve.affineFromJacobian(curve.doubleJacobian(x1, y1, z1)) } @@ -258,6 +285,12 @@ func (curve *CurveParams) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, } func (curve *CurveParams) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) { + // If there is a dedicated constant-time implementation for this curve operation, + // use that instead of the generic one. + if specific, ok := matchesSpecificCurve(curve, p224, p256, p521); ok { + return specific.ScalarMult(Bx, By, k) + } + Bz := new(big.Int).SetInt64(1) x, y, z := new(big.Int), new(big.Int), new(big.Int) @@ -275,6 +308,12 @@ func (curve *CurveParams) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big. } func (curve *CurveParams) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { + // If there is a dedicated constant-time implementation for this curve operation, + // use that instead of the generic one. + if specific, ok := matchesSpecificCurve(curve, p224, p256, p521); ok { + return specific.ScalarBaseMult(k) + } + return curve.ScalarMult(curve.Gx, curve.Gy, k) } diff --git a/src/crypto/elliptic/elliptic_test.go b/src/crypto/elliptic/elliptic_test.go index 0d43b736f9a..183861a54b5 100644 --- a/src/crypto/elliptic/elliptic_test.go +++ b/src/crypto/elliptic/elliptic_test.go @@ -12,19 +12,29 @@ import ( "testing" ) +// genericParamsForCurve returns the dereferenced CurveParams for +// the specified curve. This is used to avoid the logic for +// upgrading a curve to it's specific implementation, forcing +// usage of the generic implementation. This is only relevant +// for the P224, P256, and P521 curves. +func genericParamsForCurve(c Curve) *CurveParams { + d := *(c.Params()) + return &d +} + func testAllCurves(t *testing.T, f func(*testing.T, Curve)) { tests := []struct { name string curve Curve }{ {"P256", P256()}, - {"P256/Params", P256().Params()}, + {"P256/Params", genericParamsForCurve(P256())}, {"P224", P224()}, - {"P224/Params", P224().Params()}, + {"P224/Params", genericParamsForCurve(P224())}, {"P384", P384()}, - {"P384/Params", P384().Params()}, + {"P384/Params", genericParamsForCurve(P384())}, {"P521", P521()}, - {"P521/Params", P521().Params()}, + {"P521/Params", genericParamsForCurve(P521())}, } if testing.Short() { tests = tests[:1] diff --git a/src/crypto/elliptic/p256_asm.go b/src/crypto/elliptic/p256_asm.go index 08dbd2ea548..9a808f260ac 100644 --- a/src/crypto/elliptic/p256_asm.go +++ b/src/crypto/elliptic/p256_asm.go @@ -29,9 +29,7 @@ type ( } ) -var ( - p256 p256Curve -) +var p256 p256Curve func initP256() { // See FIPS 186-3, section D.2.3 diff --git a/src/crypto/elliptic/p256_generic.go b/src/crypto/elliptic/p256_generic.go index 8ad56638e95..25762a8f768 100644 --- a/src/crypto/elliptic/p256_generic.go +++ b/src/crypto/elliptic/p256_generic.go @@ -7,9 +7,7 @@ package elliptic -var ( - p256 p256Curve -) +var p256 p256Curve func initP256Arch() { // Use pure Go implementation. From 5c489514bc5e61ad9b5b07bd7d8ec65d66a0512a Mon Sep 17 00:00:00 2001 From: Roberto Clapis Date: Wed, 7 Apr 2021 14:36:40 +0200 Subject: [PATCH 022/940] net/http: switch HTTP1 to ASCII equivalents of string functions The current implementation uses UTF-aware functions like strings.EqualFold and strings.ToLower. This could, in some cases, cause http smuggling. Change-Id: I0e76a993470a1e1b1b472f4b2859ea0a2b22ada0 Reviewed-on: https://go-review.googlesource.com/c/go/+/308009 Run-TryBot: Filippo Valsorda TryBot-Result: Go Bot Trust: Roberto Clapis Reviewed-by: Filippo Valsorda --- src/go/build/deps_test.go | 5 +- src/net/http/client.go | 6 +- src/net/http/cookie.go | 13 ++- src/net/http/cookiejar/jar.go | 17 +++- src/net/http/cookiejar/punycode.go | 14 +--- src/net/http/header.go | 3 +- src/net/http/http.go | 9 -- src/net/http/httputil/reverseproxy.go | 12 ++- src/net/http/httputil/reverseproxy_test.go | 5 +- src/net/http/internal/ascii/print.go | 61 ++++++++++++++ src/net/http/internal/ascii/print_test.go | 95 ++++++++++++++++++++++ src/net/http/request.go | 7 +- src/net/http/transfer.go | 3 +- src/net/http/transport.go | 3 +- 14 files changed, 215 insertions(+), 38 deletions(-) create mode 100644 src/net/http/internal/ascii/print.go create mode 100644 src/net/http/internal/ascii/print_test.go diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 3a0e769284d..5d1cf7f4c97 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -440,7 +440,7 @@ var depsRules = ` # HTTP, King of Dependencies. FMT - < golang.org/x/net/http2/hpack, net/http/internal; + < golang.org/x/net/http2/hpack, net/http/internal, net/http/internal/ascii; FMT, NET, container/list, encoding/binary, log < golang.org/x/text/transform @@ -458,6 +458,7 @@ var depsRules = ` golang.org/x/net/http/httpproxy, golang.org/x/net/http2/hpack, net/http/internal, + net/http/internal/ascii, net/http/httptrace, mime/multipart, log @@ -468,7 +469,7 @@ var depsRules = ` encoding/json, net/http < expvar; - net/http + net/http, net/http/internal/ascii < net/http/cookiejar, net/http/httputil; net/http, flag diff --git a/src/net/http/client.go b/src/net/http/client.go index 82e665829e9..03c9155fbdd 100644 --- a/src/net/http/client.go +++ b/src/net/http/client.go @@ -17,6 +17,7 @@ import ( "fmt" "io" "log" + "net/http/internal/ascii" "net/url" "reflect" "sort" @@ -547,7 +548,10 @@ func urlErrorOp(method string) string { if method == "" { return "Get" } - return method[:1] + strings.ToLower(method[1:]) + if lowerMethod, ok := ascii.ToLower(method); ok { + return method[:1] + lowerMethod[1:] + } + return method } // Do sends an HTTP request and returns an HTTP response, following diff --git a/src/net/http/cookie.go b/src/net/http/cookie.go index 141bc947f6e..ca2c1c25066 100644 --- a/src/net/http/cookie.go +++ b/src/net/http/cookie.go @@ -7,6 +7,7 @@ package http import ( "log" "net" + "net/http/internal/ascii" "net/textproto" "strconv" "strings" @@ -93,15 +94,23 @@ func readSetCookies(h Header) []*Cookie { if j := strings.Index(attr, "="); j >= 0 { attr, val = attr[:j], attr[j+1:] } - lowerAttr := strings.ToLower(attr) + lowerAttr, isASCII := ascii.ToLower(attr) + if !isASCII { + continue + } val, ok = parseCookieValue(val, false) if !ok { c.Unparsed = append(c.Unparsed, parts[i]) continue } + switch lowerAttr { case "samesite": - lowerVal := strings.ToLower(val) + lowerVal, ascii := ascii.ToLower(val) + if !ascii { + c.SameSite = SameSiteDefaultMode + continue + } switch lowerVal { case "lax": c.SameSite = SameSiteLaxMode diff --git a/src/net/http/cookiejar/jar.go b/src/net/http/cookiejar/jar.go index 9f199170847..e6583da7fe6 100644 --- a/src/net/http/cookiejar/jar.go +++ b/src/net/http/cookiejar/jar.go @@ -10,6 +10,7 @@ import ( "fmt" "net" "net/http" + "net/http/internal/ascii" "net/url" "sort" "strings" @@ -296,7 +297,6 @@ func (j *Jar) setCookies(u *url.URL, cookies []*http.Cookie, now time.Time) { // host name. func canonicalHost(host string) (string, error) { var err error - host = strings.ToLower(host) if hasPort(host) { host, _, err = net.SplitHostPort(host) if err != nil { @@ -307,7 +307,13 @@ func canonicalHost(host string) (string, error) { // Strip trailing dot from fully qualified domain names. host = host[:len(host)-1] } - return toASCII(host) + encoded, err := toASCII(host) + if err != nil { + return "", err + } + // We know this is ascii, no need to check. + lower, _ := ascii.ToLower(encoded) + return lower, nil } // hasPort reports whether host contains a port number. host may be a host @@ -469,7 +475,12 @@ func (j *Jar) domainAndType(host, domain string) (string, bool, error) { // both are illegal. return "", false, errMalformedDomain } - domain = strings.ToLower(domain) + + domain, isASCII := ascii.ToLower(domain) + if !isASCII { + // Received non-ASCII domain, e.g. "perché.com" instead of "xn--perch-fsa.com" + return "", false, errMalformedDomain + } if domain[len(domain)-1] == '.' { // We received stuff like "Domain=www.example.com.". diff --git a/src/net/http/cookiejar/punycode.go b/src/net/http/cookiejar/punycode.go index a9cc666e8c9..c7f438dd007 100644 --- a/src/net/http/cookiejar/punycode.go +++ b/src/net/http/cookiejar/punycode.go @@ -8,6 +8,7 @@ package cookiejar import ( "fmt" + "net/http/internal/ascii" "strings" "unicode/utf8" ) @@ -133,12 +134,12 @@ const acePrefix = "xn--" // toASCII("bücher.example.com") is "xn--bcher-kva.example.com", and // toASCII("golang") is "golang". func toASCII(s string) (string, error) { - if ascii(s) { + if ascii.Is(s) { return s, nil } labels := strings.Split(s, ".") for i, label := range labels { - if !ascii(label) { + if !ascii.Is(label) { a, err := encode(acePrefix, label) if err != nil { return "", err @@ -148,12 +149,3 @@ func toASCII(s string) (string, error) { } return strings.Join(labels, "."), nil } - -func ascii(s string) bool { - for i := 0; i < len(s); i++ { - if s[i] >= utf8.RuneSelf { - return false - } - } - return true -} diff --git a/src/net/http/header.go b/src/net/http/header.go index b9b53911f38..4c72dcb2c88 100644 --- a/src/net/http/header.go +++ b/src/net/http/header.go @@ -7,6 +7,7 @@ package http import ( "io" "net/http/httptrace" + "net/http/internal/ascii" "net/textproto" "sort" "strings" @@ -251,7 +252,7 @@ func hasToken(v, token string) bool { if endPos := sp + len(token); endPos != len(v) && !isTokenBoundary(v[endPos]) { continue } - if strings.EqualFold(v[sp:sp+len(token)], token) { + if ascii.EqualFold(v[sp:sp+len(token)], token) { return true } } diff --git a/src/net/http/http.go b/src/net/http/http.go index 4c5054b3994..101799f574f 100644 --- a/src/net/http/http.go +++ b/src/net/http/http.go @@ -62,15 +62,6 @@ func isNotToken(r rune) bool { return !httpguts.IsTokenRune(r) } -func isASCII(s string) bool { - for i := 0; i < len(s); i++ { - if s[i] >= utf8.RuneSelf { - return false - } - } - return true -} - // stringContainsCTLByte reports whether s contains any ASCII control character. func stringContainsCTLByte(s string) bool { for i := 0; i < len(s); i++ { diff --git a/src/net/http/httputil/reverseproxy.go b/src/net/http/httputil/reverseproxy.go index db42ac6ba55..1432ee26d37 100644 --- a/src/net/http/httputil/reverseproxy.go +++ b/src/net/http/httputil/reverseproxy.go @@ -13,6 +13,7 @@ import ( "log" "net" "net/http" + "net/http/internal/ascii" "net/textproto" "net/url" "strings" @@ -242,6 +243,10 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { outreq.Close = false reqUpType := upgradeType(outreq.Header) + if !ascii.IsPrint(reqUpType) { + p.getErrorHandler()(rw, req, fmt.Errorf("client tried to switch to invalid protocol %q", reqUpType)) + return + } removeConnectionHeaders(outreq.Header) // Remove hop-by-hop headers to the backend. Especially @@ -538,13 +543,16 @@ func upgradeType(h http.Header) string { if !httpguts.HeaderValuesContainsToken(h["Connection"], "Upgrade") { return "" } - return strings.ToLower(h.Get("Upgrade")) + return h.Get("Upgrade") } func (p *ReverseProxy) handleUpgradeResponse(rw http.ResponseWriter, req *http.Request, res *http.Response) { reqUpType := upgradeType(req.Header) resUpType := upgradeType(res.Header) - if reqUpType != resUpType { + if !ascii.IsPrint(resUpType) { // We know reqUpType is ASCII, it's checked by the caller. + p.getErrorHandler()(rw, req, fmt.Errorf("backend tried to switch to invalid protocol %q", resUpType)) + } + if !ascii.EqualFold(reqUpType, resUpType) { p.getErrorHandler()(rw, req, fmt.Errorf("backend tried to switch protocol %q when %q was requested", resUpType, reqUpType)) return } diff --git a/src/net/http/httputil/reverseproxy_test.go b/src/net/http/httputil/reverseproxy_test.go index 3acbd940e4b..b89eb90ad64 100644 --- a/src/net/http/httputil/reverseproxy_test.go +++ b/src/net/http/httputil/reverseproxy_test.go @@ -16,6 +16,7 @@ import ( "log" "net/http" "net/http/httptest" + "net/http/internal/ascii" "net/url" "os" "reflect" @@ -1183,7 +1184,7 @@ func TestReverseProxyWebSocket(t *testing.T) { t.Errorf("Header(XHeader) = %q; want %q", got, want) } - if upgradeType(res.Header) != "websocket" { + if !ascii.EqualFold(upgradeType(res.Header), "websocket") { t.Fatalf("not websocket upgrade; got %#v", res.Header) } rwc, ok := res.Body.(io.ReadWriteCloser) @@ -1300,7 +1301,7 @@ func TestReverseProxyWebSocketCancelation(t *testing.T) { t.Errorf("X-Header mismatch\n\tgot: %q\n\twant: %q", g, w) } - if g, w := upgradeType(res.Header), "websocket"; g != w { + if g, w := upgradeType(res.Header), "websocket"; !ascii.EqualFold(g, w) { t.Fatalf("Upgrade header mismatch\n\tgot: %q\n\twant: %q", g, w) } diff --git a/src/net/http/internal/ascii/print.go b/src/net/http/internal/ascii/print.go new file mode 100644 index 00000000000..585e5baba40 --- /dev/null +++ b/src/net/http/internal/ascii/print.go @@ -0,0 +1,61 @@ +// Copyright 2021 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 ascii + +import ( + "strings" + "unicode" +) + +// EqualFold is strings.EqualFold, ASCII only. It reports whether s and t +// are equal, ASCII-case-insensitively. +func EqualFold(s, t string) bool { + if len(s) != len(t) { + return false + } + for i := 0; i < len(s); i++ { + if lower(s[i]) != lower(t[i]) { + return false + } + } + return true +} + +// lower returns the ASCII lowercase version of b. +func lower(b byte) byte { + if 'A' <= b && b <= 'Z' { + return b + ('a' - 'A') + } + return b +} + +// IsPrint returns whether s is ASCII and printable according to +// https://tools.ietf.org/html/rfc20#section-4.2. +func IsPrint(s string) bool { + for i := 0; i < len(s); i++ { + if s[i] < ' ' || s[i] > '~' { + return false + } + } + return true +} + +// Is returns whether s is ASCII. +func Is(s string) bool { + for i := 0; i < len(s); i++ { + if s[i] > unicode.MaxASCII { + return false + } + } + return true +} + +// ToLower returns the lowercase version of s if s is ASCII and printable. +func ToLower(s string) (lower string, ok bool) { + if !IsPrint(s) { + return "", false + } + return strings.ToLower(s), true +} diff --git a/src/net/http/internal/ascii/print_test.go b/src/net/http/internal/ascii/print_test.go new file mode 100644 index 00000000000..0b7767ca331 --- /dev/null +++ b/src/net/http/internal/ascii/print_test.go @@ -0,0 +1,95 @@ +// Copyright 2021 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 ascii + +import "testing" + +func TestEqualFold(t *testing.T) { + var tests = []struct { + name string + a, b string + want bool + }{ + { + name: "empty", + want: true, + }, + { + name: "simple match", + a: "CHUNKED", + b: "chunked", + want: true, + }, + { + name: "same string", + a: "chunked", + b: "chunked", + want: true, + }, + { + name: "Unicode Kelvin symbol", + a: "chunKed", // This "K" is 'KELVIN SIGN' (\u212A) + b: "chunked", + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := EqualFold(tt.a, tt.b); got != tt.want { + t.Errorf("AsciiEqualFold(%q,%q): got %v want %v", tt.a, tt.b, got, tt.want) + } + }) + } +} + +func TestIsPrint(t *testing.T) { + var tests = []struct { + name string + in string + want bool + }{ + { + name: "empty", + want: true, + }, + { + name: "ASCII low", + in: "This is a space: ' '", + want: true, + }, + { + name: "ASCII high", + in: "This is a tilde: '~'", + want: true, + }, + { + name: "ASCII low non-print", + in: "This is a unit separator: \x1F", + want: false, + }, + { + name: "Ascii high non-print", + in: "This is a Delete: \x7F", + want: false, + }, + { + name: "Unicode letter", + in: "Today it's 280K outside: it's freezing!", // This "K" is 'KELVIN SIGN' (\u212A) + want: false, + }, + { + name: "Unicode emoji", + in: "Gophers like 🧀", + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := IsPrint(tt.in); got != tt.want { + t.Errorf("IsASCIIPrint(%q): got %v want %v", tt.in, got, tt.want) + } + }) + } +} diff --git a/src/net/http/request.go b/src/net/http/request.go index 4a07eb1c798..7895417af50 100644 --- a/src/net/http/request.go +++ b/src/net/http/request.go @@ -19,6 +19,7 @@ import ( "mime/multipart" "net" "net/http/httptrace" + "net/http/internal/ascii" "net/textproto" "net/url" urlpkg "net/url" @@ -723,7 +724,7 @@ func idnaASCII(v string) (string, error) { // version does not. // Note that for correct ASCII IDNs ToASCII will only do considerably more // work, but it will not cause an allocation. - if isASCII(v) { + if ascii.Is(v) { return v, nil } return idna.Lookup.ToASCII(v) @@ -948,7 +949,7 @@ func (r *Request) BasicAuth() (username, password string, ok bool) { func parseBasicAuth(auth string) (username, password string, ok bool) { const prefix = "Basic " // Case insensitive prefix match. See Issue 22736. - if len(auth) < len(prefix) || !strings.EqualFold(auth[:len(prefix)], prefix) { + if len(auth) < len(prefix) || !ascii.EqualFold(auth[:len(prefix)], prefix) { return } c, err := base64.StdEncoding.DecodeString(auth[len(prefix):]) @@ -1456,5 +1457,5 @@ func requestMethodUsuallyLacksBody(method string) bool { // an HTTP/1 connection. func (r *Request) requiresHTTP1() bool { return hasToken(r.Header.Get("Connection"), "upgrade") && - strings.EqualFold(r.Header.Get("Upgrade"), "websocket") + ascii.EqualFold(r.Header.Get("Upgrade"), "websocket") } diff --git a/src/net/http/transfer.go b/src/net/http/transfer.go index fbb0c39829d..85c2e5a360d 100644 --- a/src/net/http/transfer.go +++ b/src/net/http/transfer.go @@ -12,6 +12,7 @@ import ( "io" "net/http/httptrace" "net/http/internal" + "net/http/internal/ascii" "net/textproto" "reflect" "sort" @@ -638,7 +639,7 @@ func (t *transferReader) parseTransferEncoding() error { if len(raw) != 1 { return &unsupportedTEError{fmt.Sprintf("too many transfer encodings: %q", raw)} } - if strings.ToLower(textproto.TrimString(raw[0])) != "chunked" { + if !ascii.EqualFold(textproto.TrimString(raw[0]), "chunked") { return &unsupportedTEError{fmt.Sprintf("unsupported transfer encoding: %q", raw[0])} } diff --git a/src/net/http/transport.go b/src/net/http/transport.go index 57018d23924..47cb992a502 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -21,6 +21,7 @@ import ( "log" "net" "net/http/httptrace" + "net/http/internal/ascii" "net/textproto" "net/url" "os" @@ -2185,7 +2186,7 @@ func (pc *persistConn) readLoop() { } resp.Body = body - if rc.addedGzip && strings.EqualFold(resp.Header.Get("Content-Encoding"), "gzip") { + if rc.addedGzip && ascii.EqualFold(resp.Header.Get("Content-Encoding"), "gzip") { resp.Body = &gzipReader{body: body} resp.Header.Del("Content-Encoding") resp.Header.Del("Content-Length") From 326a7925179ea669aa9f947dda82e425673cb220 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Mon, 10 May 2021 03:16:28 +1000 Subject: [PATCH 023/940] runtime,syscall: simplify openbsd related build tags openbsd/mips64 is now the only openbsd port that uses non-libc syscall - revise build tags to reflect this. Update #36435 Change-Id: I357b2dd2926d058e25e618fcca42c388587598a8 Reviewed-on: https://go-review.googlesource.com/c/go/+/317919 Trust: Joel Sing Reviewed-by: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot --- src/runtime/os_openbsd_libc.go | 4 ++-- src/runtime/os_openbsd_syscall.go | 4 ++-- src/runtime/os_openbsd_syscall1.go | 4 ++-- src/runtime/os_openbsd_syscall2.go | 4 ++-- src/runtime/sys_libc.go | 4 ++-- src/runtime/sys_openbsd.go | 4 ++-- src/runtime/sys_openbsd1.go | 4 ++-- src/runtime/sys_openbsd2.go | 4 ++-- src/runtime/sys_openbsd3.go | 4 ++-- src/syscall/exec_bsd.go | 4 ++-- src/syscall/exec_libc2.go | 4 ++-- src/syscall/syscall_openbsd1.go | 4 ++-- src/syscall/syscall_openbsd_libc.go | 4 ++-- 13 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/runtime/os_openbsd_libc.go b/src/runtime/os_openbsd_libc.go index 8150753796b..0a342e55339 100644 --- a/src/runtime/os_openbsd_libc.go +++ b/src/runtime/os_openbsd_libc.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (openbsd && 386) || (openbsd && amd64) || (openbsd && arm) || (openbsd && arm64) -// +build openbsd,386 openbsd,amd64 openbsd,arm openbsd,arm64 +//go:build openbsd && !mips64 +// +build openbsd,!mips64 package runtime diff --git a/src/runtime/os_openbsd_syscall.go b/src/runtime/os_openbsd_syscall.go index 94e851cde8d..3cdcb6c707b 100644 --- a/src/runtime/os_openbsd_syscall.go +++ b/src/runtime/os_openbsd_syscall.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build openbsd && !386 && openbsd && !amd64 && openbsd && !arm && openbsd && !arm64 -// +build openbsd,!386,openbsd,!amd64,openbsd,!arm,openbsd,!arm64 +//go:build openbsd && mips64 +// +build openbsd,mips64 package runtime diff --git a/src/runtime/os_openbsd_syscall1.go b/src/runtime/os_openbsd_syscall1.go index f8f666890aa..c20ee8300e3 100644 --- a/src/runtime/os_openbsd_syscall1.go +++ b/src/runtime/os_openbsd_syscall1.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build openbsd && !386 && !amd64 && !arm && !arm64 -// +build openbsd,!386,!amd64,!arm,!arm64 +//go:build openbsd && mips64 +// +build openbsd,mips64 package runtime diff --git a/src/runtime/os_openbsd_syscall2.go b/src/runtime/os_openbsd_syscall2.go index 84543acec4a..af1997131fe 100644 --- a/src/runtime/os_openbsd_syscall2.go +++ b/src/runtime/os_openbsd_syscall2.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build openbsd && !386 && !amd64 && !arm && !arm64 -// +build openbsd,!386,!amd64,!arm,!arm64 +//go:build openbsd && mips64 +// +build openbsd,mips64 package runtime diff --git a/src/runtime/sys_libc.go b/src/runtime/sys_libc.go index 346b1ab2850..b1a9f8b5365 100644 --- a/src/runtime/sys_libc.go +++ b/src/runtime/sys_libc.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build darwin || (openbsd && 386) || (openbsd && amd64) || (openbsd && arm) || (openbsd && arm64) -// +build darwin openbsd,386 openbsd,amd64 openbsd,arm openbsd,arm64 +//go:build darwin || (openbsd && !mips64) +// +build darwin openbsd,!mips64 package runtime diff --git a/src/runtime/sys_openbsd.go b/src/runtime/sys_openbsd.go index 89203bf85f4..ab3149558b3 100644 --- a/src/runtime/sys_openbsd.go +++ b/src/runtime/sys_openbsd.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (openbsd && 386) || (openbsd && amd64) || (openbsd && arm) || (openbsd && arm64) -// +build openbsd,386 openbsd,amd64 openbsd,arm openbsd,arm64 +//go:build openbsd && !mips64 +// +build openbsd,!mips64 package runtime diff --git a/src/runtime/sys_openbsd1.go b/src/runtime/sys_openbsd1.go index 1af48539faa..6f9ad356d44 100644 --- a/src/runtime/sys_openbsd1.go +++ b/src/runtime/sys_openbsd1.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (openbsd && 386) || (openbsd && amd64) || (openbsd && arm) || (openbsd && arm64) -// +build openbsd,386 openbsd,amd64 openbsd,arm openbsd,arm64 +//go:build openbsd && !mips64 +// +build openbsd,!mips64 package runtime diff --git a/src/runtime/sys_openbsd2.go b/src/runtime/sys_openbsd2.go index 2d53f67a616..cd1a4e879fb 100644 --- a/src/runtime/sys_openbsd2.go +++ b/src/runtime/sys_openbsd2.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (openbsd && 386) || (openbsd && amd64) || (openbsd && arm) || (openbsd && arm64) -// +build openbsd,386 openbsd,amd64 openbsd,arm openbsd,arm64 +//go:build openbsd && !mips64 +// +build openbsd,!mips64 package runtime diff --git a/src/runtime/sys_openbsd3.go b/src/runtime/sys_openbsd3.go index 4ef0bdcf77f..8d77a4b216e 100644 --- a/src/runtime/sys_openbsd3.go +++ b/src/runtime/sys_openbsd3.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (openbsd && 386) || (openbsd && amd64) || (openbsd && arm) || (openbsd && arm64) -// +build openbsd,386 openbsd,amd64 openbsd,arm openbsd,arm64 +//go:build openbsd && !mips64 +// +build openbsd,!mips64 package runtime diff --git a/src/syscall/exec_bsd.go b/src/syscall/exec_bsd.go index 569dd675ed2..709066e809b 100644 --- a/src/syscall/exec_bsd.go +++ b/src/syscall/exec_bsd.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build dragonfly || freebsd || netbsd || (openbsd && !386 && !amd64 && !arm && !arm64) -// +build dragonfly freebsd netbsd openbsd,!386,!amd64,!arm,!arm64 +//go:build dragonfly || freebsd || netbsd || (openbsd && mips64) +// +build dragonfly freebsd netbsd openbsd,mips64 package syscall diff --git a/src/syscall/exec_libc2.go b/src/syscall/exec_libc2.go index 7442d59affc..b999754c2e8 100644 --- a/src/syscall/exec_libc2.go +++ b/src/syscall/exec_libc2.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build darwin || (openbsd && 386) || (openbsd && amd64) || (openbsd && arm) || (openbsd && arm64) -// +build darwin openbsd,386 openbsd,amd64 openbsd,arm openbsd,arm64 +//go:build darwin || (openbsd && !mips64) +// +build darwin openbsd,!mips64 package syscall diff --git a/src/syscall/syscall_openbsd1.go b/src/syscall/syscall_openbsd1.go index 450f3848319..15870ce1ee1 100644 --- a/src/syscall/syscall_openbsd1.go +++ b/src/syscall/syscall_openbsd1.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build openbsd && !386 && !amd64 && !arm && !arm64 -// +build openbsd,!386,!amd64,!arm,!arm64 +//go:build openbsd && mips64 +// +build openbsd,mips64 package syscall diff --git a/src/syscall/syscall_openbsd_libc.go b/src/syscall/syscall_openbsd_libc.go index 2390912b0f5..e67ee4e571c 100644 --- a/src/syscall/syscall_openbsd_libc.go +++ b/src/syscall/syscall_openbsd_libc.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (openbsd && 386) || (openbsd && amd64) || (openbsd && arm) || (openbsd && arm64) -// +build openbsd,386 openbsd,amd64 openbsd,arm openbsd,arm64 +//go:build openbsd && !mips64 +// +build openbsd,!mips64 package syscall From 2520e72d3bbfe6651cd6324077afdb4babb36b9a Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Mon, 10 May 2021 16:50:32 -0400 Subject: [PATCH 024/940] runtime: hold sched.lock across atomic pidleget/pidleput As a cleanup, golang.org/cl/307914 unintentionally caused the idle GC work recheck to drop sched.lock between acquiring a P and committing to keep it (once a worker G was found). This is unsafe, as releasing a P requires extra checks once sched.lock is taken (such as for runSafePointFn). Since checkIdleGCNoP does not perform these extra checks, we can now race with other users. In the case of #45975, we may hang with this sequence: 1. M1: checkIdleGCNoP takes sched.lock, gets P1, releases sched.lock. 2. M2: forEachP takes sched.lock, iterates over sched.pidle without finding P1, releases sched.lock. 3. M1: checkIdleGCNoP puts P1 back in sched.pidle. 4. M2: forEachP waits forever for P1 to run the safePointFn. Change back to the old behavior of releasing sched.lock only after we are certain we will keep the P. Thus if we put it back its removal from sched.pidle was never visible. Fixes #45975 For #45916 For #45885 For #45884 Change-Id: I191a1800923b206ccaf96bdcdd0bfdad17b532e9 Reviewed-on: https://go-review.googlesource.com/c/go/+/318569 Trust: Michael Pratt Run-TryBot: Michael Pratt TryBot-Result: Go Bot Reviewed-by: David Chase --- src/runtime/proc.go | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/runtime/proc.go b/src/runtime/proc.go index ba02b149952..378d5e32f5c 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -3132,24 +3132,33 @@ func checkIdleGCNoP() (*p, *g) { return nil, nil } - // Work is available; we can start an idle GC worker only if - // there is an available P and available worker G. + // Work is available; we can start an idle GC worker only if there is + // an available P and available worker G. // - // We can attempt to acquire these in either order. Workers are - // almost always available (see comment in findRunnableGCWorker - // for the one case there may be none). Since we're slightly - // less likely to find a P, check for that first. + // We can attempt to acquire these in either order, though both have + // synchonization concerns (see below). Workers are almost always + // available (see comment in findRunnableGCWorker for the one case + // there may be none). Since we're slightly less likely to find a P, + // check for that first. + // + // Synchronization: note that we must hold sched.lock until we are + // committed to keeping it. Otherwise we cannot put the unnecessary P + // back in sched.pidle without performing the full set of idle + // transition checks. + // + // If we were to check gcBgMarkWorkerPool first, we must somehow handle + // the assumption in gcControllerState.findRunnableGCWorker that an + // empty gcBgMarkWorkerPool is only possible if gcMarkDone is running. lock(&sched.lock) pp := pidleget() - unlock(&sched.lock) if pp == nil { + unlock(&sched.lock) return nil, nil } - // Now that we own a P, gcBlackenEnabled can't change - // (as it requires STW). + // Now that we own a P, gcBlackenEnabled can't change (as it requires + // STW). if gcBlackenEnabled == 0 { - lock(&sched.lock) pidleput(pp) unlock(&sched.lock) return nil, nil @@ -3157,12 +3166,13 @@ func checkIdleGCNoP() (*p, *g) { node := (*gcBgMarkWorkerNode)(gcBgMarkWorkerPool.pop()) if node == nil { - lock(&sched.lock) pidleput(pp) unlock(&sched.lock) return nil, nil } + unlock(&sched.lock) + return pp, node.gp.ptr() } From 9b84814f6e909bfe9054eab30e423bc5e880d137 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 10 May 2021 19:32:13 +0200 Subject: [PATCH 025/940] net/http: check that Unicode-aware functions are not used Change-Id: I398aff06bec95077bfff02bfb067aa949b70c184 Reviewed-on: https://go-review.googlesource.com/c/go/+/318429 Run-TryBot: Filippo Valsorda TryBot-Result: Go Bot Reviewed-by: Roberto Clapis Trust: Filippo Valsorda --- src/net/http/http_test.go | 62 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/net/http/http_test.go b/src/net/http/http_test.go index 3f1d7cee710..0d92fe5f964 100644 --- a/src/net/http/http_test.go +++ b/src/net/http/http_test.go @@ -9,9 +9,13 @@ package http import ( "bytes" "internal/testenv" + "io/fs" "net/url" + "os" "os/exec" "reflect" + "regexp" + "strings" "testing" ) @@ -156,3 +160,61 @@ func BenchmarkCopyValues(b *testing.B) { b.Fatal("Benchmark wasn't run") } } + +var forbiddenStringsFunctions = map[string]bool{ + // Functions that use Unicode-aware case folding. + "EqualFold": true, + "Title": true, + "ToLower": true, + "ToLowerSpecial": true, + "ToTitle": true, + "ToTitleSpecial": true, + "ToUpper": true, + "ToUpperSpecial": true, + + // Functions that use Unicode-aware spaces. + "Fields": true, + "TrimSpace": true, +} + +// TestNoUnicodeStrings checks that nothing in net/http uses the Unicode-aware +// strings and bytes package functions. HTTP is mostly ASCII based, and doing +// Unicode-aware case folding or space stripping can introduce vulnerabilities. +func TestNoUnicodeStrings(t *testing.T) { + if !testenv.HasSrc() { + t.Skip("source code not available") + } + + re := regexp.MustCompile(`(strings|bytes).([A-Za-z]+)`) + if err := fs.WalkDir(os.DirFS("."), ".", func(path string, d fs.DirEntry, err error) error { + if err != nil { + t.Fatal(err) + } + + if path == "internal/ascii" { + return fs.SkipDir + } + if !strings.HasSuffix(path, ".go") || + strings.HasSuffix(path, "_test.go") || + path == "h2_bundle.go" || d.IsDir() { + return nil + } + + contents, err := os.ReadFile(path) + if err != nil { + t.Fatal(err) + } + for lineNum, line := range strings.Split(string(contents), "\n") { + for _, match := range re.FindAllStringSubmatch(line, -1) { + if !forbiddenStringsFunctions[match[2]] { + continue + } + t.Errorf("disallowed call to %s at %s:%d", match[0], path, lineNum+1) + } + } + + return nil + }); err != nil { + t.Fatal(err) + } +} From 9995c6b50aa55c1cc1236d1d688929df512dad53 Mon Sep 17 00:00:00 2001 From: Manlio Perillo Date: Tue, 11 May 2021 17:02:20 +0200 Subject: [PATCH 026/940] cmd/go: ignore implicit imports when the -find flag is set The documentation of the go list -find flag says that the Deps list will be empty. However the current implementation adds implicit imports when supporting Cgo or SWIG and when linking a main package. Update the documentation of PackageOpts.IgnoreImport to clarify that both explicit and implicit imports are ignored. Add a regression test. Fixes #46092 Change-Id: I37847528d84adb7a18eb6ff29e4af4b4318a66fe Reviewed-on: https://go-review.googlesource.com/c/go/+/318770 Trust: Jay Conrod Trust: Bryan C. Mills Run-TryBot: Jay Conrod TryBot-Result: Go Bot Reviewed-by: Jay Conrod --- src/cmd/go/internal/load/pkg.go | 56 ++++++++++--------- .../go/testdata/script/list_find_nodeps.txt | 39 +++++++++++++ 2 files changed, 69 insertions(+), 26 deletions(-) create mode 100644 src/cmd/go/testdata/script/list_find_nodeps.txt diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 3c7cd44ee33..a3b96702ce5 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -1797,35 +1797,37 @@ func (p *Package) load(ctx context.Context, opts PackageOpts, path string, stk * } } - // Cgo translation adds imports of "unsafe", "runtime/cgo" and "syscall", - // except for certain packages, to avoid circular dependencies. - if p.UsesCgo() { - addImport("unsafe", true) - } - if p.UsesCgo() && (!p.Standard || !cgoExclude[p.ImportPath]) && cfg.BuildContext.Compiler != "gccgo" { - addImport("runtime/cgo", true) - } - if p.UsesCgo() && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) { - addImport("syscall", true) - } - - // SWIG adds imports of some standard packages. - if p.UsesSwig() { - addImport("unsafe", true) - if cfg.BuildContext.Compiler != "gccgo" { + if !opts.IgnoreImports { + // Cgo translation adds imports of "unsafe", "runtime/cgo" and "syscall", + // except for certain packages, to avoid circular dependencies. + if p.UsesCgo() { + addImport("unsafe", true) + } + if p.UsesCgo() && (!p.Standard || !cgoExclude[p.ImportPath]) && cfg.BuildContext.Compiler != "gccgo" { addImport("runtime/cgo", true) } - addImport("syscall", true) - addImport("sync", true) + if p.UsesCgo() && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) { + addImport("syscall", true) + } - // TODO: The .swig and .swigcxx files can use - // %go_import directives to import other packages. - } + // SWIG adds imports of some standard packages. + if p.UsesSwig() { + addImport("unsafe", true) + if cfg.BuildContext.Compiler != "gccgo" { + addImport("runtime/cgo", true) + } + addImport("syscall", true) + addImport("sync", true) - // The linker loads implicit dependencies. - if p.Name == "main" && !p.Internal.ForceLibrary { - for _, dep := range LinkerDeps(p) { - addImport(dep, false) + // TODO: The .swig and .swigcxx files can use + // %go_import directives to import other packages. + } + + // The linker loads implicit dependencies. + if p.Name == "main" && !p.Internal.ForceLibrary { + for _, dep := range LinkerDeps(p) { + addImport(dep, false) + } } } @@ -2387,7 +2389,9 @@ func LoadImportWithFlags(path, srcDir string, parent *Package, stk *ImportStack, // PackageOpts control the behavior of PackagesAndErrors and other package // loading functions. type PackageOpts struct { - // IgnoreImports controls whether we ignore imports when loading packages. + // IgnoreImports controls whether we ignore explicit and implicit imports + // when loading packages. Implicit imports are added when supporting Cgo + // or SWIG and when linking main packages. IgnoreImports bool // ModResolveTests indicates whether calls to the module loader should also diff --git a/src/cmd/go/testdata/script/list_find_nodeps.txt b/src/cmd/go/testdata/script/list_find_nodeps.txt new file mode 100644 index 00000000000..55f98f6c6c3 --- /dev/null +++ b/src/cmd/go/testdata/script/list_find_nodeps.txt @@ -0,0 +1,39 @@ +# Issue #46092 +# go list -find should always return a package with an empty Deps list + +# The linker loads implicit dependencies +go list -find -f {{.Deps}} ./cmd +stdout '\[\]' + +# Cgo translation may add imports of "unsafe", "runtime/cgo" and "syscall" +go list -find -f {{.Deps}} ./cgo +stdout '\[\]' + +# SWIG adds imports of some standard packages +go list -find -f {{.Deps}} ./swig +stdout '\[\]' + +-- go.mod -- +module listfind + +-- cmd/main.go -- +package main + +func main() {} + +-- cgo/pkg.go -- +package cgopkg + +/* +#include +*/ +import "C" + +func F() { + println(C.INT_MAX) +} + +-- swig/pkg.go -- +package swigpkg + +-- swig/a.swigcxx -- From 1a0ea1a08b26f25d3795ca46e4a831a8ca4859ad Mon Sep 17 00:00:00 2001 From: Guilherme Souza <32180229+gqgs@users.noreply.github.com> Date: Tue, 11 May 2021 21:37:56 +0000 Subject: [PATCH 027/940] runtime: fix typo in proc.go Change-Id: I12c0befc5772a5c902a55aeb06a30ec7a34a3bd6 GitHub-Last-Rev: 7d41e1bcb9f6304e1b868701740279e845c99a66 GitHub-Pull-Request: golang/go#46112 Reviewed-on: https://go-review.googlesource.com/c/go/+/319053 Reviewed-by: Keith Randall Reviewed-by: Ian Lance Taylor --- src/runtime/proc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 378d5e32f5c..66a06feb24f 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -3136,7 +3136,7 @@ func checkIdleGCNoP() (*p, *g) { // an available P and available worker G. // // We can attempt to acquire these in either order, though both have - // synchonization concerns (see below). Workers are almost always + // synchronization concerns (see below). Workers are almost always // available (see comment in findRunnableGCWorker for the one case // there may be none). Since we're slightly less likely to find a P, // check for that first. From 485474d204297ce9ff2b7f6c2a2b0e048c61fb8e Mon Sep 17 00:00:00 2001 From: Manlio Perillo Date: Wed, 12 May 2021 15:16:20 +0200 Subject: [PATCH 028/940] cmd/go/testdata/script: fix test failing on nocgo builders The regression test introduced in https://golang.org/cl/318770 broke the the nocgo builders. Update the cgo package used in the test to ensure that it can be build both with cgo enabled and disabled. Change-Id: Iab0486f0b85ac5e5a22fdf8a1998edd50cbb4d96 Reviewed-on: https://go-review.googlesource.com/c/go/+/319210 Trust: Bryan C. Mills Trust: Jay Conrod Reviewed-by: Bryan C. Mills Reviewed-by: Jay Conrod Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot --- src/cmd/go/testdata/script/list_find_nodeps.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/cmd/go/testdata/script/list_find_nodeps.txt b/src/cmd/go/testdata/script/list_find_nodeps.txt index 55f98f6c6c3..e08ce789509 100644 --- a/src/cmd/go/testdata/script/list_find_nodeps.txt +++ b/src/cmd/go/testdata/script/list_find_nodeps.txt @@ -33,6 +33,16 @@ func F() { println(C.INT_MAX) } +-- cgo/pkg_notcgo.go -- +//go:build !cgo +// +build !cgo + +package cgopkg + +func F() { + println(0) +} + -- swig/pkg.go -- package swigpkg From af0f8c149e8a4b237910fc7b41739bedc546473c Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 11 May 2021 22:40:02 -0400 Subject: [PATCH 029/940] cmd/link: don't cast end address to int32 When linking a very large binary, the section address may not fit in int32. Don't truncate it. Change-Id: Ibcc8d74bf5662611949e547ce44ca8b973de383f Reviewed-on: https://go-review.googlesource.com/c/go/+/319289 Trust: Cherry Mui Run-TryBot: Cherry Mui Reviewed-by: Than McIntosh TryBot-Result: Go Bot --- src/cmd/link/internal/ld/elf.go | 2 +- src/cmd/link/internal/ld/macho.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go index 87d88dd957d..6f81e74da29 100644 --- a/src/cmd/link/internal/ld/elf.go +++ b/src/cmd/link/internal/ld/elf.go @@ -1171,7 +1171,7 @@ func elfrelocsect(ctxt *Link, out *OutBuf, sect *sym.Section, syms []loader.Sym) } } - eaddr := int32(sect.Vaddr + sect.Length) + eaddr := sect.Vaddr + sect.Length for _, s := range syms { if !ldr.AttrReachable(s) { continue diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go index 642113cf070..45a3971c33f 100644 --- a/src/cmd/link/internal/ld/macho.go +++ b/src/cmd/link/internal/ld/macho.go @@ -1194,7 +1194,7 @@ func machorelocsect(ctxt *Link, out *OutBuf, sect *sym.Section, syms []loader.Sy } } - eaddr := int32(sect.Vaddr + sect.Length) + eaddr := sect.Vaddr + sect.Length for _, s := range syms { if !ldr.AttrReachable(s) { continue From e03383a2e233fc89958cff31642dff917d649378 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 11 May 2021 22:40:41 -0400 Subject: [PATCH 030/940] cmd/link: check mmap error We already check mmap errors on some code paths, but we missed one. Add error check there. Change-Id: Ic0e9cb0eb03c805de40802cfc5d5500e3e065d99 Reviewed-on: https://go-review.googlesource.com/c/go/+/319290 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- src/cmd/link/internal/ld/asmb.go | 5 ++++- src/cmd/link/internal/ld/main.go | 2 +- src/cmd/link/internal/ld/outbuf.go | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/cmd/link/internal/ld/asmb.go b/src/cmd/link/internal/ld/asmb.go index 37546695556..d6ecb2895ba 100644 --- a/src/cmd/link/internal/ld/asmb.go +++ b/src/cmd/link/internal/ld/asmb.go @@ -167,7 +167,10 @@ func sizeExtRelocs(ctxt *Link, relsize uint32) { } } filesz := ctxt.Out.Offset() + sz - ctxt.Out.Mmap(uint64(filesz)) + err := ctxt.Out.Mmap(uint64(filesz)) + if err != nil { + Exitf("mapping output file failed: %v", err) + } } // relocSectFn wraps the function writing relocations of a section diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index adb39d06076..cba0e3d81fe 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -334,7 +334,7 @@ func Main(arch *sys.Arch, theArch Arch) { // Don't mmap if we're building for Wasm. Wasm file // layout is very different so filesize is meaningless. if err := ctxt.Out.Mmap(filesize); err != nil { - panic(err) + Exitf("mapping output file failed: %v", err) } } // asmb will redirect symbols to the output file mmap, and relocations diff --git a/src/cmd/link/internal/ld/outbuf.go b/src/cmd/link/internal/ld/outbuf.go index 530836ef7cf..9d5e8854fea 100644 --- a/src/cmd/link/internal/ld/outbuf.go +++ b/src/cmd/link/internal/ld/outbuf.go @@ -160,7 +160,7 @@ func (out *OutBuf) copyHeap() bool { total := uint64(bufLen + heapLen) if heapLen != 0 { if err := out.Mmap(total); err != nil { // Mmap will copy out.heap over to out.buf - panic(err) + Exitf("mapping output file failed: %v", err) } } return true From 03886707f9e8db668bd1fd7b8f99799dba0408e3 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 6 May 2021 11:38:46 -0400 Subject: [PATCH 031/940] runtime: fix handling of SPWRITE functions in traceback It is valid to see SPWRITE functions at the top of a GC stack traceback, in the case where they self-preempted during the stack growth check and haven't actually modified SP in a traceback-unfriendly manner yet. The current check is therefore too aggressive. isAsyncSafePoint is taking care of not async-preempting SPWRITE functions because it doesn't async-preempt any assembly functions at all. But perhaps it will in the future. To keep a check that SPWRITE assembly functions are not async-preempted, add one in preemptPark. Then relax the check in traceback to avoid triggering on self-preempted SPWRITE functions. The long and short of this is that the assembly we corrected in x/crypto issue #44269 was incredibly dodgy but not technically incompatible with the Go runtime. After this change, the original x/crypto assembly no longer causes GC traceback crashes during "GOGC=1 go test -count=1000". But we'll still leave the corrected assembly. This also means that we don't need to worry about diagnosing SPWRITE assembly functions that may exist in the wild. They will be skipped for async preemption and no harm no foul. Fixes #44269, which was open pending some kind of check for bad SPWRITE functions in the wild. (No longer needed.) Change-Id: I6000197b62812bbd2cd92da28eab422634cf75a8 Reviewed-on: https://go-review.googlesource.com/c/go/+/317669 Trust: Russ Cox Run-TryBot: Russ Cox TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/runtime/preempt.go | 2 ++ src/runtime/proc.go | 15 +++++++++++++++ src/runtime/traceback.go | 17 ++++++++++++----- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/runtime/preempt.go b/src/runtime/preempt.go index 372185266f7..1d5aae13631 100644 --- a/src/runtime/preempt.go +++ b/src/runtime/preempt.go @@ -413,6 +413,8 @@ func isAsyncSafePoint(gp *g, pc, sp, lr uintptr) (bool, uintptr) { // // TODO: Are there cases that are safe but don't have a // locals pointer map, like empty frame functions? + // It might be possible to preempt any assembly functions + // except the ones that have funcFlag_SPWRITE set in f.flag. return false, 0 } name := funcname(f) diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 66a06feb24f..ded406cc28d 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -3570,6 +3570,21 @@ func preemptPark(gp *g) { throw("bad g status") } gp.waitreason = waitReasonPreempted + + if gp.asyncSafePoint { + // Double-check that async preemption does not + // happen in SPWRITE assembly functions. + // isAsyncSafePoint must exclude this case. + f := findfunc(gp.sched.pc) + if !f.valid() { + throw("preempt at unknown pc") + } + if f.flag&funcFlag_SPWRITE != 0 { + println("runtime: unexpected SPWRITE function", funcname(f), "in async preempt") + throw("preempt SPWRITE") + } + } + // Transition from _Grunning to _Gscan|_Gpreempted. We can't // be in _Grunning when we dropg because then we'd be running // without an M, but the moment we're in _Gpreempted, diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index 167d51c452a..89780edc1ff 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -219,18 +219,25 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in // This function marks the top of the stack. Stop the traceback. frame.lr = 0 flr = funcInfo{} - } else if flag&funcFlag_SPWRITE != 0 { + } else if flag&funcFlag_SPWRITE != 0 && (callback == nil || n > 0) { // The function we are in does a write to SP that we don't know // how to encode in the spdelta table. Examples include context // switch routines like runtime.gogo but also any code that switches // to the g0 stack to run host C code. Since we can't reliably unwind // the SP (we might not even be on the stack we think we are), // we stop the traceback here. + // This only applies for profiling signals (callback == nil). + // + // For a GC stack traversal (callback != nil), we should only see + // a function when it has voluntarily preempted itself on entry + // during the stack growth check. In that case, the function has + // not yet had a chance to do any writes to SP and is safe to unwind. + // isAsyncSafePoint does not allow assembly functions to be async preempted, + // and preemptPark double-checks that SPWRITE functions are not async preempted. + // So for GC stack traversal we leave things alone (this if body does not execute for n == 0) + // at the bottom frame of the stack. But farther up the stack we'd better not + // find any. if callback != nil { - // Finding an SPWRITE should only happen for a profiling signal, which can - // arrive at any time. For a GC stack traversal (callback != nil), - // we shouldn't see this case, and we must be sure to walk the - // entire stack or the GC is invalid. So crash. println("traceback: unexpected SPWRITE function", funcname(f)) throw("traceback") } From 07ff596404b03a8e01ed53f1553c59eb215dc697 Mon Sep 17 00:00:00 2001 From: Jonathan Swinney Date: Sat, 17 Apr 2021 01:12:28 +0000 Subject: [PATCH 032/940] runtime/internal/atomic: add LSE atomics instructions to arm64 As a follow up to an earlier change[1] to add ARMv8+LSE instructions in the compiler generated atomic intrinsics, make the same change in the runtime library. Since not all ARMv8 systems support LSE instructions, they are protected by a feature-flag branch. [1]: golang.org/cl/234217 commit: ecc3f5112eba Change-Id: I0e2fb22e78d5eddb6547863667a8865946679a00 Reviewed-on: https://go-review.googlesource.com/c/go/+/310591 Reviewed-by: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Trust: Heschi Kreinick --- src/runtime/internal/atomic/atomic_arm64.go | 9 +- src/runtime/internal/atomic/atomic_arm64.s | 93 +++++++++++++++++---- 2 files changed, 85 insertions(+), 17 deletions(-) diff --git a/src/runtime/internal/atomic/atomic_arm64.go b/src/runtime/internal/atomic/atomic_arm64.go index 131c687e1ba..3c8736997f4 100644 --- a/src/runtime/internal/atomic/atomic_arm64.go +++ b/src/runtime/internal/atomic/atomic_arm64.go @@ -7,7 +7,14 @@ package atomic -import "unsafe" +import ( + "unsafe" + "internal/cpu" +) + +const ( + offsetARM64HasATOMICS = unsafe.Offsetof(cpu.ARM64.HasATOMICS) +) //go:noescape func Xadd(ptr *uint32, delta int32) uint32 diff --git a/src/runtime/internal/atomic/atomic_arm64.s b/src/runtime/internal/atomic/atomic_arm64.s index 587e7f05e25..e9467afecd7 100644 --- a/src/runtime/internal/atomic/atomic_arm64.s +++ b/src/runtime/internal/atomic/atomic_arm64.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include "go_asm.h" #include "textflag.h" TEXT ·Casint32(SB), NOSPLIT, $0-17 @@ -127,10 +128,15 @@ TEXT ·Store64(SB), NOSPLIT, $0-16 TEXT ·Xchg(SB), NOSPLIT, $0-20 MOVD ptr+0(FP), R0 MOVW new+8(FP), R1 -again: + MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 + CBZ R4, load_store_loop + SWPALW R1, (R0), R2 + MOVW R2, ret+16(FP) + RET +load_store_loop: LDAXRW (R0), R2 STLXRW R1, (R0), R3 - CBNZ R3, again + CBNZ R3, load_store_loop MOVW R2, ret+16(FP) RET @@ -142,10 +148,15 @@ again: TEXT ·Xchg64(SB), NOSPLIT, $0-24 MOVD ptr+0(FP), R0 MOVD new+8(FP), R1 -again: + MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 + CBZ R4, load_store_loop + SWPALD R1, (R0), R2 + MOVD R2, ret+16(FP) + RET +load_store_loop: LDAXR (R0), R2 STLXR R1, (R0), R3 - CBNZ R3, again + CBNZ R3, load_store_loop MOVD R2, ret+16(FP) RET @@ -160,12 +171,20 @@ TEXT ·Cas(SB), NOSPLIT, $0-17 MOVD ptr+0(FP), R0 MOVW old+8(FP), R1 MOVW new+12(FP), R2 -again: + MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 + CBZ R4, load_store_loop + MOVD R1, R3 + CASALW R3, (R0), R2 + CMP R1, R3 + CSET EQ, R0 + MOVB R0, ret+16(FP) + RET +load_store_loop: LDAXRW (R0), R3 CMPW R1, R3 BNE ok STLXRW R2, (R0), R3 - CBNZ R3, again + CBNZ R3, load_store_loop ok: CSET EQ, R0 MOVB R0, ret+16(FP) @@ -183,12 +202,20 @@ TEXT ·Cas64(SB), NOSPLIT, $0-25 MOVD ptr+0(FP), R0 MOVD old+8(FP), R1 MOVD new+16(FP), R2 -again: + MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 + CBZ R4, load_store_loop + MOVD R1, R3 + CASALD R3, (R0), R2 + CMP R1, R3 + CSET EQ, R0 + MOVB R0, ret+24(FP) + RET +load_store_loop: LDAXR (R0), R3 CMP R1, R3 BNE ok STLXR R2, (R0), R3 - CBNZ R3, again + CBNZ R3, load_store_loop ok: CSET EQ, R0 MOVB R0, ret+24(FP) @@ -201,11 +228,17 @@ ok: TEXT ·Xadd(SB), NOSPLIT, $0-20 MOVD ptr+0(FP), R0 MOVW delta+8(FP), R1 -again: + MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 + CBZ R4, load_store_loop + LDADDALW R1, (R0), R2 + ADD R1, R2 + MOVW R2, ret+16(FP) + RET +load_store_loop: LDAXRW (R0), R2 ADDW R2, R1, R2 STLXRW R2, (R0), R3 - CBNZ R3, again + CBNZ R3, load_store_loop MOVW R2, ret+16(FP) RET @@ -216,11 +249,17 @@ again: TEXT ·Xadd64(SB), NOSPLIT, $0-24 MOVD ptr+0(FP), R0 MOVD delta+8(FP), R1 -again: + MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 + CBZ R4, load_store_loop + LDADDALD R1, (R0), R2 + ADD R1, R2 + MOVD R2, ret+16(FP) + RET +load_store_loop: LDAXR (R0), R2 ADD R2, R1, R2 STLXR R2, (R0), R3 - CBNZ R3, again + CBNZ R3, load_store_loop MOVD R2, ret+16(FP) RET @@ -236,37 +275,59 @@ TEXT ·Xchguintptr(SB), NOSPLIT, $0-24 TEXT ·And8(SB), NOSPLIT, $0-9 MOVD ptr+0(FP), R0 MOVB val+8(FP), R1 + MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 + CBZ R4, load_store_loop + MVN R1, R2 + LDCLRALB R2, (R0), R3 + RET +load_store_loop: LDAXRB (R0), R2 AND R1, R2 STLXRB R2, (R0), R3 - CBNZ R3, -3(PC) + CBNZ R3, load_store_loop RET TEXT ·Or8(SB), NOSPLIT, $0-9 MOVD ptr+0(FP), R0 MOVB val+8(FP), R1 + MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 + CBZ R4, load_store_loop + LDORALB R1, (R0), R2 + RET +load_store_loop: LDAXRB (R0), R2 ORR R1, R2 STLXRB R2, (R0), R3 - CBNZ R3, -3(PC) + CBNZ R3, load_store_loop RET // func And(addr *uint32, v uint32) TEXT ·And(SB), NOSPLIT, $0-12 MOVD ptr+0(FP), R0 MOVW val+8(FP), R1 + MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 + CBZ R4, load_store_loop + MVN R1, R2 + LDCLRALW R2, (R0), R3 + RET +load_store_loop: LDAXRW (R0), R2 AND R1, R2 STLXRW R2, (R0), R3 - CBNZ R3, -3(PC) + CBNZ R3, load_store_loop RET // func Or(addr *uint32, v uint32) TEXT ·Or(SB), NOSPLIT, $0-12 MOVD ptr+0(FP), R0 MOVW val+8(FP), R1 + MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 + CBZ R4, load_store_loop + LDORALW R1, (R0), R2 + RET +load_store_loop: LDAXRW (R0), R2 ORR R1, R2 STLXRW R2, (R0), R3 - CBNZ R3, -3(PC) + CBNZ R3, load_store_loop RET From 3b321a9d122f0dbf8b333cc79bbf61218e3d05ba Mon Sep 17 00:00:00 2001 From: Ruslan Andreev Date: Tue, 19 Jan 2021 22:30:10 +0800 Subject: [PATCH 033/940] cmd/compile: add arch-specific inlining for runtime.memmove This CL add runtime.memmove inlining for AMD64 and ARM64. According to ssa dump from testcases generic rules can't inline memmomve properly due to one of the arguments is Phi operation. But this Phi op will be optimized out by later optimization stages. As a result memmove can be inlined during arch-specific rules. The commit add new optimization rules to arch-specific rules that can inline runtime.memmove if it possible during lowering stage. Optimization fires 5 times in Go source-code using regabi. Fixes #41662 Change-Id: Iaffaf4c482d068b5f0683d141863892202cc8824 Reviewed-on: https://go-review.googlesource.com/c/go/+/289151 Reviewed-by: Keith Randall Run-TryBot: Keith Randall TryBot-Result: Go Bot Trust: David Chase --- src/cmd/compile/internal/ssa/gen/AMD64.rules | 19 +++++ src/cmd/compile/internal/ssa/gen/ARM64.rules | 9 +++ .../compile/internal/ssa/gen/generic.rules | 6 +- src/cmd/compile/internal/ssa/rewriteAMD64.go | 74 +++++++++++++++++++ src/cmd/compile/internal/ssa/rewriteARM64.go | 50 +++++++++++++ test/codegen/copy.go | 36 +++++++++ 6 files changed, 191 insertions(+), 3 deletions(-) diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules index ec91ea1513b..4cd00732fc3 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules @@ -2216,3 +2216,22 @@ (MOVOstore [dstOff] {dstSym} ptr (MOVOload [srcOff] {srcSym} (SB) _) mem) && symIsRO(srcSym) => (MOVQstore [dstOff+8] {dstSym} ptr (MOVQconst [int64(read64(srcSym, int64(srcOff)+8, config.ctxt.Arch.ByteOrder))]) (MOVQstore [dstOff] {dstSym} ptr (MOVQconst [int64(read64(srcSym, int64(srcOff), config.ctxt.Arch.ByteOrder))]) mem)) + +// Arch-specific inlining for small or disjoint runtime.memmove +// Match post-lowering calls, memory version. +(SelectN [0] call:(CALLstatic {sym} s1:(MOVQstoreconst _ [sc] s2:(MOVQstore _ src s3:(MOVQstore _ dst mem))))) + && sc.Val64() >= 0 + && isSameCall(sym, "runtime.memmove") + && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 + && isInlinableMemmove(dst, src, sc.Val64(), config) + && clobber(s1, s2, s3, call) + => (Move [sc.Val64()] dst src mem) + +// Match post-lowering calls, register version. +(SelectN [0] call:(CALLstatic {sym} dst src (MOVQconst [sz]) mem)) + && sz >= 0 + && isSameCall(sym, "runtime.memmove") + && call.Uses == 1 + && isInlinableMemmove(dst, src, sz, config) + && clobber(call) + => (Move [sz] dst src mem) diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules index 3d2759493e5..62699f290c2 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM64.rules +++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules @@ -2859,3 +2859,12 @@ (MOVHUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVDconst [int64(read16(sym, int64(off), config.ctxt.Arch.ByteOrder))]) (MOVWUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVDconst [int64(read32(sym, int64(off), config.ctxt.Arch.ByteOrder))]) (MOVDload [off] {sym} (SB) _) && symIsRO(sym) => (MOVDconst [int64(read64(sym, int64(off), config.ctxt.Arch.ByteOrder))]) + +// Arch-specific inlining for small or disjoint runtime.memmove +(SelectN [0] call:(CALLstatic {sym} s1:(MOVDstore _ (MOVDconst [sz]) s2:(MOVDstore _ src s3:(MOVDstore {t} _ dst mem))))) + && sz >= 0 + && isSameCall(sym, "runtime.memmove") + && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 + && isInlinableMemmove(dst, src, sz, config) + && clobber(s1, s2, s3, call) + => (Move [sz] dst src mem) diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules index aad7600d793..5cbc70cf41d 100644 --- a/src/cmd/compile/internal/ssa/gen/generic.rules +++ b/src/cmd/compile/internal/ssa/gen/generic.rules @@ -2065,7 +2065,7 @@ (SelectN [0] call:(StaticCall {sym} s1:(Store _ (Const(64|32) [sz]) s2:(Store _ src s3:(Store {t} _ dst mem))))) && sz >= 0 && isSameCall(sym, "runtime.memmove") - && t.IsPtr() // avoids TUINTPTR, see issue 30061 + && t.IsPtr() // avoids TUNSAFEPTR, see issue 30061 && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, int64(sz), config) && clobber(s1, s2, s3, call) @@ -2076,7 +2076,7 @@ && sz >= 0 && call.Uses == 1 // this will exclude all calls with results && isSameCall(sym, "runtime.memmove") - && dst.Type.IsPtr() // avoids TUINTPTR, see issue 30061 + && dst.Type.IsPtr() // avoids TUNSAFEPTR, see issue 30061 && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call) => (Move {dst.Type.Elem()} [int64(sz)] dst src mem) @@ -2086,7 +2086,7 @@ && sz >= 0 && call.Uses == 1 // this will exclude all calls with results && isSameCall(sym, "runtime.memmove") - && dst.Type.IsPtr() // avoids TUINTPTR, see issue 30061 + && dst.Type.IsPtr() // avoids TUNSAFEPTR, see issue 30061 && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call) => (Move {dst.Type.Elem()} [int64(sz)] dst src mem) diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index efb5d271451..5045ba7351f 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -1038,6 +1038,8 @@ func rewriteValueAMD64(v *Value) bool { return rewriteValueAMD64_OpSelect0(v) case OpSelect1: return rewriteValueAMD64_OpSelect1(v) + case OpSelectN: + return rewriteValueAMD64_OpSelectN(v) case OpSignExt16to32: v.Op = OpAMD64MOVWQSX return true @@ -32981,6 +32983,78 @@ func rewriteValueAMD64_OpSelect1(v *Value) bool { } return false } +func rewriteValueAMD64_OpSelectN(v *Value) bool { + v_0 := v.Args[0] + b := v.Block + config := b.Func.Config + // match: (SelectN [0] call:(CALLstatic {sym} s1:(MOVQstoreconst _ [sc] s2:(MOVQstore _ src s3:(MOVQstore _ dst mem))))) + // cond: sc.Val64() >= 0 && isSameCall(sym, "runtime.memmove") && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, sc.Val64(), config) && clobber(s1, s2, s3, call) + // result: (Move [sc.Val64()] dst src mem) + for { + if auxIntToInt64(v.AuxInt) != 0 { + break + } + call := v_0 + if call.Op != OpAMD64CALLstatic || len(call.Args) != 1 { + break + } + sym := auxToCall(call.Aux) + s1 := call.Args[0] + if s1.Op != OpAMD64MOVQstoreconst { + break + } + sc := auxIntToValAndOff(s1.AuxInt) + _ = s1.Args[1] + s2 := s1.Args[1] + if s2.Op != OpAMD64MOVQstore { + break + } + _ = s2.Args[2] + src := s2.Args[1] + s3 := s2.Args[2] + if s3.Op != OpAMD64MOVQstore { + break + } + mem := s3.Args[2] + dst := s3.Args[1] + if !(sc.Val64() >= 0 && isSameCall(sym, "runtime.memmove") && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, sc.Val64(), config) && clobber(s1, s2, s3, call)) { + break + } + v.reset(OpMove) + v.AuxInt = int64ToAuxInt(sc.Val64()) + v.AddArg3(dst, src, mem) + return true + } + // match: (SelectN [0] call:(CALLstatic {sym} dst src (MOVQconst [sz]) mem)) + // cond: sz >= 0 && isSameCall(sym, "runtime.memmove") && call.Uses == 1 && isInlinableMemmove(dst, src, sz, config) && clobber(call) + // result: (Move [sz] dst src mem) + for { + if auxIntToInt64(v.AuxInt) != 0 { + break + } + call := v_0 + if call.Op != OpAMD64CALLstatic || len(call.Args) != 4 { + break + } + sym := auxToCall(call.Aux) + mem := call.Args[3] + dst := call.Args[0] + src := call.Args[1] + call_2 := call.Args[2] + if call_2.Op != OpAMD64MOVQconst { + break + } + sz := auxIntToInt64(call_2.AuxInt) + if !(sz >= 0 && isSameCall(sym, "runtime.memmove") && call.Uses == 1 && isInlinableMemmove(dst, src, sz, config) && clobber(call)) { + break + } + v.reset(OpMove) + v.AuxInt = int64ToAuxInt(sz) + v.AddArg3(dst, src, mem) + return true + } + return false +} func rewriteValueAMD64_OpSlicemask(v *Value) bool { v_0 := v.Args[0] b := v.Block diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go index 0ba3951df57..3cdc4d36cb5 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM64.go +++ b/src/cmd/compile/internal/ssa/rewriteARM64.go @@ -984,6 +984,8 @@ func rewriteValueARM64(v *Value) bool { return rewriteValueARM64_OpSelect0(v) case OpSelect1: return rewriteValueARM64_OpSelect1(v) + case OpSelectN: + return rewriteValueARM64_OpSelectN(v) case OpSignExt16to32: v.Op = OpARM64MOVHreg return true @@ -25983,6 +25985,54 @@ func rewriteValueARM64_OpSelect1(v *Value) bool { } return false } +func rewriteValueARM64_OpSelectN(v *Value) bool { + v_0 := v.Args[0] + b := v.Block + config := b.Func.Config + // match: (SelectN [0] call:(CALLstatic {sym} s1:(MOVDstore _ (MOVDconst [sz]) s2:(MOVDstore _ src s3:(MOVDstore {t} _ dst mem))))) + // cond: sz >= 0 && isSameCall(sym, "runtime.memmove") && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, sz, config) && clobber(s1, s2, s3, call) + // result: (Move [sz] dst src mem) + for { + if auxIntToInt64(v.AuxInt) != 0 { + break + } + call := v_0 + if call.Op != OpARM64CALLstatic { + break + } + sym := auxToCall(call.Aux) + s1 := call.Args[0] + if s1.Op != OpARM64MOVDstore { + break + } + _ = s1.Args[2] + s1_1 := s1.Args[1] + if s1_1.Op != OpARM64MOVDconst { + break + } + sz := auxIntToInt64(s1_1.AuxInt) + s2 := s1.Args[2] + if s2.Op != OpARM64MOVDstore { + break + } + _ = s2.Args[2] + src := s2.Args[1] + s3 := s2.Args[2] + if s3.Op != OpARM64MOVDstore { + break + } + mem := s3.Args[2] + dst := s3.Args[1] + if !(sz >= 0 && isSameCall(sym, "runtime.memmove") && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, sz, config) && clobber(s1, s2, s3, call)) { + break + } + v.reset(OpMove) + v.AuxInt = int64ToAuxInt(sz) + v.AddArg3(dst, src, mem) + return true + } + return false +} func rewriteValueARM64_OpSlicemask(v *Value) bool { v_0 := v.Args[0] b := v.Block diff --git a/test/codegen/copy.go b/test/codegen/copy.go index 0cd86d1161a..ea8a01f803f 100644 --- a/test/codegen/copy.go +++ b/test/codegen/copy.go @@ -97,6 +97,42 @@ func moveDisjointNoOverlap(a *[256]byte) { copy(a[:], a[128:]) } +// Check arch-specific memmove lowering. See issue 41662 fot details + +func moveArchLowering1(b []byte, x *[1]byte) { + _ = b[1] + // amd64:-".*memmove" + // arm64:-".*memmove" + copy(b, x[:]) +} + +func moveArchLowering2(b []byte, x *[2]byte) { + _ = b[2] + // amd64:-".*memmove" + // arm64:-".*memmove" + copy(b, x[:]) +} + +func moveArchLowering4(b []byte, x *[4]byte) { + _ = b[4] + // amd64:-".*memmove" + // arm64:-".*memmove" + copy(b, x[:]) +} + +func moveArchLowering8(b []byte, x *[8]byte) { + _ = b[8] + // amd64:-".*memmove" + // arm64:-".*memmove" + copy(b, x[:]) +} + +func moveArchLowering16(b []byte, x *[16]byte) { + _ = b[16] + // amd64:-".*memmove" + copy(b, x[:]) +} + // Check that no branches are generated when the pointers are [not] equal. func ptrEqual() { From f93b951f33add708d9e745e95a29ebe98f3e1255 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 12 May 2021 13:08:16 -0400 Subject: [PATCH 034/940] cmd/compile/abi-internal.md: fix table format The table was not rendered correctly because one line missed a column. Change-Id: I1373e4e9fb8b8f2dcd9fd0db339083362cce9b71 Reviewed-on: https://go-review.googlesource.com/c/go/+/319291 Trust: Cherry Mui Reviewed-by: Than McIntosh --- src/cmd/compile/abi-internal.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/compile/abi-internal.md b/src/cmd/compile/abi-internal.md index f901e707be3..1ae3c2538ff 100644 --- a/src/cmd/compile/abi-internal.md +++ b/src/cmd/compile/abi-internal.md @@ -402,7 +402,7 @@ without corrupting arguments or results. Special-purpose registers are as follows: | Register | Call meaning | Return meaning | Body meaning | -| --- | --- | --- | +| --- | --- | --- | --- | | RSP | Stack pointer | Same | Same | | RBP | Frame pointer | Same | Same | | RDX | Closure context pointer | Scratch | Scratch | From 6db7480f5973ced97dfb08f949889e2ff108a492 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Tue, 11 May 2021 10:15:57 -0400 Subject: [PATCH 035/940] cmd/go/internal/modload: in updateLazyRoots, do not require the main module explicitly Fixes #46078 Change-Id: I8044dac717459f1eeae1d8381a6503f22f9f51ff Reviewed-on: https://go-review.googlesource.com/c/go/+/319009 Trust: Bryan C. Mills Reviewed-by: Jay Conrod --- src/cmd/go/internal/modload/buildlist.go | 3 +- .../go/testdata/script/mod_tidy_lazy_self.txt | 71 +++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 src/cmd/go/testdata/script/mod_tidy_lazy_self.txt diff --git a/src/cmd/go/internal/modload/buildlist.go b/src/cmd/go/internal/modload/buildlist.go index 7a0cea405e3..e5db41c7486 100644 --- a/src/cmd/go/internal/modload/buildlist.go +++ b/src/cmd/go/internal/modload/buildlist.go @@ -815,7 +815,8 @@ func updateLazyRoots(ctx context.Context, direct map[string]bool, rs *Requiremen roots = make([]module.Version, 0, len(rs.rootModules)) rootsUpgraded = false - inRootPaths := make(map[string]bool, len(rs.rootModules)) + inRootPaths := make(map[string]bool, len(rs.rootModules)+1) + inRootPaths[Target.Path] = true for _, m := range rs.rootModules { if inRootPaths[m.Path] { // This root specifies a redundant path. We already retained the diff --git a/src/cmd/go/testdata/script/mod_tidy_lazy_self.txt b/src/cmd/go/testdata/script/mod_tidy_lazy_self.txt new file mode 100644 index 00000000000..ffcea186035 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_lazy_self.txt @@ -0,0 +1,71 @@ +# Regression test for https://golang.org/issue/46078: +# 'go mod tidy' should not panic if the main module initially +# requires an older version of itself. + + +# A module that explicitly requires an older version of itself should be +# rejected as inconsistent: we enforce that every explicit requirement is the +# selected version of its module path, but the selected version of the main +# module is always itself — not some explicit version. + +! go list -m all +stderr '^go: updates to go\.mod needed; to update it:\n\tgo mod tidy$' + + +# The suggested 'go mod tidy' command should succeed (not crash). + +go mod tidy + + +# We prune out redundant roots very early on in module loading, and at that +# point the indirect requirement on example.net/x v0.1.0 appears to be +# irrelevant. It should be pruned out; when the import of "example.net/x" is +# later resolved, it should resolve at the latest version (v0.2.0), not the +# version implied by the (former) misleading requirement on the older version of +# the main module. + +cmp go.mod go.mod.tidy + + +-- go.mod -- +module golang.org/issue/46078 + +go 1.17 + +replace ( + example.net/x v0.1.0 => ./x + example.net/x v0.2.0 => ./x + golang.org/issue/46078 v0.1.0 => ./old +) + +require golang.org/issue/46078 v0.1.0 +-- go.mod.tidy -- +module golang.org/issue/46078 + +go 1.17 + +replace ( + example.net/x v0.1.0 => ./x + example.net/x v0.2.0 => ./x + golang.org/issue/46078 v0.1.0 => ./old +) + +require example.net/x v0.2.0 +-- issue46078/issue.go -- +package issue46078 + +import _ "example.net/x" + +-- old/go.mod -- +module golang.org/issue/46078 + +go 1.17 + +require example.net/x v0.1.0 + +-- x/go.mod -- +module example.net/x + +go 1.17 +-- x/x.go -- +package x From 04f65d394c00cf706ba1e0949b057d94dace6b94 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Fri, 7 May 2021 13:20:34 -0700 Subject: [PATCH 036/940] [dev.typeparams] cmd/compile: fix use of method values with stenciled methods We were handling the case where an OFUNCINST node was used as a function value, but not the case when an OFUNCINST node was used as a method value. In the case of a method value, we need to create a new selector expression that references the newly stenciled method. To make this work, also needed small fix to noder2 code to properly set the Sel of a method SelectorExpr (should be just the base method name, not the full method name including the type string). This has to be correct, so that the function created by MethodValueWrapper() can be typechecked successfully. Fixes #45817 Change-Id: I7343e8a0d35fc46b44dfe4d45b77997ba6c8733e Reviewed-on: https://go-review.googlesource.com/c/go/+/319589 Reviewed-by: Keith Randall Trust: Dan Scales --- src/cmd/compile/internal/ir/expr.go | 9 ++++++-- src/cmd/compile/internal/noder/expr.go | 2 +- src/cmd/compile/internal/noder/stencil.go | 22 +++++++++++++++++--- test/typeparam/issue45817.go | 25 +++++++++++++++++++++++ 4 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 test/typeparam/issue45817.go diff --git a/src/cmd/compile/internal/ir/expr.go b/src/cmd/compile/internal/ir/expr.go index f70645f0791..9ea8b619653 100644 --- a/src/cmd/compile/internal/ir/expr.go +++ b/src/cmd/compile/internal/ir/expr.go @@ -494,8 +494,13 @@ func NewNameOffsetExpr(pos src.XPos, name *Name, offset int64, typ *types.Type) // A SelectorExpr is a selector expression X.Sel. type SelectorExpr struct { miniExpr - X Node - Sel *types.Sym + X Node + // Sel is the name of the field or method being selected, without (in the + // case of methods) any preceding type specifier. If the field/method is + // exported, than the Sym uses the local package regardless of the package + // of the containing type. + Sel *types.Sym + // The actual selected field - may not be filled in until typechecking. Selection *types.Field Prealloc *Name // preallocated storage for OCALLPART, if any } diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go index c7695ed9204..b7f7a34953a 100644 --- a/src/cmd/compile/internal/noder/expr.go +++ b/src/cmd/compile/internal/noder/expr.go @@ -266,7 +266,7 @@ func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.Selecto recvType2 = recvType2Base // method is the generic method associated with the gen type method := g.obj(types2.AsNamed(recvType2).Method(last)) - n = ir.NewSelectorExpr(pos, ir.OCALLPART, x, method.Sym()) + n = ir.NewSelectorExpr(pos, ir.OCALLPART, x, typecheck.Lookup(expr.Sel.Value)) n.(*ir.SelectorExpr).Selection = types.NewField(pos, method.Sym(), method.Type()) n.(*ir.SelectorExpr).Selection.Nname = method typed(method.Type(), n) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 3ebc8dff6d8..751a6282566 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -112,14 +112,30 @@ func (g *irgen) stencil() { // EditChildren rather than Visit), where we actually change the // OFUNCINST node to an ONAME for the instantiated function. // EditChildren is more expensive than Visit, so we only do this - // in the infrequent case of an OFUNCINSt without a corresponding + // in the infrequent case of an OFUNCINST without a corresponding // call. if foundFuncInst { var edit func(ir.Node) ir.Node edit = func(x ir.Node) ir.Node { if x.Op() == ir.OFUNCINST { - st := g.getInstantiationForNode(x.(*ir.InstExpr)) - return st.Nname + // inst.X is either a function name node + // or a selector expression for a method. + inst := x.(*ir.InstExpr) + st := g.getInstantiationForNode(inst) + modified = true + if inst.X.Op() == ir.ONAME { + return st.Nname + } + assert(inst.X.Op() == ir.OCALLPART) + + // Return a new selector expression referring + // to the newly stenciled function. + oldse := inst.X.(*ir.SelectorExpr) + newse := ir.NewSelectorExpr(oldse.Pos(), ir.OCALLPART, oldse.X, oldse.Sel) + newse.Selection = types.NewField(oldse.Pos(), st.Sym(), st.Type()) + newse.Selection.Nname = st + typed(inst.Type(), newse) + return newse } ir.EditChildren(x, edit) return x diff --git a/test/typeparam/issue45817.go b/test/typeparam/issue45817.go new file mode 100644 index 00000000000..744698f40be --- /dev/null +++ b/test/typeparam/issue45817.go @@ -0,0 +1,25 @@ +// run -gcflags=-G=3 + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" +) + +type s[T any] struct { + a T +} +func (x s[T]) f() T { + return x.a +} +func main() { + x := s[int]{a:7} + f := x.f + if got, want := f(), 7; got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } +} From 2c76a6f7f85365cefb5200b2b3408fd6bd421b3d Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 12 May 2021 17:55:42 +0200 Subject: [PATCH 037/940] all: add //go:build lines to assembly files Don't add them to files in vendor and cmd/vendor though. These will be pulled in by updating the respective dependencies. For #41184 Change-Id: Icc57458c9b3033c347124323f33084c85b224c70 Reviewed-on: https://go-review.googlesource.com/c/go/+/319389 Trust: Tobias Klauser Run-TryBot: Tobias Klauser TryBot-Result: Go Bot Reviewed-by: Russ Cox --- src/cmd/compile/internal/ssa/flags_amd64_test.s | 2 -- src/cmd/compile/internal/ssa/flags_arm64_test.s | 2 -- src/cmd/dist/vfp_arm.s | 3 ++- src/cmd/dist/vfp_default.s | 3 ++- src/crypto/cipher/xor_ppc64x.s | 1 + src/crypto/md5/md5block_ppc64x.s | 1 + src/crypto/x509/internal/macos/corefoundation.s | 1 + src/crypto/x509/internal/macos/security.s | 1 + src/internal/bytealg/compare_mips64x.s | 1 + src/internal/bytealg/compare_mipsx.s | 1 + src/internal/bytealg/compare_ppc64x.s | 1 + src/internal/bytealg/count_ppc64x.s | 1 + src/internal/bytealg/equal_mips64x.s | 1 + src/internal/bytealg/equal_mipsx.s | 1 + src/internal/bytealg/equal_ppc64x.s | 1 + src/internal/bytealg/index_ppc64x.s | 1 + src/internal/bytealg/indexbyte_mips64x.s | 1 + src/internal/bytealg/indexbyte_mipsx.s | 1 + src/internal/bytealg/indexbyte_ppc64x.s | 1 + src/internal/cpu/cpu_x86.s | 1 + src/math/big/arith_386.s | 1 + src/math/big/arith_amd64.s | 1 + src/math/big/arith_arm.s | 1 + src/math/big/arith_arm64.s | 1 + src/math/big/arith_mips64x.s | 4 +++- src/math/big/arith_mipsx.s | 4 +++- src/math/big/arith_ppc64x.s | 4 +++- src/math/big/arith_riscv64.s | 1 + src/math/big/arith_s390x.s | 3 ++- src/math/big/arith_wasm.s | 1 + src/math/floor_ppc64x.s | 1 + src/math/modf_ppc64x.s | 1 + src/math/sqrt_mipsx.s | 1 + src/math/sqrt_ppc64x.s | 1 + src/math/sqrt_riscv64.s | 2 -- src/reflect/asm_mips64x.s | 1 + src/reflect/asm_mipsx.s | 1 + src/reflect/asm_ppc64x.s | 1 + src/runtime/asm_mips64x.s | 1 + src/runtime/asm_mipsx.s | 1 + src/runtime/asm_ppc64x.s | 1 + src/runtime/atomic_mips64x.s | 1 + src/runtime/atomic_mipsx.s | 1 + src/runtime/atomic_ppc64x.s | 1 + src/runtime/cgo/asm_mips64x.s | 1 + src/runtime/cgo/asm_mipsx.s | 1 + src/runtime/cgo/asm_ppc64x.s | 1 + src/runtime/cgo/asm_riscv64.s | 2 -- src/runtime/duff_mips64x.s | 1 + src/runtime/duff_ppc64x.s | 1 + src/runtime/internal/atomic/atomic_mips64x.s | 1 + src/runtime/internal/atomic/atomic_mipsx.s | 1 + src/runtime/internal/atomic/atomic_ppc64x.s | 2 +- src/runtime/internal/atomic/sys_nonlinux_arm.s | 3 ++- src/runtime/libfuzzer_amd64.s | 1 + src/runtime/libfuzzer_arm64.s | 1 + src/runtime/memclr_386.s | 1 + src/runtime/memclr_amd64.s | 1 + src/runtime/memclr_mips64x.s | 1 + src/runtime/memclr_mipsx.s | 1 + src/runtime/memclr_ppc64x.s | 1 + src/runtime/memmove_386.s | 1 + src/runtime/memmove_amd64.s | 1 + src/runtime/memmove_mips64x.s | 1 + src/runtime/memmove_mipsx.s | 1 + src/runtime/memmove_ppc64x.s | 1 + src/runtime/mkduff.go | 2 ++ src/runtime/mkpreempt.go | 1 + src/runtime/msan_amd64.s | 1 + src/runtime/msan_arm64.s | 1 + src/runtime/preempt_mips64x.s | 1 + src/runtime/preempt_mipsx.s | 1 + src/runtime/preempt_ppc64x.s | 1 + src/runtime/race_amd64.s | 1 + src/runtime/race_arm64.s | 1 + src/runtime/race_ppc64le.s | 1 + src/runtime/rt0_linux_mips64x.s | 1 + src/runtime/rt0_linux_mipsx.s | 1 + src/runtime/sys_aix_ppc64.s | 3 --- src/runtime/sys_linux_mips64x.s | 1 + src/runtime/sys_linux_mipsx.s | 1 + src/runtime/sys_linux_ppc64x.s | 1 + src/runtime/tls_arm.s | 1 + src/runtime/tls_mips64x.s | 1 + src/runtime/tls_mipsx.s | 1 + src/runtime/tls_ppc64x.s | 1 + src/runtime/wincallback.go | 2 ++ src/runtime/zcallback_windows.s | 2 ++ src/sync/atomic/asm.s | 1 + src/sync/atomic/race.s | 1 + 90 files changed, 98 insertions(+), 19 deletions(-) diff --git a/src/cmd/compile/internal/ssa/flags_amd64_test.s b/src/cmd/compile/internal/ssa/flags_amd64_test.s index 8bd87019af7..7402f6badb1 100644 --- a/src/cmd/compile/internal/ssa/flags_amd64_test.s +++ b/src/cmd/compile/internal/ssa/flags_amd64_test.s @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build amd64 - #include "textflag.h" TEXT ·asmAddFlags(SB),NOSPLIT,$0-24 diff --git a/src/cmd/compile/internal/ssa/flags_arm64_test.s b/src/cmd/compile/internal/ssa/flags_arm64_test.s index f201bcc9943..639d7e3aedc 100644 --- a/src/cmd/compile/internal/ssa/flags_arm64_test.s +++ b/src/cmd/compile/internal/ssa/flags_arm64_test.s @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build arm64 - #include "textflag.h" TEXT ·asmAddFlags(SB),NOSPLIT,$0-24 diff --git a/src/cmd/dist/vfp_arm.s b/src/cmd/dist/vfp_arm.s index d571f8b82a2..525ee9b3661 100644 --- a/src/cmd/dist/vfp_arm.s +++ b/src/cmd/dist/vfp_arm.s @@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build gc,arm +//go:build gc +// +build gc #include "textflag.h" diff --git a/src/cmd/dist/vfp_default.s b/src/cmd/dist/vfp_default.s index 84829beeff3..0c1e16b0aa0 100644 --- a/src/cmd/dist/vfp_default.s +++ b/src/cmd/dist/vfp_default.s @@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !arm,gc +//go:build gc && !arm +// +build gc,!arm #include "textflag.h" diff --git a/src/crypto/cipher/xor_ppc64x.s b/src/crypto/cipher/xor_ppc64x.s index 4cef31d0ee3..2ba6d9639c4 100644 --- a/src/crypto/cipher/xor_ppc64x.s +++ b/src/crypto/cipher/xor_ppc64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le #include "textflag.h" diff --git a/src/crypto/md5/md5block_ppc64x.s b/src/crypto/md5/md5block_ppc64x.s index e1f859e3376..8c28ec2473c 100644 --- a/src/crypto/md5/md5block_ppc64x.s +++ b/src/crypto/md5/md5block_ppc64x.s @@ -10,6 +10,7 @@ // Licence: I hereby disclaim the copyright on this code and place it // in the public domain. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le #include "textflag.h" diff --git a/src/crypto/x509/internal/macos/corefoundation.s b/src/crypto/x509/internal/macos/corefoundation.s index a9efaa299d8..cda2336c9d1 100644 --- a/src/crypto/x509/internal/macos/corefoundation.s +++ b/src/crypto/x509/internal/macos/corefoundation.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin && !ios // +build darwin,!ios #include "textflag.h" diff --git a/src/crypto/x509/internal/macos/security.s b/src/crypto/x509/internal/macos/security.s index 09ce5c6c769..0038f25b277 100644 --- a/src/crypto/x509/internal/macos/security.s +++ b/src/crypto/x509/internal/macos/security.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin && !ios // +build darwin,!ios #include "textflag.h" diff --git a/src/internal/bytealg/compare_mips64x.s b/src/internal/bytealg/compare_mips64x.s index 4f05fceaca5..b472e510bce 100644 --- a/src/internal/bytealg/compare_mips64x.s +++ b/src/internal/bytealg/compare_mips64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips64 || mips64le // +build mips64 mips64le #include "go_asm.h" diff --git a/src/internal/bytealg/compare_mipsx.s b/src/internal/bytealg/compare_mipsx.s index 9ac5ba56877..dcc4916e567 100644 --- a/src/internal/bytealg/compare_mipsx.s +++ b/src/internal/bytealg/compare_mipsx.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips || mipsle // +build mips mipsle #include "go_asm.h" diff --git a/src/internal/bytealg/compare_ppc64x.s b/src/internal/bytealg/compare_ppc64x.s index 7819da31cd0..83444fa8260 100644 --- a/src/internal/bytealg/compare_ppc64x.s +++ b/src/internal/bytealg/compare_ppc64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le #include "go_asm.h" diff --git a/src/internal/bytealg/count_ppc64x.s b/src/internal/bytealg/count_ppc64x.s index a64d7d792d0..94163cbd8a3 100644 --- a/src/internal/bytealg/count_ppc64x.s +++ b/src/internal/bytealg/count_ppc64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64le || ppc64 // +build ppc64le ppc64 #include "go_asm.h" diff --git a/src/internal/bytealg/equal_mips64x.s b/src/internal/bytealg/equal_mips64x.s index 641e3ff06ca..c2f7d3997ed 100644 --- a/src/internal/bytealg/equal_mips64x.s +++ b/src/internal/bytealg/equal_mips64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips64 || mips64le // +build mips64 mips64le #include "go_asm.h" diff --git a/src/internal/bytealg/equal_mipsx.s b/src/internal/bytealg/equal_mipsx.s index 1cabc70178b..11e5549e45a 100644 --- a/src/internal/bytealg/equal_mipsx.s +++ b/src/internal/bytealg/equal_mipsx.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips || mipsle // +build mips mipsle #include "go_asm.h" diff --git a/src/internal/bytealg/equal_ppc64x.s b/src/internal/bytealg/equal_ppc64x.s index 18171eaedc9..5f0fea521b2 100644 --- a/src/internal/bytealg/equal_ppc64x.s +++ b/src/internal/bytealg/equal_ppc64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le #include "go_asm.h" diff --git a/src/internal/bytealg/index_ppc64x.s b/src/internal/bytealg/index_ppc64x.s index b7a1e2d7a22..3ed94421256 100644 --- a/src/internal/bytealg/index_ppc64x.s +++ b/src/internal/bytealg/index_ppc64x.s @@ -21,6 +21,7 @@ // work is still needed for a big endian // implementation on power9. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le #include "go_asm.h" diff --git a/src/internal/bytealg/indexbyte_mips64x.s b/src/internal/bytealg/indexbyte_mips64x.s index 6ebf0dee24b..0f377f5a4c9 100644 --- a/src/internal/bytealg/indexbyte_mips64x.s +++ b/src/internal/bytealg/indexbyte_mips64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips64 || mips64le // +build mips64 mips64le #include "go_asm.h" diff --git a/src/internal/bytealg/indexbyte_mipsx.s b/src/internal/bytealg/indexbyte_mipsx.s index e44440b5f9e..bed015bbd6b 100644 --- a/src/internal/bytealg/indexbyte_mipsx.s +++ b/src/internal/bytealg/indexbyte_mipsx.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips || mipsle // +build mips mipsle #include "go_asm.h" diff --git a/src/internal/bytealg/indexbyte_ppc64x.s b/src/internal/bytealg/indexbyte_ppc64x.s index 6e14e80af13..8e13c5a56e3 100644 --- a/src/internal/bytealg/indexbyte_ppc64x.s +++ b/src/internal/bytealg/indexbyte_ppc64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le #include "go_asm.h" diff --git a/src/internal/cpu/cpu_x86.s b/src/internal/cpu/cpu_x86.s index 93c712d784c..0df5da1cc74 100644 --- a/src/internal/cpu/cpu_x86.s +++ b/src/internal/cpu/cpu_x86.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build 386 || amd64 // +build 386 amd64 #include "textflag.h" diff --git a/src/math/big/arith_386.s b/src/math/big/arith_386.s index d0ea949fe66..acf2b06665a 100644 --- a/src/math/big/arith_386.s +++ b/src/math/big/arith_386.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !math_big_pure_go // +build !math_big_pure_go #include "textflag.h" diff --git a/src/math/big/arith_amd64.s b/src/math/big/arith_amd64.s index 61043ca2d97..59be952200f 100644 --- a/src/math/big/arith_amd64.s +++ b/src/math/big/arith_amd64.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !math_big_pure_go // +build !math_big_pure_go #include "textflag.h" diff --git a/src/math/big/arith_arm.s b/src/math/big/arith_arm.s index cbf7445e7ab..f2872d80a1a 100644 --- a/src/math/big/arith_arm.s +++ b/src/math/big/arith_arm.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !math_big_pure_go // +build !math_big_pure_go #include "textflag.h" diff --git a/src/math/big/arith_arm64.s b/src/math/big/arith_arm64.s index 22357d088e4..7bfe08e7b7c 100644 --- a/src/math/big/arith_arm64.s +++ b/src/math/big/arith_arm64.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !math_big_pure_go // +build !math_big_pure_go #include "textflag.h" diff --git a/src/math/big/arith_mips64x.s b/src/math/big/arith_mips64x.s index 804b9fe06ed..4b5c502440f 100644 --- a/src/math/big/arith_mips64x.s +++ b/src/math/big/arith_mips64x.s @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !math_big_pure_go,mips64 !math_big_pure_go,mips64le +//go:build !math_big_pure_go && (mips64 || mips64le) +// +build !math_big_pure_go +// +build mips64 mips64le #include "textflag.h" diff --git a/src/math/big/arith_mipsx.s b/src/math/big/arith_mipsx.s index efdecb80f32..e72e6d6377e 100644 --- a/src/math/big/arith_mipsx.s +++ b/src/math/big/arith_mipsx.s @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !math_big_pure_go,mips !math_big_pure_go,mipsle +//go:build !math_big_pure_go && (mips || mipsle) +// +build !math_big_pure_go +// +build mips mipsle #include "textflag.h" diff --git a/src/math/big/arith_ppc64x.s b/src/math/big/arith_ppc64x.s index b299ccc2fb8..68c62864946 100644 --- a/src/math/big/arith_ppc64x.s +++ b/src/math/big/arith_ppc64x.s @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !math_big_pure_go,ppc64 !math_big_pure_go,ppc64le +//go:build !math_big_pure_go && (ppc64 || ppc64le) +// +build !math_big_pure_go +// +build ppc64 ppc64le #include "textflag.h" diff --git a/src/math/big/arith_riscv64.s b/src/math/big/arith_riscv64.s index a2f7666c7b9..2e950ddd0f3 100644 --- a/src/math/big/arith_riscv64.s +++ b/src/math/big/arith_riscv64.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !math_big_pure_go && riscv64 // +build !math_big_pure_go,riscv64 #include "textflag.h" diff --git a/src/math/big/arith_s390x.s b/src/math/big/arith_s390x.s index e96480699af..ad822f76b39 100644 --- a/src/math/big/arith_s390x.s +++ b/src/math/big/arith_s390x.s @@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !math_big_pure_go,s390x +//go:build !math_big_pure_go +// +build !math_big_pure_go #include "textflag.h" diff --git a/src/math/big/arith_wasm.s b/src/math/big/arith_wasm.s index add10644690..e8605f1e153 100644 --- a/src/math/big/arith_wasm.s +++ b/src/math/big/arith_wasm.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !math_big_pure_go // +build !math_big_pure_go #include "textflag.h" diff --git a/src/math/floor_ppc64x.s b/src/math/floor_ppc64x.s index 29b92a62c34..584c27e28f6 100644 --- a/src/math/floor_ppc64x.s +++ b/src/math/floor_ppc64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le #include "textflag.h" diff --git a/src/math/modf_ppc64x.s b/src/math/modf_ppc64x.s index caa435eef91..1303067661c 100644 --- a/src/math/modf_ppc64x.s +++ b/src/math/modf_ppc64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le #include "textflag.h" diff --git a/src/math/sqrt_mipsx.s b/src/math/sqrt_mipsx.s index c619c19ec22..291d4af39cf 100644 --- a/src/math/sqrt_mipsx.s +++ b/src/math/sqrt_mipsx.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips || mipsle // +build mips mipsle #include "textflag.h" diff --git a/src/math/sqrt_ppc64x.s b/src/math/sqrt_ppc64x.s index 174b63e35a5..c929da2159a 100644 --- a/src/math/sqrt_ppc64x.s +++ b/src/math/sqrt_ppc64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le #include "textflag.h" diff --git a/src/math/sqrt_riscv64.s b/src/math/sqrt_riscv64.s index f223510c424..0dbdbc99ed6 100644 --- a/src/math/sqrt_riscv64.s +++ b/src/math/sqrt_riscv64.s @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build riscv64 - #include "textflag.h" // func archSqrt(x float64) float64 diff --git a/src/reflect/asm_mips64x.s b/src/reflect/asm_mips64x.s index ae661262cb4..8d01c5fb7ed 100644 --- a/src/reflect/asm_mips64x.s +++ b/src/reflect/asm_mips64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips64 || mips64le // +build mips64 mips64le #include "textflag.h" diff --git a/src/reflect/asm_mipsx.s b/src/reflect/asm_mipsx.s index 47fef844a19..6ea82331084 100644 --- a/src/reflect/asm_mipsx.s +++ b/src/reflect/asm_mipsx.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips || mipsle // +build mips mipsle #include "textflag.h" diff --git a/src/reflect/asm_ppc64x.s b/src/reflect/asm_ppc64x.s index 010811c31a5..d955e4110f8 100644 --- a/src/reflect/asm_ppc64x.s +++ b/src/reflect/asm_ppc64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le #include "textflag.h" diff --git a/src/runtime/asm_mips64x.s b/src/runtime/asm_mips64x.s index c3b57e472a2..d4d22801055 100644 --- a/src/runtime/asm_mips64x.s +++ b/src/runtime/asm_mips64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips64 || mips64le // +build mips64 mips64le #include "go_asm.h" diff --git a/src/runtime/asm_mipsx.s b/src/runtime/asm_mipsx.s index 1d828b03cfb..ea7edf20cf9 100644 --- a/src/runtime/asm_mipsx.s +++ b/src/runtime/asm_mipsx.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips || mipsle // +build mips mipsle #include "go_asm.h" diff --git a/src/runtime/asm_ppc64x.s b/src/runtime/asm_ppc64x.s index 2c39b38912f..942cc14f17d 100644 --- a/src/runtime/asm_ppc64x.s +++ b/src/runtime/asm_ppc64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le #include "go_asm.h" diff --git a/src/runtime/atomic_mips64x.s b/src/runtime/atomic_mips64x.s index 6f42412502b..e2118e6a20b 100644 --- a/src/runtime/atomic_mips64x.s +++ b/src/runtime/atomic_mips64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips64 || mips64le // +build mips64 mips64le #include "textflag.h" diff --git a/src/runtime/atomic_mipsx.s b/src/runtime/atomic_mipsx.s index ed078a2d8a6..1eacd273b44 100644 --- a/src/runtime/atomic_mipsx.s +++ b/src/runtime/atomic_mipsx.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips || mipsle // +build mips mipsle #include "textflag.h" diff --git a/src/runtime/atomic_ppc64x.s b/src/runtime/atomic_ppc64x.s index 57f672f3301..b63de2dbd31 100644 --- a/src/runtime/atomic_ppc64x.s +++ b/src/runtime/atomic_ppc64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le #include "textflag.h" diff --git a/src/runtime/cgo/asm_mips64x.s b/src/runtime/cgo/asm_mips64x.s index e51cdf3d127..ba948071fa9 100644 --- a/src/runtime/cgo/asm_mips64x.s +++ b/src/runtime/cgo/asm_mips64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips64 || mips64le // +build mips64 mips64le #include "textflag.h" diff --git a/src/runtime/cgo/asm_mipsx.s b/src/runtime/cgo/asm_mipsx.s index 1127c8beb48..fd5d78ef97a 100644 --- a/src/runtime/cgo/asm_mipsx.s +++ b/src/runtime/cgo/asm_mipsx.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips || mipsle // +build mips mipsle #include "textflag.h" diff --git a/src/runtime/cgo/asm_ppc64x.s b/src/runtime/cgo/asm_ppc64x.s index f4efc1e67d6..9dec8d04ce1 100644 --- a/src/runtime/cgo/asm_ppc64x.s +++ b/src/runtime/cgo/asm_ppc64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le #include "textflag.h" diff --git a/src/runtime/cgo/asm_riscv64.s b/src/runtime/cgo/asm_riscv64.s index b4ddbb020f0..fcd1d36ca84 100644 --- a/src/runtime/cgo/asm_riscv64.s +++ b/src/runtime/cgo/asm_riscv64.s @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build riscv64 - #include "textflag.h" // Called by C code generated by cmd/cgo. diff --git a/src/runtime/duff_mips64x.s b/src/runtime/duff_mips64x.s index c4e04ccc9da..a897d7fd9bf 100644 --- a/src/runtime/duff_mips64x.s +++ b/src/runtime/duff_mips64x.s @@ -2,6 +2,7 @@ // Run go generate from src/runtime to update. // See mkduff.go for comments. +//go:build mips64 || mips64le // +build mips64 mips64le #include "textflag.h" diff --git a/src/runtime/duff_ppc64x.s b/src/runtime/duff_ppc64x.s index d6b89ba9401..d4e3b409d24 100644 --- a/src/runtime/duff_ppc64x.s +++ b/src/runtime/duff_ppc64x.s @@ -2,6 +2,7 @@ // Run go generate from src/runtime to update. // See mkduff.go for comments. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le #include "textflag.h" diff --git a/src/runtime/internal/atomic/atomic_mips64x.s b/src/runtime/internal/atomic/atomic_mips64x.s index 2751c6f8082..fba668f94a8 100644 --- a/src/runtime/internal/atomic/atomic_mips64x.s +++ b/src/runtime/internal/atomic/atomic_mips64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips64 || mips64le // +build mips64 mips64le #include "textflag.h" diff --git a/src/runtime/internal/atomic/atomic_mipsx.s b/src/runtime/internal/atomic/atomic_mipsx.s index 3f613214507..c0835d66ed8 100644 --- a/src/runtime/internal/atomic/atomic_mipsx.s +++ b/src/runtime/internal/atomic/atomic_mipsx.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips || mipsle // +build mips mipsle #include "textflag.h" diff --git a/src/runtime/internal/atomic/atomic_ppc64x.s b/src/runtime/internal/atomic/atomic_ppc64x.s index 37c8515d37e..dca26cb334a 100644 --- a/src/runtime/internal/atomic/atomic_ppc64x.s +++ b/src/runtime/internal/atomic/atomic_ppc64x.s @@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le #include "textflag.h" - // For more details about how various memory models are // enforced on POWER, the following paper provides more // details about how they enforce C/C++ like models. This diff --git a/src/runtime/internal/atomic/sys_nonlinux_arm.s b/src/runtime/internal/atomic/sys_nonlinux_arm.s index 57568b2238d..04036ca9702 100644 --- a/src/runtime/internal/atomic/sys_nonlinux_arm.s +++ b/src/runtime/internal/atomic/sys_nonlinux_arm.s @@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !linux,arm +//go:build !linux +// +build !linux #include "textflag.h" diff --git a/src/runtime/libfuzzer_amd64.s b/src/runtime/libfuzzer_amd64.s index 890fde341bc..13645fc7af8 100644 --- a/src/runtime/libfuzzer_amd64.s +++ b/src/runtime/libfuzzer_amd64.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build libfuzzer // +build libfuzzer #include "go_asm.h" diff --git a/src/runtime/libfuzzer_arm64.s b/src/runtime/libfuzzer_arm64.s index 121673e0922..4ad8242804e 100644 --- a/src/runtime/libfuzzer_arm64.s +++ b/src/runtime/libfuzzer_arm64.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build libfuzzer // +build libfuzzer #include "go_asm.h" diff --git a/src/runtime/memclr_386.s b/src/runtime/memclr_386.s index d2ef17f7cee..046c3441198 100644 --- a/src/runtime/memclr_386.s +++ b/src/runtime/memclr_386.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !plan9 // +build !plan9 #include "go_asm.h" diff --git a/src/runtime/memclr_amd64.s b/src/runtime/memclr_amd64.s index 5d2bebb901b..a10f57bd8cb 100644 --- a/src/runtime/memclr_amd64.s +++ b/src/runtime/memclr_amd64.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !plan9 // +build !plan9 #include "go_asm.h" diff --git a/src/runtime/memclr_mips64x.s b/src/runtime/memclr_mips64x.s index d7a3251e204..bc037013fe7 100644 --- a/src/runtime/memclr_mips64x.s +++ b/src/runtime/memclr_mips64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips64 || mips64le // +build mips64 mips64le #include "go_asm.h" diff --git a/src/runtime/memclr_mipsx.s b/src/runtime/memclr_mipsx.s index eb2a8a7219c..3d21c3c414c 100644 --- a/src/runtime/memclr_mipsx.s +++ b/src/runtime/memclr_mipsx.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips || mipsle // +build mips mipsle #include "textflag.h" diff --git a/src/runtime/memclr_ppc64x.s b/src/runtime/memclr_ppc64x.s index 75126208942..65639322b2a 100644 --- a/src/runtime/memclr_ppc64x.s +++ b/src/runtime/memclr_ppc64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le #include "textflag.h" diff --git a/src/runtime/memmove_386.s b/src/runtime/memmove_386.s index d99546c6336..1a43a1f724d 100644 --- a/src/runtime/memmove_386.s +++ b/src/runtime/memmove_386.s @@ -23,6 +23,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +//go:build !plan9 // +build !plan9 #include "go_asm.h" diff --git a/src/runtime/memmove_amd64.s b/src/runtime/memmove_amd64.s index f1e34035962..24c6529f584 100644 --- a/src/runtime/memmove_amd64.s +++ b/src/runtime/memmove_amd64.s @@ -23,6 +23,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +//go:build !plan9 // +build !plan9 #include "go_asm.h" diff --git a/src/runtime/memmove_mips64x.s b/src/runtime/memmove_mips64x.s index 8a1b88afba7..fef3c6be827 100644 --- a/src/runtime/memmove_mips64x.s +++ b/src/runtime/memmove_mips64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips64 || mips64le // +build mips64 mips64le #include "textflag.h" diff --git a/src/runtime/memmove_mipsx.s b/src/runtime/memmove_mipsx.s index 6c86558f8d2..cd02fc25c4b 100644 --- a/src/runtime/memmove_mipsx.s +++ b/src/runtime/memmove_mipsx.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips || mipsle // +build mips mipsle #include "textflag.h" diff --git a/src/runtime/memmove_ppc64x.s b/src/runtime/memmove_ppc64x.s index dbd835506f6..fd16ad8129b 100644 --- a/src/runtime/memmove_ppc64x.s +++ b/src/runtime/memmove_ppc64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le #include "textflag.h" diff --git a/src/runtime/mkduff.go b/src/runtime/mkduff.go index 8632fe08a3d..da191cc594c 100644 --- a/src/runtime/mkduff.go +++ b/src/runtime/mkduff.go @@ -179,6 +179,7 @@ func copyARM64(w io.Writer) { func tagsPPC64x(w io.Writer) { fmt.Fprintln(w) + fmt.Fprintln(w, "//go:build ppc64 || ppc64le") fmt.Fprintln(w, "// +build ppc64 ppc64le") fmt.Fprintln(w) } @@ -202,6 +203,7 @@ func copyPPC64x(w io.Writer) { func tagsMIPS64x(w io.Writer) { fmt.Fprintln(w) + fmt.Fprintln(w, "//go:build mips64 || mips64le") fmt.Fprintln(w, "// +build mips64 mips64le") fmt.Fprintln(w) } diff --git a/src/runtime/mkpreempt.go b/src/runtime/mkpreempt.go index 3a9e6cc4780..6c980540f57 100644 --- a/src/runtime/mkpreempt.go +++ b/src/runtime/mkpreempt.go @@ -123,6 +123,7 @@ func header(arch string) { fmt.Fprintf(out, "// Code generated by mkpreempt.go; DO NOT EDIT.\n\n") if beLe[arch] { base := arch[:len(arch)-1] + fmt.Fprintf(out, "//go:build %s || %sle\n", base, base) fmt.Fprintf(out, "// +build %s %sle\n\n", base, base) } fmt.Fprintf(out, "#include \"go_asm.h\"\n") diff --git a/src/runtime/msan_amd64.s b/src/runtime/msan_amd64.s index 669e9ca73f8..1bb57a3b7e8 100644 --- a/src/runtime/msan_amd64.s +++ b/src/runtime/msan_amd64.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build msan // +build msan #include "go_asm.h" diff --git a/src/runtime/msan_arm64.s b/src/runtime/msan_arm64.s index f19906cfc83..93ade8dd897 100644 --- a/src/runtime/msan_arm64.s +++ b/src/runtime/msan_arm64.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build msan // +build msan #include "go_asm.h" diff --git a/src/runtime/preempt_mips64x.s b/src/runtime/preempt_mips64x.s index 0d0c157c36c..b755425bc5d 100644 --- a/src/runtime/preempt_mips64x.s +++ b/src/runtime/preempt_mips64x.s @@ -1,5 +1,6 @@ // Code generated by mkpreempt.go; DO NOT EDIT. +//go:build mips64 || mips64le // +build mips64 mips64le #include "go_asm.h" diff --git a/src/runtime/preempt_mipsx.s b/src/runtime/preempt_mipsx.s index 86d3a918d33..c1bff608596 100644 --- a/src/runtime/preempt_mipsx.s +++ b/src/runtime/preempt_mipsx.s @@ -1,5 +1,6 @@ // Code generated by mkpreempt.go; DO NOT EDIT. +//go:build mips || mipsle // +build mips mipsle #include "go_asm.h" diff --git a/src/runtime/preempt_ppc64x.s b/src/runtime/preempt_ppc64x.s index 90634386dbf..70bd91982bf 100644 --- a/src/runtime/preempt_ppc64x.s +++ b/src/runtime/preempt_ppc64x.s @@ -1,5 +1,6 @@ // Code generated by mkpreempt.go; DO NOT EDIT. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le #include "go_asm.h" diff --git a/src/runtime/race_amd64.s b/src/runtime/race_amd64.s index 58a919efe8d..8d4813eaddd 100644 --- a/src/runtime/race_amd64.s +++ b/src/runtime/race_amd64.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build race // +build race #include "go_asm.h" diff --git a/src/runtime/race_arm64.s b/src/runtime/race_arm64.s index 82e3caadc8f..c6d5b91edc0 100644 --- a/src/runtime/race_arm64.s +++ b/src/runtime/race_arm64.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build race // +build race #include "go_asm.h" diff --git a/src/runtime/race_ppc64le.s b/src/runtime/race_ppc64le.s index 069e4d86dd4..963e57099c9 100644 --- a/src/runtime/race_ppc64le.s +++ b/src/runtime/race_ppc64le.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build race // +build race #include "go_asm.h" diff --git a/src/runtime/rt0_linux_mips64x.s b/src/runtime/rt0_linux_mips64x.s index 55506755df2..fabd8570b57 100644 --- a/src/runtime/rt0_linux_mips64x.s +++ b/src/runtime/rt0_linux_mips64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (mips64 || mips64le) // +build linux // +build mips64 mips64le diff --git a/src/runtime/rt0_linux_mipsx.s b/src/runtime/rt0_linux_mipsx.s index 74b8f50b73f..9f5842b51a2 100644 --- a/src/runtime/rt0_linux_mipsx.s +++ b/src/runtime/rt0_linux_mipsx.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (mips || mipsle) // +build linux // +build mips mipsle diff --git a/src/runtime/sys_aix_ppc64.s b/src/runtime/sys_aix_ppc64.s index a56d043f425..c171c191c0e 100644 --- a/src/runtime/sys_aix_ppc64.s +++ b/src/runtime/sys_aix_ppc64.s @@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build aix -// +build ppc64 ppc64le - // // System calls and other sys.stuff for ppc64, Aix // diff --git a/src/runtime/sys_linux_mips64x.s b/src/runtime/sys_linux_mips64x.s index 0206cb88bd4..e18d2914456 100644 --- a/src/runtime/sys_linux_mips64x.s +++ b/src/runtime/sys_linux_mips64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (mips64 || mips64le) // +build linux // +build mips64 mips64le diff --git a/src/runtime/sys_linux_mipsx.s b/src/runtime/sys_linux_mipsx.s index d5317d39570..b3970be9cf8 100644 --- a/src/runtime/sys_linux_mipsx.s +++ b/src/runtime/sys_linux_mipsx.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (mips || mipsle) // +build linux // +build mips mipsle diff --git a/src/runtime/sys_linux_ppc64x.s b/src/runtime/sys_linux_ppc64x.s index 46387288d53..05b5916db41 100644 --- a/src/runtime/sys_linux_ppc64x.s +++ b/src/runtime/sys_linux_ppc64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (ppc64 || ppc64le) // +build linux // +build ppc64 ppc64le diff --git a/src/runtime/tls_arm.s b/src/runtime/tls_arm.s index e42de8deb4f..879caac9e16 100644 --- a/src/runtime/tls_arm.s +++ b/src/runtime/tls_arm.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !windows // +build !windows #include "go_asm.h" diff --git a/src/runtime/tls_mips64x.s b/src/runtime/tls_mips64x.s index 888c0efec6a..779d64ba31a 100644 --- a/src/runtime/tls_mips64x.s +++ b/src/runtime/tls_mips64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips64 || mips64le // +build mips64 mips64le #include "go_asm.h" diff --git a/src/runtime/tls_mipsx.s b/src/runtime/tls_mipsx.s index d2ffcd954c9..ada8d06a9e7 100644 --- a/src/runtime/tls_mipsx.s +++ b/src/runtime/tls_mipsx.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips || mipsle // +build mips mipsle #include "go_asm.h" diff --git a/src/runtime/tls_ppc64x.s b/src/runtime/tls_ppc64x.s index 25d796fcc6e..7e935d0eb29 100644 --- a/src/runtime/tls_ppc64x.s +++ b/src/runtime/tls_ppc64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le #include "go_asm.h" diff --git a/src/runtime/wincallback.go b/src/runtime/wincallback.go index 8411c98412d..a7a787d8f6d 100644 --- a/src/runtime/wincallback.go +++ b/src/runtime/wincallback.go @@ -22,7 +22,9 @@ func genasm386Amd64() { buf.WriteString(`// Code generated by wincallback.go using 'go generate'. DO NOT EDIT. +//go:build 386 || amd64 // +build 386 amd64 + // runtime·callbackasm is called by external code to // execute Go implemented callback function. It is not // called from the start, instead runtime·compilecallback diff --git a/src/runtime/zcallback_windows.s b/src/runtime/zcallback_windows.s index 37ffb38aca5..e451c2b9d05 100644 --- a/src/runtime/zcallback_windows.s +++ b/src/runtime/zcallback_windows.s @@ -1,6 +1,8 @@ // Code generated by wincallback.go using 'go generate'. DO NOT EDIT. +//go:build 386 || amd64 // +build 386 amd64 + // runtime·callbackasm is called by external code to // execute Go implemented callback function. It is not // called from the start, instead runtime·compilecallback diff --git a/src/sync/atomic/asm.s b/src/sync/atomic/asm.s index f86726f3a1a..7b8c9b9430e 100644 --- a/src/sync/atomic/asm.s +++ b/src/sync/atomic/asm.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !race // +build !race #include "textflag.h" diff --git a/src/sync/atomic/race.s b/src/sync/atomic/race.s index fd6ca22700c..0866487cc71 100644 --- a/src/sync/atomic/race.s +++ b/src/sync/atomic/race.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build race // +build race // This file is here only to allow external functions. From 0fa2302ee5db35b4caae6211656f81ebb92cdb0a Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 12 May 2021 18:07:43 +0200 Subject: [PATCH 038/940] cmd/vendor: update golang.org/x/sys to latest To pull in CL 318212. For #41184 Change-Id: Iec0d7bee2d3a5874c24a55ec20efd7746bf70902 Reviewed-on: https://go-review.googlesource.com/c/go/+/319410 Trust: Tobias Klauser Run-TryBot: Tobias Klauser TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/cmd/go.mod | 2 +- src/cmd/go.sum | 4 +- src/cmd/vendor/golang.org/x/sys/unix/mkall.sh | 12 - .../x/sys/unix/syscall_darwin.1_13.go | 4 +- .../x/sys/unix/syscall_darwin_386.go | 51 - .../x/sys/unix/syscall_darwin_arm.go | 51 - .../x/sys/unix/syscall_darwin_libSystem.go | 9 +- .../x/sys/unix/zerrors_darwin_386.go | 1789 ------------ .../x/sys/unix/zerrors_darwin_arm.go | 1789 ------------ .../x/sys/unix/zsyscall_darwin_386.1_13.go | 40 - .../x/sys/unix/zsyscall_darwin_386.1_13.s | 13 - .../x/sys/unix/zsyscall_darwin_386.go | 2431 ----------------- .../x/sys/unix/zsyscall_darwin_386.s | 291 -- .../x/sys/unix/zsyscall_darwin_amd64.1_13.go | 8 +- .../x/sys/unix/zsyscall_darwin_amd64.1_13.s | 18 +- .../x/sys/unix/zsyscall_darwin_amd64.go | 572 ++-- .../x/sys/unix/zsyscall_darwin_amd64.s | 852 +++++- .../x/sys/unix/zsyscall_darwin_arm.1_13.go | 40 - .../x/sys/unix/zsyscall_darwin_arm.1_13.s | 13 - .../x/sys/unix/zsyscall_darwin_arm.go | 2417 ---------------- .../x/sys/unix/zsyscall_darwin_arm.s | 289 -- .../x/sys/unix/zsyscall_darwin_arm64.1_13.go | 8 +- .../x/sys/unix/zsyscall_darwin_arm64.1_13.s | 18 +- .../x/sys/unix/zsyscall_darwin_arm64.go | 572 ++-- .../x/sys/unix/zsyscall_darwin_arm64.s | 852 +++++- .../x/sys/unix/zsysnum_darwin_386.go | 438 --- .../x/sys/unix/zsysnum_darwin_arm.go | 438 --- .../x/sys/unix/ztypes_darwin_386.go | 524 ---- .../x/sys/unix/ztypes_darwin_arm.go | 524 ---- .../vendor/golang.org/x/sys/windows/empty.s | 1 + src/cmd/vendor/modules.txt | 2 +- 31 files changed, 2038 insertions(+), 12034 deletions(-) delete mode 100644 src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_386.go delete mode 100644 src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_arm.go delete mode 100644 src/cmd/vendor/golang.org/x/sys/unix/zerrors_darwin_386.go delete mode 100644 src/cmd/vendor/golang.org/x/sys/unix/zerrors_darwin_arm.go delete mode 100644 src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.1_13.go delete mode 100644 src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.1_13.s delete mode 100644 src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.go delete mode 100644 src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.s delete mode 100644 src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.1_13.go delete mode 100644 src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.1_13.s delete mode 100644 src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.go delete mode 100644 src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.s delete mode 100644 src/cmd/vendor/golang.org/x/sys/unix/zsysnum_darwin_386.go delete mode 100644 src/cmd/vendor/golang.org/x/sys/unix/zsysnum_darwin_arm.go delete mode 100644 src/cmd/vendor/golang.org/x/sys/unix/ztypes_darwin_386.go delete mode 100644 src/cmd/vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go diff --git a/src/cmd/go.mod b/src/cmd/go.mod index 7a96bc64095..c3617eea0b1 100644 --- a/src/cmd/go.mod +++ b/src/cmd/go.mod @@ -8,7 +8,7 @@ require ( golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e // indirect golang.org/x/mod v0.4.3-0.20210504181020-67f1c1edc27a - golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 // indirect + golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 // indirect golang.org/x/term v0.0.0-20210503060354-a79de5458b56 golang.org/x/tools v0.1.1-0.20210505014545-7cab0ef2e9a5 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect diff --git a/src/cmd/go.sum b/src/cmd/go.sum index 1c6e2248208..f42aac70d69 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -12,8 +12,8 @@ golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5 golang.org/x/mod v0.4.3-0.20210504181020-67f1c1edc27a h1:wbpC/7Wbo5WFVox32n+KjhRRLmTLq8YW/wRlL2iVAhk= golang.org/x/mod v0.4.3-0.20210504181020-67f1c1edc27a/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 h1:cdsMqa2nXzqlgs183pHxtvoVwU7CyzaCTAUOg94af4c= -golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 h1:yhBbb4IRs2HS9PPlAg6DMC6mUOKexJBNsLf4Z+6En1Q= +golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= golang.org/x/tools v0.1.1-0.20210505014545-7cab0ef2e9a5 h1:ImcI7RFHWLu2QWpFDXaReu0j+sQAHIy65vUFZImXiqY= diff --git a/src/cmd/vendor/golang.org/x/sys/unix/mkall.sh b/src/cmd/vendor/golang.org/x/sys/unix/mkall.sh index d727cad19c1..396aadf86de 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/mkall.sh +++ b/src/cmd/vendor/golang.org/x/sys/unix/mkall.sh @@ -70,23 +70,11 @@ aix_ppc64) mksyscall="go run mksyscall_aix_ppc64.go -aix" mktypes="GOARCH=$GOARCH go tool cgo -godefs" ;; -darwin_386) - mkerrors="$mkerrors -m32" - mksyscall="go run mksyscall.go -l32" - mktypes="GOARCH=$GOARCH go tool cgo -godefs" - mkasm="go run mkasm_darwin.go" - ;; darwin_amd64) mkerrors="$mkerrors -m64" mktypes="GOARCH=$GOARCH go tool cgo -godefs" mkasm="go run mkasm_darwin.go" ;; -darwin_arm) - mkerrors="$mkerrors" - mksyscall="go run mksyscall.go -l32" - mktypes="GOARCH=$GOARCH go tool cgo -godefs" - mkasm="go run mkasm_darwin.go" - ;; darwin_arm64) mkerrors="$mkerrors -m64" mktypes="GOARCH=$GOARCH go tool cgo -godefs" diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin.1_13.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin.1_13.go index 5fc3cda6fc8..1596426b1e2 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin.1_13.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin.1_13.go @@ -17,7 +17,7 @@ import ( //sys readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno) func fdopendir(fd int) (dir uintptr, err error) { - r0, _, e1 := syscall_syscallPtr(funcPC(libc_fdopendir_trampoline), uintptr(fd), 0, 0) + r0, _, e1 := syscall_syscallPtr(libc_fdopendir_trampoline_addr, uintptr(fd), 0, 0) dir = uintptr(r0) if e1 != 0 { err = errnoErr(e1) @@ -25,7 +25,7 @@ func fdopendir(fd int) (dir uintptr, err error) { return } -func libc_fdopendir_trampoline() +var libc_fdopendir_trampoline_addr uintptr //go:cgo_import_dynamic libc_fdopendir fdopendir "/usr/lib/libSystem.B.dylib" diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_386.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_386.go deleted file mode 100644 index 64746771226..00000000000 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_386.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2009 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 386 && darwin -// +build 386,darwin - -package unix - -import "syscall" - -func setTimespec(sec, nsec int64) Timespec { - return Timespec{Sec: int32(sec), Nsec: int32(nsec)} -} - -func setTimeval(sec, usec int64) Timeval { - return Timeval{Sec: int32(sec), Usec: int32(usec)} -} - -func SetKevent(k *Kevent_t, fd, mode, flags int) { - k.Ident = uint32(fd) - k.Filter = int16(mode) - k.Flags = uint16(flags) -} - -func (iov *Iovec) SetLen(length int) { - iov.Len = uint32(length) -} - -func (msghdr *Msghdr) SetControllen(length int) { - msghdr.Controllen = uint32(length) -} - -func (msghdr *Msghdr) SetIovlen(length int) { - msghdr.Iovlen = int32(length) -} - -func (cmsg *Cmsghdr) SetLen(length int) { - cmsg.Len = uint32(length) -} - -func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) - -//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64 -//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64 -//sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64 -//sys getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT64 -//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64 -//sys ptrace1(request int, pid int, addr uintptr, data uintptr) (err error) = SYS_ptrace -//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64 -//sys Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_arm.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_arm.go deleted file mode 100644 index d30735c5d63..00000000000 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_arm.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package unix - -import "syscall" - -func ptrace1(request int, pid int, addr uintptr, data uintptr) error { - return ENOTSUP -} - -func setTimespec(sec, nsec int64) Timespec { - return Timespec{Sec: int32(sec), Nsec: int32(nsec)} -} - -func setTimeval(sec, usec int64) Timeval { - return Timeval{Sec: int32(sec), Usec: int32(usec)} -} - -func SetKevent(k *Kevent_t, fd, mode, flags int) { - k.Ident = uint32(fd) - k.Filter = int16(mode) - k.Flags = uint16(flags) -} - -func (iov *Iovec) SetLen(length int) { - iov.Len = uint32(length) -} - -func (msghdr *Msghdr) SetControllen(length int) { - msghdr.Controllen = uint32(length) -} - -func (msghdr *Msghdr) SetIovlen(length int) { - msghdr.Iovlen = int32(length) -} - -func (cmsg *Cmsghdr) SetLen(length int) { - cmsg.Len = uint32(length) -} - -func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) // sic - -//sys Fstat(fd int, stat *Stat_t) (err error) -//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) -//sys Fstatfs(fd int, stat *Statfs_t) (err error) -//sys getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT -//sys Lstat(path string, stat *Stat_t) (err error) -//sys Stat(path string, stat *Stat_t) (err error) -//sys Statfs(path string, stat *Statfs_t) (err error) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_libSystem.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_libSystem.go index 38bec300262..53c96641f81 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_libSystem.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_libSystem.go @@ -7,7 +7,7 @@ package unix -import "unsafe" +import _ "unsafe" // Implemented in the runtime package (runtime/sys_darwin.go) func syscall_syscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) @@ -25,10 +25,3 @@ func syscall_syscallPtr(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) //go:linkname syscall_rawSyscall syscall.rawSyscall //go:linkname syscall_rawSyscall6 syscall.rawSyscall6 //go:linkname syscall_syscallPtr syscall.syscallPtr - -// Find the entry point for f. See comments in runtime/proc.go for the -// function of the same name. -//go:nosplit -func funcPC(f func()) uintptr { - return **(**uintptr)(unsafe.Pointer(&f)) -} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_darwin_386.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_darwin_386.go deleted file mode 100644 index 7ee196f7fcc..00000000000 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_darwin_386.go +++ /dev/null @@ -1,1789 +0,0 @@ -// mkerrors.sh -m32 -// Code generated by the command above; see README.md. DO NOT EDIT. - -//go:build 386 && darwin -// +build 386,darwin - -// Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs -- -m32 _const.go - -package unix - -import "syscall" - -const ( - AF_APPLETALK = 0x10 - AF_CCITT = 0xa - AF_CHAOS = 0x5 - AF_CNT = 0x15 - AF_COIP = 0x14 - AF_DATAKIT = 0x9 - AF_DECnet = 0xc - AF_DLI = 0xd - AF_E164 = 0x1c - AF_ECMA = 0x8 - AF_HYLINK = 0xf - AF_IEEE80211 = 0x25 - AF_IMPLINK = 0x3 - AF_INET = 0x2 - AF_INET6 = 0x1e - AF_IPX = 0x17 - AF_ISDN = 0x1c - AF_ISO = 0x7 - AF_LAT = 0xe - AF_LINK = 0x12 - AF_LOCAL = 0x1 - AF_MAX = 0x28 - AF_NATM = 0x1f - AF_NDRV = 0x1b - AF_NETBIOS = 0x21 - AF_NS = 0x6 - AF_OSI = 0x7 - AF_PPP = 0x22 - AF_PUP = 0x4 - AF_RESERVED_36 = 0x24 - AF_ROUTE = 0x11 - AF_SIP = 0x18 - AF_SNA = 0xb - AF_SYSTEM = 0x20 - AF_SYS_CONTROL = 0x2 - AF_UNIX = 0x1 - AF_UNSPEC = 0x0 - AF_UTUN = 0x26 - ALTWERASE = 0x200 - ATTR_BIT_MAP_COUNT = 0x5 - ATTR_CMN_ACCESSMASK = 0x20000 - ATTR_CMN_ACCTIME = 0x1000 - ATTR_CMN_ADDEDTIME = 0x10000000 - ATTR_CMN_BKUPTIME = 0x2000 - ATTR_CMN_CHGTIME = 0x800 - ATTR_CMN_CRTIME = 0x200 - ATTR_CMN_DATA_PROTECT_FLAGS = 0x40000000 - ATTR_CMN_DEVID = 0x2 - ATTR_CMN_DOCUMENT_ID = 0x100000 - ATTR_CMN_ERROR = 0x20000000 - ATTR_CMN_EXTENDED_SECURITY = 0x400000 - ATTR_CMN_FILEID = 0x2000000 - ATTR_CMN_FLAGS = 0x40000 - ATTR_CMN_FNDRINFO = 0x4000 - ATTR_CMN_FSID = 0x4 - ATTR_CMN_FULLPATH = 0x8000000 - ATTR_CMN_GEN_COUNT = 0x80000 - ATTR_CMN_GRPID = 0x10000 - ATTR_CMN_GRPUUID = 0x1000000 - ATTR_CMN_MODTIME = 0x400 - ATTR_CMN_NAME = 0x1 - ATTR_CMN_NAMEDATTRCOUNT = 0x80000 - ATTR_CMN_NAMEDATTRLIST = 0x100000 - ATTR_CMN_OBJID = 0x20 - ATTR_CMN_OBJPERMANENTID = 0x40 - ATTR_CMN_OBJTAG = 0x10 - ATTR_CMN_OBJTYPE = 0x8 - ATTR_CMN_OWNERID = 0x8000 - ATTR_CMN_PARENTID = 0x4000000 - ATTR_CMN_PAROBJID = 0x80 - ATTR_CMN_RETURNED_ATTRS = 0x80000000 - ATTR_CMN_SCRIPT = 0x100 - ATTR_CMN_SETMASK = 0x41c7ff00 - ATTR_CMN_USERACCESS = 0x200000 - ATTR_CMN_UUID = 0x800000 - ATTR_CMN_VALIDMASK = 0xffffffff - ATTR_CMN_VOLSETMASK = 0x6700 - ATTR_FILE_ALLOCSIZE = 0x4 - ATTR_FILE_CLUMPSIZE = 0x10 - ATTR_FILE_DATAALLOCSIZE = 0x400 - ATTR_FILE_DATAEXTENTS = 0x800 - ATTR_FILE_DATALENGTH = 0x200 - ATTR_FILE_DEVTYPE = 0x20 - ATTR_FILE_FILETYPE = 0x40 - ATTR_FILE_FORKCOUNT = 0x80 - ATTR_FILE_FORKLIST = 0x100 - ATTR_FILE_IOBLOCKSIZE = 0x8 - ATTR_FILE_LINKCOUNT = 0x1 - ATTR_FILE_RSRCALLOCSIZE = 0x2000 - ATTR_FILE_RSRCEXTENTS = 0x4000 - ATTR_FILE_RSRCLENGTH = 0x1000 - ATTR_FILE_SETMASK = 0x20 - ATTR_FILE_TOTALSIZE = 0x2 - ATTR_FILE_VALIDMASK = 0x37ff - ATTR_VOL_ALLOCATIONCLUMP = 0x40 - ATTR_VOL_ATTRIBUTES = 0x40000000 - ATTR_VOL_CAPABILITIES = 0x20000 - ATTR_VOL_DIRCOUNT = 0x400 - ATTR_VOL_ENCODINGSUSED = 0x10000 - ATTR_VOL_FILECOUNT = 0x200 - ATTR_VOL_FSTYPE = 0x1 - ATTR_VOL_INFO = 0x80000000 - ATTR_VOL_IOBLOCKSIZE = 0x80 - ATTR_VOL_MAXOBJCOUNT = 0x800 - ATTR_VOL_MINALLOCATION = 0x20 - ATTR_VOL_MOUNTEDDEVICE = 0x8000 - ATTR_VOL_MOUNTFLAGS = 0x4000 - ATTR_VOL_MOUNTPOINT = 0x1000 - ATTR_VOL_NAME = 0x2000 - ATTR_VOL_OBJCOUNT = 0x100 - ATTR_VOL_QUOTA_SIZE = 0x10000000 - ATTR_VOL_RESERVED_SIZE = 0x20000000 - ATTR_VOL_SETMASK = 0x80002000 - ATTR_VOL_SIGNATURE = 0x2 - ATTR_VOL_SIZE = 0x4 - ATTR_VOL_SPACEAVAIL = 0x10 - ATTR_VOL_SPACEFREE = 0x8 - ATTR_VOL_UUID = 0x40000 - ATTR_VOL_VALIDMASK = 0xf007ffff - B0 = 0x0 - B110 = 0x6e - B115200 = 0x1c200 - B1200 = 0x4b0 - B134 = 0x86 - B14400 = 0x3840 - B150 = 0x96 - B1800 = 0x708 - B19200 = 0x4b00 - B200 = 0xc8 - B230400 = 0x38400 - B2400 = 0x960 - B28800 = 0x7080 - B300 = 0x12c - B38400 = 0x9600 - B4800 = 0x12c0 - B50 = 0x32 - B57600 = 0xe100 - B600 = 0x258 - B7200 = 0x1c20 - B75 = 0x4b - B76800 = 0x12c00 - B9600 = 0x2580 - BIOCFLUSH = 0x20004268 - BIOCGBLEN = 0x40044266 - BIOCGDLT = 0x4004426a - BIOCGDLTLIST = 0xc00c4279 - BIOCGETIF = 0x4020426b - BIOCGHDRCMPLT = 0x40044274 - BIOCGRSIG = 0x40044272 - BIOCGRTIMEOUT = 0x4008426e - BIOCGSEESENT = 0x40044276 - BIOCGSTATS = 0x4008426f - BIOCIMMEDIATE = 0x80044270 - BIOCPROMISC = 0x20004269 - BIOCSBLEN = 0xc0044266 - BIOCSDLT = 0x80044278 - BIOCSETF = 0x80084267 - BIOCSETFNR = 0x8008427e - BIOCSETIF = 0x8020426c - BIOCSHDRCMPLT = 0x80044275 - BIOCSRSIG = 0x80044273 - BIOCSRTIMEOUT = 0x8008426d - BIOCSSEESENT = 0x80044277 - BIOCVERSION = 0x40044271 - BPF_A = 0x10 - BPF_ABS = 0x20 - BPF_ADD = 0x0 - BPF_ALIGNMENT = 0x4 - BPF_ALU = 0x4 - BPF_AND = 0x50 - BPF_B = 0x10 - BPF_DIV = 0x30 - BPF_H = 0x8 - BPF_IMM = 0x0 - BPF_IND = 0x40 - BPF_JA = 0x0 - BPF_JEQ = 0x10 - BPF_JGE = 0x30 - BPF_JGT = 0x20 - BPF_JMP = 0x5 - BPF_JSET = 0x40 - BPF_K = 0x0 - BPF_LD = 0x0 - BPF_LDX = 0x1 - BPF_LEN = 0x80 - BPF_LSH = 0x60 - BPF_MAJOR_VERSION = 0x1 - BPF_MAXBUFSIZE = 0x80000 - BPF_MAXINSNS = 0x200 - BPF_MEM = 0x60 - BPF_MEMWORDS = 0x10 - BPF_MINBUFSIZE = 0x20 - BPF_MINOR_VERSION = 0x1 - BPF_MISC = 0x7 - BPF_MSH = 0xa0 - BPF_MUL = 0x20 - BPF_NEG = 0x80 - BPF_OR = 0x40 - BPF_RELEASE = 0x30bb6 - BPF_RET = 0x6 - BPF_RSH = 0x70 - BPF_ST = 0x2 - BPF_STX = 0x3 - BPF_SUB = 0x10 - BPF_TAX = 0x0 - BPF_TXA = 0x80 - BPF_W = 0x0 - BPF_X = 0x8 - BRKINT = 0x2 - BS0 = 0x0 - BS1 = 0x8000 - BSDLY = 0x8000 - CFLUSH = 0xf - CLOCAL = 0x8000 - CLOCK_MONOTONIC = 0x6 - CLOCK_MONOTONIC_RAW = 0x4 - CLOCK_MONOTONIC_RAW_APPROX = 0x5 - CLOCK_PROCESS_CPUTIME_ID = 0xc - CLOCK_REALTIME = 0x0 - CLOCK_THREAD_CPUTIME_ID = 0x10 - CLOCK_UPTIME_RAW = 0x8 - CLOCK_UPTIME_RAW_APPROX = 0x9 - CLONE_NOFOLLOW = 0x1 - CLONE_NOOWNERCOPY = 0x2 - CR0 = 0x0 - CR1 = 0x1000 - CR2 = 0x2000 - CR3 = 0x3000 - CRDLY = 0x3000 - CREAD = 0x800 - CRTSCTS = 0x30000 - CS5 = 0x0 - CS6 = 0x100 - CS7 = 0x200 - CS8 = 0x300 - CSIZE = 0x300 - CSTART = 0x11 - CSTATUS = 0x14 - CSTOP = 0x13 - CSTOPB = 0x400 - CSUSP = 0x1a - CTLIOCGINFO = 0xc0644e03 - CTL_HW = 0x6 - CTL_KERN = 0x1 - CTL_MAXNAME = 0xc - CTL_NET = 0x4 - DLT_A429 = 0xb8 - DLT_A653_ICM = 0xb9 - DLT_AIRONET_HEADER = 0x78 - DLT_AOS = 0xde - DLT_APPLE_IP_OVER_IEEE1394 = 0x8a - DLT_ARCNET = 0x7 - DLT_ARCNET_LINUX = 0x81 - DLT_ATM_CLIP = 0x13 - DLT_ATM_RFC1483 = 0xb - DLT_AURORA = 0x7e - DLT_AX25 = 0x3 - DLT_AX25_KISS = 0xca - DLT_BACNET_MS_TP = 0xa5 - DLT_BLUETOOTH_HCI_H4 = 0xbb - DLT_BLUETOOTH_HCI_H4_WITH_PHDR = 0xc9 - DLT_CAN20B = 0xbe - DLT_CAN_SOCKETCAN = 0xe3 - DLT_CHAOS = 0x5 - DLT_CHDLC = 0x68 - DLT_CISCO_IOS = 0x76 - DLT_C_HDLC = 0x68 - DLT_C_HDLC_WITH_DIR = 0xcd - DLT_DBUS = 0xe7 - DLT_DECT = 0xdd - DLT_DOCSIS = 0x8f - DLT_DVB_CI = 0xeb - DLT_ECONET = 0x73 - DLT_EN10MB = 0x1 - DLT_EN3MB = 0x2 - DLT_ENC = 0x6d - DLT_ERF = 0xc5 - DLT_ERF_ETH = 0xaf - DLT_ERF_POS = 0xb0 - DLT_FC_2 = 0xe0 - DLT_FC_2_WITH_FRAME_DELIMS = 0xe1 - DLT_FDDI = 0xa - DLT_FLEXRAY = 0xd2 - DLT_FRELAY = 0x6b - DLT_FRELAY_WITH_DIR = 0xce - DLT_GCOM_SERIAL = 0xad - DLT_GCOM_T1E1 = 0xac - DLT_GPF_F = 0xab - DLT_GPF_T = 0xaa - DLT_GPRS_LLC = 0xa9 - DLT_GSMTAP_ABIS = 0xda - DLT_GSMTAP_UM = 0xd9 - DLT_HHDLC = 0x79 - DLT_IBM_SN = 0x92 - DLT_IBM_SP = 0x91 - DLT_IEEE802 = 0x6 - DLT_IEEE802_11 = 0x69 - DLT_IEEE802_11_RADIO = 0x7f - DLT_IEEE802_11_RADIO_AVS = 0xa3 - DLT_IEEE802_15_4 = 0xc3 - DLT_IEEE802_15_4_LINUX = 0xbf - DLT_IEEE802_15_4_NOFCS = 0xe6 - DLT_IEEE802_15_4_NONASK_PHY = 0xd7 - DLT_IEEE802_16_MAC_CPS = 0xbc - DLT_IEEE802_16_MAC_CPS_RADIO = 0xc1 - DLT_IPFILTER = 0x74 - DLT_IPMB = 0xc7 - DLT_IPMB_LINUX = 0xd1 - DLT_IPNET = 0xe2 - DLT_IPOIB = 0xf2 - DLT_IPV4 = 0xe4 - DLT_IPV6 = 0xe5 - DLT_IP_OVER_FC = 0x7a - DLT_JUNIPER_ATM1 = 0x89 - DLT_JUNIPER_ATM2 = 0x87 - DLT_JUNIPER_ATM_CEMIC = 0xee - DLT_JUNIPER_CHDLC = 0xb5 - DLT_JUNIPER_ES = 0x84 - DLT_JUNIPER_ETHER = 0xb2 - DLT_JUNIPER_FIBRECHANNEL = 0xea - DLT_JUNIPER_FRELAY = 0xb4 - DLT_JUNIPER_GGSN = 0x85 - DLT_JUNIPER_ISM = 0xc2 - DLT_JUNIPER_MFR = 0x86 - DLT_JUNIPER_MLFR = 0x83 - DLT_JUNIPER_MLPPP = 0x82 - DLT_JUNIPER_MONITOR = 0xa4 - DLT_JUNIPER_PIC_PEER = 0xae - DLT_JUNIPER_PPP = 0xb3 - DLT_JUNIPER_PPPOE = 0xa7 - DLT_JUNIPER_PPPOE_ATM = 0xa8 - DLT_JUNIPER_SERVICES = 0x88 - DLT_JUNIPER_SRX_E2E = 0xe9 - DLT_JUNIPER_ST = 0xc8 - DLT_JUNIPER_VP = 0xb7 - DLT_JUNIPER_VS = 0xe8 - DLT_LAPB_WITH_DIR = 0xcf - DLT_LAPD = 0xcb - DLT_LIN = 0xd4 - DLT_LINUX_EVDEV = 0xd8 - DLT_LINUX_IRDA = 0x90 - DLT_LINUX_LAPD = 0xb1 - DLT_LINUX_PPP_WITHDIRECTION = 0xa6 - DLT_LINUX_SLL = 0x71 - DLT_LOOP = 0x6c - DLT_LTALK = 0x72 - DLT_MATCHING_MAX = 0xf5 - DLT_MATCHING_MIN = 0x68 - DLT_MFR = 0xb6 - DLT_MOST = 0xd3 - DLT_MPEG_2_TS = 0xf3 - DLT_MPLS = 0xdb - DLT_MTP2 = 0x8c - DLT_MTP2_WITH_PHDR = 0x8b - DLT_MTP3 = 0x8d - DLT_MUX27010 = 0xec - DLT_NETANALYZER = 0xf0 - DLT_NETANALYZER_TRANSPARENT = 0xf1 - DLT_NFC_LLCP = 0xf5 - DLT_NFLOG = 0xef - DLT_NG40 = 0xf4 - DLT_NULL = 0x0 - DLT_PCI_EXP = 0x7d - DLT_PFLOG = 0x75 - DLT_PFSYNC = 0x12 - DLT_PPI = 0xc0 - DLT_PPP = 0x9 - DLT_PPP_BSDOS = 0x10 - DLT_PPP_ETHER = 0x33 - DLT_PPP_PPPD = 0xa6 - DLT_PPP_SERIAL = 0x32 - DLT_PPP_WITH_DIR = 0xcc - DLT_PPP_WITH_DIRECTION = 0xa6 - DLT_PRISM_HEADER = 0x77 - DLT_PRONET = 0x4 - DLT_RAIF1 = 0xc6 - DLT_RAW = 0xc - DLT_RIO = 0x7c - DLT_SCCP = 0x8e - DLT_SITA = 0xc4 - DLT_SLIP = 0x8 - DLT_SLIP_BSDOS = 0xf - DLT_STANAG_5066_D_PDU = 0xed - DLT_SUNATM = 0x7b - DLT_SYMANTEC_FIREWALL = 0x63 - DLT_TZSP = 0x80 - DLT_USB = 0xba - DLT_USB_LINUX = 0xbd - DLT_USB_LINUX_MMAPPED = 0xdc - DLT_USER0 = 0x93 - DLT_USER1 = 0x94 - DLT_USER10 = 0x9d - DLT_USER11 = 0x9e - DLT_USER12 = 0x9f - DLT_USER13 = 0xa0 - DLT_USER14 = 0xa1 - DLT_USER15 = 0xa2 - DLT_USER2 = 0x95 - DLT_USER3 = 0x96 - DLT_USER4 = 0x97 - DLT_USER5 = 0x98 - DLT_USER6 = 0x99 - DLT_USER7 = 0x9a - DLT_USER8 = 0x9b - DLT_USER9 = 0x9c - DLT_WIHART = 0xdf - DLT_X2E_SERIAL = 0xd5 - DLT_X2E_XORAYA = 0xd6 - DT_BLK = 0x6 - DT_CHR = 0x2 - DT_DIR = 0x4 - DT_FIFO = 0x1 - DT_LNK = 0xa - DT_REG = 0x8 - DT_SOCK = 0xc - DT_UNKNOWN = 0x0 - DT_WHT = 0xe - ECHO = 0x8 - ECHOCTL = 0x40 - ECHOE = 0x2 - ECHOK = 0x4 - ECHOKE = 0x1 - ECHONL = 0x10 - ECHOPRT = 0x20 - EVFILT_AIO = -0x3 - EVFILT_EXCEPT = -0xf - EVFILT_FS = -0x9 - EVFILT_MACHPORT = -0x8 - EVFILT_PROC = -0x5 - EVFILT_READ = -0x1 - EVFILT_SIGNAL = -0x6 - EVFILT_SYSCOUNT = 0xf - EVFILT_THREADMARKER = 0xf - EVFILT_TIMER = -0x7 - EVFILT_USER = -0xa - EVFILT_VM = -0xc - EVFILT_VNODE = -0x4 - EVFILT_WRITE = -0x2 - EV_ADD = 0x1 - EV_CLEAR = 0x20 - EV_DELETE = 0x2 - EV_DISABLE = 0x8 - EV_DISPATCH = 0x80 - EV_DISPATCH2 = 0x180 - EV_ENABLE = 0x4 - EV_EOF = 0x8000 - EV_ERROR = 0x4000 - EV_FLAG0 = 0x1000 - EV_FLAG1 = 0x2000 - EV_ONESHOT = 0x10 - EV_OOBAND = 0x2000 - EV_POLL = 0x1000 - EV_RECEIPT = 0x40 - EV_SYSFLAGS = 0xf000 - EV_UDATA_SPECIFIC = 0x100 - EV_VANISHED = 0x200 - EXTA = 0x4b00 - EXTB = 0x9600 - EXTPROC = 0x800 - FD_CLOEXEC = 0x1 - FD_SETSIZE = 0x400 - FF0 = 0x0 - FF1 = 0x4000 - FFDLY = 0x4000 - FLUSHO = 0x800000 - FSOPT_ATTR_CMN_EXTENDED = 0x20 - FSOPT_NOFOLLOW = 0x1 - FSOPT_NOINMEMUPDATE = 0x2 - FSOPT_PACK_INVAL_ATTRS = 0x8 - FSOPT_REPORT_FULLSIZE = 0x4 - F_ADDFILESIGS = 0x3d - F_ADDFILESIGS_FOR_DYLD_SIM = 0x53 - F_ADDFILESIGS_RETURN = 0x61 - F_ADDSIGS = 0x3b - F_ALLOCATEALL = 0x4 - F_ALLOCATECONTIG = 0x2 - F_BARRIERFSYNC = 0x55 - F_CHECK_LV = 0x62 - F_CHKCLEAN = 0x29 - F_DUPFD = 0x0 - F_DUPFD_CLOEXEC = 0x43 - F_FINDSIGS = 0x4e - F_FLUSH_DATA = 0x28 - F_FREEZE_FS = 0x35 - F_FULLFSYNC = 0x33 - F_GETCODEDIR = 0x48 - F_GETFD = 0x1 - F_GETFL = 0x3 - F_GETLK = 0x7 - F_GETLKPID = 0x42 - F_GETNOSIGPIPE = 0x4a - F_GETOWN = 0x5 - F_GETPATH = 0x32 - F_GETPATH_MTMINFO = 0x47 - F_GETPROTECTIONCLASS = 0x3f - F_GETPROTECTIONLEVEL = 0x4d - F_GLOBAL_NOCACHE = 0x37 - F_LOG2PHYS = 0x31 - F_LOG2PHYS_EXT = 0x41 - F_NOCACHE = 0x30 - F_NODIRECT = 0x3e - F_OK = 0x0 - F_PATHPKG_CHECK = 0x34 - F_PEOFPOSMODE = 0x3 - F_PREALLOCATE = 0x2a - F_PUNCHHOLE = 0x63 - F_RDADVISE = 0x2c - F_RDAHEAD = 0x2d - F_RDLCK = 0x1 - F_SETBACKINGSTORE = 0x46 - F_SETFD = 0x2 - F_SETFL = 0x4 - F_SETLK = 0x8 - F_SETLKW = 0x9 - F_SETLKWTIMEOUT = 0xa - F_SETNOSIGPIPE = 0x49 - F_SETOWN = 0x6 - F_SETPROTECTIONCLASS = 0x40 - F_SETSIZE = 0x2b - F_SINGLE_WRITER = 0x4c - F_THAW_FS = 0x36 - F_TRANSCODEKEY = 0x4b - F_TRIM_ACTIVE_FILE = 0x64 - F_UNLCK = 0x2 - F_VOLPOSMODE = 0x4 - F_WRLCK = 0x3 - HUPCL = 0x4000 - HW_MACHINE = 0x1 - ICANON = 0x100 - ICMP6_FILTER = 0x12 - ICRNL = 0x100 - IEXTEN = 0x400 - IFF_ALLMULTI = 0x200 - IFF_ALTPHYS = 0x4000 - IFF_BROADCAST = 0x2 - IFF_DEBUG = 0x4 - IFF_LINK0 = 0x1000 - IFF_LINK1 = 0x2000 - IFF_LINK2 = 0x4000 - IFF_LOOPBACK = 0x8 - IFF_MULTICAST = 0x8000 - IFF_NOARP = 0x80 - IFF_NOTRAILERS = 0x20 - IFF_OACTIVE = 0x400 - IFF_POINTOPOINT = 0x10 - IFF_PROMISC = 0x100 - IFF_RUNNING = 0x40 - IFF_SIMPLEX = 0x800 - IFF_UP = 0x1 - IFNAMSIZ = 0x10 - IFT_1822 = 0x2 - IFT_AAL5 = 0x31 - IFT_ARCNET = 0x23 - IFT_ARCNETPLUS = 0x24 - IFT_ATM = 0x25 - IFT_BRIDGE = 0xd1 - IFT_CARP = 0xf8 - IFT_CELLULAR = 0xff - IFT_CEPT = 0x13 - IFT_DS3 = 0x1e - IFT_ENC = 0xf4 - IFT_EON = 0x19 - IFT_ETHER = 0x6 - IFT_FAITH = 0x38 - IFT_FDDI = 0xf - IFT_FRELAY = 0x20 - IFT_FRELAYDCE = 0x2c - IFT_GIF = 0x37 - IFT_HDH1822 = 0x3 - IFT_HIPPI = 0x2f - IFT_HSSI = 0x2e - IFT_HY = 0xe - IFT_IEEE1394 = 0x90 - IFT_IEEE8023ADLAG = 0x88 - IFT_ISDNBASIC = 0x14 - IFT_ISDNPRIMARY = 0x15 - IFT_ISO88022LLC = 0x29 - IFT_ISO88023 = 0x7 - IFT_ISO88024 = 0x8 - IFT_ISO88025 = 0x9 - IFT_ISO88026 = 0xa - IFT_L2VLAN = 0x87 - IFT_LAPB = 0x10 - IFT_LOCALTALK = 0x2a - IFT_LOOP = 0x18 - IFT_MIOX25 = 0x26 - IFT_MODEM = 0x30 - IFT_NSIP = 0x1b - IFT_OTHER = 0x1 - IFT_P10 = 0xc - IFT_P80 = 0xd - IFT_PARA = 0x22 - IFT_PDP = 0xff - IFT_PFLOG = 0xf5 - IFT_PFSYNC = 0xf6 - IFT_PKTAP = 0xfe - IFT_PPP = 0x17 - IFT_PROPMUX = 0x36 - IFT_PROPVIRTUAL = 0x35 - IFT_PTPSERIAL = 0x16 - IFT_RS232 = 0x21 - IFT_SDLC = 0x11 - IFT_SIP = 0x1f - IFT_SLIP = 0x1c - IFT_SMDSDXI = 0x2b - IFT_SMDSICIP = 0x34 - IFT_SONET = 0x27 - IFT_SONETPATH = 0x32 - IFT_SONETVT = 0x33 - IFT_STARLAN = 0xb - IFT_STF = 0x39 - IFT_T1 = 0x12 - IFT_ULTRA = 0x1d - IFT_V35 = 0x2d - IFT_X25 = 0x5 - IFT_X25DDN = 0x4 - IFT_X25PLE = 0x28 - IFT_XETHER = 0x1a - IGNBRK = 0x1 - IGNCR = 0x80 - IGNPAR = 0x4 - IMAXBEL = 0x2000 - INLCR = 0x40 - INPCK = 0x10 - IN_CLASSA_HOST = 0xffffff - IN_CLASSA_MAX = 0x80 - IN_CLASSA_NET = 0xff000000 - IN_CLASSA_NSHIFT = 0x18 - IN_CLASSB_HOST = 0xffff - IN_CLASSB_MAX = 0x10000 - IN_CLASSB_NET = 0xffff0000 - IN_CLASSB_NSHIFT = 0x10 - IN_CLASSC_HOST = 0xff - IN_CLASSC_NET = 0xffffff00 - IN_CLASSC_NSHIFT = 0x8 - IN_CLASSD_HOST = 0xfffffff - IN_CLASSD_NET = 0xf0000000 - IN_CLASSD_NSHIFT = 0x1c - IN_LINKLOCALNETNUM = 0xa9fe0000 - IN_LOOPBACKNET = 0x7f - IPPROTO_3PC = 0x22 - IPPROTO_ADFS = 0x44 - IPPROTO_AH = 0x33 - IPPROTO_AHIP = 0x3d - IPPROTO_APES = 0x63 - IPPROTO_ARGUS = 0xd - IPPROTO_AX25 = 0x5d - IPPROTO_BHA = 0x31 - IPPROTO_BLT = 0x1e - IPPROTO_BRSATMON = 0x4c - IPPROTO_CFTP = 0x3e - IPPROTO_CHAOS = 0x10 - IPPROTO_CMTP = 0x26 - IPPROTO_CPHB = 0x49 - IPPROTO_CPNX = 0x48 - IPPROTO_DDP = 0x25 - IPPROTO_DGP = 0x56 - IPPROTO_DIVERT = 0xfe - IPPROTO_DONE = 0x101 - IPPROTO_DSTOPTS = 0x3c - IPPROTO_EGP = 0x8 - IPPROTO_EMCON = 0xe - IPPROTO_ENCAP = 0x62 - IPPROTO_EON = 0x50 - IPPROTO_ESP = 0x32 - IPPROTO_ETHERIP = 0x61 - IPPROTO_FRAGMENT = 0x2c - IPPROTO_GGP = 0x3 - IPPROTO_GMTP = 0x64 - IPPROTO_GRE = 0x2f - IPPROTO_HELLO = 0x3f - IPPROTO_HMP = 0x14 - IPPROTO_HOPOPTS = 0x0 - IPPROTO_ICMP = 0x1 - IPPROTO_ICMPV6 = 0x3a - IPPROTO_IDP = 0x16 - IPPROTO_IDPR = 0x23 - IPPROTO_IDRP = 0x2d - IPPROTO_IGMP = 0x2 - IPPROTO_IGP = 0x55 - IPPROTO_IGRP = 0x58 - IPPROTO_IL = 0x28 - IPPROTO_INLSP = 0x34 - IPPROTO_INP = 0x20 - IPPROTO_IP = 0x0 - IPPROTO_IPCOMP = 0x6c - IPPROTO_IPCV = 0x47 - IPPROTO_IPEIP = 0x5e - IPPROTO_IPIP = 0x4 - IPPROTO_IPPC = 0x43 - IPPROTO_IPV4 = 0x4 - IPPROTO_IPV6 = 0x29 - IPPROTO_IRTP = 0x1c - IPPROTO_KRYPTOLAN = 0x41 - IPPROTO_LARP = 0x5b - IPPROTO_LEAF1 = 0x19 - IPPROTO_LEAF2 = 0x1a - IPPROTO_MAX = 0x100 - IPPROTO_MAXID = 0x34 - IPPROTO_MEAS = 0x13 - IPPROTO_MHRP = 0x30 - IPPROTO_MICP = 0x5f - IPPROTO_MTP = 0x5c - IPPROTO_MUX = 0x12 - IPPROTO_ND = 0x4d - IPPROTO_NHRP = 0x36 - IPPROTO_NONE = 0x3b - IPPROTO_NSP = 0x1f - IPPROTO_NVPII = 0xb - IPPROTO_OSPFIGP = 0x59 - IPPROTO_PGM = 0x71 - IPPROTO_PIGP = 0x9 - IPPROTO_PIM = 0x67 - IPPROTO_PRM = 0x15 - IPPROTO_PUP = 0xc - IPPROTO_PVP = 0x4b - IPPROTO_RAW = 0xff - IPPROTO_RCCMON = 0xa - IPPROTO_RDP = 0x1b - IPPROTO_ROUTING = 0x2b - IPPROTO_RSVP = 0x2e - IPPROTO_RVD = 0x42 - IPPROTO_SATEXPAK = 0x40 - IPPROTO_SATMON = 0x45 - IPPROTO_SCCSP = 0x60 - IPPROTO_SCTP = 0x84 - IPPROTO_SDRP = 0x2a - IPPROTO_SEP = 0x21 - IPPROTO_SRPC = 0x5a - IPPROTO_ST = 0x7 - IPPROTO_SVMTP = 0x52 - IPPROTO_SWIPE = 0x35 - IPPROTO_TCF = 0x57 - IPPROTO_TCP = 0x6 - IPPROTO_TP = 0x1d - IPPROTO_TPXX = 0x27 - IPPROTO_TRUNK1 = 0x17 - IPPROTO_TRUNK2 = 0x18 - IPPROTO_TTP = 0x54 - IPPROTO_UDP = 0x11 - IPPROTO_VINES = 0x53 - IPPROTO_VISA = 0x46 - IPPROTO_VMTP = 0x51 - IPPROTO_WBEXPAK = 0x4f - IPPROTO_WBMON = 0x4e - IPPROTO_WSN = 0x4a - IPPROTO_XNET = 0xf - IPPROTO_XTP = 0x24 - IPV6_2292DSTOPTS = 0x17 - IPV6_2292HOPLIMIT = 0x14 - IPV6_2292HOPOPTS = 0x16 - IPV6_2292NEXTHOP = 0x15 - IPV6_2292PKTINFO = 0x13 - IPV6_2292PKTOPTIONS = 0x19 - IPV6_2292RTHDR = 0x18 - IPV6_BINDV6ONLY = 0x1b - IPV6_BOUND_IF = 0x7d - IPV6_CHECKSUM = 0x1a - IPV6_DEFAULT_MULTICAST_HOPS = 0x1 - IPV6_DEFAULT_MULTICAST_LOOP = 0x1 - IPV6_DEFHLIM = 0x40 - IPV6_FAITH = 0x1d - IPV6_FLOWINFO_MASK = 0xffffff0f - IPV6_FLOWLABEL_MASK = 0xffff0f00 - IPV6_FLOW_ECN_MASK = 0x300 - IPV6_FRAGTTL = 0x3c - IPV6_FW_ADD = 0x1e - IPV6_FW_DEL = 0x1f - IPV6_FW_FLUSH = 0x20 - IPV6_FW_GET = 0x22 - IPV6_FW_ZERO = 0x21 - IPV6_HLIMDEC = 0x1 - IPV6_IPSEC_POLICY = 0x1c - IPV6_JOIN_GROUP = 0xc - IPV6_LEAVE_GROUP = 0xd - IPV6_MAXHLIM = 0xff - IPV6_MAXOPTHDR = 0x800 - IPV6_MAXPACKET = 0xffff - IPV6_MAX_GROUP_SRC_FILTER = 0x200 - IPV6_MAX_MEMBERSHIPS = 0xfff - IPV6_MAX_SOCK_SRC_FILTER = 0x80 - IPV6_MIN_MEMBERSHIPS = 0x1f - IPV6_MMTU = 0x500 - IPV6_MULTICAST_HOPS = 0xa - IPV6_MULTICAST_IF = 0x9 - IPV6_MULTICAST_LOOP = 0xb - IPV6_PORTRANGE = 0xe - IPV6_PORTRANGE_DEFAULT = 0x0 - IPV6_PORTRANGE_HIGH = 0x1 - IPV6_PORTRANGE_LOW = 0x2 - IPV6_RECVTCLASS = 0x23 - IPV6_RTHDR_LOOSE = 0x0 - IPV6_RTHDR_STRICT = 0x1 - IPV6_RTHDR_TYPE_0 = 0x0 - IPV6_SOCKOPT_RESERVED1 = 0x3 - IPV6_TCLASS = 0x24 - IPV6_UNICAST_HOPS = 0x4 - IPV6_V6ONLY = 0x1b - IPV6_VERSION = 0x60 - IPV6_VERSION_MASK = 0xf0 - IP_ADD_MEMBERSHIP = 0xc - IP_ADD_SOURCE_MEMBERSHIP = 0x46 - IP_BLOCK_SOURCE = 0x48 - IP_BOUND_IF = 0x19 - IP_DEFAULT_MULTICAST_LOOP = 0x1 - IP_DEFAULT_MULTICAST_TTL = 0x1 - IP_DF = 0x4000 - IP_DROP_MEMBERSHIP = 0xd - IP_DROP_SOURCE_MEMBERSHIP = 0x47 - IP_DUMMYNET_CONFIGURE = 0x3c - IP_DUMMYNET_DEL = 0x3d - IP_DUMMYNET_FLUSH = 0x3e - IP_DUMMYNET_GET = 0x40 - IP_FAITH = 0x16 - IP_FW_ADD = 0x28 - IP_FW_DEL = 0x29 - IP_FW_FLUSH = 0x2a - IP_FW_GET = 0x2c - IP_FW_RESETLOG = 0x2d - IP_FW_ZERO = 0x2b - IP_HDRINCL = 0x2 - IP_IPSEC_POLICY = 0x15 - IP_MAXPACKET = 0xffff - IP_MAX_GROUP_SRC_FILTER = 0x200 - IP_MAX_MEMBERSHIPS = 0xfff - IP_MAX_SOCK_MUTE_FILTER = 0x80 - IP_MAX_SOCK_SRC_FILTER = 0x80 - IP_MF = 0x2000 - IP_MIN_MEMBERSHIPS = 0x1f - IP_MSFILTER = 0x4a - IP_MSS = 0x240 - IP_MULTICAST_IF = 0x9 - IP_MULTICAST_IFINDEX = 0x42 - IP_MULTICAST_LOOP = 0xb - IP_MULTICAST_TTL = 0xa - IP_MULTICAST_VIF = 0xe - IP_NAT__XXX = 0x37 - IP_OFFMASK = 0x1fff - IP_OLD_FW_ADD = 0x32 - IP_OLD_FW_DEL = 0x33 - IP_OLD_FW_FLUSH = 0x34 - IP_OLD_FW_GET = 0x36 - IP_OLD_FW_RESETLOG = 0x38 - IP_OLD_FW_ZERO = 0x35 - IP_OPTIONS = 0x1 - IP_PKTINFO = 0x1a - IP_PORTRANGE = 0x13 - IP_PORTRANGE_DEFAULT = 0x0 - IP_PORTRANGE_HIGH = 0x1 - IP_PORTRANGE_LOW = 0x2 - IP_RECVDSTADDR = 0x7 - IP_RECVIF = 0x14 - IP_RECVOPTS = 0x5 - IP_RECVPKTINFO = 0x1a - IP_RECVRETOPTS = 0x6 - IP_RECVTOS = 0x1b - IP_RECVTTL = 0x18 - IP_RETOPTS = 0x8 - IP_RF = 0x8000 - IP_RSVP_OFF = 0x10 - IP_RSVP_ON = 0xf - IP_RSVP_VIF_OFF = 0x12 - IP_RSVP_VIF_ON = 0x11 - IP_STRIPHDR = 0x17 - IP_TOS = 0x3 - IP_TRAFFIC_MGT_BACKGROUND = 0x41 - IP_TTL = 0x4 - IP_UNBLOCK_SOURCE = 0x49 - ISIG = 0x80 - ISTRIP = 0x20 - IUTF8 = 0x4000 - IXANY = 0x800 - IXOFF = 0x400 - IXON = 0x200 - KERN_HOSTNAME = 0xa - KERN_OSRELEASE = 0x2 - KERN_OSTYPE = 0x1 - KERN_VERSION = 0x4 - LOCK_EX = 0x2 - LOCK_NB = 0x4 - LOCK_SH = 0x1 - LOCK_UN = 0x8 - MADV_CAN_REUSE = 0x9 - MADV_DONTNEED = 0x4 - MADV_FREE = 0x5 - MADV_FREE_REUSABLE = 0x7 - MADV_FREE_REUSE = 0x8 - MADV_NORMAL = 0x0 - MADV_PAGEOUT = 0xa - MADV_RANDOM = 0x1 - MADV_SEQUENTIAL = 0x2 - MADV_WILLNEED = 0x3 - MADV_ZERO_WIRED_PAGES = 0x6 - MAP_ANON = 0x1000 - MAP_ANONYMOUS = 0x1000 - MAP_COPY = 0x2 - MAP_FILE = 0x0 - MAP_FIXED = 0x10 - MAP_HASSEMAPHORE = 0x200 - MAP_JIT = 0x800 - MAP_NOCACHE = 0x400 - MAP_NOEXTEND = 0x100 - MAP_NORESERVE = 0x40 - MAP_PRIVATE = 0x2 - MAP_RENAME = 0x20 - MAP_RESERVED0080 = 0x80 - MAP_RESILIENT_CODESIGN = 0x2000 - MAP_RESILIENT_MEDIA = 0x4000 - MAP_SHARED = 0x1 - MCL_CURRENT = 0x1 - MCL_FUTURE = 0x2 - MNT_ASYNC = 0x40 - MNT_AUTOMOUNTED = 0x400000 - MNT_CMDFLAGS = 0xf0000 - MNT_CPROTECT = 0x80 - MNT_DEFWRITE = 0x2000000 - MNT_DONTBROWSE = 0x100000 - MNT_DOVOLFS = 0x8000 - MNT_DWAIT = 0x4 - MNT_EXPORTED = 0x100 - MNT_FORCE = 0x80000 - MNT_IGNORE_OWNERSHIP = 0x200000 - MNT_JOURNALED = 0x800000 - MNT_LOCAL = 0x1000 - MNT_MULTILABEL = 0x4000000 - MNT_NOATIME = 0x10000000 - MNT_NOBLOCK = 0x20000 - MNT_NODEV = 0x10 - MNT_NOEXEC = 0x4 - MNT_NOSUID = 0x8 - MNT_NOUSERXATTR = 0x1000000 - MNT_NOWAIT = 0x2 - MNT_QUARANTINE = 0x400 - MNT_QUOTA = 0x2000 - MNT_RDONLY = 0x1 - MNT_RELOAD = 0x40000 - MNT_ROOTFS = 0x4000 - MNT_SYNCHRONOUS = 0x2 - MNT_UNION = 0x20 - MNT_UNKNOWNPERMISSIONS = 0x200000 - MNT_UPDATE = 0x10000 - MNT_VISFLAGMASK = 0x17f0f5ff - MNT_WAIT = 0x1 - MSG_CTRUNC = 0x20 - MSG_DONTROUTE = 0x4 - MSG_DONTWAIT = 0x80 - MSG_EOF = 0x100 - MSG_EOR = 0x8 - MSG_FLUSH = 0x400 - MSG_HAVEMORE = 0x2000 - MSG_HOLD = 0x800 - MSG_NEEDSA = 0x10000 - MSG_OOB = 0x1 - MSG_PEEK = 0x2 - MSG_RCVMORE = 0x4000 - MSG_SEND = 0x1000 - MSG_TRUNC = 0x10 - MSG_WAITALL = 0x40 - MSG_WAITSTREAM = 0x200 - MS_ASYNC = 0x1 - MS_DEACTIVATE = 0x8 - MS_INVALIDATE = 0x2 - MS_KILLPAGES = 0x4 - MS_SYNC = 0x10 - NAME_MAX = 0xff - NET_RT_DUMP = 0x1 - NET_RT_DUMP2 = 0x7 - NET_RT_FLAGS = 0x2 - NET_RT_IFLIST = 0x3 - NET_RT_IFLIST2 = 0x6 - NET_RT_MAXID = 0xa - NET_RT_STAT = 0x4 - NET_RT_TRASH = 0x5 - NFDBITS = 0x20 - NL0 = 0x0 - NL1 = 0x100 - NL2 = 0x200 - NL3 = 0x300 - NLDLY = 0x300 - NOFLSH = 0x80000000 - NOKERNINFO = 0x2000000 - NOTE_ABSOLUTE = 0x8 - NOTE_ATTRIB = 0x8 - NOTE_BACKGROUND = 0x40 - NOTE_CHILD = 0x4 - NOTE_CRITICAL = 0x20 - NOTE_DELETE = 0x1 - NOTE_EXEC = 0x20000000 - NOTE_EXIT = 0x80000000 - NOTE_EXITSTATUS = 0x4000000 - NOTE_EXIT_CSERROR = 0x40000 - NOTE_EXIT_DECRYPTFAIL = 0x10000 - NOTE_EXIT_DETAIL = 0x2000000 - NOTE_EXIT_DETAIL_MASK = 0x70000 - NOTE_EXIT_MEMORY = 0x20000 - NOTE_EXIT_REPARENTED = 0x80000 - NOTE_EXTEND = 0x4 - NOTE_FFAND = 0x40000000 - NOTE_FFCOPY = 0xc0000000 - NOTE_FFCTRLMASK = 0xc0000000 - NOTE_FFLAGSMASK = 0xffffff - NOTE_FFNOP = 0x0 - NOTE_FFOR = 0x80000000 - NOTE_FORK = 0x40000000 - NOTE_FUNLOCK = 0x100 - NOTE_LEEWAY = 0x10 - NOTE_LINK = 0x10 - NOTE_LOWAT = 0x1 - NOTE_MACH_CONTINUOUS_TIME = 0x80 - NOTE_NONE = 0x80 - NOTE_NSECONDS = 0x4 - NOTE_OOB = 0x2 - NOTE_PCTRLMASK = -0x100000 - NOTE_PDATAMASK = 0xfffff - NOTE_REAP = 0x10000000 - NOTE_RENAME = 0x20 - NOTE_REVOKE = 0x40 - NOTE_SECONDS = 0x1 - NOTE_SIGNAL = 0x8000000 - NOTE_TRACK = 0x1 - NOTE_TRACKERR = 0x2 - NOTE_TRIGGER = 0x1000000 - NOTE_USECONDS = 0x2 - NOTE_VM_ERROR = 0x10000000 - NOTE_VM_PRESSURE = 0x80000000 - NOTE_VM_PRESSURE_SUDDEN_TERMINATE = 0x20000000 - NOTE_VM_PRESSURE_TERMINATE = 0x40000000 - NOTE_WRITE = 0x2 - OCRNL = 0x10 - OFDEL = 0x20000 - OFILL = 0x80 - ONLCR = 0x2 - ONLRET = 0x40 - ONOCR = 0x20 - ONOEOT = 0x8 - OPOST = 0x1 - OXTABS = 0x4 - O_ACCMODE = 0x3 - O_ALERT = 0x20000000 - O_APPEND = 0x8 - O_ASYNC = 0x40 - O_CLOEXEC = 0x1000000 - O_CREAT = 0x200 - O_DIRECTORY = 0x100000 - O_DP_GETRAWENCRYPTED = 0x1 - O_DP_GETRAWUNENCRYPTED = 0x2 - O_DSYNC = 0x400000 - O_EVTONLY = 0x8000 - O_EXCL = 0x800 - O_EXLOCK = 0x20 - O_FSYNC = 0x80 - O_NDELAY = 0x4 - O_NOCTTY = 0x20000 - O_NOFOLLOW = 0x100 - O_NONBLOCK = 0x4 - O_POPUP = 0x80000000 - O_RDONLY = 0x0 - O_RDWR = 0x2 - O_SHLOCK = 0x10 - O_SYMLINK = 0x200000 - O_SYNC = 0x80 - O_TRUNC = 0x400 - O_WRONLY = 0x1 - PARENB = 0x1000 - PARMRK = 0x8 - PARODD = 0x2000 - PENDIN = 0x20000000 - PRIO_PGRP = 0x1 - PRIO_PROCESS = 0x0 - PRIO_USER = 0x2 - PROT_EXEC = 0x4 - PROT_NONE = 0x0 - PROT_READ = 0x1 - PROT_WRITE = 0x2 - PT_ATTACH = 0xa - PT_ATTACHEXC = 0xe - PT_CONTINUE = 0x7 - PT_DENY_ATTACH = 0x1f - PT_DETACH = 0xb - PT_FIRSTMACH = 0x20 - PT_FORCEQUOTA = 0x1e - PT_KILL = 0x8 - PT_READ_D = 0x2 - PT_READ_I = 0x1 - PT_READ_U = 0x3 - PT_SIGEXC = 0xc - PT_STEP = 0x9 - PT_THUPDATE = 0xd - PT_TRACE_ME = 0x0 - PT_WRITE_D = 0x5 - PT_WRITE_I = 0x4 - PT_WRITE_U = 0x6 - RLIMIT_AS = 0x5 - RLIMIT_CORE = 0x4 - RLIMIT_CPU = 0x0 - RLIMIT_CPU_USAGE_MONITOR = 0x2 - RLIMIT_DATA = 0x2 - RLIMIT_FSIZE = 0x1 - RLIMIT_MEMLOCK = 0x6 - RLIMIT_NOFILE = 0x8 - RLIMIT_NPROC = 0x7 - RLIMIT_RSS = 0x5 - RLIMIT_STACK = 0x3 - RLIM_INFINITY = 0x7fffffffffffffff - RTAX_AUTHOR = 0x6 - RTAX_BRD = 0x7 - RTAX_DST = 0x0 - RTAX_GATEWAY = 0x1 - RTAX_GENMASK = 0x3 - RTAX_IFA = 0x5 - RTAX_IFP = 0x4 - RTAX_MAX = 0x8 - RTAX_NETMASK = 0x2 - RTA_AUTHOR = 0x40 - RTA_BRD = 0x80 - RTA_DST = 0x1 - RTA_GATEWAY = 0x2 - RTA_GENMASK = 0x8 - RTA_IFA = 0x20 - RTA_IFP = 0x10 - RTA_NETMASK = 0x4 - RTF_BLACKHOLE = 0x1000 - RTF_BROADCAST = 0x400000 - RTF_CLONING = 0x100 - RTF_CONDEMNED = 0x2000000 - RTF_DELCLONE = 0x80 - RTF_DONE = 0x40 - RTF_DYNAMIC = 0x10 - RTF_GATEWAY = 0x2 - RTF_HOST = 0x4 - RTF_IFREF = 0x4000000 - RTF_IFSCOPE = 0x1000000 - RTF_LLINFO = 0x400 - RTF_LOCAL = 0x200000 - RTF_MODIFIED = 0x20 - RTF_MULTICAST = 0x800000 - RTF_NOIFREF = 0x2000 - RTF_PINNED = 0x100000 - RTF_PRCLONING = 0x10000 - RTF_PROTO1 = 0x8000 - RTF_PROTO2 = 0x4000 - RTF_PROTO3 = 0x40000 - RTF_PROXY = 0x8000000 - RTF_REJECT = 0x8 - RTF_ROUTER = 0x10000000 - RTF_STATIC = 0x800 - RTF_UP = 0x1 - RTF_WASCLONED = 0x20000 - RTF_XRESOLVE = 0x200 - RTM_ADD = 0x1 - RTM_CHANGE = 0x3 - RTM_DELADDR = 0xd - RTM_DELETE = 0x2 - RTM_DELMADDR = 0x10 - RTM_GET = 0x4 - RTM_GET2 = 0x14 - RTM_IFINFO = 0xe - RTM_IFINFO2 = 0x12 - RTM_LOCK = 0x8 - RTM_LOSING = 0x5 - RTM_MISS = 0x7 - RTM_NEWADDR = 0xc - RTM_NEWMADDR = 0xf - RTM_NEWMADDR2 = 0x13 - RTM_OLDADD = 0x9 - RTM_OLDDEL = 0xa - RTM_REDIRECT = 0x6 - RTM_RESOLVE = 0xb - RTM_RTTUNIT = 0xf4240 - RTM_VERSION = 0x5 - RTV_EXPIRE = 0x4 - RTV_HOPCOUNT = 0x2 - RTV_MTU = 0x1 - RTV_RPIPE = 0x8 - RTV_RTT = 0x40 - RTV_RTTVAR = 0x80 - RTV_SPIPE = 0x10 - RTV_SSTHRESH = 0x20 - RUSAGE_CHILDREN = -0x1 - RUSAGE_SELF = 0x0 - SCM_CREDS = 0x3 - SCM_RIGHTS = 0x1 - SCM_TIMESTAMP = 0x2 - SCM_TIMESTAMP_MONOTONIC = 0x4 - SHUT_RD = 0x0 - SHUT_RDWR = 0x2 - SHUT_WR = 0x1 - SIOCADDMULTI = 0x80206931 - SIOCAIFADDR = 0x8040691a - SIOCARPIPLL = 0xc0206928 - SIOCATMARK = 0x40047307 - SIOCAUTOADDR = 0xc0206926 - SIOCAUTONETMASK = 0x80206927 - SIOCDELMULTI = 0x80206932 - SIOCDIFADDR = 0x80206919 - SIOCDIFPHYADDR = 0x80206941 - SIOCGDRVSPEC = 0xc01c697b - SIOCGETVLAN = 0xc020697f - SIOCGHIWAT = 0x40047301 - SIOCGIFADDR = 0xc0206921 - SIOCGIFALTMTU = 0xc0206948 - SIOCGIFASYNCMAP = 0xc020697c - SIOCGIFBOND = 0xc0206947 - SIOCGIFBRDADDR = 0xc0206923 - SIOCGIFCAP = 0xc020695b - SIOCGIFCONF = 0xc0086924 - SIOCGIFDEVMTU = 0xc0206944 - SIOCGIFDSTADDR = 0xc0206922 - SIOCGIFFLAGS = 0xc0206911 - SIOCGIFGENERIC = 0xc020693a - SIOCGIFKPI = 0xc0206987 - SIOCGIFMAC = 0xc0206982 - SIOCGIFMEDIA = 0xc0286938 - SIOCGIFMETRIC = 0xc0206917 - SIOCGIFMTU = 0xc0206933 - SIOCGIFNETMASK = 0xc0206925 - SIOCGIFPDSTADDR = 0xc0206940 - SIOCGIFPHYS = 0xc0206935 - SIOCGIFPSRCADDR = 0xc020693f - SIOCGIFSTATUS = 0xc331693d - SIOCGIFVLAN = 0xc020697f - SIOCGIFWAKEFLAGS = 0xc0206988 - SIOCGLOWAT = 0x40047303 - SIOCGPGRP = 0x40047309 - SIOCIFCREATE = 0xc0206978 - SIOCIFCREATE2 = 0xc020697a - SIOCIFDESTROY = 0x80206979 - SIOCIFGCLONERS = 0xc00c6981 - SIOCRSLVMULTI = 0xc008693b - SIOCSDRVSPEC = 0x801c697b - SIOCSETVLAN = 0x8020697e - SIOCSHIWAT = 0x80047300 - SIOCSIFADDR = 0x8020690c - SIOCSIFALTMTU = 0x80206945 - SIOCSIFASYNCMAP = 0x8020697d - SIOCSIFBOND = 0x80206946 - SIOCSIFBRDADDR = 0x80206913 - SIOCSIFCAP = 0x8020695a - SIOCSIFDSTADDR = 0x8020690e - SIOCSIFFLAGS = 0x80206910 - SIOCSIFGENERIC = 0x80206939 - SIOCSIFKPI = 0x80206986 - SIOCSIFLLADDR = 0x8020693c - SIOCSIFMAC = 0x80206983 - SIOCSIFMEDIA = 0xc0206937 - SIOCSIFMETRIC = 0x80206918 - SIOCSIFMTU = 0x80206934 - SIOCSIFNETMASK = 0x80206916 - SIOCSIFPHYADDR = 0x8040693e - SIOCSIFPHYS = 0x80206936 - SIOCSIFVLAN = 0x8020697e - SIOCSLOWAT = 0x80047302 - SIOCSPGRP = 0x80047308 - SOCK_DGRAM = 0x2 - SOCK_MAXADDRLEN = 0xff - SOCK_RAW = 0x3 - SOCK_RDM = 0x4 - SOCK_SEQPACKET = 0x5 - SOCK_STREAM = 0x1 - SOL_SOCKET = 0xffff - SOMAXCONN = 0x80 - SO_ACCEPTCONN = 0x2 - SO_BROADCAST = 0x20 - SO_DEBUG = 0x1 - SO_DONTROUTE = 0x10 - SO_DONTTRUNC = 0x2000 - SO_ERROR = 0x1007 - SO_KEEPALIVE = 0x8 - SO_LABEL = 0x1010 - SO_LINGER = 0x80 - SO_LINGER_SEC = 0x1080 - SO_NETSVC_MARKING_LEVEL = 0x1119 - SO_NET_SERVICE_TYPE = 0x1116 - SO_NKE = 0x1021 - SO_NOADDRERR = 0x1023 - SO_NOSIGPIPE = 0x1022 - SO_NOTIFYCONFLICT = 0x1026 - SO_NP_EXTENSIONS = 0x1083 - SO_NREAD = 0x1020 - SO_NUMRCVPKT = 0x1112 - SO_NWRITE = 0x1024 - SO_OOBINLINE = 0x100 - SO_PEERLABEL = 0x1011 - SO_RANDOMPORT = 0x1082 - SO_RCVBUF = 0x1002 - SO_RCVLOWAT = 0x1004 - SO_RCVTIMEO = 0x1006 - SO_REUSEADDR = 0x4 - SO_REUSEPORT = 0x200 - SO_REUSESHAREUID = 0x1025 - SO_SNDBUF = 0x1001 - SO_SNDLOWAT = 0x1003 - SO_SNDTIMEO = 0x1005 - SO_TIMESTAMP = 0x400 - SO_TIMESTAMP_MONOTONIC = 0x800 - SO_TYPE = 0x1008 - SO_UPCALLCLOSEWAIT = 0x1027 - SO_USELOOPBACK = 0x40 - SO_WANTMORE = 0x4000 - SO_WANTOOBFLAG = 0x8000 - S_IEXEC = 0x40 - S_IFBLK = 0x6000 - S_IFCHR = 0x2000 - S_IFDIR = 0x4000 - S_IFIFO = 0x1000 - S_IFLNK = 0xa000 - S_IFMT = 0xf000 - S_IFREG = 0x8000 - S_IFSOCK = 0xc000 - S_IFWHT = 0xe000 - S_IREAD = 0x100 - S_IRGRP = 0x20 - S_IROTH = 0x4 - S_IRUSR = 0x100 - S_IRWXG = 0x38 - S_IRWXO = 0x7 - S_IRWXU = 0x1c0 - S_ISGID = 0x400 - S_ISTXT = 0x200 - S_ISUID = 0x800 - S_ISVTX = 0x200 - S_IWGRP = 0x10 - S_IWOTH = 0x2 - S_IWRITE = 0x80 - S_IWUSR = 0x80 - S_IXGRP = 0x8 - S_IXOTH = 0x1 - S_IXUSR = 0x40 - TAB0 = 0x0 - TAB1 = 0x400 - TAB2 = 0x800 - TAB3 = 0x4 - TABDLY = 0xc04 - TCIFLUSH = 0x1 - TCIOFF = 0x3 - TCIOFLUSH = 0x3 - TCION = 0x4 - TCOFLUSH = 0x2 - TCOOFF = 0x1 - TCOON = 0x2 - TCP_CONNECTIONTIMEOUT = 0x20 - TCP_CONNECTION_INFO = 0x106 - TCP_ENABLE_ECN = 0x104 - TCP_FASTOPEN = 0x105 - TCP_KEEPALIVE = 0x10 - TCP_KEEPCNT = 0x102 - TCP_KEEPINTVL = 0x101 - TCP_MAXHLEN = 0x3c - TCP_MAXOLEN = 0x28 - TCP_MAXSEG = 0x2 - TCP_MAXWIN = 0xffff - TCP_MAX_SACK = 0x4 - TCP_MAX_WINSHIFT = 0xe - TCP_MINMSS = 0xd8 - TCP_MSS = 0x200 - TCP_NODELAY = 0x1 - TCP_NOOPT = 0x8 - TCP_NOPUSH = 0x4 - TCP_NOTSENT_LOWAT = 0x201 - TCP_RXT_CONNDROPTIME = 0x80 - TCP_RXT_FINDROP = 0x100 - TCP_SENDMOREACKS = 0x103 - TCSAFLUSH = 0x2 - TIOCCBRK = 0x2000747a - TIOCCDTR = 0x20007478 - TIOCCONS = 0x80047462 - TIOCDCDTIMESTAMP = 0x40087458 - TIOCDRAIN = 0x2000745e - TIOCDSIMICROCODE = 0x20007455 - TIOCEXCL = 0x2000740d - TIOCEXT = 0x80047460 - TIOCFLUSH = 0x80047410 - TIOCGDRAINWAIT = 0x40047456 - TIOCGETA = 0x402c7413 - TIOCGETD = 0x4004741a - TIOCGPGRP = 0x40047477 - TIOCGWINSZ = 0x40087468 - TIOCIXOFF = 0x20007480 - TIOCIXON = 0x20007481 - TIOCMBIC = 0x8004746b - TIOCMBIS = 0x8004746c - TIOCMGDTRWAIT = 0x4004745a - TIOCMGET = 0x4004746a - TIOCMODG = 0x40047403 - TIOCMODS = 0x80047404 - TIOCMSDTRWAIT = 0x8004745b - TIOCMSET = 0x8004746d - TIOCM_CAR = 0x40 - TIOCM_CD = 0x40 - TIOCM_CTS = 0x20 - TIOCM_DSR = 0x100 - TIOCM_DTR = 0x2 - TIOCM_LE = 0x1 - TIOCM_RI = 0x80 - TIOCM_RNG = 0x80 - TIOCM_RTS = 0x4 - TIOCM_SR = 0x10 - TIOCM_ST = 0x8 - TIOCNOTTY = 0x20007471 - TIOCNXCL = 0x2000740e - TIOCOUTQ = 0x40047473 - TIOCPKT = 0x80047470 - TIOCPKT_DATA = 0x0 - TIOCPKT_DOSTOP = 0x20 - TIOCPKT_FLUSHREAD = 0x1 - TIOCPKT_FLUSHWRITE = 0x2 - TIOCPKT_IOCTL = 0x40 - TIOCPKT_NOSTOP = 0x10 - TIOCPKT_START = 0x8 - TIOCPKT_STOP = 0x4 - TIOCPTYGNAME = 0x40807453 - TIOCPTYGRANT = 0x20007454 - TIOCPTYUNLK = 0x20007452 - TIOCREMOTE = 0x80047469 - TIOCSBRK = 0x2000747b - TIOCSCONS = 0x20007463 - TIOCSCTTY = 0x20007461 - TIOCSDRAINWAIT = 0x80047457 - TIOCSDTR = 0x20007479 - TIOCSETA = 0x802c7414 - TIOCSETAF = 0x802c7416 - TIOCSETAW = 0x802c7415 - TIOCSETD = 0x8004741b - TIOCSIG = 0x2000745f - TIOCSPGRP = 0x80047476 - TIOCSTART = 0x2000746e - TIOCSTAT = 0x20007465 - TIOCSTI = 0x80017472 - TIOCSTOP = 0x2000746f - TIOCSWINSZ = 0x80087467 - TIOCTIMESTAMP = 0x40087459 - TIOCUCNTL = 0x80047466 - TOSTOP = 0x400000 - VDISCARD = 0xf - VDSUSP = 0xb - VEOF = 0x0 - VEOL = 0x1 - VEOL2 = 0x2 - VERASE = 0x3 - VINTR = 0x8 - VKILL = 0x5 - VLNEXT = 0xe - VMIN = 0x10 - VM_LOADAVG = 0x2 - VM_MACHFACTOR = 0x4 - VM_MAXID = 0x6 - VM_METER = 0x1 - VM_SWAPUSAGE = 0x5 - VQUIT = 0x9 - VREPRINT = 0x6 - VSTART = 0xc - VSTATUS = 0x12 - VSTOP = 0xd - VSUSP = 0xa - VT0 = 0x0 - VT1 = 0x10000 - VTDLY = 0x10000 - VTIME = 0x11 - VWERASE = 0x4 - WCONTINUED = 0x10 - WCOREFLAG = 0x80 - WEXITED = 0x4 - WNOHANG = 0x1 - WNOWAIT = 0x20 - WORDSIZE = 0x20 - WSTOPPED = 0x8 - WUNTRACED = 0x2 - XATTR_CREATE = 0x2 - XATTR_NODEFAULT = 0x10 - XATTR_NOFOLLOW = 0x1 - XATTR_NOSECURITY = 0x8 - XATTR_REPLACE = 0x4 - XATTR_SHOWCOMPRESSION = 0x20 -) - -// Errors -const ( - E2BIG = syscall.Errno(0x7) - EACCES = syscall.Errno(0xd) - EADDRINUSE = syscall.Errno(0x30) - EADDRNOTAVAIL = syscall.Errno(0x31) - EAFNOSUPPORT = syscall.Errno(0x2f) - EAGAIN = syscall.Errno(0x23) - EALREADY = syscall.Errno(0x25) - EAUTH = syscall.Errno(0x50) - EBADARCH = syscall.Errno(0x56) - EBADEXEC = syscall.Errno(0x55) - EBADF = syscall.Errno(0x9) - EBADMACHO = syscall.Errno(0x58) - EBADMSG = syscall.Errno(0x5e) - EBADRPC = syscall.Errno(0x48) - EBUSY = syscall.Errno(0x10) - ECANCELED = syscall.Errno(0x59) - ECHILD = syscall.Errno(0xa) - ECONNABORTED = syscall.Errno(0x35) - ECONNREFUSED = syscall.Errno(0x3d) - ECONNRESET = syscall.Errno(0x36) - EDEADLK = syscall.Errno(0xb) - EDESTADDRREQ = syscall.Errno(0x27) - EDEVERR = syscall.Errno(0x53) - EDOM = syscall.Errno(0x21) - EDQUOT = syscall.Errno(0x45) - EEXIST = syscall.Errno(0x11) - EFAULT = syscall.Errno(0xe) - EFBIG = syscall.Errno(0x1b) - EFTYPE = syscall.Errno(0x4f) - EHOSTDOWN = syscall.Errno(0x40) - EHOSTUNREACH = syscall.Errno(0x41) - EIDRM = syscall.Errno(0x5a) - EILSEQ = syscall.Errno(0x5c) - EINPROGRESS = syscall.Errno(0x24) - EINTR = syscall.Errno(0x4) - EINVAL = syscall.Errno(0x16) - EIO = syscall.Errno(0x5) - EISCONN = syscall.Errno(0x38) - EISDIR = syscall.Errno(0x15) - ELAST = syscall.Errno(0x6a) - ELOOP = syscall.Errno(0x3e) - EMFILE = syscall.Errno(0x18) - EMLINK = syscall.Errno(0x1f) - EMSGSIZE = syscall.Errno(0x28) - EMULTIHOP = syscall.Errno(0x5f) - ENAMETOOLONG = syscall.Errno(0x3f) - ENEEDAUTH = syscall.Errno(0x51) - ENETDOWN = syscall.Errno(0x32) - ENETRESET = syscall.Errno(0x34) - ENETUNREACH = syscall.Errno(0x33) - ENFILE = syscall.Errno(0x17) - ENOATTR = syscall.Errno(0x5d) - ENOBUFS = syscall.Errno(0x37) - ENODATA = syscall.Errno(0x60) - ENODEV = syscall.Errno(0x13) - ENOENT = syscall.Errno(0x2) - ENOEXEC = syscall.Errno(0x8) - ENOLCK = syscall.Errno(0x4d) - ENOLINK = syscall.Errno(0x61) - ENOMEM = syscall.Errno(0xc) - ENOMSG = syscall.Errno(0x5b) - ENOPOLICY = syscall.Errno(0x67) - ENOPROTOOPT = syscall.Errno(0x2a) - ENOSPC = syscall.Errno(0x1c) - ENOSR = syscall.Errno(0x62) - ENOSTR = syscall.Errno(0x63) - ENOSYS = syscall.Errno(0x4e) - ENOTBLK = syscall.Errno(0xf) - ENOTCONN = syscall.Errno(0x39) - ENOTDIR = syscall.Errno(0x14) - ENOTEMPTY = syscall.Errno(0x42) - ENOTRECOVERABLE = syscall.Errno(0x68) - ENOTSOCK = syscall.Errno(0x26) - ENOTSUP = syscall.Errno(0x2d) - ENOTTY = syscall.Errno(0x19) - ENXIO = syscall.Errno(0x6) - EOPNOTSUPP = syscall.Errno(0x66) - EOVERFLOW = syscall.Errno(0x54) - EOWNERDEAD = syscall.Errno(0x69) - EPERM = syscall.Errno(0x1) - EPFNOSUPPORT = syscall.Errno(0x2e) - EPIPE = syscall.Errno(0x20) - EPROCLIM = syscall.Errno(0x43) - EPROCUNAVAIL = syscall.Errno(0x4c) - EPROGMISMATCH = syscall.Errno(0x4b) - EPROGUNAVAIL = syscall.Errno(0x4a) - EPROTO = syscall.Errno(0x64) - EPROTONOSUPPORT = syscall.Errno(0x2b) - EPROTOTYPE = syscall.Errno(0x29) - EPWROFF = syscall.Errno(0x52) - EQFULL = syscall.Errno(0x6a) - ERANGE = syscall.Errno(0x22) - EREMOTE = syscall.Errno(0x47) - EROFS = syscall.Errno(0x1e) - ERPCMISMATCH = syscall.Errno(0x49) - ESHLIBVERS = syscall.Errno(0x57) - ESHUTDOWN = syscall.Errno(0x3a) - ESOCKTNOSUPPORT = syscall.Errno(0x2c) - ESPIPE = syscall.Errno(0x1d) - ESRCH = syscall.Errno(0x3) - ESTALE = syscall.Errno(0x46) - ETIME = syscall.Errno(0x65) - ETIMEDOUT = syscall.Errno(0x3c) - ETOOMANYREFS = syscall.Errno(0x3b) - ETXTBSY = syscall.Errno(0x1a) - EUSERS = syscall.Errno(0x44) - EWOULDBLOCK = syscall.Errno(0x23) - EXDEV = syscall.Errno(0x12) -) - -// Signals -const ( - SIGABRT = syscall.Signal(0x6) - SIGALRM = syscall.Signal(0xe) - SIGBUS = syscall.Signal(0xa) - SIGCHLD = syscall.Signal(0x14) - SIGCONT = syscall.Signal(0x13) - SIGEMT = syscall.Signal(0x7) - SIGFPE = syscall.Signal(0x8) - SIGHUP = syscall.Signal(0x1) - SIGILL = syscall.Signal(0x4) - SIGINFO = syscall.Signal(0x1d) - SIGINT = syscall.Signal(0x2) - SIGIO = syscall.Signal(0x17) - SIGIOT = syscall.Signal(0x6) - SIGKILL = syscall.Signal(0x9) - SIGPIPE = syscall.Signal(0xd) - SIGPROF = syscall.Signal(0x1b) - SIGQUIT = syscall.Signal(0x3) - SIGSEGV = syscall.Signal(0xb) - SIGSTOP = syscall.Signal(0x11) - SIGSYS = syscall.Signal(0xc) - SIGTERM = syscall.Signal(0xf) - SIGTRAP = syscall.Signal(0x5) - SIGTSTP = syscall.Signal(0x12) - SIGTTIN = syscall.Signal(0x15) - SIGTTOU = syscall.Signal(0x16) - SIGURG = syscall.Signal(0x10) - SIGUSR1 = syscall.Signal(0x1e) - SIGUSR2 = syscall.Signal(0x1f) - SIGVTALRM = syscall.Signal(0x1a) - SIGWINCH = syscall.Signal(0x1c) - SIGXCPU = syscall.Signal(0x18) - SIGXFSZ = syscall.Signal(0x19) -) - -// Error table -var errorList = [...]struct { - num syscall.Errno - name string - desc string -}{ - {1, "EPERM", "operation not permitted"}, - {2, "ENOENT", "no such file or directory"}, - {3, "ESRCH", "no such process"}, - {4, "EINTR", "interrupted system call"}, - {5, "EIO", "input/output error"}, - {6, "ENXIO", "device not configured"}, - {7, "E2BIG", "argument list too long"}, - {8, "ENOEXEC", "exec format error"}, - {9, "EBADF", "bad file descriptor"}, - {10, "ECHILD", "no child processes"}, - {11, "EDEADLK", "resource deadlock avoided"}, - {12, "ENOMEM", "cannot allocate memory"}, - {13, "EACCES", "permission denied"}, - {14, "EFAULT", "bad address"}, - {15, "ENOTBLK", "block device required"}, - {16, "EBUSY", "resource busy"}, - {17, "EEXIST", "file exists"}, - {18, "EXDEV", "cross-device link"}, - {19, "ENODEV", "operation not supported by device"}, - {20, "ENOTDIR", "not a directory"}, - {21, "EISDIR", "is a directory"}, - {22, "EINVAL", "invalid argument"}, - {23, "ENFILE", "too many open files in system"}, - {24, "EMFILE", "too many open files"}, - {25, "ENOTTY", "inappropriate ioctl for device"}, - {26, "ETXTBSY", "text file busy"}, - {27, "EFBIG", "file too large"}, - {28, "ENOSPC", "no space left on device"}, - {29, "ESPIPE", "illegal seek"}, - {30, "EROFS", "read-only file system"}, - {31, "EMLINK", "too many links"}, - {32, "EPIPE", "broken pipe"}, - {33, "EDOM", "numerical argument out of domain"}, - {34, "ERANGE", "result too large"}, - {35, "EAGAIN", "resource temporarily unavailable"}, - {36, "EINPROGRESS", "operation now in progress"}, - {37, "EALREADY", "operation already in progress"}, - {38, "ENOTSOCK", "socket operation on non-socket"}, - {39, "EDESTADDRREQ", "destination address required"}, - {40, "EMSGSIZE", "message too long"}, - {41, "EPROTOTYPE", "protocol wrong type for socket"}, - {42, "ENOPROTOOPT", "protocol not available"}, - {43, "EPROTONOSUPPORT", "protocol not supported"}, - {44, "ESOCKTNOSUPPORT", "socket type not supported"}, - {45, "ENOTSUP", "operation not supported"}, - {46, "EPFNOSUPPORT", "protocol family not supported"}, - {47, "EAFNOSUPPORT", "address family not supported by protocol family"}, - {48, "EADDRINUSE", "address already in use"}, - {49, "EADDRNOTAVAIL", "can't assign requested address"}, - {50, "ENETDOWN", "network is down"}, - {51, "ENETUNREACH", "network is unreachable"}, - {52, "ENETRESET", "network dropped connection on reset"}, - {53, "ECONNABORTED", "software caused connection abort"}, - {54, "ECONNRESET", "connection reset by peer"}, - {55, "ENOBUFS", "no buffer space available"}, - {56, "EISCONN", "socket is already connected"}, - {57, "ENOTCONN", "socket is not connected"}, - {58, "ESHUTDOWN", "can't send after socket shutdown"}, - {59, "ETOOMANYREFS", "too many references: can't splice"}, - {60, "ETIMEDOUT", "operation timed out"}, - {61, "ECONNREFUSED", "connection refused"}, - {62, "ELOOP", "too many levels of symbolic links"}, - {63, "ENAMETOOLONG", "file name too long"}, - {64, "EHOSTDOWN", "host is down"}, - {65, "EHOSTUNREACH", "no route to host"}, - {66, "ENOTEMPTY", "directory not empty"}, - {67, "EPROCLIM", "too many processes"}, - {68, "EUSERS", "too many users"}, - {69, "EDQUOT", "disc quota exceeded"}, - {70, "ESTALE", "stale NFS file handle"}, - {71, "EREMOTE", "too many levels of remote in path"}, - {72, "EBADRPC", "RPC struct is bad"}, - {73, "ERPCMISMATCH", "RPC version wrong"}, - {74, "EPROGUNAVAIL", "RPC prog. not avail"}, - {75, "EPROGMISMATCH", "program version wrong"}, - {76, "EPROCUNAVAIL", "bad procedure for program"}, - {77, "ENOLCK", "no locks available"}, - {78, "ENOSYS", "function not implemented"}, - {79, "EFTYPE", "inappropriate file type or format"}, - {80, "EAUTH", "authentication error"}, - {81, "ENEEDAUTH", "need authenticator"}, - {82, "EPWROFF", "device power is off"}, - {83, "EDEVERR", "device error"}, - {84, "EOVERFLOW", "value too large to be stored in data type"}, - {85, "EBADEXEC", "bad executable (or shared library)"}, - {86, "EBADARCH", "bad CPU type in executable"}, - {87, "ESHLIBVERS", "shared library version mismatch"}, - {88, "EBADMACHO", "malformed Mach-o file"}, - {89, "ECANCELED", "operation canceled"}, - {90, "EIDRM", "identifier removed"}, - {91, "ENOMSG", "no message of desired type"}, - {92, "EILSEQ", "illegal byte sequence"}, - {93, "ENOATTR", "attribute not found"}, - {94, "EBADMSG", "bad message"}, - {95, "EMULTIHOP", "EMULTIHOP (Reserved)"}, - {96, "ENODATA", "no message available on STREAM"}, - {97, "ENOLINK", "ENOLINK (Reserved)"}, - {98, "ENOSR", "no STREAM resources"}, - {99, "ENOSTR", "not a STREAM"}, - {100, "EPROTO", "protocol error"}, - {101, "ETIME", "STREAM ioctl timeout"}, - {102, "EOPNOTSUPP", "operation not supported on socket"}, - {103, "ENOPOLICY", "policy not found"}, - {104, "ENOTRECOVERABLE", "state not recoverable"}, - {105, "EOWNERDEAD", "previous owner died"}, - {106, "EQFULL", "interface output queue is full"}, -} - -// Signal table -var signalList = [...]struct { - num syscall.Signal - name string - desc string -}{ - {1, "SIGHUP", "hangup"}, - {2, "SIGINT", "interrupt"}, - {3, "SIGQUIT", "quit"}, - {4, "SIGILL", "illegal instruction"}, - {5, "SIGTRAP", "trace/BPT trap"}, - {6, "SIGABRT", "abort trap"}, - {7, "SIGEMT", "EMT trap"}, - {8, "SIGFPE", "floating point exception"}, - {9, "SIGKILL", "killed"}, - {10, "SIGBUS", "bus error"}, - {11, "SIGSEGV", "segmentation fault"}, - {12, "SIGSYS", "bad system call"}, - {13, "SIGPIPE", "broken pipe"}, - {14, "SIGALRM", "alarm clock"}, - {15, "SIGTERM", "terminated"}, - {16, "SIGURG", "urgent I/O condition"}, - {17, "SIGSTOP", "suspended (signal)"}, - {18, "SIGTSTP", "suspended"}, - {19, "SIGCONT", "continued"}, - {20, "SIGCHLD", "child exited"}, - {21, "SIGTTIN", "stopped (tty input)"}, - {22, "SIGTTOU", "stopped (tty output)"}, - {23, "SIGIO", "I/O possible"}, - {24, "SIGXCPU", "cputime limit exceeded"}, - {25, "SIGXFSZ", "filesize limit exceeded"}, - {26, "SIGVTALRM", "virtual timer expired"}, - {27, "SIGPROF", "profiling timer expired"}, - {28, "SIGWINCH", "window size changes"}, - {29, "SIGINFO", "information request"}, - {30, "SIGUSR1", "user defined signal 1"}, - {31, "SIGUSR2", "user defined signal 2"}, -} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_darwin_arm.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_darwin_arm.go deleted file mode 100644 index e748cb11057..00000000000 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_darwin_arm.go +++ /dev/null @@ -1,1789 +0,0 @@ -// mkerrors.sh -// Code generated by the command above; see README.md. DO NOT EDIT. - -//go:build arm && darwin -// +build arm,darwin - -// Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs -- _const.go - -package unix - -import "syscall" - -const ( - AF_APPLETALK = 0x10 - AF_CCITT = 0xa - AF_CHAOS = 0x5 - AF_CNT = 0x15 - AF_COIP = 0x14 - AF_DATAKIT = 0x9 - AF_DECnet = 0xc - AF_DLI = 0xd - AF_E164 = 0x1c - AF_ECMA = 0x8 - AF_HYLINK = 0xf - AF_IEEE80211 = 0x25 - AF_IMPLINK = 0x3 - AF_INET = 0x2 - AF_INET6 = 0x1e - AF_IPX = 0x17 - AF_ISDN = 0x1c - AF_ISO = 0x7 - AF_LAT = 0xe - AF_LINK = 0x12 - AF_LOCAL = 0x1 - AF_MAX = 0x28 - AF_NATM = 0x1f - AF_NDRV = 0x1b - AF_NETBIOS = 0x21 - AF_NS = 0x6 - AF_OSI = 0x7 - AF_PPP = 0x22 - AF_PUP = 0x4 - AF_RESERVED_36 = 0x24 - AF_ROUTE = 0x11 - AF_SIP = 0x18 - AF_SNA = 0xb - AF_SYSTEM = 0x20 - AF_SYS_CONTROL = 0x2 - AF_UNIX = 0x1 - AF_UNSPEC = 0x0 - AF_UTUN = 0x26 - ALTWERASE = 0x200 - ATTR_BIT_MAP_COUNT = 0x5 - ATTR_CMN_ACCESSMASK = 0x20000 - ATTR_CMN_ACCTIME = 0x1000 - ATTR_CMN_ADDEDTIME = 0x10000000 - ATTR_CMN_BKUPTIME = 0x2000 - ATTR_CMN_CHGTIME = 0x800 - ATTR_CMN_CRTIME = 0x200 - ATTR_CMN_DATA_PROTECT_FLAGS = 0x40000000 - ATTR_CMN_DEVID = 0x2 - ATTR_CMN_DOCUMENT_ID = 0x100000 - ATTR_CMN_ERROR = 0x20000000 - ATTR_CMN_EXTENDED_SECURITY = 0x400000 - ATTR_CMN_FILEID = 0x2000000 - ATTR_CMN_FLAGS = 0x40000 - ATTR_CMN_FNDRINFO = 0x4000 - ATTR_CMN_FSID = 0x4 - ATTR_CMN_FULLPATH = 0x8000000 - ATTR_CMN_GEN_COUNT = 0x80000 - ATTR_CMN_GRPID = 0x10000 - ATTR_CMN_GRPUUID = 0x1000000 - ATTR_CMN_MODTIME = 0x400 - ATTR_CMN_NAME = 0x1 - ATTR_CMN_NAMEDATTRCOUNT = 0x80000 - ATTR_CMN_NAMEDATTRLIST = 0x100000 - ATTR_CMN_OBJID = 0x20 - ATTR_CMN_OBJPERMANENTID = 0x40 - ATTR_CMN_OBJTAG = 0x10 - ATTR_CMN_OBJTYPE = 0x8 - ATTR_CMN_OWNERID = 0x8000 - ATTR_CMN_PARENTID = 0x4000000 - ATTR_CMN_PAROBJID = 0x80 - ATTR_CMN_RETURNED_ATTRS = 0x80000000 - ATTR_CMN_SCRIPT = 0x100 - ATTR_CMN_SETMASK = 0x41c7ff00 - ATTR_CMN_USERACCESS = 0x200000 - ATTR_CMN_UUID = 0x800000 - ATTR_CMN_VALIDMASK = 0xffffffff - ATTR_CMN_VOLSETMASK = 0x6700 - ATTR_FILE_ALLOCSIZE = 0x4 - ATTR_FILE_CLUMPSIZE = 0x10 - ATTR_FILE_DATAALLOCSIZE = 0x400 - ATTR_FILE_DATAEXTENTS = 0x800 - ATTR_FILE_DATALENGTH = 0x200 - ATTR_FILE_DEVTYPE = 0x20 - ATTR_FILE_FILETYPE = 0x40 - ATTR_FILE_FORKCOUNT = 0x80 - ATTR_FILE_FORKLIST = 0x100 - ATTR_FILE_IOBLOCKSIZE = 0x8 - ATTR_FILE_LINKCOUNT = 0x1 - ATTR_FILE_RSRCALLOCSIZE = 0x2000 - ATTR_FILE_RSRCEXTENTS = 0x4000 - ATTR_FILE_RSRCLENGTH = 0x1000 - ATTR_FILE_SETMASK = 0x20 - ATTR_FILE_TOTALSIZE = 0x2 - ATTR_FILE_VALIDMASK = 0x37ff - ATTR_VOL_ALLOCATIONCLUMP = 0x40 - ATTR_VOL_ATTRIBUTES = 0x40000000 - ATTR_VOL_CAPABILITIES = 0x20000 - ATTR_VOL_DIRCOUNT = 0x400 - ATTR_VOL_ENCODINGSUSED = 0x10000 - ATTR_VOL_FILECOUNT = 0x200 - ATTR_VOL_FSTYPE = 0x1 - ATTR_VOL_INFO = 0x80000000 - ATTR_VOL_IOBLOCKSIZE = 0x80 - ATTR_VOL_MAXOBJCOUNT = 0x800 - ATTR_VOL_MINALLOCATION = 0x20 - ATTR_VOL_MOUNTEDDEVICE = 0x8000 - ATTR_VOL_MOUNTFLAGS = 0x4000 - ATTR_VOL_MOUNTPOINT = 0x1000 - ATTR_VOL_NAME = 0x2000 - ATTR_VOL_OBJCOUNT = 0x100 - ATTR_VOL_QUOTA_SIZE = 0x10000000 - ATTR_VOL_RESERVED_SIZE = 0x20000000 - ATTR_VOL_SETMASK = 0x80002000 - ATTR_VOL_SIGNATURE = 0x2 - ATTR_VOL_SIZE = 0x4 - ATTR_VOL_SPACEAVAIL = 0x10 - ATTR_VOL_SPACEFREE = 0x8 - ATTR_VOL_UUID = 0x40000 - ATTR_VOL_VALIDMASK = 0xf007ffff - B0 = 0x0 - B110 = 0x6e - B115200 = 0x1c200 - B1200 = 0x4b0 - B134 = 0x86 - B14400 = 0x3840 - B150 = 0x96 - B1800 = 0x708 - B19200 = 0x4b00 - B200 = 0xc8 - B230400 = 0x38400 - B2400 = 0x960 - B28800 = 0x7080 - B300 = 0x12c - B38400 = 0x9600 - B4800 = 0x12c0 - B50 = 0x32 - B57600 = 0xe100 - B600 = 0x258 - B7200 = 0x1c20 - B75 = 0x4b - B76800 = 0x12c00 - B9600 = 0x2580 - BIOCFLUSH = 0x20004268 - BIOCGBLEN = 0x40044266 - BIOCGDLT = 0x4004426a - BIOCGDLTLIST = 0xc00c4279 - BIOCGETIF = 0x4020426b - BIOCGHDRCMPLT = 0x40044274 - BIOCGRSIG = 0x40044272 - BIOCGRTIMEOUT = 0x4010426e - BIOCGSEESENT = 0x40044276 - BIOCGSTATS = 0x4008426f - BIOCIMMEDIATE = 0x80044270 - BIOCPROMISC = 0x20004269 - BIOCSBLEN = 0xc0044266 - BIOCSDLT = 0x80044278 - BIOCSETF = 0x80104267 - BIOCSETFNR = 0x8010427e - BIOCSETIF = 0x8020426c - BIOCSHDRCMPLT = 0x80044275 - BIOCSRSIG = 0x80044273 - BIOCSRTIMEOUT = 0x8010426d - BIOCSSEESENT = 0x80044277 - BIOCVERSION = 0x40044271 - BPF_A = 0x10 - BPF_ABS = 0x20 - BPF_ADD = 0x0 - BPF_ALIGNMENT = 0x4 - BPF_ALU = 0x4 - BPF_AND = 0x50 - BPF_B = 0x10 - BPF_DIV = 0x30 - BPF_H = 0x8 - BPF_IMM = 0x0 - BPF_IND = 0x40 - BPF_JA = 0x0 - BPF_JEQ = 0x10 - BPF_JGE = 0x30 - BPF_JGT = 0x20 - BPF_JMP = 0x5 - BPF_JSET = 0x40 - BPF_K = 0x0 - BPF_LD = 0x0 - BPF_LDX = 0x1 - BPF_LEN = 0x80 - BPF_LSH = 0x60 - BPF_MAJOR_VERSION = 0x1 - BPF_MAXBUFSIZE = 0x80000 - BPF_MAXINSNS = 0x200 - BPF_MEM = 0x60 - BPF_MEMWORDS = 0x10 - BPF_MINBUFSIZE = 0x20 - BPF_MINOR_VERSION = 0x1 - BPF_MISC = 0x7 - BPF_MSH = 0xa0 - BPF_MUL = 0x20 - BPF_NEG = 0x80 - BPF_OR = 0x40 - BPF_RELEASE = 0x30bb6 - BPF_RET = 0x6 - BPF_RSH = 0x70 - BPF_ST = 0x2 - BPF_STX = 0x3 - BPF_SUB = 0x10 - BPF_TAX = 0x0 - BPF_TXA = 0x80 - BPF_W = 0x0 - BPF_X = 0x8 - BRKINT = 0x2 - BS0 = 0x0 - BS1 = 0x8000 - BSDLY = 0x8000 - CFLUSH = 0xf - CLOCAL = 0x8000 - CLOCK_MONOTONIC = 0x6 - CLOCK_MONOTONIC_RAW = 0x4 - CLOCK_MONOTONIC_RAW_APPROX = 0x5 - CLOCK_PROCESS_CPUTIME_ID = 0xc - CLOCK_REALTIME = 0x0 - CLOCK_THREAD_CPUTIME_ID = 0x10 - CLOCK_UPTIME_RAW = 0x8 - CLOCK_UPTIME_RAW_APPROX = 0x9 - CLONE_NOFOLLOW = 0x1 - CLONE_NOOWNERCOPY = 0x2 - CR0 = 0x0 - CR1 = 0x1000 - CR2 = 0x2000 - CR3 = 0x3000 - CRDLY = 0x3000 - CREAD = 0x800 - CRTSCTS = 0x30000 - CS5 = 0x0 - CS6 = 0x100 - CS7 = 0x200 - CS8 = 0x300 - CSIZE = 0x300 - CSTART = 0x11 - CSTATUS = 0x14 - CSTOP = 0x13 - CSTOPB = 0x400 - CSUSP = 0x1a - CTLIOCGINFO = 0xc0644e03 - CTL_HW = 0x6 - CTL_KERN = 0x1 - CTL_MAXNAME = 0xc - CTL_NET = 0x4 - DLT_A429 = 0xb8 - DLT_A653_ICM = 0xb9 - DLT_AIRONET_HEADER = 0x78 - DLT_AOS = 0xde - DLT_APPLE_IP_OVER_IEEE1394 = 0x8a - DLT_ARCNET = 0x7 - DLT_ARCNET_LINUX = 0x81 - DLT_ATM_CLIP = 0x13 - DLT_ATM_RFC1483 = 0xb - DLT_AURORA = 0x7e - DLT_AX25 = 0x3 - DLT_AX25_KISS = 0xca - DLT_BACNET_MS_TP = 0xa5 - DLT_BLUETOOTH_HCI_H4 = 0xbb - DLT_BLUETOOTH_HCI_H4_WITH_PHDR = 0xc9 - DLT_CAN20B = 0xbe - DLT_CAN_SOCKETCAN = 0xe3 - DLT_CHAOS = 0x5 - DLT_CHDLC = 0x68 - DLT_CISCO_IOS = 0x76 - DLT_C_HDLC = 0x68 - DLT_C_HDLC_WITH_DIR = 0xcd - DLT_DBUS = 0xe7 - DLT_DECT = 0xdd - DLT_DOCSIS = 0x8f - DLT_DVB_CI = 0xeb - DLT_ECONET = 0x73 - DLT_EN10MB = 0x1 - DLT_EN3MB = 0x2 - DLT_ENC = 0x6d - DLT_ERF = 0xc5 - DLT_ERF_ETH = 0xaf - DLT_ERF_POS = 0xb0 - DLT_FC_2 = 0xe0 - DLT_FC_2_WITH_FRAME_DELIMS = 0xe1 - DLT_FDDI = 0xa - DLT_FLEXRAY = 0xd2 - DLT_FRELAY = 0x6b - DLT_FRELAY_WITH_DIR = 0xce - DLT_GCOM_SERIAL = 0xad - DLT_GCOM_T1E1 = 0xac - DLT_GPF_F = 0xab - DLT_GPF_T = 0xaa - DLT_GPRS_LLC = 0xa9 - DLT_GSMTAP_ABIS = 0xda - DLT_GSMTAP_UM = 0xd9 - DLT_HHDLC = 0x79 - DLT_IBM_SN = 0x92 - DLT_IBM_SP = 0x91 - DLT_IEEE802 = 0x6 - DLT_IEEE802_11 = 0x69 - DLT_IEEE802_11_RADIO = 0x7f - DLT_IEEE802_11_RADIO_AVS = 0xa3 - DLT_IEEE802_15_4 = 0xc3 - DLT_IEEE802_15_4_LINUX = 0xbf - DLT_IEEE802_15_4_NOFCS = 0xe6 - DLT_IEEE802_15_4_NONASK_PHY = 0xd7 - DLT_IEEE802_16_MAC_CPS = 0xbc - DLT_IEEE802_16_MAC_CPS_RADIO = 0xc1 - DLT_IPFILTER = 0x74 - DLT_IPMB = 0xc7 - DLT_IPMB_LINUX = 0xd1 - DLT_IPNET = 0xe2 - DLT_IPOIB = 0xf2 - DLT_IPV4 = 0xe4 - DLT_IPV6 = 0xe5 - DLT_IP_OVER_FC = 0x7a - DLT_JUNIPER_ATM1 = 0x89 - DLT_JUNIPER_ATM2 = 0x87 - DLT_JUNIPER_ATM_CEMIC = 0xee - DLT_JUNIPER_CHDLC = 0xb5 - DLT_JUNIPER_ES = 0x84 - DLT_JUNIPER_ETHER = 0xb2 - DLT_JUNIPER_FIBRECHANNEL = 0xea - DLT_JUNIPER_FRELAY = 0xb4 - DLT_JUNIPER_GGSN = 0x85 - DLT_JUNIPER_ISM = 0xc2 - DLT_JUNIPER_MFR = 0x86 - DLT_JUNIPER_MLFR = 0x83 - DLT_JUNIPER_MLPPP = 0x82 - DLT_JUNIPER_MONITOR = 0xa4 - DLT_JUNIPER_PIC_PEER = 0xae - DLT_JUNIPER_PPP = 0xb3 - DLT_JUNIPER_PPPOE = 0xa7 - DLT_JUNIPER_PPPOE_ATM = 0xa8 - DLT_JUNIPER_SERVICES = 0x88 - DLT_JUNIPER_SRX_E2E = 0xe9 - DLT_JUNIPER_ST = 0xc8 - DLT_JUNIPER_VP = 0xb7 - DLT_JUNIPER_VS = 0xe8 - DLT_LAPB_WITH_DIR = 0xcf - DLT_LAPD = 0xcb - DLT_LIN = 0xd4 - DLT_LINUX_EVDEV = 0xd8 - DLT_LINUX_IRDA = 0x90 - DLT_LINUX_LAPD = 0xb1 - DLT_LINUX_PPP_WITHDIRECTION = 0xa6 - DLT_LINUX_SLL = 0x71 - DLT_LOOP = 0x6c - DLT_LTALK = 0x72 - DLT_MATCHING_MAX = 0xf5 - DLT_MATCHING_MIN = 0x68 - DLT_MFR = 0xb6 - DLT_MOST = 0xd3 - DLT_MPEG_2_TS = 0xf3 - DLT_MPLS = 0xdb - DLT_MTP2 = 0x8c - DLT_MTP2_WITH_PHDR = 0x8b - DLT_MTP3 = 0x8d - DLT_MUX27010 = 0xec - DLT_NETANALYZER = 0xf0 - DLT_NETANALYZER_TRANSPARENT = 0xf1 - DLT_NFC_LLCP = 0xf5 - DLT_NFLOG = 0xef - DLT_NG40 = 0xf4 - DLT_NULL = 0x0 - DLT_PCI_EXP = 0x7d - DLT_PFLOG = 0x75 - DLT_PFSYNC = 0x12 - DLT_PPI = 0xc0 - DLT_PPP = 0x9 - DLT_PPP_BSDOS = 0x10 - DLT_PPP_ETHER = 0x33 - DLT_PPP_PPPD = 0xa6 - DLT_PPP_SERIAL = 0x32 - DLT_PPP_WITH_DIR = 0xcc - DLT_PPP_WITH_DIRECTION = 0xa6 - DLT_PRISM_HEADER = 0x77 - DLT_PRONET = 0x4 - DLT_RAIF1 = 0xc6 - DLT_RAW = 0xc - DLT_RIO = 0x7c - DLT_SCCP = 0x8e - DLT_SITA = 0xc4 - DLT_SLIP = 0x8 - DLT_SLIP_BSDOS = 0xf - DLT_STANAG_5066_D_PDU = 0xed - DLT_SUNATM = 0x7b - DLT_SYMANTEC_FIREWALL = 0x63 - DLT_TZSP = 0x80 - DLT_USB = 0xba - DLT_USB_LINUX = 0xbd - DLT_USB_LINUX_MMAPPED = 0xdc - DLT_USER0 = 0x93 - DLT_USER1 = 0x94 - DLT_USER10 = 0x9d - DLT_USER11 = 0x9e - DLT_USER12 = 0x9f - DLT_USER13 = 0xa0 - DLT_USER14 = 0xa1 - DLT_USER15 = 0xa2 - DLT_USER2 = 0x95 - DLT_USER3 = 0x96 - DLT_USER4 = 0x97 - DLT_USER5 = 0x98 - DLT_USER6 = 0x99 - DLT_USER7 = 0x9a - DLT_USER8 = 0x9b - DLT_USER9 = 0x9c - DLT_WIHART = 0xdf - DLT_X2E_SERIAL = 0xd5 - DLT_X2E_XORAYA = 0xd6 - DT_BLK = 0x6 - DT_CHR = 0x2 - DT_DIR = 0x4 - DT_FIFO = 0x1 - DT_LNK = 0xa - DT_REG = 0x8 - DT_SOCK = 0xc - DT_UNKNOWN = 0x0 - DT_WHT = 0xe - ECHO = 0x8 - ECHOCTL = 0x40 - ECHOE = 0x2 - ECHOK = 0x4 - ECHOKE = 0x1 - ECHONL = 0x10 - ECHOPRT = 0x20 - EVFILT_AIO = -0x3 - EVFILT_EXCEPT = -0xf - EVFILT_FS = -0x9 - EVFILT_MACHPORT = -0x8 - EVFILT_PROC = -0x5 - EVFILT_READ = -0x1 - EVFILT_SIGNAL = -0x6 - EVFILT_SYSCOUNT = 0xf - EVFILT_THREADMARKER = 0xf - EVFILT_TIMER = -0x7 - EVFILT_USER = -0xa - EVFILT_VM = -0xc - EVFILT_VNODE = -0x4 - EVFILT_WRITE = -0x2 - EV_ADD = 0x1 - EV_CLEAR = 0x20 - EV_DELETE = 0x2 - EV_DISABLE = 0x8 - EV_DISPATCH = 0x80 - EV_DISPATCH2 = 0x180 - EV_ENABLE = 0x4 - EV_EOF = 0x8000 - EV_ERROR = 0x4000 - EV_FLAG0 = 0x1000 - EV_FLAG1 = 0x2000 - EV_ONESHOT = 0x10 - EV_OOBAND = 0x2000 - EV_POLL = 0x1000 - EV_RECEIPT = 0x40 - EV_SYSFLAGS = 0xf000 - EV_UDATA_SPECIFIC = 0x100 - EV_VANISHED = 0x200 - EXTA = 0x4b00 - EXTB = 0x9600 - EXTPROC = 0x800 - FD_CLOEXEC = 0x1 - FD_SETSIZE = 0x400 - FF0 = 0x0 - FF1 = 0x4000 - FFDLY = 0x4000 - FLUSHO = 0x800000 - FSOPT_ATTR_CMN_EXTENDED = 0x20 - FSOPT_NOFOLLOW = 0x1 - FSOPT_NOINMEMUPDATE = 0x2 - FSOPT_PACK_INVAL_ATTRS = 0x8 - FSOPT_REPORT_FULLSIZE = 0x4 - F_ADDFILESIGS = 0x3d - F_ADDFILESIGS_FOR_DYLD_SIM = 0x53 - F_ADDFILESIGS_RETURN = 0x61 - F_ADDSIGS = 0x3b - F_ALLOCATEALL = 0x4 - F_ALLOCATECONTIG = 0x2 - F_BARRIERFSYNC = 0x55 - F_CHECK_LV = 0x62 - F_CHKCLEAN = 0x29 - F_DUPFD = 0x0 - F_DUPFD_CLOEXEC = 0x43 - F_FINDSIGS = 0x4e - F_FLUSH_DATA = 0x28 - F_FREEZE_FS = 0x35 - F_FULLFSYNC = 0x33 - F_GETCODEDIR = 0x48 - F_GETFD = 0x1 - F_GETFL = 0x3 - F_GETLK = 0x7 - F_GETLKPID = 0x42 - F_GETNOSIGPIPE = 0x4a - F_GETOWN = 0x5 - F_GETPATH = 0x32 - F_GETPATH_MTMINFO = 0x47 - F_GETPROTECTIONCLASS = 0x3f - F_GETPROTECTIONLEVEL = 0x4d - F_GLOBAL_NOCACHE = 0x37 - F_LOG2PHYS = 0x31 - F_LOG2PHYS_EXT = 0x41 - F_NOCACHE = 0x30 - F_NODIRECT = 0x3e - F_OK = 0x0 - F_PATHPKG_CHECK = 0x34 - F_PEOFPOSMODE = 0x3 - F_PREALLOCATE = 0x2a - F_PUNCHHOLE = 0x63 - F_RDADVISE = 0x2c - F_RDAHEAD = 0x2d - F_RDLCK = 0x1 - F_SETBACKINGSTORE = 0x46 - F_SETFD = 0x2 - F_SETFL = 0x4 - F_SETLK = 0x8 - F_SETLKW = 0x9 - F_SETLKWTIMEOUT = 0xa - F_SETNOSIGPIPE = 0x49 - F_SETOWN = 0x6 - F_SETPROTECTIONCLASS = 0x40 - F_SETSIZE = 0x2b - F_SINGLE_WRITER = 0x4c - F_THAW_FS = 0x36 - F_TRANSCODEKEY = 0x4b - F_TRIM_ACTIVE_FILE = 0x64 - F_UNLCK = 0x2 - F_VOLPOSMODE = 0x4 - F_WRLCK = 0x3 - HUPCL = 0x4000 - HW_MACHINE = 0x1 - ICANON = 0x100 - ICMP6_FILTER = 0x12 - ICRNL = 0x100 - IEXTEN = 0x400 - IFF_ALLMULTI = 0x200 - IFF_ALTPHYS = 0x4000 - IFF_BROADCAST = 0x2 - IFF_DEBUG = 0x4 - IFF_LINK0 = 0x1000 - IFF_LINK1 = 0x2000 - IFF_LINK2 = 0x4000 - IFF_LOOPBACK = 0x8 - IFF_MULTICAST = 0x8000 - IFF_NOARP = 0x80 - IFF_NOTRAILERS = 0x20 - IFF_OACTIVE = 0x400 - IFF_POINTOPOINT = 0x10 - IFF_PROMISC = 0x100 - IFF_RUNNING = 0x40 - IFF_SIMPLEX = 0x800 - IFF_UP = 0x1 - IFNAMSIZ = 0x10 - IFT_1822 = 0x2 - IFT_AAL5 = 0x31 - IFT_ARCNET = 0x23 - IFT_ARCNETPLUS = 0x24 - IFT_ATM = 0x25 - IFT_BRIDGE = 0xd1 - IFT_CARP = 0xf8 - IFT_CELLULAR = 0xff - IFT_CEPT = 0x13 - IFT_DS3 = 0x1e - IFT_ENC = 0xf4 - IFT_EON = 0x19 - IFT_ETHER = 0x6 - IFT_FAITH = 0x38 - IFT_FDDI = 0xf - IFT_FRELAY = 0x20 - IFT_FRELAYDCE = 0x2c - IFT_GIF = 0x37 - IFT_HDH1822 = 0x3 - IFT_HIPPI = 0x2f - IFT_HSSI = 0x2e - IFT_HY = 0xe - IFT_IEEE1394 = 0x90 - IFT_IEEE8023ADLAG = 0x88 - IFT_ISDNBASIC = 0x14 - IFT_ISDNPRIMARY = 0x15 - IFT_ISO88022LLC = 0x29 - IFT_ISO88023 = 0x7 - IFT_ISO88024 = 0x8 - IFT_ISO88025 = 0x9 - IFT_ISO88026 = 0xa - IFT_L2VLAN = 0x87 - IFT_LAPB = 0x10 - IFT_LOCALTALK = 0x2a - IFT_LOOP = 0x18 - IFT_MIOX25 = 0x26 - IFT_MODEM = 0x30 - IFT_NSIP = 0x1b - IFT_OTHER = 0x1 - IFT_P10 = 0xc - IFT_P80 = 0xd - IFT_PARA = 0x22 - IFT_PDP = 0xff - IFT_PFLOG = 0xf5 - IFT_PFSYNC = 0xf6 - IFT_PKTAP = 0xfe - IFT_PPP = 0x17 - IFT_PROPMUX = 0x36 - IFT_PROPVIRTUAL = 0x35 - IFT_PTPSERIAL = 0x16 - IFT_RS232 = 0x21 - IFT_SDLC = 0x11 - IFT_SIP = 0x1f - IFT_SLIP = 0x1c - IFT_SMDSDXI = 0x2b - IFT_SMDSICIP = 0x34 - IFT_SONET = 0x27 - IFT_SONETPATH = 0x32 - IFT_SONETVT = 0x33 - IFT_STARLAN = 0xb - IFT_STF = 0x39 - IFT_T1 = 0x12 - IFT_ULTRA = 0x1d - IFT_V35 = 0x2d - IFT_X25 = 0x5 - IFT_X25DDN = 0x4 - IFT_X25PLE = 0x28 - IFT_XETHER = 0x1a - IGNBRK = 0x1 - IGNCR = 0x80 - IGNPAR = 0x4 - IMAXBEL = 0x2000 - INLCR = 0x40 - INPCK = 0x10 - IN_CLASSA_HOST = 0xffffff - IN_CLASSA_MAX = 0x80 - IN_CLASSA_NET = 0xff000000 - IN_CLASSA_NSHIFT = 0x18 - IN_CLASSB_HOST = 0xffff - IN_CLASSB_MAX = 0x10000 - IN_CLASSB_NET = 0xffff0000 - IN_CLASSB_NSHIFT = 0x10 - IN_CLASSC_HOST = 0xff - IN_CLASSC_NET = 0xffffff00 - IN_CLASSC_NSHIFT = 0x8 - IN_CLASSD_HOST = 0xfffffff - IN_CLASSD_NET = 0xf0000000 - IN_CLASSD_NSHIFT = 0x1c - IN_LINKLOCALNETNUM = 0xa9fe0000 - IN_LOOPBACKNET = 0x7f - IPPROTO_3PC = 0x22 - IPPROTO_ADFS = 0x44 - IPPROTO_AH = 0x33 - IPPROTO_AHIP = 0x3d - IPPROTO_APES = 0x63 - IPPROTO_ARGUS = 0xd - IPPROTO_AX25 = 0x5d - IPPROTO_BHA = 0x31 - IPPROTO_BLT = 0x1e - IPPROTO_BRSATMON = 0x4c - IPPROTO_CFTP = 0x3e - IPPROTO_CHAOS = 0x10 - IPPROTO_CMTP = 0x26 - IPPROTO_CPHB = 0x49 - IPPROTO_CPNX = 0x48 - IPPROTO_DDP = 0x25 - IPPROTO_DGP = 0x56 - IPPROTO_DIVERT = 0xfe - IPPROTO_DONE = 0x101 - IPPROTO_DSTOPTS = 0x3c - IPPROTO_EGP = 0x8 - IPPROTO_EMCON = 0xe - IPPROTO_ENCAP = 0x62 - IPPROTO_EON = 0x50 - IPPROTO_ESP = 0x32 - IPPROTO_ETHERIP = 0x61 - IPPROTO_FRAGMENT = 0x2c - IPPROTO_GGP = 0x3 - IPPROTO_GMTP = 0x64 - IPPROTO_GRE = 0x2f - IPPROTO_HELLO = 0x3f - IPPROTO_HMP = 0x14 - IPPROTO_HOPOPTS = 0x0 - IPPROTO_ICMP = 0x1 - IPPROTO_ICMPV6 = 0x3a - IPPROTO_IDP = 0x16 - IPPROTO_IDPR = 0x23 - IPPROTO_IDRP = 0x2d - IPPROTO_IGMP = 0x2 - IPPROTO_IGP = 0x55 - IPPROTO_IGRP = 0x58 - IPPROTO_IL = 0x28 - IPPROTO_INLSP = 0x34 - IPPROTO_INP = 0x20 - IPPROTO_IP = 0x0 - IPPROTO_IPCOMP = 0x6c - IPPROTO_IPCV = 0x47 - IPPROTO_IPEIP = 0x5e - IPPROTO_IPIP = 0x4 - IPPROTO_IPPC = 0x43 - IPPROTO_IPV4 = 0x4 - IPPROTO_IPV6 = 0x29 - IPPROTO_IRTP = 0x1c - IPPROTO_KRYPTOLAN = 0x41 - IPPROTO_LARP = 0x5b - IPPROTO_LEAF1 = 0x19 - IPPROTO_LEAF2 = 0x1a - IPPROTO_MAX = 0x100 - IPPROTO_MAXID = 0x34 - IPPROTO_MEAS = 0x13 - IPPROTO_MHRP = 0x30 - IPPROTO_MICP = 0x5f - IPPROTO_MTP = 0x5c - IPPROTO_MUX = 0x12 - IPPROTO_ND = 0x4d - IPPROTO_NHRP = 0x36 - IPPROTO_NONE = 0x3b - IPPROTO_NSP = 0x1f - IPPROTO_NVPII = 0xb - IPPROTO_OSPFIGP = 0x59 - IPPROTO_PGM = 0x71 - IPPROTO_PIGP = 0x9 - IPPROTO_PIM = 0x67 - IPPROTO_PRM = 0x15 - IPPROTO_PUP = 0xc - IPPROTO_PVP = 0x4b - IPPROTO_RAW = 0xff - IPPROTO_RCCMON = 0xa - IPPROTO_RDP = 0x1b - IPPROTO_ROUTING = 0x2b - IPPROTO_RSVP = 0x2e - IPPROTO_RVD = 0x42 - IPPROTO_SATEXPAK = 0x40 - IPPROTO_SATMON = 0x45 - IPPROTO_SCCSP = 0x60 - IPPROTO_SCTP = 0x84 - IPPROTO_SDRP = 0x2a - IPPROTO_SEP = 0x21 - IPPROTO_SRPC = 0x5a - IPPROTO_ST = 0x7 - IPPROTO_SVMTP = 0x52 - IPPROTO_SWIPE = 0x35 - IPPROTO_TCF = 0x57 - IPPROTO_TCP = 0x6 - IPPROTO_TP = 0x1d - IPPROTO_TPXX = 0x27 - IPPROTO_TRUNK1 = 0x17 - IPPROTO_TRUNK2 = 0x18 - IPPROTO_TTP = 0x54 - IPPROTO_UDP = 0x11 - IPPROTO_VINES = 0x53 - IPPROTO_VISA = 0x46 - IPPROTO_VMTP = 0x51 - IPPROTO_WBEXPAK = 0x4f - IPPROTO_WBMON = 0x4e - IPPROTO_WSN = 0x4a - IPPROTO_XNET = 0xf - IPPROTO_XTP = 0x24 - IPV6_2292DSTOPTS = 0x17 - IPV6_2292HOPLIMIT = 0x14 - IPV6_2292HOPOPTS = 0x16 - IPV6_2292NEXTHOP = 0x15 - IPV6_2292PKTINFO = 0x13 - IPV6_2292PKTOPTIONS = 0x19 - IPV6_2292RTHDR = 0x18 - IPV6_BINDV6ONLY = 0x1b - IPV6_BOUND_IF = 0x7d - IPV6_CHECKSUM = 0x1a - IPV6_DEFAULT_MULTICAST_HOPS = 0x1 - IPV6_DEFAULT_MULTICAST_LOOP = 0x1 - IPV6_DEFHLIM = 0x40 - IPV6_FAITH = 0x1d - IPV6_FLOWINFO_MASK = 0xffffff0f - IPV6_FLOWLABEL_MASK = 0xffff0f00 - IPV6_FLOW_ECN_MASK = 0x300 - IPV6_FRAGTTL = 0x3c - IPV6_FW_ADD = 0x1e - IPV6_FW_DEL = 0x1f - IPV6_FW_FLUSH = 0x20 - IPV6_FW_GET = 0x22 - IPV6_FW_ZERO = 0x21 - IPV6_HLIMDEC = 0x1 - IPV6_IPSEC_POLICY = 0x1c - IPV6_JOIN_GROUP = 0xc - IPV6_LEAVE_GROUP = 0xd - IPV6_MAXHLIM = 0xff - IPV6_MAXOPTHDR = 0x800 - IPV6_MAXPACKET = 0xffff - IPV6_MAX_GROUP_SRC_FILTER = 0x200 - IPV6_MAX_MEMBERSHIPS = 0xfff - IPV6_MAX_SOCK_SRC_FILTER = 0x80 - IPV6_MIN_MEMBERSHIPS = 0x1f - IPV6_MMTU = 0x500 - IPV6_MULTICAST_HOPS = 0xa - IPV6_MULTICAST_IF = 0x9 - IPV6_MULTICAST_LOOP = 0xb - IPV6_PORTRANGE = 0xe - IPV6_PORTRANGE_DEFAULT = 0x0 - IPV6_PORTRANGE_HIGH = 0x1 - IPV6_PORTRANGE_LOW = 0x2 - IPV6_RECVTCLASS = 0x23 - IPV6_RTHDR_LOOSE = 0x0 - IPV6_RTHDR_STRICT = 0x1 - IPV6_RTHDR_TYPE_0 = 0x0 - IPV6_SOCKOPT_RESERVED1 = 0x3 - IPV6_TCLASS = 0x24 - IPV6_UNICAST_HOPS = 0x4 - IPV6_V6ONLY = 0x1b - IPV6_VERSION = 0x60 - IPV6_VERSION_MASK = 0xf0 - IP_ADD_MEMBERSHIP = 0xc - IP_ADD_SOURCE_MEMBERSHIP = 0x46 - IP_BLOCK_SOURCE = 0x48 - IP_BOUND_IF = 0x19 - IP_DEFAULT_MULTICAST_LOOP = 0x1 - IP_DEFAULT_MULTICAST_TTL = 0x1 - IP_DF = 0x4000 - IP_DROP_MEMBERSHIP = 0xd - IP_DROP_SOURCE_MEMBERSHIP = 0x47 - IP_DUMMYNET_CONFIGURE = 0x3c - IP_DUMMYNET_DEL = 0x3d - IP_DUMMYNET_FLUSH = 0x3e - IP_DUMMYNET_GET = 0x40 - IP_FAITH = 0x16 - IP_FW_ADD = 0x28 - IP_FW_DEL = 0x29 - IP_FW_FLUSH = 0x2a - IP_FW_GET = 0x2c - IP_FW_RESETLOG = 0x2d - IP_FW_ZERO = 0x2b - IP_HDRINCL = 0x2 - IP_IPSEC_POLICY = 0x15 - IP_MAXPACKET = 0xffff - IP_MAX_GROUP_SRC_FILTER = 0x200 - IP_MAX_MEMBERSHIPS = 0xfff - IP_MAX_SOCK_MUTE_FILTER = 0x80 - IP_MAX_SOCK_SRC_FILTER = 0x80 - IP_MF = 0x2000 - IP_MIN_MEMBERSHIPS = 0x1f - IP_MSFILTER = 0x4a - IP_MSS = 0x240 - IP_MULTICAST_IF = 0x9 - IP_MULTICAST_IFINDEX = 0x42 - IP_MULTICAST_LOOP = 0xb - IP_MULTICAST_TTL = 0xa - IP_MULTICAST_VIF = 0xe - IP_NAT__XXX = 0x37 - IP_OFFMASK = 0x1fff - IP_OLD_FW_ADD = 0x32 - IP_OLD_FW_DEL = 0x33 - IP_OLD_FW_FLUSH = 0x34 - IP_OLD_FW_GET = 0x36 - IP_OLD_FW_RESETLOG = 0x38 - IP_OLD_FW_ZERO = 0x35 - IP_OPTIONS = 0x1 - IP_PKTINFO = 0x1a - IP_PORTRANGE = 0x13 - IP_PORTRANGE_DEFAULT = 0x0 - IP_PORTRANGE_HIGH = 0x1 - IP_PORTRANGE_LOW = 0x2 - IP_RECVDSTADDR = 0x7 - IP_RECVIF = 0x14 - IP_RECVOPTS = 0x5 - IP_RECVPKTINFO = 0x1a - IP_RECVRETOPTS = 0x6 - IP_RECVTOS = 0x1b - IP_RECVTTL = 0x18 - IP_RETOPTS = 0x8 - IP_RF = 0x8000 - IP_RSVP_OFF = 0x10 - IP_RSVP_ON = 0xf - IP_RSVP_VIF_OFF = 0x12 - IP_RSVP_VIF_ON = 0x11 - IP_STRIPHDR = 0x17 - IP_TOS = 0x3 - IP_TRAFFIC_MGT_BACKGROUND = 0x41 - IP_TTL = 0x4 - IP_UNBLOCK_SOURCE = 0x49 - ISIG = 0x80 - ISTRIP = 0x20 - IUTF8 = 0x4000 - IXANY = 0x800 - IXOFF = 0x400 - IXON = 0x200 - KERN_HOSTNAME = 0xa - KERN_OSRELEASE = 0x2 - KERN_OSTYPE = 0x1 - KERN_VERSION = 0x4 - LOCK_EX = 0x2 - LOCK_NB = 0x4 - LOCK_SH = 0x1 - LOCK_UN = 0x8 - MADV_CAN_REUSE = 0x9 - MADV_DONTNEED = 0x4 - MADV_FREE = 0x5 - MADV_FREE_REUSABLE = 0x7 - MADV_FREE_REUSE = 0x8 - MADV_NORMAL = 0x0 - MADV_PAGEOUT = 0xa - MADV_RANDOM = 0x1 - MADV_SEQUENTIAL = 0x2 - MADV_WILLNEED = 0x3 - MADV_ZERO_WIRED_PAGES = 0x6 - MAP_ANON = 0x1000 - MAP_ANONYMOUS = 0x1000 - MAP_COPY = 0x2 - MAP_FILE = 0x0 - MAP_FIXED = 0x10 - MAP_HASSEMAPHORE = 0x200 - MAP_JIT = 0x800 - MAP_NOCACHE = 0x400 - MAP_NOEXTEND = 0x100 - MAP_NORESERVE = 0x40 - MAP_PRIVATE = 0x2 - MAP_RENAME = 0x20 - MAP_RESERVED0080 = 0x80 - MAP_RESILIENT_CODESIGN = 0x2000 - MAP_RESILIENT_MEDIA = 0x4000 - MAP_SHARED = 0x1 - MCL_CURRENT = 0x1 - MCL_FUTURE = 0x2 - MNT_ASYNC = 0x40 - MNT_AUTOMOUNTED = 0x400000 - MNT_CMDFLAGS = 0xf0000 - MNT_CPROTECT = 0x80 - MNT_DEFWRITE = 0x2000000 - MNT_DONTBROWSE = 0x100000 - MNT_DOVOLFS = 0x8000 - MNT_DWAIT = 0x4 - MNT_EXPORTED = 0x100 - MNT_FORCE = 0x80000 - MNT_IGNORE_OWNERSHIP = 0x200000 - MNT_JOURNALED = 0x800000 - MNT_LOCAL = 0x1000 - MNT_MULTILABEL = 0x4000000 - MNT_NOATIME = 0x10000000 - MNT_NOBLOCK = 0x20000 - MNT_NODEV = 0x10 - MNT_NOEXEC = 0x4 - MNT_NOSUID = 0x8 - MNT_NOUSERXATTR = 0x1000000 - MNT_NOWAIT = 0x2 - MNT_QUARANTINE = 0x400 - MNT_QUOTA = 0x2000 - MNT_RDONLY = 0x1 - MNT_RELOAD = 0x40000 - MNT_ROOTFS = 0x4000 - MNT_SYNCHRONOUS = 0x2 - MNT_UNION = 0x20 - MNT_UNKNOWNPERMISSIONS = 0x200000 - MNT_UPDATE = 0x10000 - MNT_VISFLAGMASK = 0x17f0f5ff - MNT_WAIT = 0x1 - MSG_CTRUNC = 0x20 - MSG_DONTROUTE = 0x4 - MSG_DONTWAIT = 0x80 - MSG_EOF = 0x100 - MSG_EOR = 0x8 - MSG_FLUSH = 0x400 - MSG_HAVEMORE = 0x2000 - MSG_HOLD = 0x800 - MSG_NEEDSA = 0x10000 - MSG_OOB = 0x1 - MSG_PEEK = 0x2 - MSG_RCVMORE = 0x4000 - MSG_SEND = 0x1000 - MSG_TRUNC = 0x10 - MSG_WAITALL = 0x40 - MSG_WAITSTREAM = 0x200 - MS_ASYNC = 0x1 - MS_DEACTIVATE = 0x8 - MS_INVALIDATE = 0x2 - MS_KILLPAGES = 0x4 - MS_SYNC = 0x10 - NAME_MAX = 0xff - NET_RT_DUMP = 0x1 - NET_RT_DUMP2 = 0x7 - NET_RT_FLAGS = 0x2 - NET_RT_IFLIST = 0x3 - NET_RT_IFLIST2 = 0x6 - NET_RT_MAXID = 0xa - NET_RT_STAT = 0x4 - NET_RT_TRASH = 0x5 - NFDBITS = 0x20 - NL0 = 0x0 - NL1 = 0x100 - NL2 = 0x200 - NL3 = 0x300 - NLDLY = 0x300 - NOFLSH = 0x80000000 - NOKERNINFO = 0x2000000 - NOTE_ABSOLUTE = 0x8 - NOTE_ATTRIB = 0x8 - NOTE_BACKGROUND = 0x40 - NOTE_CHILD = 0x4 - NOTE_CRITICAL = 0x20 - NOTE_DELETE = 0x1 - NOTE_EXEC = 0x20000000 - NOTE_EXIT = 0x80000000 - NOTE_EXITSTATUS = 0x4000000 - NOTE_EXIT_CSERROR = 0x40000 - NOTE_EXIT_DECRYPTFAIL = 0x10000 - NOTE_EXIT_DETAIL = 0x2000000 - NOTE_EXIT_DETAIL_MASK = 0x70000 - NOTE_EXIT_MEMORY = 0x20000 - NOTE_EXIT_REPARENTED = 0x80000 - NOTE_EXTEND = 0x4 - NOTE_FFAND = 0x40000000 - NOTE_FFCOPY = 0xc0000000 - NOTE_FFCTRLMASK = 0xc0000000 - NOTE_FFLAGSMASK = 0xffffff - NOTE_FFNOP = 0x0 - NOTE_FFOR = 0x80000000 - NOTE_FORK = 0x40000000 - NOTE_FUNLOCK = 0x100 - NOTE_LEEWAY = 0x10 - NOTE_LINK = 0x10 - NOTE_LOWAT = 0x1 - NOTE_MACH_CONTINUOUS_TIME = 0x80 - NOTE_NONE = 0x80 - NOTE_NSECONDS = 0x4 - NOTE_OOB = 0x2 - NOTE_PCTRLMASK = -0x100000 - NOTE_PDATAMASK = 0xfffff - NOTE_REAP = 0x10000000 - NOTE_RENAME = 0x20 - NOTE_REVOKE = 0x40 - NOTE_SECONDS = 0x1 - NOTE_SIGNAL = 0x8000000 - NOTE_TRACK = 0x1 - NOTE_TRACKERR = 0x2 - NOTE_TRIGGER = 0x1000000 - NOTE_USECONDS = 0x2 - NOTE_VM_ERROR = 0x10000000 - NOTE_VM_PRESSURE = 0x80000000 - NOTE_VM_PRESSURE_SUDDEN_TERMINATE = 0x20000000 - NOTE_VM_PRESSURE_TERMINATE = 0x40000000 - NOTE_WRITE = 0x2 - OCRNL = 0x10 - OFDEL = 0x20000 - OFILL = 0x80 - ONLCR = 0x2 - ONLRET = 0x40 - ONOCR = 0x20 - ONOEOT = 0x8 - OPOST = 0x1 - OXTABS = 0x4 - O_ACCMODE = 0x3 - O_ALERT = 0x20000000 - O_APPEND = 0x8 - O_ASYNC = 0x40 - O_CLOEXEC = 0x1000000 - O_CREAT = 0x200 - O_DIRECTORY = 0x100000 - O_DP_GETRAWENCRYPTED = 0x1 - O_DP_GETRAWUNENCRYPTED = 0x2 - O_DSYNC = 0x400000 - O_EVTONLY = 0x8000 - O_EXCL = 0x800 - O_EXLOCK = 0x20 - O_FSYNC = 0x80 - O_NDELAY = 0x4 - O_NOCTTY = 0x20000 - O_NOFOLLOW = 0x100 - O_NONBLOCK = 0x4 - O_POPUP = 0x80000000 - O_RDONLY = 0x0 - O_RDWR = 0x2 - O_SHLOCK = 0x10 - O_SYMLINK = 0x200000 - O_SYNC = 0x80 - O_TRUNC = 0x400 - O_WRONLY = 0x1 - PARENB = 0x1000 - PARMRK = 0x8 - PARODD = 0x2000 - PENDIN = 0x20000000 - PRIO_PGRP = 0x1 - PRIO_PROCESS = 0x0 - PRIO_USER = 0x2 - PROT_EXEC = 0x4 - PROT_NONE = 0x0 - PROT_READ = 0x1 - PROT_WRITE = 0x2 - PT_ATTACH = 0xa - PT_ATTACHEXC = 0xe - PT_CONTINUE = 0x7 - PT_DENY_ATTACH = 0x1f - PT_DETACH = 0xb - PT_FIRSTMACH = 0x20 - PT_FORCEQUOTA = 0x1e - PT_KILL = 0x8 - PT_READ_D = 0x2 - PT_READ_I = 0x1 - PT_READ_U = 0x3 - PT_SIGEXC = 0xc - PT_STEP = 0x9 - PT_THUPDATE = 0xd - PT_TRACE_ME = 0x0 - PT_WRITE_D = 0x5 - PT_WRITE_I = 0x4 - PT_WRITE_U = 0x6 - RLIMIT_AS = 0x5 - RLIMIT_CORE = 0x4 - RLIMIT_CPU = 0x0 - RLIMIT_CPU_USAGE_MONITOR = 0x2 - RLIMIT_DATA = 0x2 - RLIMIT_FSIZE = 0x1 - RLIMIT_MEMLOCK = 0x6 - RLIMIT_NOFILE = 0x8 - RLIMIT_NPROC = 0x7 - RLIMIT_RSS = 0x5 - RLIMIT_STACK = 0x3 - RLIM_INFINITY = 0x7fffffffffffffff - RTAX_AUTHOR = 0x6 - RTAX_BRD = 0x7 - RTAX_DST = 0x0 - RTAX_GATEWAY = 0x1 - RTAX_GENMASK = 0x3 - RTAX_IFA = 0x5 - RTAX_IFP = 0x4 - RTAX_MAX = 0x8 - RTAX_NETMASK = 0x2 - RTA_AUTHOR = 0x40 - RTA_BRD = 0x80 - RTA_DST = 0x1 - RTA_GATEWAY = 0x2 - RTA_GENMASK = 0x8 - RTA_IFA = 0x20 - RTA_IFP = 0x10 - RTA_NETMASK = 0x4 - RTF_BLACKHOLE = 0x1000 - RTF_BROADCAST = 0x400000 - RTF_CLONING = 0x100 - RTF_CONDEMNED = 0x2000000 - RTF_DELCLONE = 0x80 - RTF_DONE = 0x40 - RTF_DYNAMIC = 0x10 - RTF_GATEWAY = 0x2 - RTF_HOST = 0x4 - RTF_IFREF = 0x4000000 - RTF_IFSCOPE = 0x1000000 - RTF_LLINFO = 0x400 - RTF_LOCAL = 0x200000 - RTF_MODIFIED = 0x20 - RTF_MULTICAST = 0x800000 - RTF_NOIFREF = 0x2000 - RTF_PINNED = 0x100000 - RTF_PRCLONING = 0x10000 - RTF_PROTO1 = 0x8000 - RTF_PROTO2 = 0x4000 - RTF_PROTO3 = 0x40000 - RTF_PROXY = 0x8000000 - RTF_REJECT = 0x8 - RTF_ROUTER = 0x10000000 - RTF_STATIC = 0x800 - RTF_UP = 0x1 - RTF_WASCLONED = 0x20000 - RTF_XRESOLVE = 0x200 - RTM_ADD = 0x1 - RTM_CHANGE = 0x3 - RTM_DELADDR = 0xd - RTM_DELETE = 0x2 - RTM_DELMADDR = 0x10 - RTM_GET = 0x4 - RTM_GET2 = 0x14 - RTM_IFINFO = 0xe - RTM_IFINFO2 = 0x12 - RTM_LOCK = 0x8 - RTM_LOSING = 0x5 - RTM_MISS = 0x7 - RTM_NEWADDR = 0xc - RTM_NEWMADDR = 0xf - RTM_NEWMADDR2 = 0x13 - RTM_OLDADD = 0x9 - RTM_OLDDEL = 0xa - RTM_REDIRECT = 0x6 - RTM_RESOLVE = 0xb - RTM_RTTUNIT = 0xf4240 - RTM_VERSION = 0x5 - RTV_EXPIRE = 0x4 - RTV_HOPCOUNT = 0x2 - RTV_MTU = 0x1 - RTV_RPIPE = 0x8 - RTV_RTT = 0x40 - RTV_RTTVAR = 0x80 - RTV_SPIPE = 0x10 - RTV_SSTHRESH = 0x20 - RUSAGE_CHILDREN = -0x1 - RUSAGE_SELF = 0x0 - SCM_CREDS = 0x3 - SCM_RIGHTS = 0x1 - SCM_TIMESTAMP = 0x2 - SCM_TIMESTAMP_MONOTONIC = 0x4 - SHUT_RD = 0x0 - SHUT_RDWR = 0x2 - SHUT_WR = 0x1 - SIOCADDMULTI = 0x80206931 - SIOCAIFADDR = 0x8040691a - SIOCARPIPLL = 0xc0206928 - SIOCATMARK = 0x40047307 - SIOCAUTOADDR = 0xc0206926 - SIOCAUTONETMASK = 0x80206927 - SIOCDELMULTI = 0x80206932 - SIOCDIFADDR = 0x80206919 - SIOCDIFPHYADDR = 0x80206941 - SIOCGDRVSPEC = 0xc028697b - SIOCGETVLAN = 0xc020697f - SIOCGHIWAT = 0x40047301 - SIOCGIFADDR = 0xc0206921 - SIOCGIFALTMTU = 0xc0206948 - SIOCGIFASYNCMAP = 0xc020697c - SIOCGIFBOND = 0xc0206947 - SIOCGIFBRDADDR = 0xc0206923 - SIOCGIFCAP = 0xc020695b - SIOCGIFCONF = 0xc00c6924 - SIOCGIFDEVMTU = 0xc0206944 - SIOCGIFDSTADDR = 0xc0206922 - SIOCGIFFLAGS = 0xc0206911 - SIOCGIFGENERIC = 0xc020693a - SIOCGIFKPI = 0xc0206987 - SIOCGIFMAC = 0xc0206982 - SIOCGIFMEDIA = 0xc02c6938 - SIOCGIFMETRIC = 0xc0206917 - SIOCGIFMTU = 0xc0206933 - SIOCGIFNETMASK = 0xc0206925 - SIOCGIFPDSTADDR = 0xc0206940 - SIOCGIFPHYS = 0xc0206935 - SIOCGIFPSRCADDR = 0xc020693f - SIOCGIFSTATUS = 0xc331693d - SIOCGIFVLAN = 0xc020697f - SIOCGIFWAKEFLAGS = 0xc0206988 - SIOCGLOWAT = 0x40047303 - SIOCGPGRP = 0x40047309 - SIOCIFCREATE = 0xc0206978 - SIOCIFCREATE2 = 0xc020697a - SIOCIFDESTROY = 0x80206979 - SIOCIFGCLONERS = 0xc0106981 - SIOCRSLVMULTI = 0xc010693b - SIOCSDRVSPEC = 0x8028697b - SIOCSETVLAN = 0x8020697e - SIOCSHIWAT = 0x80047300 - SIOCSIFADDR = 0x8020690c - SIOCSIFALTMTU = 0x80206945 - SIOCSIFASYNCMAP = 0x8020697d - SIOCSIFBOND = 0x80206946 - SIOCSIFBRDADDR = 0x80206913 - SIOCSIFCAP = 0x8020695a - SIOCSIFDSTADDR = 0x8020690e - SIOCSIFFLAGS = 0x80206910 - SIOCSIFGENERIC = 0x80206939 - SIOCSIFKPI = 0x80206986 - SIOCSIFLLADDR = 0x8020693c - SIOCSIFMAC = 0x80206983 - SIOCSIFMEDIA = 0xc0206937 - SIOCSIFMETRIC = 0x80206918 - SIOCSIFMTU = 0x80206934 - SIOCSIFNETMASK = 0x80206916 - SIOCSIFPHYADDR = 0x8040693e - SIOCSIFPHYS = 0x80206936 - SIOCSIFVLAN = 0x8020697e - SIOCSLOWAT = 0x80047302 - SIOCSPGRP = 0x80047308 - SOCK_DGRAM = 0x2 - SOCK_MAXADDRLEN = 0xff - SOCK_RAW = 0x3 - SOCK_RDM = 0x4 - SOCK_SEQPACKET = 0x5 - SOCK_STREAM = 0x1 - SOL_SOCKET = 0xffff - SOMAXCONN = 0x80 - SO_ACCEPTCONN = 0x2 - SO_BROADCAST = 0x20 - SO_DEBUG = 0x1 - SO_DONTROUTE = 0x10 - SO_DONTTRUNC = 0x2000 - SO_ERROR = 0x1007 - SO_KEEPALIVE = 0x8 - SO_LABEL = 0x1010 - SO_LINGER = 0x80 - SO_LINGER_SEC = 0x1080 - SO_NETSVC_MARKING_LEVEL = 0x1119 - SO_NET_SERVICE_TYPE = 0x1116 - SO_NKE = 0x1021 - SO_NOADDRERR = 0x1023 - SO_NOSIGPIPE = 0x1022 - SO_NOTIFYCONFLICT = 0x1026 - SO_NP_EXTENSIONS = 0x1083 - SO_NREAD = 0x1020 - SO_NUMRCVPKT = 0x1112 - SO_NWRITE = 0x1024 - SO_OOBINLINE = 0x100 - SO_PEERLABEL = 0x1011 - SO_RANDOMPORT = 0x1082 - SO_RCVBUF = 0x1002 - SO_RCVLOWAT = 0x1004 - SO_RCVTIMEO = 0x1006 - SO_REUSEADDR = 0x4 - SO_REUSEPORT = 0x200 - SO_REUSESHAREUID = 0x1025 - SO_SNDBUF = 0x1001 - SO_SNDLOWAT = 0x1003 - SO_SNDTIMEO = 0x1005 - SO_TIMESTAMP = 0x400 - SO_TIMESTAMP_MONOTONIC = 0x800 - SO_TYPE = 0x1008 - SO_UPCALLCLOSEWAIT = 0x1027 - SO_USELOOPBACK = 0x40 - SO_WANTMORE = 0x4000 - SO_WANTOOBFLAG = 0x8000 - S_IEXEC = 0x40 - S_IFBLK = 0x6000 - S_IFCHR = 0x2000 - S_IFDIR = 0x4000 - S_IFIFO = 0x1000 - S_IFLNK = 0xa000 - S_IFMT = 0xf000 - S_IFREG = 0x8000 - S_IFSOCK = 0xc000 - S_IFWHT = 0xe000 - S_IREAD = 0x100 - S_IRGRP = 0x20 - S_IROTH = 0x4 - S_IRUSR = 0x100 - S_IRWXG = 0x38 - S_IRWXO = 0x7 - S_IRWXU = 0x1c0 - S_ISGID = 0x400 - S_ISTXT = 0x200 - S_ISUID = 0x800 - S_ISVTX = 0x200 - S_IWGRP = 0x10 - S_IWOTH = 0x2 - S_IWRITE = 0x80 - S_IWUSR = 0x80 - S_IXGRP = 0x8 - S_IXOTH = 0x1 - S_IXUSR = 0x40 - TAB0 = 0x0 - TAB1 = 0x400 - TAB2 = 0x800 - TAB3 = 0x4 - TABDLY = 0xc04 - TCIFLUSH = 0x1 - TCIOFF = 0x3 - TCIOFLUSH = 0x3 - TCION = 0x4 - TCOFLUSH = 0x2 - TCOOFF = 0x1 - TCOON = 0x2 - TCP_CONNECTIONTIMEOUT = 0x20 - TCP_CONNECTION_INFO = 0x106 - TCP_ENABLE_ECN = 0x104 - TCP_FASTOPEN = 0x105 - TCP_KEEPALIVE = 0x10 - TCP_KEEPCNT = 0x102 - TCP_KEEPINTVL = 0x101 - TCP_MAXHLEN = 0x3c - TCP_MAXOLEN = 0x28 - TCP_MAXSEG = 0x2 - TCP_MAXWIN = 0xffff - TCP_MAX_SACK = 0x4 - TCP_MAX_WINSHIFT = 0xe - TCP_MINMSS = 0xd8 - TCP_MSS = 0x200 - TCP_NODELAY = 0x1 - TCP_NOOPT = 0x8 - TCP_NOPUSH = 0x4 - TCP_NOTSENT_LOWAT = 0x201 - TCP_RXT_CONNDROPTIME = 0x80 - TCP_RXT_FINDROP = 0x100 - TCP_SENDMOREACKS = 0x103 - TCSAFLUSH = 0x2 - TIOCCBRK = 0x2000747a - TIOCCDTR = 0x20007478 - TIOCCONS = 0x80047462 - TIOCDCDTIMESTAMP = 0x40107458 - TIOCDRAIN = 0x2000745e - TIOCDSIMICROCODE = 0x20007455 - TIOCEXCL = 0x2000740d - TIOCEXT = 0x80047460 - TIOCFLUSH = 0x80047410 - TIOCGDRAINWAIT = 0x40047456 - TIOCGETA = 0x40487413 - TIOCGETD = 0x4004741a - TIOCGPGRP = 0x40047477 - TIOCGWINSZ = 0x40087468 - TIOCIXOFF = 0x20007480 - TIOCIXON = 0x20007481 - TIOCMBIC = 0x8004746b - TIOCMBIS = 0x8004746c - TIOCMGDTRWAIT = 0x4004745a - TIOCMGET = 0x4004746a - TIOCMODG = 0x40047403 - TIOCMODS = 0x80047404 - TIOCMSDTRWAIT = 0x8004745b - TIOCMSET = 0x8004746d - TIOCM_CAR = 0x40 - TIOCM_CD = 0x40 - TIOCM_CTS = 0x20 - TIOCM_DSR = 0x100 - TIOCM_DTR = 0x2 - TIOCM_LE = 0x1 - TIOCM_RI = 0x80 - TIOCM_RNG = 0x80 - TIOCM_RTS = 0x4 - TIOCM_SR = 0x10 - TIOCM_ST = 0x8 - TIOCNOTTY = 0x20007471 - TIOCNXCL = 0x2000740e - TIOCOUTQ = 0x40047473 - TIOCPKT = 0x80047470 - TIOCPKT_DATA = 0x0 - TIOCPKT_DOSTOP = 0x20 - TIOCPKT_FLUSHREAD = 0x1 - TIOCPKT_FLUSHWRITE = 0x2 - TIOCPKT_IOCTL = 0x40 - TIOCPKT_NOSTOP = 0x10 - TIOCPKT_START = 0x8 - TIOCPKT_STOP = 0x4 - TIOCPTYGNAME = 0x40807453 - TIOCPTYGRANT = 0x20007454 - TIOCPTYUNLK = 0x20007452 - TIOCREMOTE = 0x80047469 - TIOCSBRK = 0x2000747b - TIOCSCONS = 0x20007463 - TIOCSCTTY = 0x20007461 - TIOCSDRAINWAIT = 0x80047457 - TIOCSDTR = 0x20007479 - TIOCSETA = 0x80487414 - TIOCSETAF = 0x80487416 - TIOCSETAW = 0x80487415 - TIOCSETD = 0x8004741b - TIOCSIG = 0x2000745f - TIOCSPGRP = 0x80047476 - TIOCSTART = 0x2000746e - TIOCSTAT = 0x20007465 - TIOCSTI = 0x80017472 - TIOCSTOP = 0x2000746f - TIOCSWINSZ = 0x80087467 - TIOCTIMESTAMP = 0x40107459 - TIOCUCNTL = 0x80047466 - TOSTOP = 0x400000 - VDISCARD = 0xf - VDSUSP = 0xb - VEOF = 0x0 - VEOL = 0x1 - VEOL2 = 0x2 - VERASE = 0x3 - VINTR = 0x8 - VKILL = 0x5 - VLNEXT = 0xe - VMIN = 0x10 - VM_LOADAVG = 0x2 - VM_MACHFACTOR = 0x4 - VM_MAXID = 0x6 - VM_METER = 0x1 - VM_SWAPUSAGE = 0x5 - VQUIT = 0x9 - VREPRINT = 0x6 - VSTART = 0xc - VSTATUS = 0x12 - VSTOP = 0xd - VSUSP = 0xa - VT0 = 0x0 - VT1 = 0x10000 - VTDLY = 0x10000 - VTIME = 0x11 - VWERASE = 0x4 - WCONTINUED = 0x10 - WCOREFLAG = 0x80 - WEXITED = 0x4 - WNOHANG = 0x1 - WNOWAIT = 0x20 - WORDSIZE = 0x40 - WSTOPPED = 0x8 - WUNTRACED = 0x2 - XATTR_CREATE = 0x2 - XATTR_NODEFAULT = 0x10 - XATTR_NOFOLLOW = 0x1 - XATTR_NOSECURITY = 0x8 - XATTR_REPLACE = 0x4 - XATTR_SHOWCOMPRESSION = 0x20 -) - -// Errors -const ( - E2BIG = syscall.Errno(0x7) - EACCES = syscall.Errno(0xd) - EADDRINUSE = syscall.Errno(0x30) - EADDRNOTAVAIL = syscall.Errno(0x31) - EAFNOSUPPORT = syscall.Errno(0x2f) - EAGAIN = syscall.Errno(0x23) - EALREADY = syscall.Errno(0x25) - EAUTH = syscall.Errno(0x50) - EBADARCH = syscall.Errno(0x56) - EBADEXEC = syscall.Errno(0x55) - EBADF = syscall.Errno(0x9) - EBADMACHO = syscall.Errno(0x58) - EBADMSG = syscall.Errno(0x5e) - EBADRPC = syscall.Errno(0x48) - EBUSY = syscall.Errno(0x10) - ECANCELED = syscall.Errno(0x59) - ECHILD = syscall.Errno(0xa) - ECONNABORTED = syscall.Errno(0x35) - ECONNREFUSED = syscall.Errno(0x3d) - ECONNRESET = syscall.Errno(0x36) - EDEADLK = syscall.Errno(0xb) - EDESTADDRREQ = syscall.Errno(0x27) - EDEVERR = syscall.Errno(0x53) - EDOM = syscall.Errno(0x21) - EDQUOT = syscall.Errno(0x45) - EEXIST = syscall.Errno(0x11) - EFAULT = syscall.Errno(0xe) - EFBIG = syscall.Errno(0x1b) - EFTYPE = syscall.Errno(0x4f) - EHOSTDOWN = syscall.Errno(0x40) - EHOSTUNREACH = syscall.Errno(0x41) - EIDRM = syscall.Errno(0x5a) - EILSEQ = syscall.Errno(0x5c) - EINPROGRESS = syscall.Errno(0x24) - EINTR = syscall.Errno(0x4) - EINVAL = syscall.Errno(0x16) - EIO = syscall.Errno(0x5) - EISCONN = syscall.Errno(0x38) - EISDIR = syscall.Errno(0x15) - ELAST = syscall.Errno(0x6a) - ELOOP = syscall.Errno(0x3e) - EMFILE = syscall.Errno(0x18) - EMLINK = syscall.Errno(0x1f) - EMSGSIZE = syscall.Errno(0x28) - EMULTIHOP = syscall.Errno(0x5f) - ENAMETOOLONG = syscall.Errno(0x3f) - ENEEDAUTH = syscall.Errno(0x51) - ENETDOWN = syscall.Errno(0x32) - ENETRESET = syscall.Errno(0x34) - ENETUNREACH = syscall.Errno(0x33) - ENFILE = syscall.Errno(0x17) - ENOATTR = syscall.Errno(0x5d) - ENOBUFS = syscall.Errno(0x37) - ENODATA = syscall.Errno(0x60) - ENODEV = syscall.Errno(0x13) - ENOENT = syscall.Errno(0x2) - ENOEXEC = syscall.Errno(0x8) - ENOLCK = syscall.Errno(0x4d) - ENOLINK = syscall.Errno(0x61) - ENOMEM = syscall.Errno(0xc) - ENOMSG = syscall.Errno(0x5b) - ENOPOLICY = syscall.Errno(0x67) - ENOPROTOOPT = syscall.Errno(0x2a) - ENOSPC = syscall.Errno(0x1c) - ENOSR = syscall.Errno(0x62) - ENOSTR = syscall.Errno(0x63) - ENOSYS = syscall.Errno(0x4e) - ENOTBLK = syscall.Errno(0xf) - ENOTCONN = syscall.Errno(0x39) - ENOTDIR = syscall.Errno(0x14) - ENOTEMPTY = syscall.Errno(0x42) - ENOTRECOVERABLE = syscall.Errno(0x68) - ENOTSOCK = syscall.Errno(0x26) - ENOTSUP = syscall.Errno(0x2d) - ENOTTY = syscall.Errno(0x19) - ENXIO = syscall.Errno(0x6) - EOPNOTSUPP = syscall.Errno(0x66) - EOVERFLOW = syscall.Errno(0x54) - EOWNERDEAD = syscall.Errno(0x69) - EPERM = syscall.Errno(0x1) - EPFNOSUPPORT = syscall.Errno(0x2e) - EPIPE = syscall.Errno(0x20) - EPROCLIM = syscall.Errno(0x43) - EPROCUNAVAIL = syscall.Errno(0x4c) - EPROGMISMATCH = syscall.Errno(0x4b) - EPROGUNAVAIL = syscall.Errno(0x4a) - EPROTO = syscall.Errno(0x64) - EPROTONOSUPPORT = syscall.Errno(0x2b) - EPROTOTYPE = syscall.Errno(0x29) - EPWROFF = syscall.Errno(0x52) - EQFULL = syscall.Errno(0x6a) - ERANGE = syscall.Errno(0x22) - EREMOTE = syscall.Errno(0x47) - EROFS = syscall.Errno(0x1e) - ERPCMISMATCH = syscall.Errno(0x49) - ESHLIBVERS = syscall.Errno(0x57) - ESHUTDOWN = syscall.Errno(0x3a) - ESOCKTNOSUPPORT = syscall.Errno(0x2c) - ESPIPE = syscall.Errno(0x1d) - ESRCH = syscall.Errno(0x3) - ESTALE = syscall.Errno(0x46) - ETIME = syscall.Errno(0x65) - ETIMEDOUT = syscall.Errno(0x3c) - ETOOMANYREFS = syscall.Errno(0x3b) - ETXTBSY = syscall.Errno(0x1a) - EUSERS = syscall.Errno(0x44) - EWOULDBLOCK = syscall.Errno(0x23) - EXDEV = syscall.Errno(0x12) -) - -// Signals -const ( - SIGABRT = syscall.Signal(0x6) - SIGALRM = syscall.Signal(0xe) - SIGBUS = syscall.Signal(0xa) - SIGCHLD = syscall.Signal(0x14) - SIGCONT = syscall.Signal(0x13) - SIGEMT = syscall.Signal(0x7) - SIGFPE = syscall.Signal(0x8) - SIGHUP = syscall.Signal(0x1) - SIGILL = syscall.Signal(0x4) - SIGINFO = syscall.Signal(0x1d) - SIGINT = syscall.Signal(0x2) - SIGIO = syscall.Signal(0x17) - SIGIOT = syscall.Signal(0x6) - SIGKILL = syscall.Signal(0x9) - SIGPIPE = syscall.Signal(0xd) - SIGPROF = syscall.Signal(0x1b) - SIGQUIT = syscall.Signal(0x3) - SIGSEGV = syscall.Signal(0xb) - SIGSTOP = syscall.Signal(0x11) - SIGSYS = syscall.Signal(0xc) - SIGTERM = syscall.Signal(0xf) - SIGTRAP = syscall.Signal(0x5) - SIGTSTP = syscall.Signal(0x12) - SIGTTIN = syscall.Signal(0x15) - SIGTTOU = syscall.Signal(0x16) - SIGURG = syscall.Signal(0x10) - SIGUSR1 = syscall.Signal(0x1e) - SIGUSR2 = syscall.Signal(0x1f) - SIGVTALRM = syscall.Signal(0x1a) - SIGWINCH = syscall.Signal(0x1c) - SIGXCPU = syscall.Signal(0x18) - SIGXFSZ = syscall.Signal(0x19) -) - -// Error table -var errorList = [...]struct { - num syscall.Errno - name string - desc string -}{ - {1, "EPERM", "operation not permitted"}, - {2, "ENOENT", "no such file or directory"}, - {3, "ESRCH", "no such process"}, - {4, "EINTR", "interrupted system call"}, - {5, "EIO", "input/output error"}, - {6, "ENXIO", "device not configured"}, - {7, "E2BIG", "argument list too long"}, - {8, "ENOEXEC", "exec format error"}, - {9, "EBADF", "bad file descriptor"}, - {10, "ECHILD", "no child processes"}, - {11, "EDEADLK", "resource deadlock avoided"}, - {12, "ENOMEM", "cannot allocate memory"}, - {13, "EACCES", "permission denied"}, - {14, "EFAULT", "bad address"}, - {15, "ENOTBLK", "block device required"}, - {16, "EBUSY", "resource busy"}, - {17, "EEXIST", "file exists"}, - {18, "EXDEV", "cross-device link"}, - {19, "ENODEV", "operation not supported by device"}, - {20, "ENOTDIR", "not a directory"}, - {21, "EISDIR", "is a directory"}, - {22, "EINVAL", "invalid argument"}, - {23, "ENFILE", "too many open files in system"}, - {24, "EMFILE", "too many open files"}, - {25, "ENOTTY", "inappropriate ioctl for device"}, - {26, "ETXTBSY", "text file busy"}, - {27, "EFBIG", "file too large"}, - {28, "ENOSPC", "no space left on device"}, - {29, "ESPIPE", "illegal seek"}, - {30, "EROFS", "read-only file system"}, - {31, "EMLINK", "too many links"}, - {32, "EPIPE", "broken pipe"}, - {33, "EDOM", "numerical argument out of domain"}, - {34, "ERANGE", "result too large"}, - {35, "EAGAIN", "resource temporarily unavailable"}, - {36, "EINPROGRESS", "operation now in progress"}, - {37, "EALREADY", "operation already in progress"}, - {38, "ENOTSOCK", "socket operation on non-socket"}, - {39, "EDESTADDRREQ", "destination address required"}, - {40, "EMSGSIZE", "message too long"}, - {41, "EPROTOTYPE", "protocol wrong type for socket"}, - {42, "ENOPROTOOPT", "protocol not available"}, - {43, "EPROTONOSUPPORT", "protocol not supported"}, - {44, "ESOCKTNOSUPPORT", "socket type not supported"}, - {45, "ENOTSUP", "operation not supported"}, - {46, "EPFNOSUPPORT", "protocol family not supported"}, - {47, "EAFNOSUPPORT", "address family not supported by protocol family"}, - {48, "EADDRINUSE", "address already in use"}, - {49, "EADDRNOTAVAIL", "can't assign requested address"}, - {50, "ENETDOWN", "network is down"}, - {51, "ENETUNREACH", "network is unreachable"}, - {52, "ENETRESET", "network dropped connection on reset"}, - {53, "ECONNABORTED", "software caused connection abort"}, - {54, "ECONNRESET", "connection reset by peer"}, - {55, "ENOBUFS", "no buffer space available"}, - {56, "EISCONN", "socket is already connected"}, - {57, "ENOTCONN", "socket is not connected"}, - {58, "ESHUTDOWN", "can't send after socket shutdown"}, - {59, "ETOOMANYREFS", "too many references: can't splice"}, - {60, "ETIMEDOUT", "operation timed out"}, - {61, "ECONNREFUSED", "connection refused"}, - {62, "ELOOP", "too many levels of symbolic links"}, - {63, "ENAMETOOLONG", "file name too long"}, - {64, "EHOSTDOWN", "host is down"}, - {65, "EHOSTUNREACH", "no route to host"}, - {66, "ENOTEMPTY", "directory not empty"}, - {67, "EPROCLIM", "too many processes"}, - {68, "EUSERS", "too many users"}, - {69, "EDQUOT", "disc quota exceeded"}, - {70, "ESTALE", "stale NFS file handle"}, - {71, "EREMOTE", "too many levels of remote in path"}, - {72, "EBADRPC", "RPC struct is bad"}, - {73, "ERPCMISMATCH", "RPC version wrong"}, - {74, "EPROGUNAVAIL", "RPC prog. not avail"}, - {75, "EPROGMISMATCH", "program version wrong"}, - {76, "EPROCUNAVAIL", "bad procedure for program"}, - {77, "ENOLCK", "no locks available"}, - {78, "ENOSYS", "function not implemented"}, - {79, "EFTYPE", "inappropriate file type or format"}, - {80, "EAUTH", "authentication error"}, - {81, "ENEEDAUTH", "need authenticator"}, - {82, "EPWROFF", "device power is off"}, - {83, "EDEVERR", "device error"}, - {84, "EOVERFLOW", "value too large to be stored in data type"}, - {85, "EBADEXEC", "bad executable (or shared library)"}, - {86, "EBADARCH", "bad CPU type in executable"}, - {87, "ESHLIBVERS", "shared library version mismatch"}, - {88, "EBADMACHO", "malformed Mach-o file"}, - {89, "ECANCELED", "operation canceled"}, - {90, "EIDRM", "identifier removed"}, - {91, "ENOMSG", "no message of desired type"}, - {92, "EILSEQ", "illegal byte sequence"}, - {93, "ENOATTR", "attribute not found"}, - {94, "EBADMSG", "bad message"}, - {95, "EMULTIHOP", "EMULTIHOP (Reserved)"}, - {96, "ENODATA", "no message available on STREAM"}, - {97, "ENOLINK", "ENOLINK (Reserved)"}, - {98, "ENOSR", "no STREAM resources"}, - {99, "ENOSTR", "not a STREAM"}, - {100, "EPROTO", "protocol error"}, - {101, "ETIME", "STREAM ioctl timeout"}, - {102, "EOPNOTSUPP", "operation not supported on socket"}, - {103, "ENOPOLICY", "policy not found"}, - {104, "ENOTRECOVERABLE", "state not recoverable"}, - {105, "EOWNERDEAD", "previous owner died"}, - {106, "EQFULL", "interface output queue is full"}, -} - -// Signal table -var signalList = [...]struct { - num syscall.Signal - name string - desc string -}{ - {1, "SIGHUP", "hangup"}, - {2, "SIGINT", "interrupt"}, - {3, "SIGQUIT", "quit"}, - {4, "SIGILL", "illegal instruction"}, - {5, "SIGTRAP", "trace/BPT trap"}, - {6, "SIGABRT", "abort trap"}, - {7, "SIGEMT", "EMT trap"}, - {8, "SIGFPE", "floating point exception"}, - {9, "SIGKILL", "killed"}, - {10, "SIGBUS", "bus error"}, - {11, "SIGSEGV", "segmentation fault"}, - {12, "SIGSYS", "bad system call"}, - {13, "SIGPIPE", "broken pipe"}, - {14, "SIGALRM", "alarm clock"}, - {15, "SIGTERM", "terminated"}, - {16, "SIGURG", "urgent I/O condition"}, - {17, "SIGSTOP", "suspended (signal)"}, - {18, "SIGTSTP", "suspended"}, - {19, "SIGCONT", "continued"}, - {20, "SIGCHLD", "child exited"}, - {21, "SIGTTIN", "stopped (tty input)"}, - {22, "SIGTTOU", "stopped (tty output)"}, - {23, "SIGIO", "I/O possible"}, - {24, "SIGXCPU", "cputime limit exceeded"}, - {25, "SIGXFSZ", "filesize limit exceeded"}, - {26, "SIGVTALRM", "virtual timer expired"}, - {27, "SIGPROF", "profiling timer expired"}, - {28, "SIGWINCH", "window size changes"}, - {29, "SIGINFO", "information request"}, - {30, "SIGUSR1", "user defined signal 1"}, - {31, "SIGUSR2", "user defined signal 2"}, -} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.1_13.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.1_13.go deleted file mode 100644 index 48a62e39062..00000000000 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.1_13.go +++ /dev/null @@ -1,40 +0,0 @@ -// go run mksyscall.go -l32 -tags darwin,386,go1.13 syscall_darwin.1_13.go -// Code generated by the command above; see README.md. DO NOT EDIT. - -//go:build darwin && 386 && go1.13 -// +build darwin,386,go1.13 - -package unix - -import ( - "syscall" - "unsafe" -) - -var _ syscall.Errno - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func closedir(dir uintptr) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_closedir_trampoline), uintptr(dir), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_closedir_trampoline() - -//go:cgo_import_dynamic libc_closedir closedir "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno) { - r0, _, _ := syscall_syscall(funcPC(libc_readdir_r_trampoline), uintptr(dir), uintptr(unsafe.Pointer(entry)), uintptr(unsafe.Pointer(result))) - res = Errno(r0) - return -} - -func libc_readdir_r_trampoline() - -//go:cgo_import_dynamic libc_readdir_r readdir_r "/usr/lib/libSystem.B.dylib" diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.1_13.s b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.1_13.s deleted file mode 100644 index 1c73a1921d7..00000000000 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.1_13.s +++ /dev/null @@ -1,13 +0,0 @@ -// go run mkasm_darwin.go 386 -// Code generated by the command above; DO NOT EDIT. - -//go:build go1.13 -// +build go1.13 - -#include "textflag.h" -TEXT ·libc_fdopendir_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fdopendir(SB) -TEXT ·libc_closedir_trampoline(SB),NOSPLIT,$0-0 - JMP libc_closedir(SB) -TEXT ·libc_readdir_r_trampoline(SB),NOSPLIT,$0-0 - JMP libc_readdir_r(SB) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.go deleted file mode 100644 index a266636af67..00000000000 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.go +++ /dev/null @@ -1,2431 +0,0 @@ -// go run mksyscall.go -l32 -tags darwin,386,go1.12 syscall_bsd.go syscall_darwin.go syscall_darwin_386.go -// Code generated by the command above; see README.md. DO NOT EDIT. - -//go:build darwin && 386 && go1.12 -// +build darwin,386,go1.12 - -package unix - -import ( - "syscall" - "unsafe" -) - -var _ syscall.Errno - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func getgroups(ngid int, gid *_Gid_t) (n int, err error) { - r0, _, e1 := syscall_rawSyscall(funcPC(libc_getgroups_trampoline), uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_getgroups_trampoline() - -//go:cgo_import_dynamic libc_getgroups getgroups "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func setgroups(ngid int, gid *_Gid_t) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setgroups_trampoline), uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setgroups_trampoline() - -//go:cgo_import_dynamic libc_setgroups setgroups "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) { - r0, _, e1 := syscall_syscall6(funcPC(libc_wait4_trampoline), uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) - wpid = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_wait4_trampoline() - -//go:cgo_import_dynamic libc_wait4 wait4 "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_accept_trampoline), uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_accept_trampoline() - -//go:cgo_import_dynamic libc_accept accept "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_bind_trampoline), uintptr(s), uintptr(addr), uintptr(addrlen)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_bind_trampoline() - -//go:cgo_import_dynamic libc_bind bind "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_connect_trampoline), uintptr(s), uintptr(addr), uintptr(addrlen)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_connect_trampoline() - -//go:cgo_import_dynamic libc_connect connect "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func socket(domain int, typ int, proto int) (fd int, err error) { - r0, _, e1 := syscall_rawSyscall(funcPC(libc_socket_trampoline), uintptr(domain), uintptr(typ), uintptr(proto)) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_socket_trampoline() - -//go:cgo_import_dynamic libc_socket socket "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) { - _, _, e1 := syscall_syscall6(funcPC(libc_getsockopt_trampoline), uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_getsockopt_trampoline() - -//go:cgo_import_dynamic libc_getsockopt getsockopt "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { - _, _, e1 := syscall_syscall6(funcPC(libc_setsockopt_trampoline), uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setsockopt_trampoline() - -//go:cgo_import_dynamic libc_setsockopt setsockopt "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_getpeername_trampoline), uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_getpeername_trampoline() - -//go:cgo_import_dynamic libc_getpeername getpeername "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_getsockname_trampoline), uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_getsockname_trampoline() - -//go:cgo_import_dynamic libc_getsockname getsockname "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Shutdown(s int, how int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_shutdown_trampoline), uintptr(s), uintptr(how), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_shutdown_trampoline() - -//go:cgo_import_dynamic libc_shutdown shutdown "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) { - _, _, e1 := syscall_rawSyscall6(funcPC(libc_socketpair_trampoline), uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_socketpair_trampoline() - -//go:cgo_import_dynamic libc_socketpair socketpair "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) { - var _p0 unsafe.Pointer - if len(p) > 0 { - _p0 = unsafe.Pointer(&p[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := syscall_syscall6(funcPC(libc_recvfrom_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_recvfrom_trampoline() - -//go:cgo_import_dynamic libc_recvfrom recvfrom "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) { - var _p0 unsafe.Pointer - if len(buf) > 0 { - _p0 = unsafe.Pointer(&buf[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - _, _, e1 := syscall_syscall6(funcPC(libc_sendto_trampoline), uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_sendto_trampoline() - -//go:cgo_import_dynamic libc_sendto sendto "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_recvmsg_trampoline), uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_recvmsg_trampoline() - -//go:cgo_import_dynamic libc_recvmsg recvmsg "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_sendmsg_trampoline), uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_sendmsg_trampoline() - -//go:cgo_import_dynamic libc_sendmsg sendmsg "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) { - r0, _, e1 := syscall_syscall6(funcPC(libc_kevent_trampoline), uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_kevent_trampoline() - -//go:cgo_import_dynamic libc_kevent kevent "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func utimes(path string, timeval *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_utimes_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_utimes_trampoline() - -//go:cgo_import_dynamic libc_utimes utimes "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func futimes(fd int, timeval *[2]Timeval) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_futimes_trampoline), uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_futimes_trampoline() - -//go:cgo_import_dynamic libc_futimes futimes "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_poll_trampoline), uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_poll_trampoline() - -//go:cgo_import_dynamic libc_poll poll "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Madvise(b []byte, behav int) (err error) { - var _p0 unsafe.Pointer - if len(b) > 0 { - _p0 = unsafe.Pointer(&b[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - _, _, e1 := syscall_syscall(funcPC(libc_madvise_trampoline), uintptr(_p0), uintptr(len(b)), uintptr(behav)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_madvise_trampoline() - -//go:cgo_import_dynamic libc_madvise madvise "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Mlock(b []byte) (err error) { - var _p0 unsafe.Pointer - if len(b) > 0 { - _p0 = unsafe.Pointer(&b[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - _, _, e1 := syscall_syscall(funcPC(libc_mlock_trampoline), uintptr(_p0), uintptr(len(b)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_mlock_trampoline() - -//go:cgo_import_dynamic libc_mlock mlock "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Mlockall(flags int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_mlockall_trampoline), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_mlockall_trampoline() - -//go:cgo_import_dynamic libc_mlockall mlockall "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Mprotect(b []byte, prot int) (err error) { - var _p0 unsafe.Pointer - if len(b) > 0 { - _p0 = unsafe.Pointer(&b[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - _, _, e1 := syscall_syscall(funcPC(libc_mprotect_trampoline), uintptr(_p0), uintptr(len(b)), uintptr(prot)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_mprotect_trampoline() - -//go:cgo_import_dynamic libc_mprotect mprotect "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Msync(b []byte, flags int) (err error) { - var _p0 unsafe.Pointer - if len(b) > 0 { - _p0 = unsafe.Pointer(&b[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - _, _, e1 := syscall_syscall(funcPC(libc_msync_trampoline), uintptr(_p0), uintptr(len(b)), uintptr(flags)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_msync_trampoline() - -//go:cgo_import_dynamic libc_msync msync "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Munlock(b []byte) (err error) { - var _p0 unsafe.Pointer - if len(b) > 0 { - _p0 = unsafe.Pointer(&b[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - _, _, e1 := syscall_syscall(funcPC(libc_munlock_trampoline), uintptr(_p0), uintptr(len(b)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_munlock_trampoline() - -//go:cgo_import_dynamic libc_munlock munlock "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Munlockall() (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_munlockall_trampoline), 0, 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_munlockall_trampoline() - -//go:cgo_import_dynamic libc_munlockall munlockall "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func pipe(p *[2]int32) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_pipe_trampoline), uintptr(unsafe.Pointer(p)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_pipe_trampoline() - -//go:cgo_import_dynamic libc_pipe pipe "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func getxattr(path string, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(attr) - if err != nil { - return - } - r0, _, e1 := syscall_syscall6(funcPC(libc_getxattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) - sz = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_getxattr_trampoline() - -//go:cgo_import_dynamic libc_getxattr getxattr "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func fgetxattr(fd int, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(attr) - if err != nil { - return - } - r0, _, e1 := syscall_syscall6(funcPC(libc_fgetxattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) - sz = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fgetxattr_trampoline() - -//go:cgo_import_dynamic libc_fgetxattr fgetxattr "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func setxattr(path string, attr string, data *byte, size int, position uint32, options int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(attr) - if err != nil { - return - } - _, _, e1 := syscall_syscall6(funcPC(libc_setxattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setxattr_trampoline() - -//go:cgo_import_dynamic libc_setxattr setxattr "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func fsetxattr(fd int, attr string, data *byte, size int, position uint32, options int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(attr) - if err != nil { - return - } - _, _, e1 := syscall_syscall6(funcPC(libc_fsetxattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fsetxattr_trampoline() - -//go:cgo_import_dynamic libc_fsetxattr fsetxattr "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func removexattr(path string, attr string, options int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(attr) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_removexattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_removexattr_trampoline() - -//go:cgo_import_dynamic libc_removexattr removexattr "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func fremovexattr(fd int, attr string, options int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(attr) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_fremovexattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(options)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fremovexattr_trampoline() - -//go:cgo_import_dynamic libc_fremovexattr fremovexattr "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func listxattr(path string, dest *byte, size int, options int) (sz int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - r0, _, e1 := syscall_syscall6(funcPC(libc_listxattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) - sz = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_listxattr_trampoline() - -//go:cgo_import_dynamic libc_listxattr listxattr "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func flistxattr(fd int, dest *byte, size int, options int) (sz int, err error) { - r0, _, e1 := syscall_syscall6(funcPC(libc_flistxattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) - sz = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_flistxattr_trampoline() - -//go:cgo_import_dynamic libc_flistxattr flistxattr "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func setattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) { - _, _, e1 := syscall_syscall6(funcPC(libc_setattrlist_trampoline), uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setattrlist_trampoline() - -//go:cgo_import_dynamic libc_setattrlist setattrlist "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func fcntl(fd int, cmd int, arg int) (val int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_fcntl_trampoline), uintptr(fd), uintptr(cmd), uintptr(arg)) - val = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fcntl_trampoline() - -//go:cgo_import_dynamic libc_fcntl fcntl "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func kill(pid int, signum int, posix int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_kill_trampoline), uintptr(pid), uintptr(signum), uintptr(posix)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_kill_trampoline() - -//go:cgo_import_dynamic libc_kill kill "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func ioctl(fd int, req uint, arg uintptr) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_ioctl_trampoline), uintptr(fd), uintptr(req), uintptr(arg)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_ioctl_trampoline() - -//go:cgo_import_dynamic libc_ioctl ioctl "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { - var _p0 unsafe.Pointer - if len(mib) > 0 { - _p0 = unsafe.Pointer(&mib[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - _, _, e1 := syscall_syscall6(funcPC(libc_sysctl_trampoline), uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_sysctl_trampoline() - -//go:cgo_import_dynamic libc_sysctl sysctl "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) { - _, _, e1 := syscall_syscall9(funcPC(libc_sendfile_trampoline), uintptr(infd), uintptr(outfd), uintptr(offset), uintptr(offset>>32), uintptr(unsafe.Pointer(len)), uintptr(hdtr), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_sendfile_trampoline() - -//go:cgo_import_dynamic libc_sendfile sendfile "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Access(path string, mode uint32) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_access_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_access_trampoline() - -//go:cgo_import_dynamic libc_access access "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Adjtime(delta *Timeval, olddelta *Timeval) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_adjtime_trampoline), uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_adjtime_trampoline() - -//go:cgo_import_dynamic libc_adjtime adjtime "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Chdir(path string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_chdir_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_chdir_trampoline() - -//go:cgo_import_dynamic libc_chdir chdir "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Chflags(path string, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_chflags_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_chflags_trampoline() - -//go:cgo_import_dynamic libc_chflags chflags "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Chmod(path string, mode uint32) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_chmod_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_chmod_trampoline() - -//go:cgo_import_dynamic libc_chmod chmod "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Chown(path string, uid int, gid int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_chown_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_chown_trampoline() - -//go:cgo_import_dynamic libc_chown chown "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Chroot(path string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_chroot_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_chroot_trampoline() - -//go:cgo_import_dynamic libc_chroot chroot "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func ClockGettime(clockid int32, time *Timespec) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_clock_gettime_trampoline), uintptr(clockid), uintptr(unsafe.Pointer(time)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_clock_gettime_trampoline() - -//go:cgo_import_dynamic libc_clock_gettime clock_gettime "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Close(fd int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_close_trampoline), uintptr(fd), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_close_trampoline() - -//go:cgo_import_dynamic libc_close close "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Clonefile(src string, dst string, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(src) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(dst) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_clonefile_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flags)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_clonefile_trampoline() - -//go:cgo_import_dynamic libc_clonefile clonefile "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Clonefileat(srcDirfd int, src string, dstDirfd int, dst string, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(src) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(dst) - if err != nil { - return - } - _, _, e1 := syscall_syscall6(funcPC(libc_clonefileat_trampoline), uintptr(srcDirfd), uintptr(unsafe.Pointer(_p0)), uintptr(dstDirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_clonefileat_trampoline() - -//go:cgo_import_dynamic libc_clonefileat clonefileat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Dup(fd int) (nfd int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_dup_trampoline), uintptr(fd), 0, 0) - nfd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_dup_trampoline() - -//go:cgo_import_dynamic libc_dup dup "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Dup2(from int, to int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_dup2_trampoline), uintptr(from), uintptr(to), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_dup2_trampoline() - -//go:cgo_import_dynamic libc_dup2 dup2 "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Exchangedata(path1 string, path2 string, options int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path1) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(path2) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_exchangedata_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_exchangedata_trampoline() - -//go:cgo_import_dynamic libc_exchangedata exchangedata "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Exit(code int) { - syscall_syscall(funcPC(libc_exit_trampoline), uintptr(code), 0, 0) - return -} - -func libc_exit_trampoline() - -//go:cgo_import_dynamic libc_exit exit "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall6(funcPC(libc_faccessat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_faccessat_trampoline() - -//go:cgo_import_dynamic libc_faccessat faccessat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fchdir(fd int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fchdir_trampoline), uintptr(fd), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fchdir_trampoline() - -//go:cgo_import_dynamic libc_fchdir fchdir "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fchflags(fd int, flags int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fchflags_trampoline), uintptr(fd), uintptr(flags), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fchflags_trampoline() - -//go:cgo_import_dynamic libc_fchflags fchflags "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fchmod(fd int, mode uint32) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fchmod_trampoline), uintptr(fd), uintptr(mode), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fchmod_trampoline() - -//go:cgo_import_dynamic libc_fchmod fchmod "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall6(funcPC(libc_fchmodat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fchmodat_trampoline() - -//go:cgo_import_dynamic libc_fchmodat fchmodat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fchown(fd int, uid int, gid int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fchown_trampoline), uintptr(fd), uintptr(uid), uintptr(gid)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fchown_trampoline() - -//go:cgo_import_dynamic libc_fchown fchown "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall6(funcPC(libc_fchownat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fchownat_trampoline() - -//go:cgo_import_dynamic libc_fchownat fchownat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fclonefileat(srcDirfd int, dstDirfd int, dst string, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(dst) - if err != nil { - return - } - _, _, e1 := syscall_syscall6(funcPC(libc_fclonefileat_trampoline), uintptr(srcDirfd), uintptr(dstDirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fclonefileat_trampoline() - -//go:cgo_import_dynamic libc_fclonefileat fclonefileat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Flock(fd int, how int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_flock_trampoline), uintptr(fd), uintptr(how), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_flock_trampoline() - -//go:cgo_import_dynamic libc_flock flock "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fpathconf(fd int, name int) (val int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_fpathconf_trampoline), uintptr(fd), uintptr(name), 0) - val = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fpathconf_trampoline() - -//go:cgo_import_dynamic libc_fpathconf fpathconf "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fsync(fd int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fsync_trampoline), uintptr(fd), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fsync_trampoline() - -//go:cgo_import_dynamic libc_fsync fsync "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Ftruncate(fd int, length int64) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_ftruncate_trampoline), uintptr(fd), uintptr(length), uintptr(length>>32)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_ftruncate_trampoline() - -//go:cgo_import_dynamic libc_ftruncate ftruncate "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getcwd(buf []byte) (n int, err error) { - var _p0 unsafe.Pointer - if len(buf) > 0 { - _p0 = unsafe.Pointer(&buf[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := syscall_syscall(funcPC(libc_getcwd_trampoline), uintptr(_p0), uintptr(len(buf)), 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_getcwd_trampoline() - -//go:cgo_import_dynamic libc_getcwd getcwd "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getdtablesize() (size int) { - r0, _, _ := syscall_syscall(funcPC(libc_getdtablesize_trampoline), 0, 0, 0) - size = int(r0) - return -} - -func libc_getdtablesize_trampoline() - -//go:cgo_import_dynamic libc_getdtablesize getdtablesize "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getegid() (egid int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_getegid_trampoline), 0, 0, 0) - egid = int(r0) - return -} - -func libc_getegid_trampoline() - -//go:cgo_import_dynamic libc_getegid getegid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Geteuid() (uid int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_geteuid_trampoline), 0, 0, 0) - uid = int(r0) - return -} - -func libc_geteuid_trampoline() - -//go:cgo_import_dynamic libc_geteuid geteuid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getgid() (gid int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_getgid_trampoline), 0, 0, 0) - gid = int(r0) - return -} - -func libc_getgid_trampoline() - -//go:cgo_import_dynamic libc_getgid getgid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getpgid(pid int) (pgid int, err error) { - r0, _, e1 := syscall_rawSyscall(funcPC(libc_getpgid_trampoline), uintptr(pid), 0, 0) - pgid = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_getpgid_trampoline() - -//go:cgo_import_dynamic libc_getpgid getpgid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getpgrp() (pgrp int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_getpgrp_trampoline), 0, 0, 0) - pgrp = int(r0) - return -} - -func libc_getpgrp_trampoline() - -//go:cgo_import_dynamic libc_getpgrp getpgrp "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getpid() (pid int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_getpid_trampoline), 0, 0, 0) - pid = int(r0) - return -} - -func libc_getpid_trampoline() - -//go:cgo_import_dynamic libc_getpid getpid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getppid() (ppid int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_getppid_trampoline), 0, 0, 0) - ppid = int(r0) - return -} - -func libc_getppid_trampoline() - -//go:cgo_import_dynamic libc_getppid getppid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getpriority(which int, who int) (prio int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_getpriority_trampoline), uintptr(which), uintptr(who), 0) - prio = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_getpriority_trampoline() - -//go:cgo_import_dynamic libc_getpriority getpriority "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getrlimit(which int, lim *Rlimit) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_getrlimit_trampoline), uintptr(which), uintptr(unsafe.Pointer(lim)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_getrlimit_trampoline() - -//go:cgo_import_dynamic libc_getrlimit getrlimit "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getrusage(who int, rusage *Rusage) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_getrusage_trampoline), uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_getrusage_trampoline() - -//go:cgo_import_dynamic libc_getrusage getrusage "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getsid(pid int) (sid int, err error) { - r0, _, e1 := syscall_rawSyscall(funcPC(libc_getsid_trampoline), uintptr(pid), 0, 0) - sid = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_getsid_trampoline() - -//go:cgo_import_dynamic libc_getsid getsid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Gettimeofday(tp *Timeval) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_gettimeofday_trampoline), uintptr(unsafe.Pointer(tp)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_gettimeofday_trampoline() - -//go:cgo_import_dynamic libc_gettimeofday gettimeofday "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getuid() (uid int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_getuid_trampoline), 0, 0, 0) - uid = int(r0) - return -} - -func libc_getuid_trampoline() - -//go:cgo_import_dynamic libc_getuid getuid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Issetugid() (tainted bool) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_issetugid_trampoline), 0, 0, 0) - tainted = bool(r0 != 0) - return -} - -func libc_issetugid_trampoline() - -//go:cgo_import_dynamic libc_issetugid issetugid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Kqueue() (fd int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_kqueue_trampoline), 0, 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_kqueue_trampoline() - -//go:cgo_import_dynamic libc_kqueue kqueue "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Lchown(path string, uid int, gid int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_lchown_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_lchown_trampoline() - -//go:cgo_import_dynamic libc_lchown lchown "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Link(path string, link string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(link) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_link_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_link_trampoline() - -//go:cgo_import_dynamic libc_link link "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(link) - if err != nil { - return - } - _, _, e1 := syscall_syscall6(funcPC(libc_linkat_trampoline), uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_linkat_trampoline() - -//go:cgo_import_dynamic libc_linkat linkat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Listen(s int, backlog int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_listen_trampoline), uintptr(s), uintptr(backlog), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_listen_trampoline() - -//go:cgo_import_dynamic libc_listen listen "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Mkdir(path string, mode uint32) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_mkdir_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_mkdir_trampoline() - -//go:cgo_import_dynamic libc_mkdir mkdir "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Mkdirat(dirfd int, path string, mode uint32) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_mkdirat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_mkdirat_trampoline() - -//go:cgo_import_dynamic libc_mkdirat mkdirat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Mkfifo(path string, mode uint32) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_mkfifo_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_mkfifo_trampoline() - -//go:cgo_import_dynamic libc_mkfifo mkfifo "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Mknod(path string, mode uint32, dev int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_mknod_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_mknod_trampoline() - -//go:cgo_import_dynamic libc_mknod mknod "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Open(path string, mode int, perm uint32) (fd int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - r0, _, e1 := syscall_syscall(funcPC(libc_open_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_open_trampoline() - -//go:cgo_import_dynamic libc_open open "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - r0, _, e1 := syscall_syscall6(funcPC(libc_openat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_openat_trampoline() - -//go:cgo_import_dynamic libc_openat openat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Pathconf(path string, name int) (val int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - r0, _, e1 := syscall_syscall(funcPC(libc_pathconf_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) - val = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_pathconf_trampoline() - -//go:cgo_import_dynamic libc_pathconf pathconf "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Pread(fd int, p []byte, offset int64) (n int, err error) { - var _p0 unsafe.Pointer - if len(p) > 0 { - _p0 = unsafe.Pointer(&p[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := syscall_syscall6(funcPC(libc_pread_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_pread_trampoline() - -//go:cgo_import_dynamic libc_pread pread "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Pwrite(fd int, p []byte, offset int64) (n int, err error) { - var _p0 unsafe.Pointer - if len(p) > 0 { - _p0 = unsafe.Pointer(&p[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := syscall_syscall6(funcPC(libc_pwrite_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_pwrite_trampoline() - -//go:cgo_import_dynamic libc_pwrite pwrite "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func read(fd int, p []byte) (n int, err error) { - var _p0 unsafe.Pointer - if len(p) > 0 { - _p0 = unsafe.Pointer(&p[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := syscall_syscall(funcPC(libc_read_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p))) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_read_trampoline() - -//go:cgo_import_dynamic libc_read read "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Readlink(path string, buf []byte) (n int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - var _p1 unsafe.Pointer - if len(buf) > 0 { - _p1 = unsafe.Pointer(&buf[0]) - } else { - _p1 = unsafe.Pointer(&_zero) - } - r0, _, e1 := syscall_syscall(funcPC(libc_readlink_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_readlink_trampoline() - -//go:cgo_import_dynamic libc_readlink readlink "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - var _p1 unsafe.Pointer - if len(buf) > 0 { - _p1 = unsafe.Pointer(&buf[0]) - } else { - _p1 = unsafe.Pointer(&_zero) - } - r0, _, e1 := syscall_syscall6(funcPC(libc_readlinkat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_readlinkat_trampoline() - -//go:cgo_import_dynamic libc_readlinkat readlinkat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Rename(from string, to string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(from) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(to) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_rename_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_rename_trampoline() - -//go:cgo_import_dynamic libc_rename rename "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Renameat(fromfd int, from string, tofd int, to string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(from) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(to) - if err != nil { - return - } - _, _, e1 := syscall_syscall6(funcPC(libc_renameat_trampoline), uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_renameat_trampoline() - -//go:cgo_import_dynamic libc_renameat renameat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Revoke(path string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_revoke_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_revoke_trampoline() - -//go:cgo_import_dynamic libc_revoke revoke "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Rmdir(path string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_rmdir_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_rmdir_trampoline() - -//go:cgo_import_dynamic libc_rmdir rmdir "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { - r0, r1, e1 := syscall_syscall6(funcPC(libc_lseek_trampoline), uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(whence), 0, 0) - newoffset = int64(int64(r1)<<32 | int64(r0)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_lseek_trampoline() - -//go:cgo_import_dynamic libc_lseek lseek "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) { - r0, _, e1 := syscall_syscall6(funcPC(libc_select_trampoline), uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_select_trampoline() - -//go:cgo_import_dynamic libc_select select "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Setegid(egid int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_setegid_trampoline), uintptr(egid), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setegid_trampoline() - -//go:cgo_import_dynamic libc_setegid setegid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Seteuid(euid int) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_seteuid_trampoline), uintptr(euid), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_seteuid_trampoline() - -//go:cgo_import_dynamic libc_seteuid seteuid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Setgid(gid int) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setgid_trampoline), uintptr(gid), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setgid_trampoline() - -//go:cgo_import_dynamic libc_setgid setgid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Setlogin(name string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(name) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_setlogin_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setlogin_trampoline() - -//go:cgo_import_dynamic libc_setlogin setlogin "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Setpgid(pid int, pgid int) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setpgid_trampoline), uintptr(pid), uintptr(pgid), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setpgid_trampoline() - -//go:cgo_import_dynamic libc_setpgid setpgid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Setpriority(which int, who int, prio int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_setpriority_trampoline), uintptr(which), uintptr(who), uintptr(prio)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setpriority_trampoline() - -//go:cgo_import_dynamic libc_setpriority setpriority "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Setprivexec(flag int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_setprivexec_trampoline), uintptr(flag), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setprivexec_trampoline() - -//go:cgo_import_dynamic libc_setprivexec setprivexec "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Setregid(rgid int, egid int) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setregid_trampoline), uintptr(rgid), uintptr(egid), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setregid_trampoline() - -//go:cgo_import_dynamic libc_setregid setregid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Setreuid(ruid int, euid int) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setreuid_trampoline), uintptr(ruid), uintptr(euid), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setreuid_trampoline() - -//go:cgo_import_dynamic libc_setreuid setreuid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Setrlimit(which int, lim *Rlimit) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setrlimit_trampoline), uintptr(which), uintptr(unsafe.Pointer(lim)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setrlimit_trampoline() - -//go:cgo_import_dynamic libc_setrlimit setrlimit "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Setsid() (pid int, err error) { - r0, _, e1 := syscall_rawSyscall(funcPC(libc_setsid_trampoline), 0, 0, 0) - pid = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setsid_trampoline() - -//go:cgo_import_dynamic libc_setsid setsid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Settimeofday(tp *Timeval) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_settimeofday_trampoline), uintptr(unsafe.Pointer(tp)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_settimeofday_trampoline() - -//go:cgo_import_dynamic libc_settimeofday settimeofday "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Setuid(uid int) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setuid_trampoline), uintptr(uid), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setuid_trampoline() - -//go:cgo_import_dynamic libc_setuid setuid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Symlink(path string, link string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(link) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_symlink_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_symlink_trampoline() - -//go:cgo_import_dynamic libc_symlink symlink "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(oldpath) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(newpath) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_symlinkat_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_symlinkat_trampoline() - -//go:cgo_import_dynamic libc_symlinkat symlinkat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Sync() (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_sync_trampoline), 0, 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_sync_trampoline() - -//go:cgo_import_dynamic libc_sync sync "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Truncate(path string, length int64) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_truncate_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_truncate_trampoline() - -//go:cgo_import_dynamic libc_truncate truncate "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Umask(newmask int) (oldmask int) { - r0, _, _ := syscall_syscall(funcPC(libc_umask_trampoline), uintptr(newmask), 0, 0) - oldmask = int(r0) - return -} - -func libc_umask_trampoline() - -//go:cgo_import_dynamic libc_umask umask "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Undelete(path string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_undelete_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_undelete_trampoline() - -//go:cgo_import_dynamic libc_undelete undelete "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Unlink(path string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_unlink_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_unlink_trampoline() - -//go:cgo_import_dynamic libc_unlink unlink "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Unlinkat(dirfd int, path string, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_unlinkat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_unlinkat_trampoline() - -//go:cgo_import_dynamic libc_unlinkat unlinkat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Unmount(path string, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_unmount_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_unmount_trampoline() - -//go:cgo_import_dynamic libc_unmount unmount "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func write(fd int, p []byte) (n int, err error) { - var _p0 unsafe.Pointer - if len(p) > 0 { - _p0 = unsafe.Pointer(&p[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := syscall_syscall(funcPC(libc_write_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p))) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_write_trampoline() - -//go:cgo_import_dynamic libc_write write "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) { - r0, _, e1 := syscall_syscall9(funcPC(libc_mmap_trampoline), uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos), uintptr(pos>>32), 0, 0) - ret = uintptr(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_mmap_trampoline() - -//go:cgo_import_dynamic libc_mmap mmap "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func munmap(addr uintptr, length uintptr) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_munmap_trampoline), uintptr(addr), uintptr(length), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_munmap_trampoline() - -//go:cgo_import_dynamic libc_munmap munmap "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func readlen(fd int, buf *byte, nbuf int) (n int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_read_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func writelen(fd int, buf *byte, nbuf int) (n int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_write_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fstat(fd int, stat *Stat_t) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fstat64_trampoline), uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fstat64_trampoline() - -//go:cgo_import_dynamic libc_fstat64 fstat64 "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall6(funcPC(libc_fstatat64_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fstatat64_trampoline() - -//go:cgo_import_dynamic libc_fstatat64 fstatat64 "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fstatfs(fd int, stat *Statfs_t) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fstatfs64_trampoline), uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fstatfs64_trampoline() - -//go:cgo_import_dynamic libc_fstatfs64 fstatfs64 "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_getfsstat64_trampoline), uintptr(buf), uintptr(size), uintptr(flags)) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_getfsstat64_trampoline() - -//go:cgo_import_dynamic libc_getfsstat64 getfsstat64 "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Lstat(path string, stat *Stat_t) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_lstat64_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_lstat64_trampoline() - -//go:cgo_import_dynamic libc_lstat64 lstat64 "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func ptrace1(request int, pid int, addr uintptr, data uintptr) (err error) { - _, _, e1 := syscall_syscall6(funcPC(libc_ptrace_trampoline), uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_ptrace_trampoline() - -//go:cgo_import_dynamic libc_ptrace ptrace "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Stat(path string, stat *Stat_t) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_stat64_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_stat64_trampoline() - -//go:cgo_import_dynamic libc_stat64 stat64 "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Statfs(path string, stat *Statfs_t) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_statfs64_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_statfs64_trampoline() - -//go:cgo_import_dynamic libc_statfs64 statfs64 "/usr/lib/libSystem.B.dylib" diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.s b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.s deleted file mode 100644 index 8cc7928d929..00000000000 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.s +++ /dev/null @@ -1,291 +0,0 @@ -// go run mkasm_darwin.go 386 -// Code generated by the command above; DO NOT EDIT. - -//go:build go1.12 -// +build go1.12 - -#include "textflag.h" -TEXT ·libc_getgroups_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getgroups(SB) -TEXT ·libc_setgroups_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setgroups(SB) -TEXT ·libc_wait4_trampoline(SB),NOSPLIT,$0-0 - JMP libc_wait4(SB) -TEXT ·libc_accept_trampoline(SB),NOSPLIT,$0-0 - JMP libc_accept(SB) -TEXT ·libc_bind_trampoline(SB),NOSPLIT,$0-0 - JMP libc_bind(SB) -TEXT ·libc_connect_trampoline(SB),NOSPLIT,$0-0 - JMP libc_connect(SB) -TEXT ·libc_socket_trampoline(SB),NOSPLIT,$0-0 - JMP libc_socket(SB) -TEXT ·libc_getsockopt_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getsockopt(SB) -TEXT ·libc_setsockopt_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setsockopt(SB) -TEXT ·libc_getpeername_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getpeername(SB) -TEXT ·libc_getsockname_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getsockname(SB) -TEXT ·libc_shutdown_trampoline(SB),NOSPLIT,$0-0 - JMP libc_shutdown(SB) -TEXT ·libc_socketpair_trampoline(SB),NOSPLIT,$0-0 - JMP libc_socketpair(SB) -TEXT ·libc_recvfrom_trampoline(SB),NOSPLIT,$0-0 - JMP libc_recvfrom(SB) -TEXT ·libc_sendto_trampoline(SB),NOSPLIT,$0-0 - JMP libc_sendto(SB) -TEXT ·libc_recvmsg_trampoline(SB),NOSPLIT,$0-0 - JMP libc_recvmsg(SB) -TEXT ·libc_sendmsg_trampoline(SB),NOSPLIT,$0-0 - JMP libc_sendmsg(SB) -TEXT ·libc_kevent_trampoline(SB),NOSPLIT,$0-0 - JMP libc_kevent(SB) -TEXT ·libc_utimes_trampoline(SB),NOSPLIT,$0-0 - JMP libc_utimes(SB) -TEXT ·libc_futimes_trampoline(SB),NOSPLIT,$0-0 - JMP libc_futimes(SB) -TEXT ·libc_poll_trampoline(SB),NOSPLIT,$0-0 - JMP libc_poll(SB) -TEXT ·libc_madvise_trampoline(SB),NOSPLIT,$0-0 - JMP libc_madvise(SB) -TEXT ·libc_mlock_trampoline(SB),NOSPLIT,$0-0 - JMP libc_mlock(SB) -TEXT ·libc_mlockall_trampoline(SB),NOSPLIT,$0-0 - JMP libc_mlockall(SB) -TEXT ·libc_mprotect_trampoline(SB),NOSPLIT,$0-0 - JMP libc_mprotect(SB) -TEXT ·libc_msync_trampoline(SB),NOSPLIT,$0-0 - JMP libc_msync(SB) -TEXT ·libc_munlock_trampoline(SB),NOSPLIT,$0-0 - JMP libc_munlock(SB) -TEXT ·libc_munlockall_trampoline(SB),NOSPLIT,$0-0 - JMP libc_munlockall(SB) -TEXT ·libc_pipe_trampoline(SB),NOSPLIT,$0-0 - JMP libc_pipe(SB) -TEXT ·libc_getxattr_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getxattr(SB) -TEXT ·libc_fgetxattr_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fgetxattr(SB) -TEXT ·libc_setxattr_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setxattr(SB) -TEXT ·libc_fsetxattr_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fsetxattr(SB) -TEXT ·libc_removexattr_trampoline(SB),NOSPLIT,$0-0 - JMP libc_removexattr(SB) -TEXT ·libc_fremovexattr_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fremovexattr(SB) -TEXT ·libc_listxattr_trampoline(SB),NOSPLIT,$0-0 - JMP libc_listxattr(SB) -TEXT ·libc_flistxattr_trampoline(SB),NOSPLIT,$0-0 - JMP libc_flistxattr(SB) -TEXT ·libc_setattrlist_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setattrlist(SB) -TEXT ·libc_fcntl_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fcntl(SB) -TEXT ·libc_kill_trampoline(SB),NOSPLIT,$0-0 - JMP libc_kill(SB) -TEXT ·libc_ioctl_trampoline(SB),NOSPLIT,$0-0 - JMP libc_ioctl(SB) -TEXT ·libc_sysctl_trampoline(SB),NOSPLIT,$0-0 - JMP libc_sysctl(SB) -TEXT ·libc_sendfile_trampoline(SB),NOSPLIT,$0-0 - JMP libc_sendfile(SB) -TEXT ·libc_access_trampoline(SB),NOSPLIT,$0-0 - JMP libc_access(SB) -TEXT ·libc_adjtime_trampoline(SB),NOSPLIT,$0-0 - JMP libc_adjtime(SB) -TEXT ·libc_chdir_trampoline(SB),NOSPLIT,$0-0 - JMP libc_chdir(SB) -TEXT ·libc_chflags_trampoline(SB),NOSPLIT,$0-0 - JMP libc_chflags(SB) -TEXT ·libc_chmod_trampoline(SB),NOSPLIT,$0-0 - JMP libc_chmod(SB) -TEXT ·libc_chown_trampoline(SB),NOSPLIT,$0-0 - JMP libc_chown(SB) -TEXT ·libc_chroot_trampoline(SB),NOSPLIT,$0-0 - JMP libc_chroot(SB) -TEXT ·libc_clock_gettime_trampoline(SB),NOSPLIT,$0-0 - JMP libc_clock_gettime(SB) -TEXT ·libc_close_trampoline(SB),NOSPLIT,$0-0 - JMP libc_close(SB) -TEXT ·libc_clonefile_trampoline(SB),NOSPLIT,$0-0 - JMP libc_clonefile(SB) -TEXT ·libc_clonefileat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_clonefileat(SB) -TEXT ·libc_dup_trampoline(SB),NOSPLIT,$0-0 - JMP libc_dup(SB) -TEXT ·libc_dup2_trampoline(SB),NOSPLIT,$0-0 - JMP libc_dup2(SB) -TEXT ·libc_exchangedata_trampoline(SB),NOSPLIT,$0-0 - JMP libc_exchangedata(SB) -TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0 - JMP libc_exit(SB) -TEXT ·libc_faccessat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_faccessat(SB) -TEXT ·libc_fchdir_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fchdir(SB) -TEXT ·libc_fchflags_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fchflags(SB) -TEXT ·libc_fchmod_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fchmod(SB) -TEXT ·libc_fchmodat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fchmodat(SB) -TEXT ·libc_fchown_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fchown(SB) -TEXT ·libc_fchownat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fchownat(SB) -TEXT ·libc_fclonefileat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fclonefileat(SB) -TEXT ·libc_flock_trampoline(SB),NOSPLIT,$0-0 - JMP libc_flock(SB) -TEXT ·libc_fpathconf_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fpathconf(SB) -TEXT ·libc_fsync_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fsync(SB) -TEXT ·libc_ftruncate_trampoline(SB),NOSPLIT,$0-0 - JMP libc_ftruncate(SB) -TEXT ·libc_getcwd_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getcwd(SB) -TEXT ·libc_getdtablesize_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getdtablesize(SB) -TEXT ·libc_getegid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getegid(SB) -TEXT ·libc_geteuid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_geteuid(SB) -TEXT ·libc_getgid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getgid(SB) -TEXT ·libc_getpgid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getpgid(SB) -TEXT ·libc_getpgrp_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getpgrp(SB) -TEXT ·libc_getpid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getpid(SB) -TEXT ·libc_getppid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getppid(SB) -TEXT ·libc_getpriority_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getpriority(SB) -TEXT ·libc_getrlimit_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getrlimit(SB) -TEXT ·libc_getrusage_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getrusage(SB) -TEXT ·libc_getsid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getsid(SB) -TEXT ·libc_gettimeofday_trampoline(SB),NOSPLIT,$0-0 - JMP libc_gettimeofday(SB) -TEXT ·libc_getuid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getuid(SB) -TEXT ·libc_issetugid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_issetugid(SB) -TEXT ·libc_kqueue_trampoline(SB),NOSPLIT,$0-0 - JMP libc_kqueue(SB) -TEXT ·libc_lchown_trampoline(SB),NOSPLIT,$0-0 - JMP libc_lchown(SB) -TEXT ·libc_link_trampoline(SB),NOSPLIT,$0-0 - JMP libc_link(SB) -TEXT ·libc_linkat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_linkat(SB) -TEXT ·libc_listen_trampoline(SB),NOSPLIT,$0-0 - JMP libc_listen(SB) -TEXT ·libc_mkdir_trampoline(SB),NOSPLIT,$0-0 - JMP libc_mkdir(SB) -TEXT ·libc_mkdirat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_mkdirat(SB) -TEXT ·libc_mkfifo_trampoline(SB),NOSPLIT,$0-0 - JMP libc_mkfifo(SB) -TEXT ·libc_mknod_trampoline(SB),NOSPLIT,$0-0 - JMP libc_mknod(SB) -TEXT ·libc_open_trampoline(SB),NOSPLIT,$0-0 - JMP libc_open(SB) -TEXT ·libc_openat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_openat(SB) -TEXT ·libc_pathconf_trampoline(SB),NOSPLIT,$0-0 - JMP libc_pathconf(SB) -TEXT ·libc_pread_trampoline(SB),NOSPLIT,$0-0 - JMP libc_pread(SB) -TEXT ·libc_pwrite_trampoline(SB),NOSPLIT,$0-0 - JMP libc_pwrite(SB) -TEXT ·libc_read_trampoline(SB),NOSPLIT,$0-0 - JMP libc_read(SB) -TEXT ·libc_readlink_trampoline(SB),NOSPLIT,$0-0 - JMP libc_readlink(SB) -TEXT ·libc_readlinkat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_readlinkat(SB) -TEXT ·libc_rename_trampoline(SB),NOSPLIT,$0-0 - JMP libc_rename(SB) -TEXT ·libc_renameat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_renameat(SB) -TEXT ·libc_revoke_trampoline(SB),NOSPLIT,$0-0 - JMP libc_revoke(SB) -TEXT ·libc_rmdir_trampoline(SB),NOSPLIT,$0-0 - JMP libc_rmdir(SB) -TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 - JMP libc_lseek(SB) -TEXT ·libc_select_trampoline(SB),NOSPLIT,$0-0 - JMP libc_select(SB) -TEXT ·libc_setegid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setegid(SB) -TEXT ·libc_seteuid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_seteuid(SB) -TEXT ·libc_setgid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setgid(SB) -TEXT ·libc_setlogin_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setlogin(SB) -TEXT ·libc_setpgid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setpgid(SB) -TEXT ·libc_setpriority_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setpriority(SB) -TEXT ·libc_setprivexec_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setprivexec(SB) -TEXT ·libc_setregid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setregid(SB) -TEXT ·libc_setreuid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setreuid(SB) -TEXT ·libc_setrlimit_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setrlimit(SB) -TEXT ·libc_setsid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setsid(SB) -TEXT ·libc_settimeofday_trampoline(SB),NOSPLIT,$0-0 - JMP libc_settimeofday(SB) -TEXT ·libc_setuid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setuid(SB) -TEXT ·libc_symlink_trampoline(SB),NOSPLIT,$0-0 - JMP libc_symlink(SB) -TEXT ·libc_symlinkat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_symlinkat(SB) -TEXT ·libc_sync_trampoline(SB),NOSPLIT,$0-0 - JMP libc_sync(SB) -TEXT ·libc_truncate_trampoline(SB),NOSPLIT,$0-0 - JMP libc_truncate(SB) -TEXT ·libc_umask_trampoline(SB),NOSPLIT,$0-0 - JMP libc_umask(SB) -TEXT ·libc_undelete_trampoline(SB),NOSPLIT,$0-0 - JMP libc_undelete(SB) -TEXT ·libc_unlink_trampoline(SB),NOSPLIT,$0-0 - JMP libc_unlink(SB) -TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_unlinkat(SB) -TEXT ·libc_unmount_trampoline(SB),NOSPLIT,$0-0 - JMP libc_unmount(SB) -TEXT ·libc_write_trampoline(SB),NOSPLIT,$0-0 - JMP libc_write(SB) -TEXT ·libc_mmap_trampoline(SB),NOSPLIT,$0-0 - JMP libc_mmap(SB) -TEXT ·libc_munmap_trampoline(SB),NOSPLIT,$0-0 - JMP libc_munmap(SB) -TEXT ·libc_fstat64_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fstat64(SB) -TEXT ·libc_fstatat64_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fstatat64(SB) -TEXT ·libc_fstatfs64_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fstatfs64(SB) -TEXT ·libc_getfsstat64_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getfsstat64(SB) -TEXT ·libc_lstat64_trampoline(SB),NOSPLIT,$0-0 - JMP libc_lstat64(SB) -TEXT ·libc_ptrace_trampoline(SB),NOSPLIT,$0-0 - JMP libc_ptrace(SB) -TEXT ·libc_stat64_trampoline(SB),NOSPLIT,$0-0 - JMP libc_stat64(SB) -TEXT ·libc_statfs64_trampoline(SB),NOSPLIT,$0-0 - JMP libc_statfs64(SB) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.go index e36299ead09..a06eb093242 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.go @@ -16,25 +16,25 @@ var _ syscall.Errno // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func closedir(dir uintptr) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_closedir_trampoline), uintptr(dir), 0, 0) + _, _, e1 := syscall_syscall(libc_closedir_trampoline_addr, uintptr(dir), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_closedir_trampoline() +var libc_closedir_trampoline_addr uintptr //go:cgo_import_dynamic libc_closedir closedir "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno) { - r0, _, _ := syscall_syscall(funcPC(libc_readdir_r_trampoline), uintptr(dir), uintptr(unsafe.Pointer(entry)), uintptr(unsafe.Pointer(result))) + r0, _, _ := syscall_syscall(libc_readdir_r_trampoline_addr, uintptr(dir), uintptr(unsafe.Pointer(entry)), uintptr(unsafe.Pointer(result))) res = Errno(r0) return } -func libc_readdir_r_trampoline() +var libc_readdir_r_trampoline_addr uintptr //go:cgo_import_dynamic libc_readdir_r readdir_r "/usr/lib/libSystem.B.dylib" diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.s b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.s index ab59833fcd2..d6c3e25c018 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.s +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.s @@ -5,9 +5,21 @@ // +build go1.13 #include "textflag.h" -TEXT ·libc_fdopendir_trampoline(SB),NOSPLIT,$0-0 + +TEXT libc_fdopendir_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fdopendir(SB) -TEXT ·libc_closedir_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fdopendir_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fdopendir_trampoline_addr(SB)/8, $libc_fdopendir_trampoline<>(SB) + +TEXT libc_closedir_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_closedir(SB) -TEXT ·libc_readdir_r_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_closedir_trampoline_addr(SB), RODATA, $8 +DATA ·libc_closedir_trampoline_addr(SB)/8, $libc_closedir_trampoline<>(SB) + +TEXT libc_readdir_r_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_readdir_r(SB) + +GLOBL ·libc_readdir_r_trampoline_addr(SB), RODATA, $8 +DATA ·libc_readdir_r_trampoline_addr(SB)/8, $libc_readdir_r_trampoline<>(SB) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go index f4111628823..d4efe8d457a 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go @@ -16,7 +16,7 @@ var _ syscall.Errno // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getgroups(ngid int, gid *_Gid_t) (n int, err error) { - r0, _, e1 := syscall_rawSyscall(funcPC(libc_getgroups_trampoline), uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + r0, _, e1 := syscall_rawSyscall(libc_getgroups_trampoline_addr, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -24,28 +24,28 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) { return } -func libc_getgroups_trampoline() +var libc_getgroups_trampoline_addr uintptr //go:cgo_import_dynamic libc_getgroups getgroups "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func setgroups(ngid int, gid *_Gid_t) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setgroups_trampoline), uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + _, _, e1 := syscall_rawSyscall(libc_setgroups_trampoline_addr, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setgroups_trampoline() +var libc_setgroups_trampoline_addr uintptr //go:cgo_import_dynamic libc_setgroups setgroups "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) { - r0, _, e1 := syscall_syscall6(funcPC(libc_wait4_trampoline), uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) + r0, _, e1 := syscall_syscall6(libc_wait4_trampoline_addr, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) wpid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -53,14 +53,14 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err return } -func libc_wait4_trampoline() +var libc_wait4_trampoline_addr uintptr //go:cgo_import_dynamic libc_wait4 wait4 "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_accept_trampoline), uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + r0, _, e1 := syscall_syscall(libc_accept_trampoline_addr, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -68,42 +68,42 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { return } -func libc_accept_trampoline() +var libc_accept_trampoline_addr uintptr //go:cgo_import_dynamic libc_accept accept "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_bind_trampoline), uintptr(s), uintptr(addr), uintptr(addrlen)) + _, _, e1 := syscall_syscall(libc_bind_trampoline_addr, uintptr(s), uintptr(addr), uintptr(addrlen)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_bind_trampoline() +var libc_bind_trampoline_addr uintptr //go:cgo_import_dynamic libc_bind bind "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_connect_trampoline), uintptr(s), uintptr(addr), uintptr(addrlen)) + _, _, e1 := syscall_syscall(libc_connect_trampoline_addr, uintptr(s), uintptr(addr), uintptr(addrlen)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_connect_trampoline() +var libc_connect_trampoline_addr uintptr //go:cgo_import_dynamic libc_connect connect "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func socket(domain int, typ int, proto int) (fd int, err error) { - r0, _, e1 := syscall_rawSyscall(funcPC(libc_socket_trampoline), uintptr(domain), uintptr(typ), uintptr(proto)) + r0, _, e1 := syscall_rawSyscall(libc_socket_trampoline_addr, uintptr(domain), uintptr(typ), uintptr(proto)) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -111,91 +111,91 @@ func socket(domain int, typ int, proto int) (fd int, err error) { return } -func libc_socket_trampoline() +var libc_socket_trampoline_addr uintptr //go:cgo_import_dynamic libc_socket socket "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) { - _, _, e1 := syscall_syscall6(funcPC(libc_getsockopt_trampoline), uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) + _, _, e1 := syscall_syscall6(libc_getsockopt_trampoline_addr, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_getsockopt_trampoline() +var libc_getsockopt_trampoline_addr uintptr //go:cgo_import_dynamic libc_getsockopt getsockopt "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { - _, _, e1 := syscall_syscall6(funcPC(libc_setsockopt_trampoline), uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) + _, _, e1 := syscall_syscall6(libc_setsockopt_trampoline_addr, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setsockopt_trampoline() +var libc_setsockopt_trampoline_addr uintptr //go:cgo_import_dynamic libc_setsockopt setsockopt "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_getpeername_trampoline), uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + _, _, e1 := syscall_rawSyscall(libc_getpeername_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) if e1 != 0 { err = errnoErr(e1) } return } -func libc_getpeername_trampoline() +var libc_getpeername_trampoline_addr uintptr //go:cgo_import_dynamic libc_getpeername getpeername "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_getsockname_trampoline), uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + _, _, e1 := syscall_rawSyscall(libc_getsockname_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) if e1 != 0 { err = errnoErr(e1) } return } -func libc_getsockname_trampoline() +var libc_getsockname_trampoline_addr uintptr //go:cgo_import_dynamic libc_getsockname getsockname "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Shutdown(s int, how int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_shutdown_trampoline), uintptr(s), uintptr(how), 0) + _, _, e1 := syscall_syscall(libc_shutdown_trampoline_addr, uintptr(s), uintptr(how), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_shutdown_trampoline() +var libc_shutdown_trampoline_addr uintptr //go:cgo_import_dynamic libc_shutdown shutdown "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) { - _, _, e1 := syscall_rawSyscall6(funcPC(libc_socketpair_trampoline), uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) + _, _, e1 := syscall_rawSyscall6(libc_socketpair_trampoline_addr, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_socketpair_trampoline() +var libc_socketpair_trampoline_addr uintptr //go:cgo_import_dynamic libc_socketpair socketpair "/usr/lib/libSystem.B.dylib" @@ -208,7 +208,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := syscall_syscall6(funcPC(libc_recvfrom_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) + r0, _, e1 := syscall_syscall6(libc_recvfrom_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -216,7 +216,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl return } -func libc_recvfrom_trampoline() +var libc_recvfrom_trampoline_addr uintptr //go:cgo_import_dynamic libc_recvfrom recvfrom "/usr/lib/libSystem.B.dylib" @@ -229,21 +229,21 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) ( } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := syscall_syscall6(funcPC(libc_sendto_trampoline), uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) + _, _, e1 := syscall_syscall6(libc_sendto_trampoline_addr, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_sendto_trampoline() +var libc_sendto_trampoline_addr uintptr //go:cgo_import_dynamic libc_sendto sendto "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_recvmsg_trampoline), uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + r0, _, e1 := syscall_syscall(libc_recvmsg_trampoline_addr, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -251,14 +251,14 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { return } -func libc_recvmsg_trampoline() +var libc_recvmsg_trampoline_addr uintptr //go:cgo_import_dynamic libc_recvmsg recvmsg "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_sendmsg_trampoline), uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + r0, _, e1 := syscall_syscall(libc_sendmsg_trampoline_addr, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -266,14 +266,14 @@ func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { return } -func libc_sendmsg_trampoline() +var libc_sendmsg_trampoline_addr uintptr //go:cgo_import_dynamic libc_sendmsg sendmsg "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) { - r0, _, e1 := syscall_syscall6(funcPC(libc_kevent_trampoline), uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))) + r0, _, e1 := syscall_syscall6(libc_kevent_trampoline_addr, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -281,7 +281,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne return } -func libc_kevent_trampoline() +var libc_kevent_trampoline_addr uintptr //go:cgo_import_dynamic libc_kevent kevent "/usr/lib/libSystem.B.dylib" @@ -293,35 +293,35 @@ func utimes(path string, timeval *[2]Timeval) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_utimes_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + _, _, e1 := syscall_syscall(libc_utimes_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_utimes_trampoline() +var libc_utimes_trampoline_addr uintptr //go:cgo_import_dynamic libc_utimes utimes "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func futimes(fd int, timeval *[2]Timeval) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_futimes_trampoline), uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0) + _, _, e1 := syscall_syscall(libc_futimes_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_futimes_trampoline() +var libc_futimes_trampoline_addr uintptr //go:cgo_import_dynamic libc_futimes futimes "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_poll_trampoline), uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) + r0, _, e1 := syscall_syscall(libc_poll_trampoline_addr, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -329,7 +329,7 @@ func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { return } -func libc_poll_trampoline() +var libc_poll_trampoline_addr uintptr //go:cgo_import_dynamic libc_poll poll "/usr/lib/libSystem.B.dylib" @@ -342,14 +342,14 @@ func Madvise(b []byte, behav int) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := syscall_syscall(funcPC(libc_madvise_trampoline), uintptr(_p0), uintptr(len(b)), uintptr(behav)) + _, _, e1 := syscall_syscall(libc_madvise_trampoline_addr, uintptr(_p0), uintptr(len(b)), uintptr(behav)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_madvise_trampoline() +var libc_madvise_trampoline_addr uintptr //go:cgo_import_dynamic libc_madvise madvise "/usr/lib/libSystem.B.dylib" @@ -362,28 +362,28 @@ func Mlock(b []byte) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := syscall_syscall(funcPC(libc_mlock_trampoline), uintptr(_p0), uintptr(len(b)), 0) + _, _, e1 := syscall_syscall(libc_mlock_trampoline_addr, uintptr(_p0), uintptr(len(b)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_mlock_trampoline() +var libc_mlock_trampoline_addr uintptr //go:cgo_import_dynamic libc_mlock mlock "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mlockall(flags int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_mlockall_trampoline), uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall(libc_mlockall_trampoline_addr, uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_mlockall_trampoline() +var libc_mlockall_trampoline_addr uintptr //go:cgo_import_dynamic libc_mlockall mlockall "/usr/lib/libSystem.B.dylib" @@ -396,14 +396,14 @@ func Mprotect(b []byte, prot int) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := syscall_syscall(funcPC(libc_mprotect_trampoline), uintptr(_p0), uintptr(len(b)), uintptr(prot)) + _, _, e1 := syscall_syscall(libc_mprotect_trampoline_addr, uintptr(_p0), uintptr(len(b)), uintptr(prot)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_mprotect_trampoline() +var libc_mprotect_trampoline_addr uintptr //go:cgo_import_dynamic libc_mprotect mprotect "/usr/lib/libSystem.B.dylib" @@ -416,14 +416,14 @@ func Msync(b []byte, flags int) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := syscall_syscall(funcPC(libc_msync_trampoline), uintptr(_p0), uintptr(len(b)), uintptr(flags)) + _, _, e1 := syscall_syscall(libc_msync_trampoline_addr, uintptr(_p0), uintptr(len(b)), uintptr(flags)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_msync_trampoline() +var libc_msync_trampoline_addr uintptr //go:cgo_import_dynamic libc_msync msync "/usr/lib/libSystem.B.dylib" @@ -436,42 +436,42 @@ func Munlock(b []byte) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := syscall_syscall(funcPC(libc_munlock_trampoline), uintptr(_p0), uintptr(len(b)), 0) + _, _, e1 := syscall_syscall(libc_munlock_trampoline_addr, uintptr(_p0), uintptr(len(b)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_munlock_trampoline() +var libc_munlock_trampoline_addr uintptr //go:cgo_import_dynamic libc_munlock munlock "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Munlockall() (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_munlockall_trampoline), 0, 0, 0) + _, _, e1 := syscall_syscall(libc_munlockall_trampoline_addr, 0, 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_munlockall_trampoline() +var libc_munlockall_trampoline_addr uintptr //go:cgo_import_dynamic libc_munlockall munlockall "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func pipe(p *[2]int32) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_pipe_trampoline), uintptr(unsafe.Pointer(p)), 0, 0) + _, _, e1 := syscall_rawSyscall(libc_pipe_trampoline_addr, uintptr(unsafe.Pointer(p)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_pipe_trampoline() +var libc_pipe_trampoline_addr uintptr //go:cgo_import_dynamic libc_pipe pipe "/usr/lib/libSystem.B.dylib" @@ -488,7 +488,7 @@ func getxattr(path string, attr string, dest *byte, size int, position uint32, o if err != nil { return } - r0, _, e1 := syscall_syscall6(funcPC(libc_getxattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) + r0, _, e1 := syscall_syscall6(libc_getxattr_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) sz = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -496,7 +496,7 @@ func getxattr(path string, attr string, dest *byte, size int, position uint32, o return } -func libc_getxattr_trampoline() +var libc_getxattr_trampoline_addr uintptr //go:cgo_import_dynamic libc_getxattr getxattr "/usr/lib/libSystem.B.dylib" @@ -508,7 +508,7 @@ func fgetxattr(fd int, attr string, dest *byte, size int, position uint32, optio if err != nil { return } - r0, _, e1 := syscall_syscall6(funcPC(libc_fgetxattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) + r0, _, e1 := syscall_syscall6(libc_fgetxattr_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) sz = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -516,7 +516,7 @@ func fgetxattr(fd int, attr string, dest *byte, size int, position uint32, optio return } -func libc_fgetxattr_trampoline() +var libc_fgetxattr_trampoline_addr uintptr //go:cgo_import_dynamic libc_fgetxattr fgetxattr "/usr/lib/libSystem.B.dylib" @@ -533,14 +533,14 @@ func setxattr(path string, attr string, data *byte, size int, position uint32, o if err != nil { return } - _, _, e1 := syscall_syscall6(funcPC(libc_setxattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) + _, _, e1 := syscall_syscall6(libc_setxattr_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setxattr_trampoline() +var libc_setxattr_trampoline_addr uintptr //go:cgo_import_dynamic libc_setxattr setxattr "/usr/lib/libSystem.B.dylib" @@ -552,14 +552,14 @@ func fsetxattr(fd int, attr string, data *byte, size int, position uint32, optio if err != nil { return } - _, _, e1 := syscall_syscall6(funcPC(libc_fsetxattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) + _, _, e1 := syscall_syscall6(libc_fsetxattr_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fsetxattr_trampoline() +var libc_fsetxattr_trampoline_addr uintptr //go:cgo_import_dynamic libc_fsetxattr fsetxattr "/usr/lib/libSystem.B.dylib" @@ -576,14 +576,14 @@ func removexattr(path string, attr string, options int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_removexattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) + _, _, e1 := syscall_syscall(libc_removexattr_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_removexattr_trampoline() +var libc_removexattr_trampoline_addr uintptr //go:cgo_import_dynamic libc_removexattr removexattr "/usr/lib/libSystem.B.dylib" @@ -595,14 +595,14 @@ func fremovexattr(fd int, attr string, options int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_fremovexattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(options)) + _, _, e1 := syscall_syscall(libc_fremovexattr_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(options)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fremovexattr_trampoline() +var libc_fremovexattr_trampoline_addr uintptr //go:cgo_import_dynamic libc_fremovexattr fremovexattr "/usr/lib/libSystem.B.dylib" @@ -614,7 +614,7 @@ func listxattr(path string, dest *byte, size int, options int) (sz int, err erro if err != nil { return } - r0, _, e1 := syscall_syscall6(funcPC(libc_listxattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) + r0, _, e1 := syscall_syscall6(libc_listxattr_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) sz = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -622,14 +622,14 @@ func listxattr(path string, dest *byte, size int, options int) (sz int, err erro return } -func libc_listxattr_trampoline() +var libc_listxattr_trampoline_addr uintptr //go:cgo_import_dynamic libc_listxattr listxattr "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func flistxattr(fd int, dest *byte, size int, options int) (sz int, err error) { - r0, _, e1 := syscall_syscall6(funcPC(libc_flistxattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) + r0, _, e1 := syscall_syscall6(libc_flistxattr_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) sz = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -637,28 +637,28 @@ func flistxattr(fd int, dest *byte, size int, options int) (sz int, err error) { return } -func libc_flistxattr_trampoline() +var libc_flistxattr_trampoline_addr uintptr //go:cgo_import_dynamic libc_flistxattr flistxattr "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func setattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) { - _, _, e1 := syscall_syscall6(funcPC(libc_setattrlist_trampoline), uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) + _, _, e1 := syscall_syscall6(libc_setattrlist_trampoline_addr, uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setattrlist_trampoline() +var libc_setattrlist_trampoline_addr uintptr //go:cgo_import_dynamic libc_setattrlist setattrlist "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func fcntl(fd int, cmd int, arg int) (val int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_fcntl_trampoline), uintptr(fd), uintptr(cmd), uintptr(arg)) + r0, _, e1 := syscall_syscall(libc_fcntl_trampoline_addr, uintptr(fd), uintptr(cmd), uintptr(arg)) val = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -666,35 +666,35 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) { return } -func libc_fcntl_trampoline() +var libc_fcntl_trampoline_addr uintptr //go:cgo_import_dynamic libc_fcntl fcntl "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func kill(pid int, signum int, posix int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_kill_trampoline), uintptr(pid), uintptr(signum), uintptr(posix)) + _, _, e1 := syscall_syscall(libc_kill_trampoline_addr, uintptr(pid), uintptr(signum), uintptr(posix)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_kill_trampoline() +var libc_kill_trampoline_addr uintptr //go:cgo_import_dynamic libc_kill kill "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func ioctl(fd int, req uint, arg uintptr) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_ioctl_trampoline), uintptr(fd), uintptr(req), uintptr(arg)) + _, _, e1 := syscall_syscall(libc_ioctl_trampoline_addr, uintptr(fd), uintptr(req), uintptr(arg)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_ioctl_trampoline() +var libc_ioctl_trampoline_addr uintptr //go:cgo_import_dynamic libc_ioctl ioctl "/usr/lib/libSystem.B.dylib" @@ -707,28 +707,28 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := syscall_syscall6(funcPC(libc_sysctl_trampoline), uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + _, _, e1 := syscall_syscall6(libc_sysctl_trampoline_addr, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_sysctl_trampoline() +var libc_sysctl_trampoline_addr uintptr //go:cgo_import_dynamic libc_sysctl sysctl "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) { - _, _, e1 := syscall_syscall6(funcPC(libc_sendfile_trampoline), uintptr(infd), uintptr(outfd), uintptr(offset), uintptr(unsafe.Pointer(len)), uintptr(hdtr), uintptr(flags)) + _, _, e1 := syscall_syscall6(libc_sendfile_trampoline_addr, uintptr(infd), uintptr(outfd), uintptr(offset), uintptr(unsafe.Pointer(len)), uintptr(hdtr), uintptr(flags)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_sendfile_trampoline() +var libc_sendfile_trampoline_addr uintptr //go:cgo_import_dynamic libc_sendfile sendfile "/usr/lib/libSystem.B.dylib" @@ -740,28 +740,28 @@ func Access(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_access_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(libc_access_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_access_trampoline() +var libc_access_trampoline_addr uintptr //go:cgo_import_dynamic libc_access access "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Adjtime(delta *Timeval, olddelta *Timeval) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_adjtime_trampoline), uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0) + _, _, e1 := syscall_syscall(libc_adjtime_trampoline_addr, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_adjtime_trampoline() +var libc_adjtime_trampoline_addr uintptr //go:cgo_import_dynamic libc_adjtime adjtime "/usr/lib/libSystem.B.dylib" @@ -773,14 +773,14 @@ func Chdir(path string) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_chdir_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(libc_chdir_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_chdir_trampoline() +var libc_chdir_trampoline_addr uintptr //go:cgo_import_dynamic libc_chdir chdir "/usr/lib/libSystem.B.dylib" @@ -792,14 +792,14 @@ func Chflags(path string, flags int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_chflags_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + _, _, e1 := syscall_syscall(libc_chflags_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_chflags_trampoline() +var libc_chflags_trampoline_addr uintptr //go:cgo_import_dynamic libc_chflags chflags "/usr/lib/libSystem.B.dylib" @@ -811,14 +811,14 @@ func Chmod(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_chmod_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(libc_chmod_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_chmod_trampoline() +var libc_chmod_trampoline_addr uintptr //go:cgo_import_dynamic libc_chmod chmod "/usr/lib/libSystem.B.dylib" @@ -830,14 +830,14 @@ func Chown(path string, uid int, gid int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_chown_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + _, _, e1 := syscall_syscall(libc_chown_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_chown_trampoline() +var libc_chown_trampoline_addr uintptr //go:cgo_import_dynamic libc_chown chown "/usr/lib/libSystem.B.dylib" @@ -849,42 +849,42 @@ func Chroot(path string) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_chroot_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(libc_chroot_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_chroot_trampoline() +var libc_chroot_trampoline_addr uintptr //go:cgo_import_dynamic libc_chroot chroot "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func ClockGettime(clockid int32, time *Timespec) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_clock_gettime_trampoline), uintptr(clockid), uintptr(unsafe.Pointer(time)), 0) + _, _, e1 := syscall_syscall(libc_clock_gettime_trampoline_addr, uintptr(clockid), uintptr(unsafe.Pointer(time)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_clock_gettime_trampoline() +var libc_clock_gettime_trampoline_addr uintptr //go:cgo_import_dynamic libc_clock_gettime clock_gettime "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Close(fd int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_close_trampoline), uintptr(fd), 0, 0) + _, _, e1 := syscall_syscall(libc_close_trampoline_addr, uintptr(fd), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_close_trampoline() +var libc_close_trampoline_addr uintptr //go:cgo_import_dynamic libc_close close "/usr/lib/libSystem.B.dylib" @@ -901,14 +901,14 @@ func Clonefile(src string, dst string, flags int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_clonefile_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flags)) + _, _, e1 := syscall_syscall(libc_clonefile_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flags)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_clonefile_trampoline() +var libc_clonefile_trampoline_addr uintptr //go:cgo_import_dynamic libc_clonefile clonefile "/usr/lib/libSystem.B.dylib" @@ -925,21 +925,21 @@ func Clonefileat(srcDirfd int, src string, dstDirfd int, dst string, flags int) if err != nil { return } - _, _, e1 := syscall_syscall6(funcPC(libc_clonefileat_trampoline), uintptr(srcDirfd), uintptr(unsafe.Pointer(_p0)), uintptr(dstDirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + _, _, e1 := syscall_syscall6(libc_clonefileat_trampoline_addr, uintptr(srcDirfd), uintptr(unsafe.Pointer(_p0)), uintptr(dstDirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_clonefileat_trampoline() +var libc_clonefileat_trampoline_addr uintptr //go:cgo_import_dynamic libc_clonefileat clonefileat "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Dup(fd int) (nfd int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_dup_trampoline), uintptr(fd), 0, 0) + r0, _, e1 := syscall_syscall(libc_dup_trampoline_addr, uintptr(fd), 0, 0) nfd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -947,21 +947,21 @@ func Dup(fd int) (nfd int, err error) { return } -func libc_dup_trampoline() +var libc_dup_trampoline_addr uintptr //go:cgo_import_dynamic libc_dup dup "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Dup2(from int, to int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_dup2_trampoline), uintptr(from), uintptr(to), 0) + _, _, e1 := syscall_syscall(libc_dup2_trampoline_addr, uintptr(from), uintptr(to), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_dup2_trampoline() +var libc_dup2_trampoline_addr uintptr //go:cgo_import_dynamic libc_dup2 dup2 "/usr/lib/libSystem.B.dylib" @@ -978,25 +978,25 @@ func Exchangedata(path1 string, path2 string, options int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_exchangedata_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) + _, _, e1 := syscall_syscall(libc_exchangedata_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_exchangedata_trampoline() +var libc_exchangedata_trampoline_addr uintptr //go:cgo_import_dynamic libc_exchangedata exchangedata "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Exit(code int) { - syscall_syscall(funcPC(libc_exit_trampoline), uintptr(code), 0, 0) + syscall_syscall(libc_exit_trampoline_addr, uintptr(code), 0, 0) return } -func libc_exit_trampoline() +var libc_exit_trampoline_addr uintptr //go:cgo_import_dynamic libc_exit exit "/usr/lib/libSystem.B.dylib" @@ -1008,56 +1008,56 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall6(funcPC(libc_faccessat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall6(libc_faccessat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_faccessat_trampoline() +var libc_faccessat_trampoline_addr uintptr //go:cgo_import_dynamic libc_faccessat faccessat "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchdir(fd int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fchdir_trampoline), uintptr(fd), 0, 0) + _, _, e1 := syscall_syscall(libc_fchdir_trampoline_addr, uintptr(fd), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fchdir_trampoline() +var libc_fchdir_trampoline_addr uintptr //go:cgo_import_dynamic libc_fchdir fchdir "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchflags(fd int, flags int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fchflags_trampoline), uintptr(fd), uintptr(flags), 0) + _, _, e1 := syscall_syscall(libc_fchflags_trampoline_addr, uintptr(fd), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fchflags_trampoline() +var libc_fchflags_trampoline_addr uintptr //go:cgo_import_dynamic libc_fchflags fchflags "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchmod(fd int, mode uint32) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fchmod_trampoline), uintptr(fd), uintptr(mode), 0) + _, _, e1 := syscall_syscall(libc_fchmod_trampoline_addr, uintptr(fd), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fchmod_trampoline() +var libc_fchmod_trampoline_addr uintptr //go:cgo_import_dynamic libc_fchmod fchmod "/usr/lib/libSystem.B.dylib" @@ -1069,28 +1069,28 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall6(funcPC(libc_fchmodat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall6(libc_fchmodat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fchmodat_trampoline() +var libc_fchmodat_trampoline_addr uintptr //go:cgo_import_dynamic libc_fchmodat fchmodat "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchown(fd int, uid int, gid int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fchown_trampoline), uintptr(fd), uintptr(uid), uintptr(gid)) + _, _, e1 := syscall_syscall(libc_fchown_trampoline_addr, uintptr(fd), uintptr(uid), uintptr(gid)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fchown_trampoline() +var libc_fchown_trampoline_addr uintptr //go:cgo_import_dynamic libc_fchown fchown "/usr/lib/libSystem.B.dylib" @@ -1102,14 +1102,14 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall6(funcPC(libc_fchownat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + _, _, e1 := syscall_syscall6(libc_fchownat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fchownat_trampoline() +var libc_fchownat_trampoline_addr uintptr //go:cgo_import_dynamic libc_fchownat fchownat "/usr/lib/libSystem.B.dylib" @@ -1121,35 +1121,35 @@ func Fclonefileat(srcDirfd int, dstDirfd int, dst string, flags int) (err error) if err != nil { return } - _, _, e1 := syscall_syscall6(funcPC(libc_fclonefileat_trampoline), uintptr(srcDirfd), uintptr(dstDirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall6(libc_fclonefileat_trampoline_addr, uintptr(srcDirfd), uintptr(dstDirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fclonefileat_trampoline() +var libc_fclonefileat_trampoline_addr uintptr //go:cgo_import_dynamic libc_fclonefileat fclonefileat "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Flock(fd int, how int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_flock_trampoline), uintptr(fd), uintptr(how), 0) + _, _, e1 := syscall_syscall(libc_flock_trampoline_addr, uintptr(fd), uintptr(how), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_flock_trampoline() +var libc_flock_trampoline_addr uintptr //go:cgo_import_dynamic libc_flock flock "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fpathconf(fd int, name int) (val int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_fpathconf_trampoline), uintptr(fd), uintptr(name), 0) + r0, _, e1 := syscall_syscall(libc_fpathconf_trampoline_addr, uintptr(fd), uintptr(name), 0) val = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1157,35 +1157,35 @@ func Fpathconf(fd int, name int) (val int, err error) { return } -func libc_fpathconf_trampoline() +var libc_fpathconf_trampoline_addr uintptr //go:cgo_import_dynamic libc_fpathconf fpathconf "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fsync(fd int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fsync_trampoline), uintptr(fd), 0, 0) + _, _, e1 := syscall_syscall(libc_fsync_trampoline_addr, uintptr(fd), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fsync_trampoline() +var libc_fsync_trampoline_addr uintptr //go:cgo_import_dynamic libc_fsync fsync "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Ftruncate(fd int, length int64) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_ftruncate_trampoline), uintptr(fd), uintptr(length), 0) + _, _, e1 := syscall_syscall(libc_ftruncate_trampoline_addr, uintptr(fd), uintptr(length), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_ftruncate_trampoline() +var libc_ftruncate_trampoline_addr uintptr //go:cgo_import_dynamic libc_ftruncate ftruncate "/usr/lib/libSystem.B.dylib" @@ -1198,7 +1198,7 @@ func Getcwd(buf []byte) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := syscall_syscall(funcPC(libc_getcwd_trampoline), uintptr(_p0), uintptr(len(buf)), 0) + r0, _, e1 := syscall_syscall(libc_getcwd_trampoline_addr, uintptr(_p0), uintptr(len(buf)), 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1206,62 +1206,62 @@ func Getcwd(buf []byte) (n int, err error) { return } -func libc_getcwd_trampoline() +var libc_getcwd_trampoline_addr uintptr //go:cgo_import_dynamic libc_getcwd getcwd "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getdtablesize() (size int) { - r0, _, _ := syscall_syscall(funcPC(libc_getdtablesize_trampoline), 0, 0, 0) + r0, _, _ := syscall_syscall(libc_getdtablesize_trampoline_addr, 0, 0, 0) size = int(r0) return } -func libc_getdtablesize_trampoline() +var libc_getdtablesize_trampoline_addr uintptr //go:cgo_import_dynamic libc_getdtablesize getdtablesize "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getegid() (egid int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_getegid_trampoline), 0, 0, 0) + r0, _, _ := syscall_rawSyscall(libc_getegid_trampoline_addr, 0, 0, 0) egid = int(r0) return } -func libc_getegid_trampoline() +var libc_getegid_trampoline_addr uintptr //go:cgo_import_dynamic libc_getegid getegid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (uid int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_geteuid_trampoline), 0, 0, 0) + r0, _, _ := syscall_rawSyscall(libc_geteuid_trampoline_addr, 0, 0, 0) uid = int(r0) return } -func libc_geteuid_trampoline() +var libc_geteuid_trampoline_addr uintptr //go:cgo_import_dynamic libc_geteuid geteuid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_getgid_trampoline), 0, 0, 0) + r0, _, _ := syscall_rawSyscall(libc_getgid_trampoline_addr, 0, 0, 0) gid = int(r0) return } -func libc_getgid_trampoline() +var libc_getgid_trampoline_addr uintptr //go:cgo_import_dynamic libc_getgid getgid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpgid(pid int) (pgid int, err error) { - r0, _, e1 := syscall_rawSyscall(funcPC(libc_getpgid_trampoline), uintptr(pid), 0, 0) + r0, _, e1 := syscall_rawSyscall(libc_getpgid_trampoline_addr, uintptr(pid), 0, 0) pgid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1269,50 +1269,50 @@ func Getpgid(pid int) (pgid int, err error) { return } -func libc_getpgid_trampoline() +var libc_getpgid_trampoline_addr uintptr //go:cgo_import_dynamic libc_getpgid getpgid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpgrp() (pgrp int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_getpgrp_trampoline), 0, 0, 0) + r0, _, _ := syscall_rawSyscall(libc_getpgrp_trampoline_addr, 0, 0, 0) pgrp = int(r0) return } -func libc_getpgrp_trampoline() +var libc_getpgrp_trampoline_addr uintptr //go:cgo_import_dynamic libc_getpgrp getpgrp "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_getpid_trampoline), 0, 0, 0) + r0, _, _ := syscall_rawSyscall(libc_getpid_trampoline_addr, 0, 0, 0) pid = int(r0) return } -func libc_getpid_trampoline() +var libc_getpid_trampoline_addr uintptr //go:cgo_import_dynamic libc_getpid getpid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_getppid_trampoline), 0, 0, 0) + r0, _, _ := syscall_rawSyscall(libc_getppid_trampoline_addr, 0, 0, 0) ppid = int(r0) return } -func libc_getppid_trampoline() +var libc_getppid_trampoline_addr uintptr //go:cgo_import_dynamic libc_getppid getppid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpriority(which int, who int) (prio int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_getpriority_trampoline), uintptr(which), uintptr(who), 0) + r0, _, e1 := syscall_syscall(libc_getpriority_trampoline_addr, uintptr(which), uintptr(who), 0) prio = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1320,42 +1320,42 @@ func Getpriority(which int, who int) (prio int, err error) { return } -func libc_getpriority_trampoline() +var libc_getpriority_trampoline_addr uintptr //go:cgo_import_dynamic libc_getpriority getpriority "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getrlimit(which int, lim *Rlimit) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_getrlimit_trampoline), uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + _, _, e1 := syscall_rawSyscall(libc_getrlimit_trampoline_addr, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_getrlimit_trampoline() +var libc_getrlimit_trampoline_addr uintptr //go:cgo_import_dynamic libc_getrlimit getrlimit "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getrusage(who int, rusage *Rusage) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_getrusage_trampoline), uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) + _, _, e1 := syscall_rawSyscall(libc_getrusage_trampoline_addr, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_getrusage_trampoline() +var libc_getrusage_trampoline_addr uintptr //go:cgo_import_dynamic libc_getrusage getrusage "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getsid(pid int) (sid int, err error) { - r0, _, e1 := syscall_rawSyscall(funcPC(libc_getsid_trampoline), uintptr(pid), 0, 0) + r0, _, e1 := syscall_rawSyscall(libc_getsid_trampoline_addr, uintptr(pid), 0, 0) sid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1363,52 +1363,52 @@ func Getsid(pid int) (sid int, err error) { return } -func libc_getsid_trampoline() +var libc_getsid_trampoline_addr uintptr //go:cgo_import_dynamic libc_getsid getsid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Gettimeofday(tp *Timeval) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_gettimeofday_trampoline), uintptr(unsafe.Pointer(tp)), 0, 0) + _, _, e1 := syscall_rawSyscall(libc_gettimeofday_trampoline_addr, uintptr(unsafe.Pointer(tp)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_gettimeofday_trampoline() +var libc_gettimeofday_trampoline_addr uintptr //go:cgo_import_dynamic libc_gettimeofday gettimeofday "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_getuid_trampoline), 0, 0, 0) + r0, _, _ := syscall_rawSyscall(libc_getuid_trampoline_addr, 0, 0, 0) uid = int(r0) return } -func libc_getuid_trampoline() +var libc_getuid_trampoline_addr uintptr //go:cgo_import_dynamic libc_getuid getuid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Issetugid() (tainted bool) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_issetugid_trampoline), 0, 0, 0) + r0, _, _ := syscall_rawSyscall(libc_issetugid_trampoline_addr, 0, 0, 0) tainted = bool(r0 != 0) return } -func libc_issetugid_trampoline() +var libc_issetugid_trampoline_addr uintptr //go:cgo_import_dynamic libc_issetugid issetugid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Kqueue() (fd int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_kqueue_trampoline), 0, 0, 0) + r0, _, e1 := syscall_syscall(libc_kqueue_trampoline_addr, 0, 0, 0) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1416,7 +1416,7 @@ func Kqueue() (fd int, err error) { return } -func libc_kqueue_trampoline() +var libc_kqueue_trampoline_addr uintptr //go:cgo_import_dynamic libc_kqueue kqueue "/usr/lib/libSystem.B.dylib" @@ -1428,14 +1428,14 @@ func Lchown(path string, uid int, gid int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_lchown_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + _, _, e1 := syscall_syscall(libc_lchown_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_lchown_trampoline() +var libc_lchown_trampoline_addr uintptr //go:cgo_import_dynamic libc_lchown lchown "/usr/lib/libSystem.B.dylib" @@ -1452,14 +1452,14 @@ func Link(path string, link string) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_link_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + _, _, e1 := syscall_syscall(libc_link_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_link_trampoline() +var libc_link_trampoline_addr uintptr //go:cgo_import_dynamic libc_link link "/usr/lib/libSystem.B.dylib" @@ -1476,28 +1476,28 @@ func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err er if err != nil { return } - _, _, e1 := syscall_syscall6(funcPC(libc_linkat_trampoline), uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + _, _, e1 := syscall_syscall6(libc_linkat_trampoline_addr, uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_linkat_trampoline() +var libc_linkat_trampoline_addr uintptr //go:cgo_import_dynamic libc_linkat linkat "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Listen(s int, backlog int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_listen_trampoline), uintptr(s), uintptr(backlog), 0) + _, _, e1 := syscall_syscall(libc_listen_trampoline_addr, uintptr(s), uintptr(backlog), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_listen_trampoline() +var libc_listen_trampoline_addr uintptr //go:cgo_import_dynamic libc_listen listen "/usr/lib/libSystem.B.dylib" @@ -1509,14 +1509,14 @@ func Mkdir(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_mkdir_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(libc_mkdir_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_mkdir_trampoline() +var libc_mkdir_trampoline_addr uintptr //go:cgo_import_dynamic libc_mkdir mkdir "/usr/lib/libSystem.B.dylib" @@ -1528,14 +1528,14 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_mkdirat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + _, _, e1 := syscall_syscall(libc_mkdirat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_mkdirat_trampoline() +var libc_mkdirat_trampoline_addr uintptr //go:cgo_import_dynamic libc_mkdirat mkdirat "/usr/lib/libSystem.B.dylib" @@ -1547,14 +1547,14 @@ func Mkfifo(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_mkfifo_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(libc_mkfifo_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_mkfifo_trampoline() +var libc_mkfifo_trampoline_addr uintptr //go:cgo_import_dynamic libc_mkfifo mkfifo "/usr/lib/libSystem.B.dylib" @@ -1566,14 +1566,14 @@ func Mknod(path string, mode uint32, dev int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_mknod_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + _, _, e1 := syscall_syscall(libc_mknod_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_mknod_trampoline() +var libc_mknod_trampoline_addr uintptr //go:cgo_import_dynamic libc_mknod mknod "/usr/lib/libSystem.B.dylib" @@ -1585,7 +1585,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { if err != nil { return } - r0, _, e1 := syscall_syscall(funcPC(libc_open_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + r0, _, e1 := syscall_syscall(libc_open_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1593,7 +1593,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { return } -func libc_open_trampoline() +var libc_open_trampoline_addr uintptr //go:cgo_import_dynamic libc_open open "/usr/lib/libSystem.B.dylib" @@ -1605,7 +1605,7 @@ func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { if err != nil { return } - r0, _, e1 := syscall_syscall6(funcPC(libc_openat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) + r0, _, e1 := syscall_syscall6(libc_openat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1613,7 +1613,7 @@ func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { return } -func libc_openat_trampoline() +var libc_openat_trampoline_addr uintptr //go:cgo_import_dynamic libc_openat openat "/usr/lib/libSystem.B.dylib" @@ -1625,7 +1625,7 @@ func Pathconf(path string, name int) (val int, err error) { if err != nil { return } - r0, _, e1 := syscall_syscall(funcPC(libc_pathconf_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + r0, _, e1 := syscall_syscall(libc_pathconf_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) val = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1633,7 +1633,7 @@ func Pathconf(path string, name int) (val int, err error) { return } -func libc_pathconf_trampoline() +var libc_pathconf_trampoline_addr uintptr //go:cgo_import_dynamic libc_pathconf pathconf "/usr/lib/libSystem.B.dylib" @@ -1646,7 +1646,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := syscall_syscall6(funcPC(libc_pread_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0) + r0, _, e1 := syscall_syscall6(libc_pread_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1654,7 +1654,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) { return } -func libc_pread_trampoline() +var libc_pread_trampoline_addr uintptr //go:cgo_import_dynamic libc_pread pread "/usr/lib/libSystem.B.dylib" @@ -1667,7 +1667,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := syscall_syscall6(funcPC(libc_pwrite_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0) + r0, _, e1 := syscall_syscall6(libc_pwrite_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1675,7 +1675,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { return } -func libc_pwrite_trampoline() +var libc_pwrite_trampoline_addr uintptr //go:cgo_import_dynamic libc_pwrite pwrite "/usr/lib/libSystem.B.dylib" @@ -1688,7 +1688,7 @@ func read(fd int, p []byte) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := syscall_syscall(funcPC(libc_read_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p))) + r0, _, e1 := syscall_syscall(libc_read_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(p))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1696,7 +1696,7 @@ func read(fd int, p []byte) (n int, err error) { return } -func libc_read_trampoline() +var libc_read_trampoline_addr uintptr //go:cgo_import_dynamic libc_read read "/usr/lib/libSystem.B.dylib" @@ -1714,7 +1714,7 @@ func Readlink(path string, buf []byte) (n int, err error) { } else { _p1 = unsafe.Pointer(&_zero) } - r0, _, e1 := syscall_syscall(funcPC(libc_readlink_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + r0, _, e1 := syscall_syscall(libc_readlink_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1722,7 +1722,7 @@ func Readlink(path string, buf []byte) (n int, err error) { return } -func libc_readlink_trampoline() +var libc_readlink_trampoline_addr uintptr //go:cgo_import_dynamic libc_readlink readlink "/usr/lib/libSystem.B.dylib" @@ -1740,7 +1740,7 @@ func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { } else { _p1 = unsafe.Pointer(&_zero) } - r0, _, e1 := syscall_syscall6(funcPC(libc_readlinkat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) + r0, _, e1 := syscall_syscall6(libc_readlinkat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1748,7 +1748,7 @@ func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { return } -func libc_readlinkat_trampoline() +var libc_readlinkat_trampoline_addr uintptr //go:cgo_import_dynamic libc_readlinkat readlinkat "/usr/lib/libSystem.B.dylib" @@ -1765,14 +1765,14 @@ func Rename(from string, to string) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_rename_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + _, _, e1 := syscall_syscall(libc_rename_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_rename_trampoline() +var libc_rename_trampoline_addr uintptr //go:cgo_import_dynamic libc_rename rename "/usr/lib/libSystem.B.dylib" @@ -1789,14 +1789,14 @@ func Renameat(fromfd int, from string, tofd int, to string) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall6(funcPC(libc_renameat_trampoline), uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) + _, _, e1 := syscall_syscall6(libc_renameat_trampoline_addr, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_renameat_trampoline() +var libc_renameat_trampoline_addr uintptr //go:cgo_import_dynamic libc_renameat renameat "/usr/lib/libSystem.B.dylib" @@ -1808,14 +1808,14 @@ func Revoke(path string) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_revoke_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(libc_revoke_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_revoke_trampoline() +var libc_revoke_trampoline_addr uintptr //go:cgo_import_dynamic libc_revoke revoke "/usr/lib/libSystem.B.dylib" @@ -1827,21 +1827,21 @@ func Rmdir(path string) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_rmdir_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(libc_rmdir_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_rmdir_trampoline() +var libc_rmdir_trampoline_addr uintptr //go:cgo_import_dynamic libc_rmdir rmdir "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_lseek_trampoline), uintptr(fd), uintptr(offset), uintptr(whence)) + r0, _, e1 := syscall_syscall(libc_lseek_trampoline_addr, uintptr(fd), uintptr(offset), uintptr(whence)) newoffset = int64(r0) if e1 != 0 { err = errnoErr(e1) @@ -1849,14 +1849,14 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { return } -func libc_lseek_trampoline() +var libc_lseek_trampoline_addr uintptr //go:cgo_import_dynamic libc_lseek lseek "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) { - r0, _, e1 := syscall_syscall6(funcPC(libc_select_trampoline), uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) + r0, _, e1 := syscall_syscall6(libc_select_trampoline_addr, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1864,49 +1864,49 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err return } -func libc_select_trampoline() +var libc_select_trampoline_addr uintptr //go:cgo_import_dynamic libc_select select "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setegid(egid int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_setegid_trampoline), uintptr(egid), 0, 0) + _, _, e1 := syscall_syscall(libc_setegid_trampoline_addr, uintptr(egid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setegid_trampoline() +var libc_setegid_trampoline_addr uintptr //go:cgo_import_dynamic libc_setegid setegid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Seteuid(euid int) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_seteuid_trampoline), uintptr(euid), 0, 0) + _, _, e1 := syscall_rawSyscall(libc_seteuid_trampoline_addr, uintptr(euid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_seteuid_trampoline() +var libc_seteuid_trampoline_addr uintptr //go:cgo_import_dynamic libc_seteuid seteuid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setgid(gid int) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setgid_trampoline), uintptr(gid), 0, 0) + _, _, e1 := syscall_rawSyscall(libc_setgid_trampoline_addr, uintptr(gid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setgid_trampoline() +var libc_setgid_trampoline_addr uintptr //go:cgo_import_dynamic libc_setgid setgid "/usr/lib/libSystem.B.dylib" @@ -1918,105 +1918,105 @@ func Setlogin(name string) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_setlogin_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(libc_setlogin_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setlogin_trampoline() +var libc_setlogin_trampoline_addr uintptr //go:cgo_import_dynamic libc_setlogin setlogin "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setpgid(pid int, pgid int) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setpgid_trampoline), uintptr(pid), uintptr(pgid), 0) + _, _, e1 := syscall_rawSyscall(libc_setpgid_trampoline_addr, uintptr(pid), uintptr(pgid), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setpgid_trampoline() +var libc_setpgid_trampoline_addr uintptr //go:cgo_import_dynamic libc_setpgid setpgid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setpriority(which int, who int, prio int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_setpriority_trampoline), uintptr(which), uintptr(who), uintptr(prio)) + _, _, e1 := syscall_syscall(libc_setpriority_trampoline_addr, uintptr(which), uintptr(who), uintptr(prio)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setpriority_trampoline() +var libc_setpriority_trampoline_addr uintptr //go:cgo_import_dynamic libc_setpriority setpriority "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setprivexec(flag int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_setprivexec_trampoline), uintptr(flag), 0, 0) + _, _, e1 := syscall_syscall(libc_setprivexec_trampoline_addr, uintptr(flag), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setprivexec_trampoline() +var libc_setprivexec_trampoline_addr uintptr //go:cgo_import_dynamic libc_setprivexec setprivexec "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setregid(rgid int, egid int) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setregid_trampoline), uintptr(rgid), uintptr(egid), 0) + _, _, e1 := syscall_rawSyscall(libc_setregid_trampoline_addr, uintptr(rgid), uintptr(egid), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setregid_trampoline() +var libc_setregid_trampoline_addr uintptr //go:cgo_import_dynamic libc_setregid setregid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setreuid(ruid int, euid int) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setreuid_trampoline), uintptr(ruid), uintptr(euid), 0) + _, _, e1 := syscall_rawSyscall(libc_setreuid_trampoline_addr, uintptr(ruid), uintptr(euid), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setreuid_trampoline() +var libc_setreuid_trampoline_addr uintptr //go:cgo_import_dynamic libc_setreuid setreuid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setrlimit(which int, lim *Rlimit) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setrlimit_trampoline), uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + _, _, e1 := syscall_rawSyscall(libc_setrlimit_trampoline_addr, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setrlimit_trampoline() +var libc_setrlimit_trampoline_addr uintptr //go:cgo_import_dynamic libc_setrlimit setrlimit "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setsid() (pid int, err error) { - r0, _, e1 := syscall_rawSyscall(funcPC(libc_setsid_trampoline), 0, 0, 0) + r0, _, e1 := syscall_rawSyscall(libc_setsid_trampoline_addr, 0, 0, 0) pid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -2024,35 +2024,35 @@ func Setsid() (pid int, err error) { return } -func libc_setsid_trampoline() +var libc_setsid_trampoline_addr uintptr //go:cgo_import_dynamic libc_setsid setsid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Settimeofday(tp *Timeval) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_settimeofday_trampoline), uintptr(unsafe.Pointer(tp)), 0, 0) + _, _, e1 := syscall_rawSyscall(libc_settimeofday_trampoline_addr, uintptr(unsafe.Pointer(tp)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_settimeofday_trampoline() +var libc_settimeofday_trampoline_addr uintptr //go:cgo_import_dynamic libc_settimeofday settimeofday "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setuid(uid int) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setuid_trampoline), uintptr(uid), 0, 0) + _, _, e1 := syscall_rawSyscall(libc_setuid_trampoline_addr, uintptr(uid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setuid_trampoline() +var libc_setuid_trampoline_addr uintptr //go:cgo_import_dynamic libc_setuid setuid "/usr/lib/libSystem.B.dylib" @@ -2069,14 +2069,14 @@ func Symlink(path string, link string) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_symlink_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + _, _, e1 := syscall_syscall(libc_symlink_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_symlink_trampoline() +var libc_symlink_trampoline_addr uintptr //go:cgo_import_dynamic libc_symlink symlink "/usr/lib/libSystem.B.dylib" @@ -2093,28 +2093,28 @@ func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_symlinkat_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) + _, _, e1 := syscall_syscall(libc_symlinkat_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) if e1 != 0 { err = errnoErr(e1) } return } -func libc_symlinkat_trampoline() +var libc_symlinkat_trampoline_addr uintptr //go:cgo_import_dynamic libc_symlinkat symlinkat "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Sync() (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_sync_trampoline), 0, 0, 0) + _, _, e1 := syscall_syscall(libc_sync_trampoline_addr, 0, 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_sync_trampoline() +var libc_sync_trampoline_addr uintptr //go:cgo_import_dynamic libc_sync sync "/usr/lib/libSystem.B.dylib" @@ -2126,26 +2126,26 @@ func Truncate(path string, length int64) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_truncate_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(length), 0) + _, _, e1 := syscall_syscall(libc_truncate_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_truncate_trampoline() +var libc_truncate_trampoline_addr uintptr //go:cgo_import_dynamic libc_truncate truncate "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(newmask int) (oldmask int) { - r0, _, _ := syscall_syscall(funcPC(libc_umask_trampoline), uintptr(newmask), 0, 0) + r0, _, _ := syscall_syscall(libc_umask_trampoline_addr, uintptr(newmask), 0, 0) oldmask = int(r0) return } -func libc_umask_trampoline() +var libc_umask_trampoline_addr uintptr //go:cgo_import_dynamic libc_umask umask "/usr/lib/libSystem.B.dylib" @@ -2157,14 +2157,14 @@ func Undelete(path string) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_undelete_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(libc_undelete_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_undelete_trampoline() +var libc_undelete_trampoline_addr uintptr //go:cgo_import_dynamic libc_undelete undelete "/usr/lib/libSystem.B.dylib" @@ -2176,14 +2176,14 @@ func Unlink(path string) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_unlink_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(libc_unlink_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_unlink_trampoline() +var libc_unlink_trampoline_addr uintptr //go:cgo_import_dynamic libc_unlink unlink "/usr/lib/libSystem.B.dylib" @@ -2195,14 +2195,14 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_unlinkat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + _, _, e1 := syscall_syscall(libc_unlinkat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_unlinkat_trampoline() +var libc_unlinkat_trampoline_addr uintptr //go:cgo_import_dynamic libc_unlinkat unlinkat "/usr/lib/libSystem.B.dylib" @@ -2214,14 +2214,14 @@ func Unmount(path string, flags int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_unmount_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + _, _, e1 := syscall_syscall(libc_unmount_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_unmount_trampoline() +var libc_unmount_trampoline_addr uintptr //go:cgo_import_dynamic libc_unmount unmount "/usr/lib/libSystem.B.dylib" @@ -2234,7 +2234,7 @@ func write(fd int, p []byte) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := syscall_syscall(funcPC(libc_write_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p))) + r0, _, e1 := syscall_syscall(libc_write_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(p))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -2242,14 +2242,14 @@ func write(fd int, p []byte) (n int, err error) { return } -func libc_write_trampoline() +var libc_write_trampoline_addr uintptr //go:cgo_import_dynamic libc_write write "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) { - r0, _, e1 := syscall_syscall6(funcPC(libc_mmap_trampoline), uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos)) + r0, _, e1 := syscall_syscall6(libc_mmap_trampoline_addr, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos)) ret = uintptr(r0) if e1 != 0 { err = errnoErr(e1) @@ -2257,28 +2257,28 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) ( return } -func libc_mmap_trampoline() +var libc_mmap_trampoline_addr uintptr //go:cgo_import_dynamic libc_mmap mmap "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func munmap(addr uintptr, length uintptr) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_munmap_trampoline), uintptr(addr), uintptr(length), 0) + _, _, e1 := syscall_syscall(libc_munmap_trampoline_addr, uintptr(addr), uintptr(length), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_munmap_trampoline() +var libc_munmap_trampoline_addr uintptr //go:cgo_import_dynamic libc_munmap munmap "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func readlen(fd int, buf *byte, nbuf int) (n int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_read_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + r0, _, e1 := syscall_syscall(libc_read_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -2289,7 +2289,7 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func writelen(fd int, buf *byte, nbuf int) (n int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_write_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + r0, _, e1 := syscall_syscall(libc_write_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -2300,14 +2300,14 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fstat(fd int, stat *Stat_t) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fstat64_trampoline), uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + _, _, e1 := syscall_syscall(libc_fstat64_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fstat64_trampoline() +var libc_fstat64_trampoline_addr uintptr //go:cgo_import_dynamic libc_fstat64 fstat64 "/usr/lib/libSystem.B.dylib" @@ -2319,35 +2319,35 @@ func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall6(funcPC(libc_fstatat64_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall6(libc_fstatat64_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fstatat64_trampoline() +var libc_fstatat64_trampoline_addr uintptr //go:cgo_import_dynamic libc_fstatat64 fstatat64 "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fstatfs(fd int, stat *Statfs_t) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fstatfs64_trampoline), uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + _, _, e1 := syscall_syscall(libc_fstatfs64_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fstatfs64_trampoline() +var libc_fstatfs64_trampoline_addr uintptr //go:cgo_import_dynamic libc_fstatfs64 fstatfs64 "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_getfsstat64_trampoline), uintptr(buf), uintptr(size), uintptr(flags)) + r0, _, e1 := syscall_syscall(libc_getfsstat64_trampoline_addr, uintptr(buf), uintptr(size), uintptr(flags)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -2355,7 +2355,7 @@ func getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) { return } -func libc_getfsstat64_trampoline() +var libc_getfsstat64_trampoline_addr uintptr //go:cgo_import_dynamic libc_getfsstat64 getfsstat64 "/usr/lib/libSystem.B.dylib" @@ -2367,28 +2367,28 @@ func Lstat(path string, stat *Stat_t) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_lstat64_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + _, _, e1 := syscall_syscall(libc_lstat64_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_lstat64_trampoline() +var libc_lstat64_trampoline_addr uintptr //go:cgo_import_dynamic libc_lstat64 lstat64 "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func ptrace1(request int, pid int, addr uintptr, data uintptr) (err error) { - _, _, e1 := syscall_syscall6(funcPC(libc_ptrace_trampoline), uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) + _, _, e1 := syscall_syscall6(libc_ptrace_trampoline_addr, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_ptrace_trampoline() +var libc_ptrace_trampoline_addr uintptr //go:cgo_import_dynamic libc_ptrace ptrace "/usr/lib/libSystem.B.dylib" @@ -2400,14 +2400,14 @@ func Stat(path string, stat *Stat_t) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_stat64_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + _, _, e1 := syscall_syscall(libc_stat64_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_stat64_trampoline() +var libc_stat64_trampoline_addr uintptr //go:cgo_import_dynamic libc_stat64 stat64 "/usr/lib/libSystem.B.dylib" @@ -2419,13 +2419,13 @@ func Statfs(path string, stat *Statfs_t) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_statfs64_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + _, _, e1 := syscall_syscall(libc_statfs64_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_statfs64_trampoline() +var libc_statfs64_trampoline_addr uintptr //go:cgo_import_dynamic libc_statfs64 statfs64 "/usr/lib/libSystem.B.dylib" diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s index b8f316e676d..bc169c2ab9c 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s @@ -5,287 +5,855 @@ // +build go1.12 #include "textflag.h" -TEXT ·libc_getgroups_trampoline(SB),NOSPLIT,$0-0 + +TEXT libc_getgroups_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getgroups(SB) -TEXT ·libc_setgroups_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getgroups_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getgroups_trampoline_addr(SB)/8, $libc_getgroups_trampoline<>(SB) + +TEXT libc_setgroups_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setgroups(SB) -TEXT ·libc_wait4_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setgroups_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setgroups_trampoline_addr(SB)/8, $libc_setgroups_trampoline<>(SB) + +TEXT libc_wait4_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_wait4(SB) -TEXT ·libc_accept_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_wait4_trampoline_addr(SB), RODATA, $8 +DATA ·libc_wait4_trampoline_addr(SB)/8, $libc_wait4_trampoline<>(SB) + +TEXT libc_accept_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_accept(SB) -TEXT ·libc_bind_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_accept_trampoline_addr(SB), RODATA, $8 +DATA ·libc_accept_trampoline_addr(SB)/8, $libc_accept_trampoline<>(SB) + +TEXT libc_bind_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_bind(SB) -TEXT ·libc_connect_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_bind_trampoline_addr(SB), RODATA, $8 +DATA ·libc_bind_trampoline_addr(SB)/8, $libc_bind_trampoline<>(SB) + +TEXT libc_connect_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_connect(SB) -TEXT ·libc_socket_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_connect_trampoline_addr(SB), RODATA, $8 +DATA ·libc_connect_trampoline_addr(SB)/8, $libc_connect_trampoline<>(SB) + +TEXT libc_socket_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_socket(SB) -TEXT ·libc_getsockopt_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_socket_trampoline_addr(SB), RODATA, $8 +DATA ·libc_socket_trampoline_addr(SB)/8, $libc_socket_trampoline<>(SB) + +TEXT libc_getsockopt_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getsockopt(SB) -TEXT ·libc_setsockopt_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getsockopt_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getsockopt_trampoline_addr(SB)/8, $libc_getsockopt_trampoline<>(SB) + +TEXT libc_setsockopt_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setsockopt(SB) -TEXT ·libc_getpeername_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setsockopt_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setsockopt_trampoline_addr(SB)/8, $libc_setsockopt_trampoline<>(SB) + +TEXT libc_getpeername_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getpeername(SB) -TEXT ·libc_getsockname_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getpeername_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getpeername_trampoline_addr(SB)/8, $libc_getpeername_trampoline<>(SB) + +TEXT libc_getsockname_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getsockname(SB) -TEXT ·libc_shutdown_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getsockname_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getsockname_trampoline_addr(SB)/8, $libc_getsockname_trampoline<>(SB) + +TEXT libc_shutdown_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_shutdown(SB) -TEXT ·libc_socketpair_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_shutdown_trampoline_addr(SB), RODATA, $8 +DATA ·libc_shutdown_trampoline_addr(SB)/8, $libc_shutdown_trampoline<>(SB) + +TEXT libc_socketpair_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_socketpair(SB) -TEXT ·libc_recvfrom_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_socketpair_trampoline_addr(SB), RODATA, $8 +DATA ·libc_socketpair_trampoline_addr(SB)/8, $libc_socketpair_trampoline<>(SB) + +TEXT libc_recvfrom_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_recvfrom(SB) -TEXT ·libc_sendto_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_recvfrom_trampoline_addr(SB), RODATA, $8 +DATA ·libc_recvfrom_trampoline_addr(SB)/8, $libc_recvfrom_trampoline<>(SB) + +TEXT libc_sendto_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_sendto(SB) -TEXT ·libc_recvmsg_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_sendto_trampoline_addr(SB), RODATA, $8 +DATA ·libc_sendto_trampoline_addr(SB)/8, $libc_sendto_trampoline<>(SB) + +TEXT libc_recvmsg_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_recvmsg(SB) -TEXT ·libc_sendmsg_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_recvmsg_trampoline_addr(SB), RODATA, $8 +DATA ·libc_recvmsg_trampoline_addr(SB)/8, $libc_recvmsg_trampoline<>(SB) + +TEXT libc_sendmsg_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_sendmsg(SB) -TEXT ·libc_kevent_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_sendmsg_trampoline_addr(SB), RODATA, $8 +DATA ·libc_sendmsg_trampoline_addr(SB)/8, $libc_sendmsg_trampoline<>(SB) + +TEXT libc_kevent_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_kevent(SB) -TEXT ·libc_utimes_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_kevent_trampoline_addr(SB), RODATA, $8 +DATA ·libc_kevent_trampoline_addr(SB)/8, $libc_kevent_trampoline<>(SB) + +TEXT libc_utimes_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_utimes(SB) -TEXT ·libc_futimes_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_utimes_trampoline_addr(SB), RODATA, $8 +DATA ·libc_utimes_trampoline_addr(SB)/8, $libc_utimes_trampoline<>(SB) + +TEXT libc_futimes_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_futimes(SB) -TEXT ·libc_poll_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_futimes_trampoline_addr(SB), RODATA, $8 +DATA ·libc_futimes_trampoline_addr(SB)/8, $libc_futimes_trampoline<>(SB) + +TEXT libc_poll_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_poll(SB) -TEXT ·libc_madvise_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_poll_trampoline_addr(SB), RODATA, $8 +DATA ·libc_poll_trampoline_addr(SB)/8, $libc_poll_trampoline<>(SB) + +TEXT libc_madvise_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_madvise(SB) -TEXT ·libc_mlock_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_madvise_trampoline_addr(SB), RODATA, $8 +DATA ·libc_madvise_trampoline_addr(SB)/8, $libc_madvise_trampoline<>(SB) + +TEXT libc_mlock_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_mlock(SB) -TEXT ·libc_mlockall_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_mlock_trampoline_addr(SB), RODATA, $8 +DATA ·libc_mlock_trampoline_addr(SB)/8, $libc_mlock_trampoline<>(SB) + +TEXT libc_mlockall_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_mlockall(SB) -TEXT ·libc_mprotect_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_mlockall_trampoline_addr(SB), RODATA, $8 +DATA ·libc_mlockall_trampoline_addr(SB)/8, $libc_mlockall_trampoline<>(SB) + +TEXT libc_mprotect_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_mprotect(SB) -TEXT ·libc_msync_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_mprotect_trampoline_addr(SB), RODATA, $8 +DATA ·libc_mprotect_trampoline_addr(SB)/8, $libc_mprotect_trampoline<>(SB) + +TEXT libc_msync_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_msync(SB) -TEXT ·libc_munlock_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_msync_trampoline_addr(SB), RODATA, $8 +DATA ·libc_msync_trampoline_addr(SB)/8, $libc_msync_trampoline<>(SB) + +TEXT libc_munlock_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_munlock(SB) -TEXT ·libc_munlockall_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_munlock_trampoline_addr(SB), RODATA, $8 +DATA ·libc_munlock_trampoline_addr(SB)/8, $libc_munlock_trampoline<>(SB) + +TEXT libc_munlockall_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_munlockall(SB) -TEXT ·libc_pipe_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_munlockall_trampoline_addr(SB), RODATA, $8 +DATA ·libc_munlockall_trampoline_addr(SB)/8, $libc_munlockall_trampoline<>(SB) + +TEXT libc_pipe_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_pipe(SB) -TEXT ·libc_getxattr_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_pipe_trampoline_addr(SB), RODATA, $8 +DATA ·libc_pipe_trampoline_addr(SB)/8, $libc_pipe_trampoline<>(SB) + +TEXT libc_getxattr_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getxattr(SB) -TEXT ·libc_fgetxattr_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getxattr_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getxattr_trampoline_addr(SB)/8, $libc_getxattr_trampoline<>(SB) + +TEXT libc_fgetxattr_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fgetxattr(SB) -TEXT ·libc_setxattr_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fgetxattr_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fgetxattr_trampoline_addr(SB)/8, $libc_fgetxattr_trampoline<>(SB) + +TEXT libc_setxattr_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setxattr(SB) -TEXT ·libc_fsetxattr_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setxattr_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setxattr_trampoline_addr(SB)/8, $libc_setxattr_trampoline<>(SB) + +TEXT libc_fsetxattr_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fsetxattr(SB) -TEXT ·libc_removexattr_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fsetxattr_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fsetxattr_trampoline_addr(SB)/8, $libc_fsetxattr_trampoline<>(SB) + +TEXT libc_removexattr_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_removexattr(SB) -TEXT ·libc_fremovexattr_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_removexattr_trampoline_addr(SB), RODATA, $8 +DATA ·libc_removexattr_trampoline_addr(SB)/8, $libc_removexattr_trampoline<>(SB) + +TEXT libc_fremovexattr_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fremovexattr(SB) -TEXT ·libc_listxattr_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fremovexattr_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fremovexattr_trampoline_addr(SB)/8, $libc_fremovexattr_trampoline<>(SB) + +TEXT libc_listxattr_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_listxattr(SB) -TEXT ·libc_flistxattr_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_listxattr_trampoline_addr(SB), RODATA, $8 +DATA ·libc_listxattr_trampoline_addr(SB)/8, $libc_listxattr_trampoline<>(SB) + +TEXT libc_flistxattr_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_flistxattr(SB) -TEXT ·libc_setattrlist_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_flistxattr_trampoline_addr(SB), RODATA, $8 +DATA ·libc_flistxattr_trampoline_addr(SB)/8, $libc_flistxattr_trampoline<>(SB) + +TEXT libc_setattrlist_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setattrlist(SB) -TEXT ·libc_fcntl_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setattrlist_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setattrlist_trampoline_addr(SB)/8, $libc_setattrlist_trampoline<>(SB) + +TEXT libc_fcntl_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fcntl(SB) -TEXT ·libc_kill_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fcntl_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fcntl_trampoline_addr(SB)/8, $libc_fcntl_trampoline<>(SB) + +TEXT libc_kill_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_kill(SB) -TEXT ·libc_ioctl_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_kill_trampoline_addr(SB), RODATA, $8 +DATA ·libc_kill_trampoline_addr(SB)/8, $libc_kill_trampoline<>(SB) + +TEXT libc_ioctl_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_ioctl(SB) -TEXT ·libc_sysctl_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_ioctl_trampoline_addr(SB), RODATA, $8 +DATA ·libc_ioctl_trampoline_addr(SB)/8, $libc_ioctl_trampoline<>(SB) + +TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_sysctl(SB) -TEXT ·libc_sendfile_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $8 +DATA ·libc_sysctl_trampoline_addr(SB)/8, $libc_sysctl_trampoline<>(SB) + +TEXT libc_sendfile_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_sendfile(SB) -TEXT ·libc_access_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_sendfile_trampoline_addr(SB), RODATA, $8 +DATA ·libc_sendfile_trampoline_addr(SB)/8, $libc_sendfile_trampoline<>(SB) + +TEXT libc_access_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_access(SB) -TEXT ·libc_adjtime_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_access_trampoline_addr(SB), RODATA, $8 +DATA ·libc_access_trampoline_addr(SB)/8, $libc_access_trampoline<>(SB) + +TEXT libc_adjtime_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_adjtime(SB) -TEXT ·libc_chdir_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_adjtime_trampoline_addr(SB), RODATA, $8 +DATA ·libc_adjtime_trampoline_addr(SB)/8, $libc_adjtime_trampoline<>(SB) + +TEXT libc_chdir_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_chdir(SB) -TEXT ·libc_chflags_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_chdir_trampoline_addr(SB), RODATA, $8 +DATA ·libc_chdir_trampoline_addr(SB)/8, $libc_chdir_trampoline<>(SB) + +TEXT libc_chflags_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_chflags(SB) -TEXT ·libc_chmod_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_chflags_trampoline_addr(SB), RODATA, $8 +DATA ·libc_chflags_trampoline_addr(SB)/8, $libc_chflags_trampoline<>(SB) + +TEXT libc_chmod_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_chmod(SB) -TEXT ·libc_chown_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_chmod_trampoline_addr(SB), RODATA, $8 +DATA ·libc_chmod_trampoline_addr(SB)/8, $libc_chmod_trampoline<>(SB) + +TEXT libc_chown_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_chown(SB) -TEXT ·libc_chroot_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_chown_trampoline_addr(SB), RODATA, $8 +DATA ·libc_chown_trampoline_addr(SB)/8, $libc_chown_trampoline<>(SB) + +TEXT libc_chroot_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_chroot(SB) -TEXT ·libc_clock_gettime_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_chroot_trampoline_addr(SB), RODATA, $8 +DATA ·libc_chroot_trampoline_addr(SB)/8, $libc_chroot_trampoline<>(SB) + +TEXT libc_clock_gettime_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_clock_gettime(SB) -TEXT ·libc_close_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_clock_gettime_trampoline_addr(SB), RODATA, $8 +DATA ·libc_clock_gettime_trampoline_addr(SB)/8, $libc_clock_gettime_trampoline<>(SB) + +TEXT libc_close_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_close(SB) -TEXT ·libc_clonefile_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_close_trampoline_addr(SB), RODATA, $8 +DATA ·libc_close_trampoline_addr(SB)/8, $libc_close_trampoline<>(SB) + +TEXT libc_clonefile_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_clonefile(SB) -TEXT ·libc_clonefileat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_clonefile_trampoline_addr(SB), RODATA, $8 +DATA ·libc_clonefile_trampoline_addr(SB)/8, $libc_clonefile_trampoline<>(SB) + +TEXT libc_clonefileat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_clonefileat(SB) -TEXT ·libc_dup_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_clonefileat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_clonefileat_trampoline_addr(SB)/8, $libc_clonefileat_trampoline<>(SB) + +TEXT libc_dup_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_dup(SB) -TEXT ·libc_dup2_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_dup_trampoline_addr(SB), RODATA, $8 +DATA ·libc_dup_trampoline_addr(SB)/8, $libc_dup_trampoline<>(SB) + +TEXT libc_dup2_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_dup2(SB) -TEXT ·libc_exchangedata_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_dup2_trampoline_addr(SB), RODATA, $8 +DATA ·libc_dup2_trampoline_addr(SB)/8, $libc_dup2_trampoline<>(SB) + +TEXT libc_exchangedata_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_exchangedata(SB) -TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_exchangedata_trampoline_addr(SB), RODATA, $8 +DATA ·libc_exchangedata_trampoline_addr(SB)/8, $libc_exchangedata_trampoline<>(SB) + +TEXT libc_exit_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_exit(SB) -TEXT ·libc_faccessat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_exit_trampoline_addr(SB), RODATA, $8 +DATA ·libc_exit_trampoline_addr(SB)/8, $libc_exit_trampoline<>(SB) + +TEXT libc_faccessat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_faccessat(SB) -TEXT ·libc_fchdir_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_faccessat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_faccessat_trampoline_addr(SB)/8, $libc_faccessat_trampoline<>(SB) + +TEXT libc_fchdir_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fchdir(SB) -TEXT ·libc_fchflags_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fchdir_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fchdir_trampoline_addr(SB)/8, $libc_fchdir_trampoline<>(SB) + +TEXT libc_fchflags_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fchflags(SB) -TEXT ·libc_fchmod_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fchflags_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fchflags_trampoline_addr(SB)/8, $libc_fchflags_trampoline<>(SB) + +TEXT libc_fchmod_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fchmod(SB) -TEXT ·libc_fchmodat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fchmod_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fchmod_trampoline_addr(SB)/8, $libc_fchmod_trampoline<>(SB) + +TEXT libc_fchmodat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fchmodat(SB) -TEXT ·libc_fchown_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fchmodat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fchmodat_trampoline_addr(SB)/8, $libc_fchmodat_trampoline<>(SB) + +TEXT libc_fchown_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fchown(SB) -TEXT ·libc_fchownat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fchown_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fchown_trampoline_addr(SB)/8, $libc_fchown_trampoline<>(SB) + +TEXT libc_fchownat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fchownat(SB) -TEXT ·libc_fclonefileat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fchownat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fchownat_trampoline_addr(SB)/8, $libc_fchownat_trampoline<>(SB) + +TEXT libc_fclonefileat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fclonefileat(SB) -TEXT ·libc_flock_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fclonefileat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fclonefileat_trampoline_addr(SB)/8, $libc_fclonefileat_trampoline<>(SB) + +TEXT libc_flock_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_flock(SB) -TEXT ·libc_fpathconf_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_flock_trampoline_addr(SB), RODATA, $8 +DATA ·libc_flock_trampoline_addr(SB)/8, $libc_flock_trampoline<>(SB) + +TEXT libc_fpathconf_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fpathconf(SB) -TEXT ·libc_fsync_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fpathconf_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fpathconf_trampoline_addr(SB)/8, $libc_fpathconf_trampoline<>(SB) + +TEXT libc_fsync_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fsync(SB) -TEXT ·libc_ftruncate_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fsync_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fsync_trampoline_addr(SB)/8, $libc_fsync_trampoline<>(SB) + +TEXT libc_ftruncate_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_ftruncate(SB) -TEXT ·libc_getcwd_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_ftruncate_trampoline_addr(SB), RODATA, $8 +DATA ·libc_ftruncate_trampoline_addr(SB)/8, $libc_ftruncate_trampoline<>(SB) + +TEXT libc_getcwd_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getcwd(SB) -TEXT ·libc_getdtablesize_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getcwd_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getcwd_trampoline_addr(SB)/8, $libc_getcwd_trampoline<>(SB) + +TEXT libc_getdtablesize_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getdtablesize(SB) -TEXT ·libc_getegid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getdtablesize_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getdtablesize_trampoline_addr(SB)/8, $libc_getdtablesize_trampoline<>(SB) + +TEXT libc_getegid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getegid(SB) -TEXT ·libc_geteuid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getegid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getegid_trampoline_addr(SB)/8, $libc_getegid_trampoline<>(SB) + +TEXT libc_geteuid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_geteuid(SB) -TEXT ·libc_getgid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_geteuid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_geteuid_trampoline_addr(SB)/8, $libc_geteuid_trampoline<>(SB) + +TEXT libc_getgid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getgid(SB) -TEXT ·libc_getpgid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getgid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getgid_trampoline_addr(SB)/8, $libc_getgid_trampoline<>(SB) + +TEXT libc_getpgid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getpgid(SB) -TEXT ·libc_getpgrp_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getpgid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getpgid_trampoline_addr(SB)/8, $libc_getpgid_trampoline<>(SB) + +TEXT libc_getpgrp_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getpgrp(SB) -TEXT ·libc_getpid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getpgrp_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getpgrp_trampoline_addr(SB)/8, $libc_getpgrp_trampoline<>(SB) + +TEXT libc_getpid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getpid(SB) -TEXT ·libc_getppid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getpid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getpid_trampoline_addr(SB)/8, $libc_getpid_trampoline<>(SB) + +TEXT libc_getppid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getppid(SB) -TEXT ·libc_getpriority_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getppid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getppid_trampoline_addr(SB)/8, $libc_getppid_trampoline<>(SB) + +TEXT libc_getpriority_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getpriority(SB) -TEXT ·libc_getrlimit_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getpriority_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getpriority_trampoline_addr(SB)/8, $libc_getpriority_trampoline<>(SB) + +TEXT libc_getrlimit_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getrlimit(SB) -TEXT ·libc_getrusage_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getrlimit_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getrlimit_trampoline_addr(SB)/8, $libc_getrlimit_trampoline<>(SB) + +TEXT libc_getrusage_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getrusage(SB) -TEXT ·libc_getsid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getrusage_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getrusage_trampoline_addr(SB)/8, $libc_getrusage_trampoline<>(SB) + +TEXT libc_getsid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getsid(SB) -TEXT ·libc_gettimeofday_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getsid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getsid_trampoline_addr(SB)/8, $libc_getsid_trampoline<>(SB) + +TEXT libc_gettimeofday_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_gettimeofday(SB) -TEXT ·libc_getuid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_gettimeofday_trampoline_addr(SB), RODATA, $8 +DATA ·libc_gettimeofday_trampoline_addr(SB)/8, $libc_gettimeofday_trampoline<>(SB) + +TEXT libc_getuid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getuid(SB) -TEXT ·libc_issetugid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getuid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getuid_trampoline_addr(SB)/8, $libc_getuid_trampoline<>(SB) + +TEXT libc_issetugid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_issetugid(SB) -TEXT ·libc_kqueue_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_issetugid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_issetugid_trampoline_addr(SB)/8, $libc_issetugid_trampoline<>(SB) + +TEXT libc_kqueue_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_kqueue(SB) -TEXT ·libc_lchown_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_kqueue_trampoline_addr(SB), RODATA, $8 +DATA ·libc_kqueue_trampoline_addr(SB)/8, $libc_kqueue_trampoline<>(SB) + +TEXT libc_lchown_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_lchown(SB) -TEXT ·libc_link_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_lchown_trampoline_addr(SB), RODATA, $8 +DATA ·libc_lchown_trampoline_addr(SB)/8, $libc_lchown_trampoline<>(SB) + +TEXT libc_link_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_link(SB) -TEXT ·libc_linkat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_link_trampoline_addr(SB), RODATA, $8 +DATA ·libc_link_trampoline_addr(SB)/8, $libc_link_trampoline<>(SB) + +TEXT libc_linkat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_linkat(SB) -TEXT ·libc_listen_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_linkat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_linkat_trampoline_addr(SB)/8, $libc_linkat_trampoline<>(SB) + +TEXT libc_listen_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_listen(SB) -TEXT ·libc_mkdir_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_listen_trampoline_addr(SB), RODATA, $8 +DATA ·libc_listen_trampoline_addr(SB)/8, $libc_listen_trampoline<>(SB) + +TEXT libc_mkdir_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_mkdir(SB) -TEXT ·libc_mkdirat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_mkdir_trampoline_addr(SB), RODATA, $8 +DATA ·libc_mkdir_trampoline_addr(SB)/8, $libc_mkdir_trampoline<>(SB) + +TEXT libc_mkdirat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_mkdirat(SB) -TEXT ·libc_mkfifo_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_mkdirat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_mkdirat_trampoline_addr(SB)/8, $libc_mkdirat_trampoline<>(SB) + +TEXT libc_mkfifo_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_mkfifo(SB) -TEXT ·libc_mknod_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_mkfifo_trampoline_addr(SB), RODATA, $8 +DATA ·libc_mkfifo_trampoline_addr(SB)/8, $libc_mkfifo_trampoline<>(SB) + +TEXT libc_mknod_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_mknod(SB) -TEXT ·libc_open_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_mknod_trampoline_addr(SB), RODATA, $8 +DATA ·libc_mknod_trampoline_addr(SB)/8, $libc_mknod_trampoline<>(SB) + +TEXT libc_open_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_open(SB) -TEXT ·libc_openat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_open_trampoline_addr(SB), RODATA, $8 +DATA ·libc_open_trampoline_addr(SB)/8, $libc_open_trampoline<>(SB) + +TEXT libc_openat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_openat(SB) -TEXT ·libc_pathconf_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_openat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_openat_trampoline_addr(SB)/8, $libc_openat_trampoline<>(SB) + +TEXT libc_pathconf_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_pathconf(SB) -TEXT ·libc_pread_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_pathconf_trampoline_addr(SB), RODATA, $8 +DATA ·libc_pathconf_trampoline_addr(SB)/8, $libc_pathconf_trampoline<>(SB) + +TEXT libc_pread_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_pread(SB) -TEXT ·libc_pwrite_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_pread_trampoline_addr(SB), RODATA, $8 +DATA ·libc_pread_trampoline_addr(SB)/8, $libc_pread_trampoline<>(SB) + +TEXT libc_pwrite_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_pwrite(SB) -TEXT ·libc_read_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_pwrite_trampoline_addr(SB), RODATA, $8 +DATA ·libc_pwrite_trampoline_addr(SB)/8, $libc_pwrite_trampoline<>(SB) + +TEXT libc_read_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_read(SB) -TEXT ·libc_readlink_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_read_trampoline_addr(SB), RODATA, $8 +DATA ·libc_read_trampoline_addr(SB)/8, $libc_read_trampoline<>(SB) + +TEXT libc_readlink_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_readlink(SB) -TEXT ·libc_readlinkat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_readlink_trampoline_addr(SB), RODATA, $8 +DATA ·libc_readlink_trampoline_addr(SB)/8, $libc_readlink_trampoline<>(SB) + +TEXT libc_readlinkat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_readlinkat(SB) -TEXT ·libc_rename_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_readlinkat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_readlinkat_trampoline_addr(SB)/8, $libc_readlinkat_trampoline<>(SB) + +TEXT libc_rename_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_rename(SB) -TEXT ·libc_renameat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_rename_trampoline_addr(SB), RODATA, $8 +DATA ·libc_rename_trampoline_addr(SB)/8, $libc_rename_trampoline<>(SB) + +TEXT libc_renameat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_renameat(SB) -TEXT ·libc_revoke_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_renameat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_renameat_trampoline_addr(SB)/8, $libc_renameat_trampoline<>(SB) + +TEXT libc_revoke_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_revoke(SB) -TEXT ·libc_rmdir_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_revoke_trampoline_addr(SB), RODATA, $8 +DATA ·libc_revoke_trampoline_addr(SB)/8, $libc_revoke_trampoline<>(SB) + +TEXT libc_rmdir_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_rmdir(SB) -TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_rmdir_trampoline_addr(SB), RODATA, $8 +DATA ·libc_rmdir_trampoline_addr(SB)/8, $libc_rmdir_trampoline<>(SB) + +TEXT libc_lseek_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_lseek(SB) -TEXT ·libc_select_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_lseek_trampoline_addr(SB), RODATA, $8 +DATA ·libc_lseek_trampoline_addr(SB)/8, $libc_lseek_trampoline<>(SB) + +TEXT libc_select_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_select(SB) -TEXT ·libc_setegid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_select_trampoline_addr(SB), RODATA, $8 +DATA ·libc_select_trampoline_addr(SB)/8, $libc_select_trampoline<>(SB) + +TEXT libc_setegid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setegid(SB) -TEXT ·libc_seteuid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setegid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setegid_trampoline_addr(SB)/8, $libc_setegid_trampoline<>(SB) + +TEXT libc_seteuid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_seteuid(SB) -TEXT ·libc_setgid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_seteuid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_seteuid_trampoline_addr(SB)/8, $libc_seteuid_trampoline<>(SB) + +TEXT libc_setgid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setgid(SB) -TEXT ·libc_setlogin_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setgid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setgid_trampoline_addr(SB)/8, $libc_setgid_trampoline<>(SB) + +TEXT libc_setlogin_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setlogin(SB) -TEXT ·libc_setpgid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setlogin_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setlogin_trampoline_addr(SB)/8, $libc_setlogin_trampoline<>(SB) + +TEXT libc_setpgid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setpgid(SB) -TEXT ·libc_setpriority_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setpgid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setpgid_trampoline_addr(SB)/8, $libc_setpgid_trampoline<>(SB) + +TEXT libc_setpriority_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setpriority(SB) -TEXT ·libc_setprivexec_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setpriority_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setpriority_trampoline_addr(SB)/8, $libc_setpriority_trampoline<>(SB) + +TEXT libc_setprivexec_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setprivexec(SB) -TEXT ·libc_setregid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setprivexec_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setprivexec_trampoline_addr(SB)/8, $libc_setprivexec_trampoline<>(SB) + +TEXT libc_setregid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setregid(SB) -TEXT ·libc_setreuid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setregid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setregid_trampoline_addr(SB)/8, $libc_setregid_trampoline<>(SB) + +TEXT libc_setreuid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setreuid(SB) -TEXT ·libc_setrlimit_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setreuid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setreuid_trampoline_addr(SB)/8, $libc_setreuid_trampoline<>(SB) + +TEXT libc_setrlimit_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setrlimit(SB) -TEXT ·libc_setsid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setrlimit_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setrlimit_trampoline_addr(SB)/8, $libc_setrlimit_trampoline<>(SB) + +TEXT libc_setsid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setsid(SB) -TEXT ·libc_settimeofday_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setsid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setsid_trampoline_addr(SB)/8, $libc_setsid_trampoline<>(SB) + +TEXT libc_settimeofday_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_settimeofday(SB) -TEXT ·libc_setuid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_settimeofday_trampoline_addr(SB), RODATA, $8 +DATA ·libc_settimeofday_trampoline_addr(SB)/8, $libc_settimeofday_trampoline<>(SB) + +TEXT libc_setuid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setuid(SB) -TEXT ·libc_symlink_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setuid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setuid_trampoline_addr(SB)/8, $libc_setuid_trampoline<>(SB) + +TEXT libc_symlink_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_symlink(SB) -TEXT ·libc_symlinkat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_symlink_trampoline_addr(SB), RODATA, $8 +DATA ·libc_symlink_trampoline_addr(SB)/8, $libc_symlink_trampoline<>(SB) + +TEXT libc_symlinkat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_symlinkat(SB) -TEXT ·libc_sync_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_symlinkat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_symlinkat_trampoline_addr(SB)/8, $libc_symlinkat_trampoline<>(SB) + +TEXT libc_sync_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_sync(SB) -TEXT ·libc_truncate_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_sync_trampoline_addr(SB), RODATA, $8 +DATA ·libc_sync_trampoline_addr(SB)/8, $libc_sync_trampoline<>(SB) + +TEXT libc_truncate_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_truncate(SB) -TEXT ·libc_umask_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_truncate_trampoline_addr(SB), RODATA, $8 +DATA ·libc_truncate_trampoline_addr(SB)/8, $libc_truncate_trampoline<>(SB) + +TEXT libc_umask_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_umask(SB) -TEXT ·libc_undelete_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_umask_trampoline_addr(SB), RODATA, $8 +DATA ·libc_umask_trampoline_addr(SB)/8, $libc_umask_trampoline<>(SB) + +TEXT libc_undelete_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_undelete(SB) -TEXT ·libc_unlink_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_undelete_trampoline_addr(SB), RODATA, $8 +DATA ·libc_undelete_trampoline_addr(SB)/8, $libc_undelete_trampoline<>(SB) + +TEXT libc_unlink_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_unlink(SB) -TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_unlink_trampoline_addr(SB), RODATA, $8 +DATA ·libc_unlink_trampoline_addr(SB)/8, $libc_unlink_trampoline<>(SB) + +TEXT libc_unlinkat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_unlinkat(SB) -TEXT ·libc_unmount_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_unlinkat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_unlinkat_trampoline_addr(SB)/8, $libc_unlinkat_trampoline<>(SB) + +TEXT libc_unmount_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_unmount(SB) -TEXT ·libc_write_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_unmount_trampoline_addr(SB), RODATA, $8 +DATA ·libc_unmount_trampoline_addr(SB)/8, $libc_unmount_trampoline<>(SB) + +TEXT libc_write_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_write(SB) -TEXT ·libc_mmap_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_write_trampoline_addr(SB), RODATA, $8 +DATA ·libc_write_trampoline_addr(SB)/8, $libc_write_trampoline<>(SB) + +TEXT libc_mmap_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_mmap(SB) -TEXT ·libc_munmap_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_mmap_trampoline_addr(SB), RODATA, $8 +DATA ·libc_mmap_trampoline_addr(SB)/8, $libc_mmap_trampoline<>(SB) + +TEXT libc_munmap_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_munmap(SB) -TEXT ·libc_fstat64_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_munmap_trampoline_addr(SB), RODATA, $8 +DATA ·libc_munmap_trampoline_addr(SB)/8, $libc_munmap_trampoline<>(SB) + +TEXT libc_fstat64_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fstat64(SB) -TEXT ·libc_fstatat64_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fstat64_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fstat64_trampoline_addr(SB)/8, $libc_fstat64_trampoline<>(SB) + +TEXT libc_fstatat64_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fstatat64(SB) -TEXT ·libc_fstatfs64_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fstatat64_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fstatat64_trampoline_addr(SB)/8, $libc_fstatat64_trampoline<>(SB) + +TEXT libc_fstatfs64_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fstatfs64(SB) -TEXT ·libc_getfsstat64_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fstatfs64_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fstatfs64_trampoline_addr(SB)/8, $libc_fstatfs64_trampoline<>(SB) + +TEXT libc_getfsstat64_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getfsstat64(SB) -TEXT ·libc_lstat64_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getfsstat64_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getfsstat64_trampoline_addr(SB)/8, $libc_getfsstat64_trampoline<>(SB) + +TEXT libc_lstat64_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_lstat64(SB) -TEXT ·libc_ptrace_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_lstat64_trampoline_addr(SB), RODATA, $8 +DATA ·libc_lstat64_trampoline_addr(SB)/8, $libc_lstat64_trampoline<>(SB) + +TEXT libc_ptrace_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_ptrace(SB) -TEXT ·libc_stat64_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_ptrace_trampoline_addr(SB), RODATA, $8 +DATA ·libc_ptrace_trampoline_addr(SB)/8, $libc_ptrace_trampoline<>(SB) + +TEXT libc_stat64_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_stat64(SB) -TEXT ·libc_statfs64_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_stat64_trampoline_addr(SB), RODATA, $8 +DATA ·libc_stat64_trampoline_addr(SB)/8, $libc_stat64_trampoline<>(SB) + +TEXT libc_statfs64_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_statfs64(SB) + +GLOBL ·libc_statfs64_trampoline_addr(SB), RODATA, $8 +DATA ·libc_statfs64_trampoline_addr(SB)/8, $libc_statfs64_trampoline<>(SB) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.1_13.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.1_13.go deleted file mode 100644 index ed437f89a9e..00000000000 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.1_13.go +++ /dev/null @@ -1,40 +0,0 @@ -// go run mksyscall.go -l32 -tags darwin,arm,go1.13 syscall_darwin.1_13.go -// Code generated by the command above; see README.md. DO NOT EDIT. - -//go:build darwin && arm && go1.13 -// +build darwin,arm,go1.13 - -package unix - -import ( - "syscall" - "unsafe" -) - -var _ syscall.Errno - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func closedir(dir uintptr) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_closedir_trampoline), uintptr(dir), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_closedir_trampoline() - -//go:cgo_import_dynamic libc_closedir closedir "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno) { - r0, _, _ := syscall_syscall(funcPC(libc_readdir_r_trampoline), uintptr(dir), uintptr(unsafe.Pointer(entry)), uintptr(unsafe.Pointer(result))) - res = Errno(r0) - return -} - -func libc_readdir_r_trampoline() - -//go:cgo_import_dynamic libc_readdir_r readdir_r "/usr/lib/libSystem.B.dylib" diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.1_13.s b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.1_13.s deleted file mode 100644 index 0cc80ad87ea..00000000000 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.1_13.s +++ /dev/null @@ -1,13 +0,0 @@ -// go run mkasm_darwin.go arm -// Code generated by the command above; DO NOT EDIT. - -//go:build go1.13 -// +build go1.13 - -#include "textflag.h" -TEXT ·libc_fdopendir_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fdopendir(SB) -TEXT ·libc_closedir_trampoline(SB),NOSPLIT,$0-0 - JMP libc_closedir(SB) -TEXT ·libc_readdir_r_trampoline(SB),NOSPLIT,$0-0 - JMP libc_readdir_r(SB) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.go deleted file mode 100644 index 7f88cb5ea22..00000000000 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.go +++ /dev/null @@ -1,2417 +0,0 @@ -// go run mksyscall.go -l32 -tags darwin,arm,go1.12 syscall_bsd.go syscall_darwin.go syscall_darwin_arm.go -// Code generated by the command above; see README.md. DO NOT EDIT. - -//go:build darwin && arm && go1.12 -// +build darwin,arm,go1.12 - -package unix - -import ( - "syscall" - "unsafe" -) - -var _ syscall.Errno - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func getgroups(ngid int, gid *_Gid_t) (n int, err error) { - r0, _, e1 := syscall_rawSyscall(funcPC(libc_getgroups_trampoline), uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_getgroups_trampoline() - -//go:cgo_import_dynamic libc_getgroups getgroups "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func setgroups(ngid int, gid *_Gid_t) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setgroups_trampoline), uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setgroups_trampoline() - -//go:cgo_import_dynamic libc_setgroups setgroups "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) { - r0, _, e1 := syscall_syscall6(funcPC(libc_wait4_trampoline), uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) - wpid = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_wait4_trampoline() - -//go:cgo_import_dynamic libc_wait4 wait4 "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_accept_trampoline), uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_accept_trampoline() - -//go:cgo_import_dynamic libc_accept accept "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_bind_trampoline), uintptr(s), uintptr(addr), uintptr(addrlen)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_bind_trampoline() - -//go:cgo_import_dynamic libc_bind bind "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_connect_trampoline), uintptr(s), uintptr(addr), uintptr(addrlen)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_connect_trampoline() - -//go:cgo_import_dynamic libc_connect connect "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func socket(domain int, typ int, proto int) (fd int, err error) { - r0, _, e1 := syscall_rawSyscall(funcPC(libc_socket_trampoline), uintptr(domain), uintptr(typ), uintptr(proto)) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_socket_trampoline() - -//go:cgo_import_dynamic libc_socket socket "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) { - _, _, e1 := syscall_syscall6(funcPC(libc_getsockopt_trampoline), uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_getsockopt_trampoline() - -//go:cgo_import_dynamic libc_getsockopt getsockopt "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { - _, _, e1 := syscall_syscall6(funcPC(libc_setsockopt_trampoline), uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setsockopt_trampoline() - -//go:cgo_import_dynamic libc_setsockopt setsockopt "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_getpeername_trampoline), uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_getpeername_trampoline() - -//go:cgo_import_dynamic libc_getpeername getpeername "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_getsockname_trampoline), uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_getsockname_trampoline() - -//go:cgo_import_dynamic libc_getsockname getsockname "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Shutdown(s int, how int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_shutdown_trampoline), uintptr(s), uintptr(how), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_shutdown_trampoline() - -//go:cgo_import_dynamic libc_shutdown shutdown "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) { - _, _, e1 := syscall_rawSyscall6(funcPC(libc_socketpair_trampoline), uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_socketpair_trampoline() - -//go:cgo_import_dynamic libc_socketpair socketpair "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) { - var _p0 unsafe.Pointer - if len(p) > 0 { - _p0 = unsafe.Pointer(&p[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := syscall_syscall6(funcPC(libc_recvfrom_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_recvfrom_trampoline() - -//go:cgo_import_dynamic libc_recvfrom recvfrom "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) { - var _p0 unsafe.Pointer - if len(buf) > 0 { - _p0 = unsafe.Pointer(&buf[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - _, _, e1 := syscall_syscall6(funcPC(libc_sendto_trampoline), uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_sendto_trampoline() - -//go:cgo_import_dynamic libc_sendto sendto "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_recvmsg_trampoline), uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_recvmsg_trampoline() - -//go:cgo_import_dynamic libc_recvmsg recvmsg "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_sendmsg_trampoline), uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_sendmsg_trampoline() - -//go:cgo_import_dynamic libc_sendmsg sendmsg "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) { - r0, _, e1 := syscall_syscall6(funcPC(libc_kevent_trampoline), uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_kevent_trampoline() - -//go:cgo_import_dynamic libc_kevent kevent "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func utimes(path string, timeval *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_utimes_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_utimes_trampoline() - -//go:cgo_import_dynamic libc_utimes utimes "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func futimes(fd int, timeval *[2]Timeval) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_futimes_trampoline), uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_futimes_trampoline() - -//go:cgo_import_dynamic libc_futimes futimes "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_poll_trampoline), uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_poll_trampoline() - -//go:cgo_import_dynamic libc_poll poll "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Madvise(b []byte, behav int) (err error) { - var _p0 unsafe.Pointer - if len(b) > 0 { - _p0 = unsafe.Pointer(&b[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - _, _, e1 := syscall_syscall(funcPC(libc_madvise_trampoline), uintptr(_p0), uintptr(len(b)), uintptr(behav)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_madvise_trampoline() - -//go:cgo_import_dynamic libc_madvise madvise "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Mlock(b []byte) (err error) { - var _p0 unsafe.Pointer - if len(b) > 0 { - _p0 = unsafe.Pointer(&b[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - _, _, e1 := syscall_syscall(funcPC(libc_mlock_trampoline), uintptr(_p0), uintptr(len(b)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_mlock_trampoline() - -//go:cgo_import_dynamic libc_mlock mlock "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Mlockall(flags int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_mlockall_trampoline), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_mlockall_trampoline() - -//go:cgo_import_dynamic libc_mlockall mlockall "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Mprotect(b []byte, prot int) (err error) { - var _p0 unsafe.Pointer - if len(b) > 0 { - _p0 = unsafe.Pointer(&b[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - _, _, e1 := syscall_syscall(funcPC(libc_mprotect_trampoline), uintptr(_p0), uintptr(len(b)), uintptr(prot)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_mprotect_trampoline() - -//go:cgo_import_dynamic libc_mprotect mprotect "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Msync(b []byte, flags int) (err error) { - var _p0 unsafe.Pointer - if len(b) > 0 { - _p0 = unsafe.Pointer(&b[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - _, _, e1 := syscall_syscall(funcPC(libc_msync_trampoline), uintptr(_p0), uintptr(len(b)), uintptr(flags)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_msync_trampoline() - -//go:cgo_import_dynamic libc_msync msync "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Munlock(b []byte) (err error) { - var _p0 unsafe.Pointer - if len(b) > 0 { - _p0 = unsafe.Pointer(&b[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - _, _, e1 := syscall_syscall(funcPC(libc_munlock_trampoline), uintptr(_p0), uintptr(len(b)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_munlock_trampoline() - -//go:cgo_import_dynamic libc_munlock munlock "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Munlockall() (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_munlockall_trampoline), 0, 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_munlockall_trampoline() - -//go:cgo_import_dynamic libc_munlockall munlockall "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func pipe(p *[2]int32) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_pipe_trampoline), uintptr(unsafe.Pointer(p)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_pipe_trampoline() - -//go:cgo_import_dynamic libc_pipe pipe "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func getxattr(path string, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(attr) - if err != nil { - return - } - r0, _, e1 := syscall_syscall6(funcPC(libc_getxattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) - sz = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_getxattr_trampoline() - -//go:cgo_import_dynamic libc_getxattr getxattr "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func fgetxattr(fd int, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(attr) - if err != nil { - return - } - r0, _, e1 := syscall_syscall6(funcPC(libc_fgetxattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) - sz = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fgetxattr_trampoline() - -//go:cgo_import_dynamic libc_fgetxattr fgetxattr "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func setxattr(path string, attr string, data *byte, size int, position uint32, options int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(attr) - if err != nil { - return - } - _, _, e1 := syscall_syscall6(funcPC(libc_setxattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setxattr_trampoline() - -//go:cgo_import_dynamic libc_setxattr setxattr "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func fsetxattr(fd int, attr string, data *byte, size int, position uint32, options int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(attr) - if err != nil { - return - } - _, _, e1 := syscall_syscall6(funcPC(libc_fsetxattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fsetxattr_trampoline() - -//go:cgo_import_dynamic libc_fsetxattr fsetxattr "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func removexattr(path string, attr string, options int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(attr) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_removexattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_removexattr_trampoline() - -//go:cgo_import_dynamic libc_removexattr removexattr "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func fremovexattr(fd int, attr string, options int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(attr) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_fremovexattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(options)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fremovexattr_trampoline() - -//go:cgo_import_dynamic libc_fremovexattr fremovexattr "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func listxattr(path string, dest *byte, size int, options int) (sz int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - r0, _, e1 := syscall_syscall6(funcPC(libc_listxattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) - sz = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_listxattr_trampoline() - -//go:cgo_import_dynamic libc_listxattr listxattr "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func flistxattr(fd int, dest *byte, size int, options int) (sz int, err error) { - r0, _, e1 := syscall_syscall6(funcPC(libc_flistxattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) - sz = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_flistxattr_trampoline() - -//go:cgo_import_dynamic libc_flistxattr flistxattr "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func setattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) { - _, _, e1 := syscall_syscall6(funcPC(libc_setattrlist_trampoline), uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setattrlist_trampoline() - -//go:cgo_import_dynamic libc_setattrlist setattrlist "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func fcntl(fd int, cmd int, arg int) (val int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_fcntl_trampoline), uintptr(fd), uintptr(cmd), uintptr(arg)) - val = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fcntl_trampoline() - -//go:cgo_import_dynamic libc_fcntl fcntl "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func kill(pid int, signum int, posix int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_kill_trampoline), uintptr(pid), uintptr(signum), uintptr(posix)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_kill_trampoline() - -//go:cgo_import_dynamic libc_kill kill "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func ioctl(fd int, req uint, arg uintptr) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_ioctl_trampoline), uintptr(fd), uintptr(req), uintptr(arg)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_ioctl_trampoline() - -//go:cgo_import_dynamic libc_ioctl ioctl "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { - var _p0 unsafe.Pointer - if len(mib) > 0 { - _p0 = unsafe.Pointer(&mib[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - _, _, e1 := syscall_syscall6(funcPC(libc_sysctl_trampoline), uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_sysctl_trampoline() - -//go:cgo_import_dynamic libc_sysctl sysctl "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) { - _, _, e1 := syscall_syscall9(funcPC(libc_sendfile_trampoline), uintptr(infd), uintptr(outfd), uintptr(offset), uintptr(offset>>32), uintptr(unsafe.Pointer(len)), uintptr(hdtr), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_sendfile_trampoline() - -//go:cgo_import_dynamic libc_sendfile sendfile "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Access(path string, mode uint32) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_access_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_access_trampoline() - -//go:cgo_import_dynamic libc_access access "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Adjtime(delta *Timeval, olddelta *Timeval) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_adjtime_trampoline), uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_adjtime_trampoline() - -//go:cgo_import_dynamic libc_adjtime adjtime "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Chdir(path string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_chdir_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_chdir_trampoline() - -//go:cgo_import_dynamic libc_chdir chdir "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Chflags(path string, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_chflags_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_chflags_trampoline() - -//go:cgo_import_dynamic libc_chflags chflags "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Chmod(path string, mode uint32) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_chmod_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_chmod_trampoline() - -//go:cgo_import_dynamic libc_chmod chmod "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Chown(path string, uid int, gid int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_chown_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_chown_trampoline() - -//go:cgo_import_dynamic libc_chown chown "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Chroot(path string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_chroot_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_chroot_trampoline() - -//go:cgo_import_dynamic libc_chroot chroot "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func ClockGettime(clockid int32, time *Timespec) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_clock_gettime_trampoline), uintptr(clockid), uintptr(unsafe.Pointer(time)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_clock_gettime_trampoline() - -//go:cgo_import_dynamic libc_clock_gettime clock_gettime "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Close(fd int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_close_trampoline), uintptr(fd), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_close_trampoline() - -//go:cgo_import_dynamic libc_close close "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Clonefile(src string, dst string, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(src) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(dst) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_clonefile_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flags)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_clonefile_trampoline() - -//go:cgo_import_dynamic libc_clonefile clonefile "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Clonefileat(srcDirfd int, src string, dstDirfd int, dst string, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(src) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(dst) - if err != nil { - return - } - _, _, e1 := syscall_syscall6(funcPC(libc_clonefileat_trampoline), uintptr(srcDirfd), uintptr(unsafe.Pointer(_p0)), uintptr(dstDirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_clonefileat_trampoline() - -//go:cgo_import_dynamic libc_clonefileat clonefileat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Dup(fd int) (nfd int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_dup_trampoline), uintptr(fd), 0, 0) - nfd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_dup_trampoline() - -//go:cgo_import_dynamic libc_dup dup "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Dup2(from int, to int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_dup2_trampoline), uintptr(from), uintptr(to), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_dup2_trampoline() - -//go:cgo_import_dynamic libc_dup2 dup2 "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Exchangedata(path1 string, path2 string, options int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path1) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(path2) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_exchangedata_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_exchangedata_trampoline() - -//go:cgo_import_dynamic libc_exchangedata exchangedata "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Exit(code int) { - syscall_syscall(funcPC(libc_exit_trampoline), uintptr(code), 0, 0) - return -} - -func libc_exit_trampoline() - -//go:cgo_import_dynamic libc_exit exit "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall6(funcPC(libc_faccessat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_faccessat_trampoline() - -//go:cgo_import_dynamic libc_faccessat faccessat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fchdir(fd int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fchdir_trampoline), uintptr(fd), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fchdir_trampoline() - -//go:cgo_import_dynamic libc_fchdir fchdir "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fchflags(fd int, flags int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fchflags_trampoline), uintptr(fd), uintptr(flags), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fchflags_trampoline() - -//go:cgo_import_dynamic libc_fchflags fchflags "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fchmod(fd int, mode uint32) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fchmod_trampoline), uintptr(fd), uintptr(mode), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fchmod_trampoline() - -//go:cgo_import_dynamic libc_fchmod fchmod "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall6(funcPC(libc_fchmodat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fchmodat_trampoline() - -//go:cgo_import_dynamic libc_fchmodat fchmodat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fchown(fd int, uid int, gid int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fchown_trampoline), uintptr(fd), uintptr(uid), uintptr(gid)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fchown_trampoline() - -//go:cgo_import_dynamic libc_fchown fchown "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall6(funcPC(libc_fchownat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fchownat_trampoline() - -//go:cgo_import_dynamic libc_fchownat fchownat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fclonefileat(srcDirfd int, dstDirfd int, dst string, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(dst) - if err != nil { - return - } - _, _, e1 := syscall_syscall6(funcPC(libc_fclonefileat_trampoline), uintptr(srcDirfd), uintptr(dstDirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fclonefileat_trampoline() - -//go:cgo_import_dynamic libc_fclonefileat fclonefileat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Flock(fd int, how int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_flock_trampoline), uintptr(fd), uintptr(how), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_flock_trampoline() - -//go:cgo_import_dynamic libc_flock flock "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fpathconf(fd int, name int) (val int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_fpathconf_trampoline), uintptr(fd), uintptr(name), 0) - val = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fpathconf_trampoline() - -//go:cgo_import_dynamic libc_fpathconf fpathconf "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fsync(fd int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fsync_trampoline), uintptr(fd), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fsync_trampoline() - -//go:cgo_import_dynamic libc_fsync fsync "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Ftruncate(fd int, length int64) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_ftruncate_trampoline), uintptr(fd), uintptr(length), uintptr(length>>32)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_ftruncate_trampoline() - -//go:cgo_import_dynamic libc_ftruncate ftruncate "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getcwd(buf []byte) (n int, err error) { - var _p0 unsafe.Pointer - if len(buf) > 0 { - _p0 = unsafe.Pointer(&buf[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := syscall_syscall(funcPC(libc_getcwd_trampoline), uintptr(_p0), uintptr(len(buf)), 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_getcwd_trampoline() - -//go:cgo_import_dynamic libc_getcwd getcwd "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getdtablesize() (size int) { - r0, _, _ := syscall_syscall(funcPC(libc_getdtablesize_trampoline), 0, 0, 0) - size = int(r0) - return -} - -func libc_getdtablesize_trampoline() - -//go:cgo_import_dynamic libc_getdtablesize getdtablesize "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getegid() (egid int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_getegid_trampoline), 0, 0, 0) - egid = int(r0) - return -} - -func libc_getegid_trampoline() - -//go:cgo_import_dynamic libc_getegid getegid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Geteuid() (uid int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_geteuid_trampoline), 0, 0, 0) - uid = int(r0) - return -} - -func libc_geteuid_trampoline() - -//go:cgo_import_dynamic libc_geteuid geteuid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getgid() (gid int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_getgid_trampoline), 0, 0, 0) - gid = int(r0) - return -} - -func libc_getgid_trampoline() - -//go:cgo_import_dynamic libc_getgid getgid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getpgid(pid int) (pgid int, err error) { - r0, _, e1 := syscall_rawSyscall(funcPC(libc_getpgid_trampoline), uintptr(pid), 0, 0) - pgid = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_getpgid_trampoline() - -//go:cgo_import_dynamic libc_getpgid getpgid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getpgrp() (pgrp int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_getpgrp_trampoline), 0, 0, 0) - pgrp = int(r0) - return -} - -func libc_getpgrp_trampoline() - -//go:cgo_import_dynamic libc_getpgrp getpgrp "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getpid() (pid int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_getpid_trampoline), 0, 0, 0) - pid = int(r0) - return -} - -func libc_getpid_trampoline() - -//go:cgo_import_dynamic libc_getpid getpid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getppid() (ppid int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_getppid_trampoline), 0, 0, 0) - ppid = int(r0) - return -} - -func libc_getppid_trampoline() - -//go:cgo_import_dynamic libc_getppid getppid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getpriority(which int, who int) (prio int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_getpriority_trampoline), uintptr(which), uintptr(who), 0) - prio = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_getpriority_trampoline() - -//go:cgo_import_dynamic libc_getpriority getpriority "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getrlimit(which int, lim *Rlimit) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_getrlimit_trampoline), uintptr(which), uintptr(unsafe.Pointer(lim)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_getrlimit_trampoline() - -//go:cgo_import_dynamic libc_getrlimit getrlimit "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getrusage(who int, rusage *Rusage) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_getrusage_trampoline), uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_getrusage_trampoline() - -//go:cgo_import_dynamic libc_getrusage getrusage "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getsid(pid int) (sid int, err error) { - r0, _, e1 := syscall_rawSyscall(funcPC(libc_getsid_trampoline), uintptr(pid), 0, 0) - sid = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_getsid_trampoline() - -//go:cgo_import_dynamic libc_getsid getsid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Gettimeofday(tp *Timeval) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_gettimeofday_trampoline), uintptr(unsafe.Pointer(tp)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_gettimeofday_trampoline() - -//go:cgo_import_dynamic libc_gettimeofday gettimeofday "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Getuid() (uid int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_getuid_trampoline), 0, 0, 0) - uid = int(r0) - return -} - -func libc_getuid_trampoline() - -//go:cgo_import_dynamic libc_getuid getuid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Issetugid() (tainted bool) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_issetugid_trampoline), 0, 0, 0) - tainted = bool(r0 != 0) - return -} - -func libc_issetugid_trampoline() - -//go:cgo_import_dynamic libc_issetugid issetugid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Kqueue() (fd int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_kqueue_trampoline), 0, 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_kqueue_trampoline() - -//go:cgo_import_dynamic libc_kqueue kqueue "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Lchown(path string, uid int, gid int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_lchown_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_lchown_trampoline() - -//go:cgo_import_dynamic libc_lchown lchown "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Link(path string, link string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(link) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_link_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_link_trampoline() - -//go:cgo_import_dynamic libc_link link "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(link) - if err != nil { - return - } - _, _, e1 := syscall_syscall6(funcPC(libc_linkat_trampoline), uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_linkat_trampoline() - -//go:cgo_import_dynamic libc_linkat linkat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Listen(s int, backlog int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_listen_trampoline), uintptr(s), uintptr(backlog), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_listen_trampoline() - -//go:cgo_import_dynamic libc_listen listen "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Mkdir(path string, mode uint32) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_mkdir_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_mkdir_trampoline() - -//go:cgo_import_dynamic libc_mkdir mkdir "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Mkdirat(dirfd int, path string, mode uint32) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_mkdirat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_mkdirat_trampoline() - -//go:cgo_import_dynamic libc_mkdirat mkdirat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Mkfifo(path string, mode uint32) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_mkfifo_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_mkfifo_trampoline() - -//go:cgo_import_dynamic libc_mkfifo mkfifo "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Mknod(path string, mode uint32, dev int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_mknod_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_mknod_trampoline() - -//go:cgo_import_dynamic libc_mknod mknod "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Open(path string, mode int, perm uint32) (fd int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - r0, _, e1 := syscall_syscall(funcPC(libc_open_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_open_trampoline() - -//go:cgo_import_dynamic libc_open open "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - r0, _, e1 := syscall_syscall6(funcPC(libc_openat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_openat_trampoline() - -//go:cgo_import_dynamic libc_openat openat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Pathconf(path string, name int) (val int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - r0, _, e1 := syscall_syscall(funcPC(libc_pathconf_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) - val = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_pathconf_trampoline() - -//go:cgo_import_dynamic libc_pathconf pathconf "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Pread(fd int, p []byte, offset int64) (n int, err error) { - var _p0 unsafe.Pointer - if len(p) > 0 { - _p0 = unsafe.Pointer(&p[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := syscall_syscall6(funcPC(libc_pread_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_pread_trampoline() - -//go:cgo_import_dynamic libc_pread pread "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Pwrite(fd int, p []byte, offset int64) (n int, err error) { - var _p0 unsafe.Pointer - if len(p) > 0 { - _p0 = unsafe.Pointer(&p[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := syscall_syscall6(funcPC(libc_pwrite_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_pwrite_trampoline() - -//go:cgo_import_dynamic libc_pwrite pwrite "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func read(fd int, p []byte) (n int, err error) { - var _p0 unsafe.Pointer - if len(p) > 0 { - _p0 = unsafe.Pointer(&p[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := syscall_syscall(funcPC(libc_read_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p))) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_read_trampoline() - -//go:cgo_import_dynamic libc_read read "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Readlink(path string, buf []byte) (n int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - var _p1 unsafe.Pointer - if len(buf) > 0 { - _p1 = unsafe.Pointer(&buf[0]) - } else { - _p1 = unsafe.Pointer(&_zero) - } - r0, _, e1 := syscall_syscall(funcPC(libc_readlink_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_readlink_trampoline() - -//go:cgo_import_dynamic libc_readlink readlink "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - var _p1 unsafe.Pointer - if len(buf) > 0 { - _p1 = unsafe.Pointer(&buf[0]) - } else { - _p1 = unsafe.Pointer(&_zero) - } - r0, _, e1 := syscall_syscall6(funcPC(libc_readlinkat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_readlinkat_trampoline() - -//go:cgo_import_dynamic libc_readlinkat readlinkat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Rename(from string, to string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(from) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(to) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_rename_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_rename_trampoline() - -//go:cgo_import_dynamic libc_rename rename "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Renameat(fromfd int, from string, tofd int, to string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(from) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(to) - if err != nil { - return - } - _, _, e1 := syscall_syscall6(funcPC(libc_renameat_trampoline), uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_renameat_trampoline() - -//go:cgo_import_dynamic libc_renameat renameat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Revoke(path string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_revoke_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_revoke_trampoline() - -//go:cgo_import_dynamic libc_revoke revoke "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Rmdir(path string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_rmdir_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_rmdir_trampoline() - -//go:cgo_import_dynamic libc_rmdir rmdir "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { - r0, r1, e1 := syscall_syscall6(funcPC(libc_lseek_trampoline), uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(whence), 0, 0) - newoffset = int64(int64(r1)<<32 | int64(r0)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_lseek_trampoline() - -//go:cgo_import_dynamic libc_lseek lseek "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) { - r0, _, e1 := syscall_syscall6(funcPC(libc_select_trampoline), uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_select_trampoline() - -//go:cgo_import_dynamic libc_select select "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Setegid(egid int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_setegid_trampoline), uintptr(egid), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setegid_trampoline() - -//go:cgo_import_dynamic libc_setegid setegid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Seteuid(euid int) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_seteuid_trampoline), uintptr(euid), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_seteuid_trampoline() - -//go:cgo_import_dynamic libc_seteuid seteuid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Setgid(gid int) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setgid_trampoline), uintptr(gid), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setgid_trampoline() - -//go:cgo_import_dynamic libc_setgid setgid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Setlogin(name string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(name) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_setlogin_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setlogin_trampoline() - -//go:cgo_import_dynamic libc_setlogin setlogin "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Setpgid(pid int, pgid int) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setpgid_trampoline), uintptr(pid), uintptr(pgid), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setpgid_trampoline() - -//go:cgo_import_dynamic libc_setpgid setpgid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Setpriority(which int, who int, prio int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_setpriority_trampoline), uintptr(which), uintptr(who), uintptr(prio)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setpriority_trampoline() - -//go:cgo_import_dynamic libc_setpriority setpriority "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Setprivexec(flag int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_setprivexec_trampoline), uintptr(flag), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setprivexec_trampoline() - -//go:cgo_import_dynamic libc_setprivexec setprivexec "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Setregid(rgid int, egid int) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setregid_trampoline), uintptr(rgid), uintptr(egid), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setregid_trampoline() - -//go:cgo_import_dynamic libc_setregid setregid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Setreuid(ruid int, euid int) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setreuid_trampoline), uintptr(ruid), uintptr(euid), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setreuid_trampoline() - -//go:cgo_import_dynamic libc_setreuid setreuid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Setrlimit(which int, lim *Rlimit) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setrlimit_trampoline), uintptr(which), uintptr(unsafe.Pointer(lim)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setrlimit_trampoline() - -//go:cgo_import_dynamic libc_setrlimit setrlimit "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Setsid() (pid int, err error) { - r0, _, e1 := syscall_rawSyscall(funcPC(libc_setsid_trampoline), 0, 0, 0) - pid = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setsid_trampoline() - -//go:cgo_import_dynamic libc_setsid setsid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Settimeofday(tp *Timeval) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_settimeofday_trampoline), uintptr(unsafe.Pointer(tp)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_settimeofday_trampoline() - -//go:cgo_import_dynamic libc_settimeofday settimeofday "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Setuid(uid int) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setuid_trampoline), uintptr(uid), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_setuid_trampoline() - -//go:cgo_import_dynamic libc_setuid setuid "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Symlink(path string, link string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(link) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_symlink_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_symlink_trampoline() - -//go:cgo_import_dynamic libc_symlink symlink "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(oldpath) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(newpath) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_symlinkat_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_symlinkat_trampoline() - -//go:cgo_import_dynamic libc_symlinkat symlinkat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Sync() (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_sync_trampoline), 0, 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_sync_trampoline() - -//go:cgo_import_dynamic libc_sync sync "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Truncate(path string, length int64) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_truncate_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_truncate_trampoline() - -//go:cgo_import_dynamic libc_truncate truncate "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Umask(newmask int) (oldmask int) { - r0, _, _ := syscall_syscall(funcPC(libc_umask_trampoline), uintptr(newmask), 0, 0) - oldmask = int(r0) - return -} - -func libc_umask_trampoline() - -//go:cgo_import_dynamic libc_umask umask "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Undelete(path string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_undelete_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_undelete_trampoline() - -//go:cgo_import_dynamic libc_undelete undelete "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Unlink(path string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_unlink_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_unlink_trampoline() - -//go:cgo_import_dynamic libc_unlink unlink "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Unlinkat(dirfd int, path string, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_unlinkat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_unlinkat_trampoline() - -//go:cgo_import_dynamic libc_unlinkat unlinkat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Unmount(path string, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_unmount_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_unmount_trampoline() - -//go:cgo_import_dynamic libc_unmount unmount "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func write(fd int, p []byte) (n int, err error) { - var _p0 unsafe.Pointer - if len(p) > 0 { - _p0 = unsafe.Pointer(&p[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := syscall_syscall(funcPC(libc_write_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p))) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_write_trampoline() - -//go:cgo_import_dynamic libc_write write "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) { - r0, _, e1 := syscall_syscall9(funcPC(libc_mmap_trampoline), uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos), uintptr(pos>>32), 0, 0) - ret = uintptr(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_mmap_trampoline() - -//go:cgo_import_dynamic libc_mmap mmap "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func munmap(addr uintptr, length uintptr) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_munmap_trampoline), uintptr(addr), uintptr(length), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_munmap_trampoline() - -//go:cgo_import_dynamic libc_munmap munmap "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func readlen(fd int, buf *byte, nbuf int) (n int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_read_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func writelen(fd int, buf *byte, nbuf int) (n int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_write_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fstat(fd int, stat *Stat_t) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fstat_trampoline), uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fstat_trampoline() - -//go:cgo_import_dynamic libc_fstat fstat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall6(funcPC(libc_fstatat_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fstatat_trampoline() - -//go:cgo_import_dynamic libc_fstatat fstatat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fstatfs(fd int, stat *Statfs_t) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fstatfs_trampoline), uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_fstatfs_trampoline() - -//go:cgo_import_dynamic libc_fstatfs fstatfs "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_getfsstat_trampoline), uintptr(buf), uintptr(size), uintptr(flags)) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_getfsstat_trampoline() - -//go:cgo_import_dynamic libc_getfsstat getfsstat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Lstat(path string, stat *Stat_t) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_lstat_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_lstat_trampoline() - -//go:cgo_import_dynamic libc_lstat lstat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Stat(path string, stat *Stat_t) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_stat_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_stat_trampoline() - -//go:cgo_import_dynamic libc_stat stat "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Statfs(path string, stat *Statfs_t) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := syscall_syscall(funcPC(libc_statfs_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_statfs_trampoline() - -//go:cgo_import_dynamic libc_statfs statfs "/usr/lib/libSystem.B.dylib" diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.s b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.s deleted file mode 100644 index a99f9c1113e..00000000000 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.s +++ /dev/null @@ -1,289 +0,0 @@ -// go run mkasm_darwin.go arm -// Code generated by the command above; DO NOT EDIT. - -//go:build go1.12 -// +build go1.12 - -#include "textflag.h" -TEXT ·libc_getgroups_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getgroups(SB) -TEXT ·libc_setgroups_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setgroups(SB) -TEXT ·libc_wait4_trampoline(SB),NOSPLIT,$0-0 - JMP libc_wait4(SB) -TEXT ·libc_accept_trampoline(SB),NOSPLIT,$0-0 - JMP libc_accept(SB) -TEXT ·libc_bind_trampoline(SB),NOSPLIT,$0-0 - JMP libc_bind(SB) -TEXT ·libc_connect_trampoline(SB),NOSPLIT,$0-0 - JMP libc_connect(SB) -TEXT ·libc_socket_trampoline(SB),NOSPLIT,$0-0 - JMP libc_socket(SB) -TEXT ·libc_getsockopt_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getsockopt(SB) -TEXT ·libc_setsockopt_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setsockopt(SB) -TEXT ·libc_getpeername_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getpeername(SB) -TEXT ·libc_getsockname_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getsockname(SB) -TEXT ·libc_shutdown_trampoline(SB),NOSPLIT,$0-0 - JMP libc_shutdown(SB) -TEXT ·libc_socketpair_trampoline(SB),NOSPLIT,$0-0 - JMP libc_socketpair(SB) -TEXT ·libc_recvfrom_trampoline(SB),NOSPLIT,$0-0 - JMP libc_recvfrom(SB) -TEXT ·libc_sendto_trampoline(SB),NOSPLIT,$0-0 - JMP libc_sendto(SB) -TEXT ·libc_recvmsg_trampoline(SB),NOSPLIT,$0-0 - JMP libc_recvmsg(SB) -TEXT ·libc_sendmsg_trampoline(SB),NOSPLIT,$0-0 - JMP libc_sendmsg(SB) -TEXT ·libc_kevent_trampoline(SB),NOSPLIT,$0-0 - JMP libc_kevent(SB) -TEXT ·libc_utimes_trampoline(SB),NOSPLIT,$0-0 - JMP libc_utimes(SB) -TEXT ·libc_futimes_trampoline(SB),NOSPLIT,$0-0 - JMP libc_futimes(SB) -TEXT ·libc_poll_trampoline(SB),NOSPLIT,$0-0 - JMP libc_poll(SB) -TEXT ·libc_madvise_trampoline(SB),NOSPLIT,$0-0 - JMP libc_madvise(SB) -TEXT ·libc_mlock_trampoline(SB),NOSPLIT,$0-0 - JMP libc_mlock(SB) -TEXT ·libc_mlockall_trampoline(SB),NOSPLIT,$0-0 - JMP libc_mlockall(SB) -TEXT ·libc_mprotect_trampoline(SB),NOSPLIT,$0-0 - JMP libc_mprotect(SB) -TEXT ·libc_msync_trampoline(SB),NOSPLIT,$0-0 - JMP libc_msync(SB) -TEXT ·libc_munlock_trampoline(SB),NOSPLIT,$0-0 - JMP libc_munlock(SB) -TEXT ·libc_munlockall_trampoline(SB),NOSPLIT,$0-0 - JMP libc_munlockall(SB) -TEXT ·libc_pipe_trampoline(SB),NOSPLIT,$0-0 - JMP libc_pipe(SB) -TEXT ·libc_getxattr_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getxattr(SB) -TEXT ·libc_fgetxattr_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fgetxattr(SB) -TEXT ·libc_setxattr_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setxattr(SB) -TEXT ·libc_fsetxattr_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fsetxattr(SB) -TEXT ·libc_removexattr_trampoline(SB),NOSPLIT,$0-0 - JMP libc_removexattr(SB) -TEXT ·libc_fremovexattr_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fremovexattr(SB) -TEXT ·libc_listxattr_trampoline(SB),NOSPLIT,$0-0 - JMP libc_listxattr(SB) -TEXT ·libc_flistxattr_trampoline(SB),NOSPLIT,$0-0 - JMP libc_flistxattr(SB) -TEXT ·libc_setattrlist_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setattrlist(SB) -TEXT ·libc_fcntl_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fcntl(SB) -TEXT ·libc_kill_trampoline(SB),NOSPLIT,$0-0 - JMP libc_kill(SB) -TEXT ·libc_ioctl_trampoline(SB),NOSPLIT,$0-0 - JMP libc_ioctl(SB) -TEXT ·libc_sysctl_trampoline(SB),NOSPLIT,$0-0 - JMP libc_sysctl(SB) -TEXT ·libc_sendfile_trampoline(SB),NOSPLIT,$0-0 - JMP libc_sendfile(SB) -TEXT ·libc_access_trampoline(SB),NOSPLIT,$0-0 - JMP libc_access(SB) -TEXT ·libc_adjtime_trampoline(SB),NOSPLIT,$0-0 - JMP libc_adjtime(SB) -TEXT ·libc_chdir_trampoline(SB),NOSPLIT,$0-0 - JMP libc_chdir(SB) -TEXT ·libc_chflags_trampoline(SB),NOSPLIT,$0-0 - JMP libc_chflags(SB) -TEXT ·libc_chmod_trampoline(SB),NOSPLIT,$0-0 - JMP libc_chmod(SB) -TEXT ·libc_chown_trampoline(SB),NOSPLIT,$0-0 - JMP libc_chown(SB) -TEXT ·libc_chroot_trampoline(SB),NOSPLIT,$0-0 - JMP libc_chroot(SB) -TEXT ·libc_clock_gettime_trampoline(SB),NOSPLIT,$0-0 - JMP libc_clock_gettime(SB) -TEXT ·libc_close_trampoline(SB),NOSPLIT,$0-0 - JMP libc_close(SB) -TEXT ·libc_clonefile_trampoline(SB),NOSPLIT,$0-0 - JMP libc_clonefile(SB) -TEXT ·libc_clonefileat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_clonefileat(SB) -TEXT ·libc_dup_trampoline(SB),NOSPLIT,$0-0 - JMP libc_dup(SB) -TEXT ·libc_dup2_trampoline(SB),NOSPLIT,$0-0 - JMP libc_dup2(SB) -TEXT ·libc_exchangedata_trampoline(SB),NOSPLIT,$0-0 - JMP libc_exchangedata(SB) -TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0 - JMP libc_exit(SB) -TEXT ·libc_faccessat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_faccessat(SB) -TEXT ·libc_fchdir_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fchdir(SB) -TEXT ·libc_fchflags_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fchflags(SB) -TEXT ·libc_fchmod_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fchmod(SB) -TEXT ·libc_fchmodat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fchmodat(SB) -TEXT ·libc_fchown_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fchown(SB) -TEXT ·libc_fchownat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fchownat(SB) -TEXT ·libc_fclonefileat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fclonefileat(SB) -TEXT ·libc_flock_trampoline(SB),NOSPLIT,$0-0 - JMP libc_flock(SB) -TEXT ·libc_fpathconf_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fpathconf(SB) -TEXT ·libc_fsync_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fsync(SB) -TEXT ·libc_ftruncate_trampoline(SB),NOSPLIT,$0-0 - JMP libc_ftruncate(SB) -TEXT ·libc_getcwd_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getcwd(SB) -TEXT ·libc_getdtablesize_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getdtablesize(SB) -TEXT ·libc_getegid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getegid(SB) -TEXT ·libc_geteuid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_geteuid(SB) -TEXT ·libc_getgid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getgid(SB) -TEXT ·libc_getpgid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getpgid(SB) -TEXT ·libc_getpgrp_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getpgrp(SB) -TEXT ·libc_getpid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getpid(SB) -TEXT ·libc_getppid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getppid(SB) -TEXT ·libc_getpriority_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getpriority(SB) -TEXT ·libc_getrlimit_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getrlimit(SB) -TEXT ·libc_getrusage_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getrusage(SB) -TEXT ·libc_getsid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getsid(SB) -TEXT ·libc_gettimeofday_trampoline(SB),NOSPLIT,$0-0 - JMP libc_gettimeofday(SB) -TEXT ·libc_getuid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getuid(SB) -TEXT ·libc_issetugid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_issetugid(SB) -TEXT ·libc_kqueue_trampoline(SB),NOSPLIT,$0-0 - JMP libc_kqueue(SB) -TEXT ·libc_lchown_trampoline(SB),NOSPLIT,$0-0 - JMP libc_lchown(SB) -TEXT ·libc_link_trampoline(SB),NOSPLIT,$0-0 - JMP libc_link(SB) -TEXT ·libc_linkat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_linkat(SB) -TEXT ·libc_listen_trampoline(SB),NOSPLIT,$0-0 - JMP libc_listen(SB) -TEXT ·libc_mkdir_trampoline(SB),NOSPLIT,$0-0 - JMP libc_mkdir(SB) -TEXT ·libc_mkdirat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_mkdirat(SB) -TEXT ·libc_mkfifo_trampoline(SB),NOSPLIT,$0-0 - JMP libc_mkfifo(SB) -TEXT ·libc_mknod_trampoline(SB),NOSPLIT,$0-0 - JMP libc_mknod(SB) -TEXT ·libc_open_trampoline(SB),NOSPLIT,$0-0 - JMP libc_open(SB) -TEXT ·libc_openat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_openat(SB) -TEXT ·libc_pathconf_trampoline(SB),NOSPLIT,$0-0 - JMP libc_pathconf(SB) -TEXT ·libc_pread_trampoline(SB),NOSPLIT,$0-0 - JMP libc_pread(SB) -TEXT ·libc_pwrite_trampoline(SB),NOSPLIT,$0-0 - JMP libc_pwrite(SB) -TEXT ·libc_read_trampoline(SB),NOSPLIT,$0-0 - JMP libc_read(SB) -TEXT ·libc_readlink_trampoline(SB),NOSPLIT,$0-0 - JMP libc_readlink(SB) -TEXT ·libc_readlinkat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_readlinkat(SB) -TEXT ·libc_rename_trampoline(SB),NOSPLIT,$0-0 - JMP libc_rename(SB) -TEXT ·libc_renameat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_renameat(SB) -TEXT ·libc_revoke_trampoline(SB),NOSPLIT,$0-0 - JMP libc_revoke(SB) -TEXT ·libc_rmdir_trampoline(SB),NOSPLIT,$0-0 - JMP libc_rmdir(SB) -TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 - JMP libc_lseek(SB) -TEXT ·libc_select_trampoline(SB),NOSPLIT,$0-0 - JMP libc_select(SB) -TEXT ·libc_setegid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setegid(SB) -TEXT ·libc_seteuid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_seteuid(SB) -TEXT ·libc_setgid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setgid(SB) -TEXT ·libc_setlogin_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setlogin(SB) -TEXT ·libc_setpgid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setpgid(SB) -TEXT ·libc_setpriority_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setpriority(SB) -TEXT ·libc_setprivexec_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setprivexec(SB) -TEXT ·libc_setregid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setregid(SB) -TEXT ·libc_setreuid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setreuid(SB) -TEXT ·libc_setrlimit_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setrlimit(SB) -TEXT ·libc_setsid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setsid(SB) -TEXT ·libc_settimeofday_trampoline(SB),NOSPLIT,$0-0 - JMP libc_settimeofday(SB) -TEXT ·libc_setuid_trampoline(SB),NOSPLIT,$0-0 - JMP libc_setuid(SB) -TEXT ·libc_symlink_trampoline(SB),NOSPLIT,$0-0 - JMP libc_symlink(SB) -TEXT ·libc_symlinkat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_symlinkat(SB) -TEXT ·libc_sync_trampoline(SB),NOSPLIT,$0-0 - JMP libc_sync(SB) -TEXT ·libc_truncate_trampoline(SB),NOSPLIT,$0-0 - JMP libc_truncate(SB) -TEXT ·libc_umask_trampoline(SB),NOSPLIT,$0-0 - JMP libc_umask(SB) -TEXT ·libc_undelete_trampoline(SB),NOSPLIT,$0-0 - JMP libc_undelete(SB) -TEXT ·libc_unlink_trampoline(SB),NOSPLIT,$0-0 - JMP libc_unlink(SB) -TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_unlinkat(SB) -TEXT ·libc_unmount_trampoline(SB),NOSPLIT,$0-0 - JMP libc_unmount(SB) -TEXT ·libc_write_trampoline(SB),NOSPLIT,$0-0 - JMP libc_write(SB) -TEXT ·libc_mmap_trampoline(SB),NOSPLIT,$0-0 - JMP libc_mmap(SB) -TEXT ·libc_munmap_trampoline(SB),NOSPLIT,$0-0 - JMP libc_munmap(SB) -TEXT ·libc_fstat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fstat(SB) -TEXT ·libc_fstatat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fstatat(SB) -TEXT ·libc_fstatfs_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fstatfs(SB) -TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_getfsstat(SB) -TEXT ·libc_lstat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_lstat(SB) -TEXT ·libc_stat_trampoline(SB),NOSPLIT,$0-0 - JMP libc_stat(SB) -TEXT ·libc_statfs_trampoline(SB),NOSPLIT,$0-0 - JMP libc_statfs(SB) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.go index d30ec4e29a0..cec595d553a 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.go @@ -16,25 +16,25 @@ var _ syscall.Errno // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func closedir(dir uintptr) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_closedir_trampoline), uintptr(dir), 0, 0) + _, _, e1 := syscall_syscall(libc_closedir_trampoline_addr, uintptr(dir), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_closedir_trampoline() +var libc_closedir_trampoline_addr uintptr //go:cgo_import_dynamic libc_closedir closedir "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno) { - r0, _, _ := syscall_syscall(funcPC(libc_readdir_r_trampoline), uintptr(dir), uintptr(unsafe.Pointer(entry)), uintptr(unsafe.Pointer(result))) + r0, _, _ := syscall_syscall(libc_readdir_r_trampoline_addr, uintptr(dir), uintptr(unsafe.Pointer(entry)), uintptr(unsafe.Pointer(result))) res = Errno(r0) return } -func libc_readdir_r_trampoline() +var libc_readdir_r_trampoline_addr uintptr //go:cgo_import_dynamic libc_readdir_r readdir_r "/usr/lib/libSystem.B.dylib" diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.s b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.s index a5f96ffb07d..357989722cf 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.s +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.s @@ -5,9 +5,21 @@ // +build go1.13 #include "textflag.h" -TEXT ·libc_fdopendir_trampoline(SB),NOSPLIT,$0-0 + +TEXT libc_fdopendir_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fdopendir(SB) -TEXT ·libc_closedir_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fdopendir_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fdopendir_trampoline_addr(SB)/8, $libc_fdopendir_trampoline<>(SB) + +TEXT libc_closedir_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_closedir(SB) -TEXT ·libc_readdir_r_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_closedir_trampoline_addr(SB), RODATA, $8 +DATA ·libc_closedir_trampoline_addr(SB)/8, $libc_closedir_trampoline<>(SB) + +TEXT libc_readdir_r_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_readdir_r(SB) + +GLOBL ·libc_readdir_r_trampoline_addr(SB), RODATA, $8 +DATA ·libc_readdir_r_trampoline_addr(SB)/8, $libc_readdir_r_trampoline<>(SB) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go index a10df58d00e..f2ee2bd33b9 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go @@ -16,7 +16,7 @@ var _ syscall.Errno // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getgroups(ngid int, gid *_Gid_t) (n int, err error) { - r0, _, e1 := syscall_rawSyscall(funcPC(libc_getgroups_trampoline), uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + r0, _, e1 := syscall_rawSyscall(libc_getgroups_trampoline_addr, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -24,28 +24,28 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) { return } -func libc_getgroups_trampoline() +var libc_getgroups_trampoline_addr uintptr //go:cgo_import_dynamic libc_getgroups getgroups "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func setgroups(ngid int, gid *_Gid_t) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setgroups_trampoline), uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + _, _, e1 := syscall_rawSyscall(libc_setgroups_trampoline_addr, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setgroups_trampoline() +var libc_setgroups_trampoline_addr uintptr //go:cgo_import_dynamic libc_setgroups setgroups "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) { - r0, _, e1 := syscall_syscall6(funcPC(libc_wait4_trampoline), uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) + r0, _, e1 := syscall_syscall6(libc_wait4_trampoline_addr, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) wpid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -53,14 +53,14 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err return } -func libc_wait4_trampoline() +var libc_wait4_trampoline_addr uintptr //go:cgo_import_dynamic libc_wait4 wait4 "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_accept_trampoline), uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + r0, _, e1 := syscall_syscall(libc_accept_trampoline_addr, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -68,42 +68,42 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { return } -func libc_accept_trampoline() +var libc_accept_trampoline_addr uintptr //go:cgo_import_dynamic libc_accept accept "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_bind_trampoline), uintptr(s), uintptr(addr), uintptr(addrlen)) + _, _, e1 := syscall_syscall(libc_bind_trampoline_addr, uintptr(s), uintptr(addr), uintptr(addrlen)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_bind_trampoline() +var libc_bind_trampoline_addr uintptr //go:cgo_import_dynamic libc_bind bind "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_connect_trampoline), uintptr(s), uintptr(addr), uintptr(addrlen)) + _, _, e1 := syscall_syscall(libc_connect_trampoline_addr, uintptr(s), uintptr(addr), uintptr(addrlen)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_connect_trampoline() +var libc_connect_trampoline_addr uintptr //go:cgo_import_dynamic libc_connect connect "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func socket(domain int, typ int, proto int) (fd int, err error) { - r0, _, e1 := syscall_rawSyscall(funcPC(libc_socket_trampoline), uintptr(domain), uintptr(typ), uintptr(proto)) + r0, _, e1 := syscall_rawSyscall(libc_socket_trampoline_addr, uintptr(domain), uintptr(typ), uintptr(proto)) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -111,91 +111,91 @@ func socket(domain int, typ int, proto int) (fd int, err error) { return } -func libc_socket_trampoline() +var libc_socket_trampoline_addr uintptr //go:cgo_import_dynamic libc_socket socket "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) { - _, _, e1 := syscall_syscall6(funcPC(libc_getsockopt_trampoline), uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) + _, _, e1 := syscall_syscall6(libc_getsockopt_trampoline_addr, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_getsockopt_trampoline() +var libc_getsockopt_trampoline_addr uintptr //go:cgo_import_dynamic libc_getsockopt getsockopt "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { - _, _, e1 := syscall_syscall6(funcPC(libc_setsockopt_trampoline), uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) + _, _, e1 := syscall_syscall6(libc_setsockopt_trampoline_addr, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setsockopt_trampoline() +var libc_setsockopt_trampoline_addr uintptr //go:cgo_import_dynamic libc_setsockopt setsockopt "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_getpeername_trampoline), uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + _, _, e1 := syscall_rawSyscall(libc_getpeername_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) if e1 != 0 { err = errnoErr(e1) } return } -func libc_getpeername_trampoline() +var libc_getpeername_trampoline_addr uintptr //go:cgo_import_dynamic libc_getpeername getpeername "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_getsockname_trampoline), uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + _, _, e1 := syscall_rawSyscall(libc_getsockname_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) if e1 != 0 { err = errnoErr(e1) } return } -func libc_getsockname_trampoline() +var libc_getsockname_trampoline_addr uintptr //go:cgo_import_dynamic libc_getsockname getsockname "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Shutdown(s int, how int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_shutdown_trampoline), uintptr(s), uintptr(how), 0) + _, _, e1 := syscall_syscall(libc_shutdown_trampoline_addr, uintptr(s), uintptr(how), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_shutdown_trampoline() +var libc_shutdown_trampoline_addr uintptr //go:cgo_import_dynamic libc_shutdown shutdown "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) { - _, _, e1 := syscall_rawSyscall6(funcPC(libc_socketpair_trampoline), uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) + _, _, e1 := syscall_rawSyscall6(libc_socketpair_trampoline_addr, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_socketpair_trampoline() +var libc_socketpair_trampoline_addr uintptr //go:cgo_import_dynamic libc_socketpair socketpair "/usr/lib/libSystem.B.dylib" @@ -208,7 +208,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := syscall_syscall6(funcPC(libc_recvfrom_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) + r0, _, e1 := syscall_syscall6(libc_recvfrom_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -216,7 +216,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl return } -func libc_recvfrom_trampoline() +var libc_recvfrom_trampoline_addr uintptr //go:cgo_import_dynamic libc_recvfrom recvfrom "/usr/lib/libSystem.B.dylib" @@ -229,21 +229,21 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) ( } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := syscall_syscall6(funcPC(libc_sendto_trampoline), uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) + _, _, e1 := syscall_syscall6(libc_sendto_trampoline_addr, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_sendto_trampoline() +var libc_sendto_trampoline_addr uintptr //go:cgo_import_dynamic libc_sendto sendto "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_recvmsg_trampoline), uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + r0, _, e1 := syscall_syscall(libc_recvmsg_trampoline_addr, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -251,14 +251,14 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { return } -func libc_recvmsg_trampoline() +var libc_recvmsg_trampoline_addr uintptr //go:cgo_import_dynamic libc_recvmsg recvmsg "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_sendmsg_trampoline), uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + r0, _, e1 := syscall_syscall(libc_sendmsg_trampoline_addr, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -266,14 +266,14 @@ func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { return } -func libc_sendmsg_trampoline() +var libc_sendmsg_trampoline_addr uintptr //go:cgo_import_dynamic libc_sendmsg sendmsg "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) { - r0, _, e1 := syscall_syscall6(funcPC(libc_kevent_trampoline), uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))) + r0, _, e1 := syscall_syscall6(libc_kevent_trampoline_addr, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -281,7 +281,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne return } -func libc_kevent_trampoline() +var libc_kevent_trampoline_addr uintptr //go:cgo_import_dynamic libc_kevent kevent "/usr/lib/libSystem.B.dylib" @@ -293,35 +293,35 @@ func utimes(path string, timeval *[2]Timeval) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_utimes_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + _, _, e1 := syscall_syscall(libc_utimes_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_utimes_trampoline() +var libc_utimes_trampoline_addr uintptr //go:cgo_import_dynamic libc_utimes utimes "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func futimes(fd int, timeval *[2]Timeval) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_futimes_trampoline), uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0) + _, _, e1 := syscall_syscall(libc_futimes_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_futimes_trampoline() +var libc_futimes_trampoline_addr uintptr //go:cgo_import_dynamic libc_futimes futimes "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_poll_trampoline), uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) + r0, _, e1 := syscall_syscall(libc_poll_trampoline_addr, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -329,7 +329,7 @@ func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { return } -func libc_poll_trampoline() +var libc_poll_trampoline_addr uintptr //go:cgo_import_dynamic libc_poll poll "/usr/lib/libSystem.B.dylib" @@ -342,14 +342,14 @@ func Madvise(b []byte, behav int) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := syscall_syscall(funcPC(libc_madvise_trampoline), uintptr(_p0), uintptr(len(b)), uintptr(behav)) + _, _, e1 := syscall_syscall(libc_madvise_trampoline_addr, uintptr(_p0), uintptr(len(b)), uintptr(behav)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_madvise_trampoline() +var libc_madvise_trampoline_addr uintptr //go:cgo_import_dynamic libc_madvise madvise "/usr/lib/libSystem.B.dylib" @@ -362,28 +362,28 @@ func Mlock(b []byte) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := syscall_syscall(funcPC(libc_mlock_trampoline), uintptr(_p0), uintptr(len(b)), 0) + _, _, e1 := syscall_syscall(libc_mlock_trampoline_addr, uintptr(_p0), uintptr(len(b)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_mlock_trampoline() +var libc_mlock_trampoline_addr uintptr //go:cgo_import_dynamic libc_mlock mlock "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mlockall(flags int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_mlockall_trampoline), uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall(libc_mlockall_trampoline_addr, uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_mlockall_trampoline() +var libc_mlockall_trampoline_addr uintptr //go:cgo_import_dynamic libc_mlockall mlockall "/usr/lib/libSystem.B.dylib" @@ -396,14 +396,14 @@ func Mprotect(b []byte, prot int) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := syscall_syscall(funcPC(libc_mprotect_trampoline), uintptr(_p0), uintptr(len(b)), uintptr(prot)) + _, _, e1 := syscall_syscall(libc_mprotect_trampoline_addr, uintptr(_p0), uintptr(len(b)), uintptr(prot)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_mprotect_trampoline() +var libc_mprotect_trampoline_addr uintptr //go:cgo_import_dynamic libc_mprotect mprotect "/usr/lib/libSystem.B.dylib" @@ -416,14 +416,14 @@ func Msync(b []byte, flags int) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := syscall_syscall(funcPC(libc_msync_trampoline), uintptr(_p0), uintptr(len(b)), uintptr(flags)) + _, _, e1 := syscall_syscall(libc_msync_trampoline_addr, uintptr(_p0), uintptr(len(b)), uintptr(flags)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_msync_trampoline() +var libc_msync_trampoline_addr uintptr //go:cgo_import_dynamic libc_msync msync "/usr/lib/libSystem.B.dylib" @@ -436,42 +436,42 @@ func Munlock(b []byte) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := syscall_syscall(funcPC(libc_munlock_trampoline), uintptr(_p0), uintptr(len(b)), 0) + _, _, e1 := syscall_syscall(libc_munlock_trampoline_addr, uintptr(_p0), uintptr(len(b)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_munlock_trampoline() +var libc_munlock_trampoline_addr uintptr //go:cgo_import_dynamic libc_munlock munlock "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Munlockall() (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_munlockall_trampoline), 0, 0, 0) + _, _, e1 := syscall_syscall(libc_munlockall_trampoline_addr, 0, 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_munlockall_trampoline() +var libc_munlockall_trampoline_addr uintptr //go:cgo_import_dynamic libc_munlockall munlockall "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func pipe(p *[2]int32) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_pipe_trampoline), uintptr(unsafe.Pointer(p)), 0, 0) + _, _, e1 := syscall_rawSyscall(libc_pipe_trampoline_addr, uintptr(unsafe.Pointer(p)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_pipe_trampoline() +var libc_pipe_trampoline_addr uintptr //go:cgo_import_dynamic libc_pipe pipe "/usr/lib/libSystem.B.dylib" @@ -488,7 +488,7 @@ func getxattr(path string, attr string, dest *byte, size int, position uint32, o if err != nil { return } - r0, _, e1 := syscall_syscall6(funcPC(libc_getxattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) + r0, _, e1 := syscall_syscall6(libc_getxattr_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) sz = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -496,7 +496,7 @@ func getxattr(path string, attr string, dest *byte, size int, position uint32, o return } -func libc_getxattr_trampoline() +var libc_getxattr_trampoline_addr uintptr //go:cgo_import_dynamic libc_getxattr getxattr "/usr/lib/libSystem.B.dylib" @@ -508,7 +508,7 @@ func fgetxattr(fd int, attr string, dest *byte, size int, position uint32, optio if err != nil { return } - r0, _, e1 := syscall_syscall6(funcPC(libc_fgetxattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) + r0, _, e1 := syscall_syscall6(libc_fgetxattr_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) sz = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -516,7 +516,7 @@ func fgetxattr(fd int, attr string, dest *byte, size int, position uint32, optio return } -func libc_fgetxattr_trampoline() +var libc_fgetxattr_trampoline_addr uintptr //go:cgo_import_dynamic libc_fgetxattr fgetxattr "/usr/lib/libSystem.B.dylib" @@ -533,14 +533,14 @@ func setxattr(path string, attr string, data *byte, size int, position uint32, o if err != nil { return } - _, _, e1 := syscall_syscall6(funcPC(libc_setxattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) + _, _, e1 := syscall_syscall6(libc_setxattr_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setxattr_trampoline() +var libc_setxattr_trampoline_addr uintptr //go:cgo_import_dynamic libc_setxattr setxattr "/usr/lib/libSystem.B.dylib" @@ -552,14 +552,14 @@ func fsetxattr(fd int, attr string, data *byte, size int, position uint32, optio if err != nil { return } - _, _, e1 := syscall_syscall6(funcPC(libc_fsetxattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) + _, _, e1 := syscall_syscall6(libc_fsetxattr_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fsetxattr_trampoline() +var libc_fsetxattr_trampoline_addr uintptr //go:cgo_import_dynamic libc_fsetxattr fsetxattr "/usr/lib/libSystem.B.dylib" @@ -576,14 +576,14 @@ func removexattr(path string, attr string, options int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_removexattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) + _, _, e1 := syscall_syscall(libc_removexattr_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_removexattr_trampoline() +var libc_removexattr_trampoline_addr uintptr //go:cgo_import_dynamic libc_removexattr removexattr "/usr/lib/libSystem.B.dylib" @@ -595,14 +595,14 @@ func fremovexattr(fd int, attr string, options int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_fremovexattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(options)) + _, _, e1 := syscall_syscall(libc_fremovexattr_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(options)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fremovexattr_trampoline() +var libc_fremovexattr_trampoline_addr uintptr //go:cgo_import_dynamic libc_fremovexattr fremovexattr "/usr/lib/libSystem.B.dylib" @@ -614,7 +614,7 @@ func listxattr(path string, dest *byte, size int, options int) (sz int, err erro if err != nil { return } - r0, _, e1 := syscall_syscall6(funcPC(libc_listxattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) + r0, _, e1 := syscall_syscall6(libc_listxattr_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) sz = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -622,14 +622,14 @@ func listxattr(path string, dest *byte, size int, options int) (sz int, err erro return } -func libc_listxattr_trampoline() +var libc_listxattr_trampoline_addr uintptr //go:cgo_import_dynamic libc_listxattr listxattr "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func flistxattr(fd int, dest *byte, size int, options int) (sz int, err error) { - r0, _, e1 := syscall_syscall6(funcPC(libc_flistxattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) + r0, _, e1 := syscall_syscall6(libc_flistxattr_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) sz = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -637,28 +637,28 @@ func flistxattr(fd int, dest *byte, size int, options int) (sz int, err error) { return } -func libc_flistxattr_trampoline() +var libc_flistxattr_trampoline_addr uintptr //go:cgo_import_dynamic libc_flistxattr flistxattr "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func setattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) { - _, _, e1 := syscall_syscall6(funcPC(libc_setattrlist_trampoline), uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) + _, _, e1 := syscall_syscall6(libc_setattrlist_trampoline_addr, uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setattrlist_trampoline() +var libc_setattrlist_trampoline_addr uintptr //go:cgo_import_dynamic libc_setattrlist setattrlist "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func fcntl(fd int, cmd int, arg int) (val int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_fcntl_trampoline), uintptr(fd), uintptr(cmd), uintptr(arg)) + r0, _, e1 := syscall_syscall(libc_fcntl_trampoline_addr, uintptr(fd), uintptr(cmd), uintptr(arg)) val = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -666,35 +666,35 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) { return } -func libc_fcntl_trampoline() +var libc_fcntl_trampoline_addr uintptr //go:cgo_import_dynamic libc_fcntl fcntl "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func kill(pid int, signum int, posix int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_kill_trampoline), uintptr(pid), uintptr(signum), uintptr(posix)) + _, _, e1 := syscall_syscall(libc_kill_trampoline_addr, uintptr(pid), uintptr(signum), uintptr(posix)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_kill_trampoline() +var libc_kill_trampoline_addr uintptr //go:cgo_import_dynamic libc_kill kill "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func ioctl(fd int, req uint, arg uintptr) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_ioctl_trampoline), uintptr(fd), uintptr(req), uintptr(arg)) + _, _, e1 := syscall_syscall(libc_ioctl_trampoline_addr, uintptr(fd), uintptr(req), uintptr(arg)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_ioctl_trampoline() +var libc_ioctl_trampoline_addr uintptr //go:cgo_import_dynamic libc_ioctl ioctl "/usr/lib/libSystem.B.dylib" @@ -707,28 +707,28 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := syscall_syscall6(funcPC(libc_sysctl_trampoline), uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + _, _, e1 := syscall_syscall6(libc_sysctl_trampoline_addr, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_sysctl_trampoline() +var libc_sysctl_trampoline_addr uintptr //go:cgo_import_dynamic libc_sysctl sysctl "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) { - _, _, e1 := syscall_syscall6(funcPC(libc_sendfile_trampoline), uintptr(infd), uintptr(outfd), uintptr(offset), uintptr(unsafe.Pointer(len)), uintptr(hdtr), uintptr(flags)) + _, _, e1 := syscall_syscall6(libc_sendfile_trampoline_addr, uintptr(infd), uintptr(outfd), uintptr(offset), uintptr(unsafe.Pointer(len)), uintptr(hdtr), uintptr(flags)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_sendfile_trampoline() +var libc_sendfile_trampoline_addr uintptr //go:cgo_import_dynamic libc_sendfile sendfile "/usr/lib/libSystem.B.dylib" @@ -740,28 +740,28 @@ func Access(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_access_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(libc_access_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_access_trampoline() +var libc_access_trampoline_addr uintptr //go:cgo_import_dynamic libc_access access "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Adjtime(delta *Timeval, olddelta *Timeval) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_adjtime_trampoline), uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0) + _, _, e1 := syscall_syscall(libc_adjtime_trampoline_addr, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_adjtime_trampoline() +var libc_adjtime_trampoline_addr uintptr //go:cgo_import_dynamic libc_adjtime adjtime "/usr/lib/libSystem.B.dylib" @@ -773,14 +773,14 @@ func Chdir(path string) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_chdir_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(libc_chdir_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_chdir_trampoline() +var libc_chdir_trampoline_addr uintptr //go:cgo_import_dynamic libc_chdir chdir "/usr/lib/libSystem.B.dylib" @@ -792,14 +792,14 @@ func Chflags(path string, flags int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_chflags_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + _, _, e1 := syscall_syscall(libc_chflags_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_chflags_trampoline() +var libc_chflags_trampoline_addr uintptr //go:cgo_import_dynamic libc_chflags chflags "/usr/lib/libSystem.B.dylib" @@ -811,14 +811,14 @@ func Chmod(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_chmod_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(libc_chmod_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_chmod_trampoline() +var libc_chmod_trampoline_addr uintptr //go:cgo_import_dynamic libc_chmod chmod "/usr/lib/libSystem.B.dylib" @@ -830,14 +830,14 @@ func Chown(path string, uid int, gid int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_chown_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + _, _, e1 := syscall_syscall(libc_chown_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_chown_trampoline() +var libc_chown_trampoline_addr uintptr //go:cgo_import_dynamic libc_chown chown "/usr/lib/libSystem.B.dylib" @@ -849,42 +849,42 @@ func Chroot(path string) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_chroot_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(libc_chroot_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_chroot_trampoline() +var libc_chroot_trampoline_addr uintptr //go:cgo_import_dynamic libc_chroot chroot "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func ClockGettime(clockid int32, time *Timespec) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_clock_gettime_trampoline), uintptr(clockid), uintptr(unsafe.Pointer(time)), 0) + _, _, e1 := syscall_syscall(libc_clock_gettime_trampoline_addr, uintptr(clockid), uintptr(unsafe.Pointer(time)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_clock_gettime_trampoline() +var libc_clock_gettime_trampoline_addr uintptr //go:cgo_import_dynamic libc_clock_gettime clock_gettime "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Close(fd int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_close_trampoline), uintptr(fd), 0, 0) + _, _, e1 := syscall_syscall(libc_close_trampoline_addr, uintptr(fd), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_close_trampoline() +var libc_close_trampoline_addr uintptr //go:cgo_import_dynamic libc_close close "/usr/lib/libSystem.B.dylib" @@ -901,14 +901,14 @@ func Clonefile(src string, dst string, flags int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_clonefile_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flags)) + _, _, e1 := syscall_syscall(libc_clonefile_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flags)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_clonefile_trampoline() +var libc_clonefile_trampoline_addr uintptr //go:cgo_import_dynamic libc_clonefile clonefile "/usr/lib/libSystem.B.dylib" @@ -925,21 +925,21 @@ func Clonefileat(srcDirfd int, src string, dstDirfd int, dst string, flags int) if err != nil { return } - _, _, e1 := syscall_syscall6(funcPC(libc_clonefileat_trampoline), uintptr(srcDirfd), uintptr(unsafe.Pointer(_p0)), uintptr(dstDirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + _, _, e1 := syscall_syscall6(libc_clonefileat_trampoline_addr, uintptr(srcDirfd), uintptr(unsafe.Pointer(_p0)), uintptr(dstDirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_clonefileat_trampoline() +var libc_clonefileat_trampoline_addr uintptr //go:cgo_import_dynamic libc_clonefileat clonefileat "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Dup(fd int) (nfd int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_dup_trampoline), uintptr(fd), 0, 0) + r0, _, e1 := syscall_syscall(libc_dup_trampoline_addr, uintptr(fd), 0, 0) nfd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -947,21 +947,21 @@ func Dup(fd int) (nfd int, err error) { return } -func libc_dup_trampoline() +var libc_dup_trampoline_addr uintptr //go:cgo_import_dynamic libc_dup dup "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Dup2(from int, to int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_dup2_trampoline), uintptr(from), uintptr(to), 0) + _, _, e1 := syscall_syscall(libc_dup2_trampoline_addr, uintptr(from), uintptr(to), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_dup2_trampoline() +var libc_dup2_trampoline_addr uintptr //go:cgo_import_dynamic libc_dup2 dup2 "/usr/lib/libSystem.B.dylib" @@ -978,25 +978,25 @@ func Exchangedata(path1 string, path2 string, options int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_exchangedata_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) + _, _, e1 := syscall_syscall(libc_exchangedata_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_exchangedata_trampoline() +var libc_exchangedata_trampoline_addr uintptr //go:cgo_import_dynamic libc_exchangedata exchangedata "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Exit(code int) { - syscall_syscall(funcPC(libc_exit_trampoline), uintptr(code), 0, 0) + syscall_syscall(libc_exit_trampoline_addr, uintptr(code), 0, 0) return } -func libc_exit_trampoline() +var libc_exit_trampoline_addr uintptr //go:cgo_import_dynamic libc_exit exit "/usr/lib/libSystem.B.dylib" @@ -1008,56 +1008,56 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall6(funcPC(libc_faccessat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall6(libc_faccessat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_faccessat_trampoline() +var libc_faccessat_trampoline_addr uintptr //go:cgo_import_dynamic libc_faccessat faccessat "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchdir(fd int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fchdir_trampoline), uintptr(fd), 0, 0) + _, _, e1 := syscall_syscall(libc_fchdir_trampoline_addr, uintptr(fd), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fchdir_trampoline() +var libc_fchdir_trampoline_addr uintptr //go:cgo_import_dynamic libc_fchdir fchdir "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchflags(fd int, flags int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fchflags_trampoline), uintptr(fd), uintptr(flags), 0) + _, _, e1 := syscall_syscall(libc_fchflags_trampoline_addr, uintptr(fd), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fchflags_trampoline() +var libc_fchflags_trampoline_addr uintptr //go:cgo_import_dynamic libc_fchflags fchflags "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchmod(fd int, mode uint32) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fchmod_trampoline), uintptr(fd), uintptr(mode), 0) + _, _, e1 := syscall_syscall(libc_fchmod_trampoline_addr, uintptr(fd), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fchmod_trampoline() +var libc_fchmod_trampoline_addr uintptr //go:cgo_import_dynamic libc_fchmod fchmod "/usr/lib/libSystem.B.dylib" @@ -1069,28 +1069,28 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall6(funcPC(libc_fchmodat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall6(libc_fchmodat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fchmodat_trampoline() +var libc_fchmodat_trampoline_addr uintptr //go:cgo_import_dynamic libc_fchmodat fchmodat "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchown(fd int, uid int, gid int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fchown_trampoline), uintptr(fd), uintptr(uid), uintptr(gid)) + _, _, e1 := syscall_syscall(libc_fchown_trampoline_addr, uintptr(fd), uintptr(uid), uintptr(gid)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fchown_trampoline() +var libc_fchown_trampoline_addr uintptr //go:cgo_import_dynamic libc_fchown fchown "/usr/lib/libSystem.B.dylib" @@ -1102,14 +1102,14 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall6(funcPC(libc_fchownat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + _, _, e1 := syscall_syscall6(libc_fchownat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fchownat_trampoline() +var libc_fchownat_trampoline_addr uintptr //go:cgo_import_dynamic libc_fchownat fchownat "/usr/lib/libSystem.B.dylib" @@ -1121,35 +1121,35 @@ func Fclonefileat(srcDirfd int, dstDirfd int, dst string, flags int) (err error) if err != nil { return } - _, _, e1 := syscall_syscall6(funcPC(libc_fclonefileat_trampoline), uintptr(srcDirfd), uintptr(dstDirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall6(libc_fclonefileat_trampoline_addr, uintptr(srcDirfd), uintptr(dstDirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fclonefileat_trampoline() +var libc_fclonefileat_trampoline_addr uintptr //go:cgo_import_dynamic libc_fclonefileat fclonefileat "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Flock(fd int, how int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_flock_trampoline), uintptr(fd), uintptr(how), 0) + _, _, e1 := syscall_syscall(libc_flock_trampoline_addr, uintptr(fd), uintptr(how), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_flock_trampoline() +var libc_flock_trampoline_addr uintptr //go:cgo_import_dynamic libc_flock flock "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fpathconf(fd int, name int) (val int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_fpathconf_trampoline), uintptr(fd), uintptr(name), 0) + r0, _, e1 := syscall_syscall(libc_fpathconf_trampoline_addr, uintptr(fd), uintptr(name), 0) val = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1157,35 +1157,35 @@ func Fpathconf(fd int, name int) (val int, err error) { return } -func libc_fpathconf_trampoline() +var libc_fpathconf_trampoline_addr uintptr //go:cgo_import_dynamic libc_fpathconf fpathconf "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fsync(fd int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fsync_trampoline), uintptr(fd), 0, 0) + _, _, e1 := syscall_syscall(libc_fsync_trampoline_addr, uintptr(fd), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fsync_trampoline() +var libc_fsync_trampoline_addr uintptr //go:cgo_import_dynamic libc_fsync fsync "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Ftruncate(fd int, length int64) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_ftruncate_trampoline), uintptr(fd), uintptr(length), 0) + _, _, e1 := syscall_syscall(libc_ftruncate_trampoline_addr, uintptr(fd), uintptr(length), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_ftruncate_trampoline() +var libc_ftruncate_trampoline_addr uintptr //go:cgo_import_dynamic libc_ftruncate ftruncate "/usr/lib/libSystem.B.dylib" @@ -1198,7 +1198,7 @@ func Getcwd(buf []byte) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := syscall_syscall(funcPC(libc_getcwd_trampoline), uintptr(_p0), uintptr(len(buf)), 0) + r0, _, e1 := syscall_syscall(libc_getcwd_trampoline_addr, uintptr(_p0), uintptr(len(buf)), 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1206,62 +1206,62 @@ func Getcwd(buf []byte) (n int, err error) { return } -func libc_getcwd_trampoline() +var libc_getcwd_trampoline_addr uintptr //go:cgo_import_dynamic libc_getcwd getcwd "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getdtablesize() (size int) { - r0, _, _ := syscall_syscall(funcPC(libc_getdtablesize_trampoline), 0, 0, 0) + r0, _, _ := syscall_syscall(libc_getdtablesize_trampoline_addr, 0, 0, 0) size = int(r0) return } -func libc_getdtablesize_trampoline() +var libc_getdtablesize_trampoline_addr uintptr //go:cgo_import_dynamic libc_getdtablesize getdtablesize "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getegid() (egid int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_getegid_trampoline), 0, 0, 0) + r0, _, _ := syscall_rawSyscall(libc_getegid_trampoline_addr, 0, 0, 0) egid = int(r0) return } -func libc_getegid_trampoline() +var libc_getegid_trampoline_addr uintptr //go:cgo_import_dynamic libc_getegid getegid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (uid int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_geteuid_trampoline), 0, 0, 0) + r0, _, _ := syscall_rawSyscall(libc_geteuid_trampoline_addr, 0, 0, 0) uid = int(r0) return } -func libc_geteuid_trampoline() +var libc_geteuid_trampoline_addr uintptr //go:cgo_import_dynamic libc_geteuid geteuid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_getgid_trampoline), 0, 0, 0) + r0, _, _ := syscall_rawSyscall(libc_getgid_trampoline_addr, 0, 0, 0) gid = int(r0) return } -func libc_getgid_trampoline() +var libc_getgid_trampoline_addr uintptr //go:cgo_import_dynamic libc_getgid getgid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpgid(pid int) (pgid int, err error) { - r0, _, e1 := syscall_rawSyscall(funcPC(libc_getpgid_trampoline), uintptr(pid), 0, 0) + r0, _, e1 := syscall_rawSyscall(libc_getpgid_trampoline_addr, uintptr(pid), 0, 0) pgid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1269,50 +1269,50 @@ func Getpgid(pid int) (pgid int, err error) { return } -func libc_getpgid_trampoline() +var libc_getpgid_trampoline_addr uintptr //go:cgo_import_dynamic libc_getpgid getpgid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpgrp() (pgrp int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_getpgrp_trampoline), 0, 0, 0) + r0, _, _ := syscall_rawSyscall(libc_getpgrp_trampoline_addr, 0, 0, 0) pgrp = int(r0) return } -func libc_getpgrp_trampoline() +var libc_getpgrp_trampoline_addr uintptr //go:cgo_import_dynamic libc_getpgrp getpgrp "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_getpid_trampoline), 0, 0, 0) + r0, _, _ := syscall_rawSyscall(libc_getpid_trampoline_addr, 0, 0, 0) pid = int(r0) return } -func libc_getpid_trampoline() +var libc_getpid_trampoline_addr uintptr //go:cgo_import_dynamic libc_getpid getpid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_getppid_trampoline), 0, 0, 0) + r0, _, _ := syscall_rawSyscall(libc_getppid_trampoline_addr, 0, 0, 0) ppid = int(r0) return } -func libc_getppid_trampoline() +var libc_getppid_trampoline_addr uintptr //go:cgo_import_dynamic libc_getppid getppid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpriority(which int, who int) (prio int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_getpriority_trampoline), uintptr(which), uintptr(who), 0) + r0, _, e1 := syscall_syscall(libc_getpriority_trampoline_addr, uintptr(which), uintptr(who), 0) prio = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1320,42 +1320,42 @@ func Getpriority(which int, who int) (prio int, err error) { return } -func libc_getpriority_trampoline() +var libc_getpriority_trampoline_addr uintptr //go:cgo_import_dynamic libc_getpriority getpriority "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getrlimit(which int, lim *Rlimit) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_getrlimit_trampoline), uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + _, _, e1 := syscall_rawSyscall(libc_getrlimit_trampoline_addr, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_getrlimit_trampoline() +var libc_getrlimit_trampoline_addr uintptr //go:cgo_import_dynamic libc_getrlimit getrlimit "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getrusage(who int, rusage *Rusage) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_getrusage_trampoline), uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) + _, _, e1 := syscall_rawSyscall(libc_getrusage_trampoline_addr, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_getrusage_trampoline() +var libc_getrusage_trampoline_addr uintptr //go:cgo_import_dynamic libc_getrusage getrusage "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getsid(pid int) (sid int, err error) { - r0, _, e1 := syscall_rawSyscall(funcPC(libc_getsid_trampoline), uintptr(pid), 0, 0) + r0, _, e1 := syscall_rawSyscall(libc_getsid_trampoline_addr, uintptr(pid), 0, 0) sid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1363,52 +1363,52 @@ func Getsid(pid int) (sid int, err error) { return } -func libc_getsid_trampoline() +var libc_getsid_trampoline_addr uintptr //go:cgo_import_dynamic libc_getsid getsid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Gettimeofday(tp *Timeval) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_gettimeofday_trampoline), uintptr(unsafe.Pointer(tp)), 0, 0) + _, _, e1 := syscall_rawSyscall(libc_gettimeofday_trampoline_addr, uintptr(unsafe.Pointer(tp)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_gettimeofday_trampoline() +var libc_gettimeofday_trampoline_addr uintptr //go:cgo_import_dynamic libc_gettimeofday gettimeofday "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_getuid_trampoline), 0, 0, 0) + r0, _, _ := syscall_rawSyscall(libc_getuid_trampoline_addr, 0, 0, 0) uid = int(r0) return } -func libc_getuid_trampoline() +var libc_getuid_trampoline_addr uintptr //go:cgo_import_dynamic libc_getuid getuid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Issetugid() (tainted bool) { - r0, _, _ := syscall_rawSyscall(funcPC(libc_issetugid_trampoline), 0, 0, 0) + r0, _, _ := syscall_rawSyscall(libc_issetugid_trampoline_addr, 0, 0, 0) tainted = bool(r0 != 0) return } -func libc_issetugid_trampoline() +var libc_issetugid_trampoline_addr uintptr //go:cgo_import_dynamic libc_issetugid issetugid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Kqueue() (fd int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_kqueue_trampoline), 0, 0, 0) + r0, _, e1 := syscall_syscall(libc_kqueue_trampoline_addr, 0, 0, 0) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1416,7 +1416,7 @@ func Kqueue() (fd int, err error) { return } -func libc_kqueue_trampoline() +var libc_kqueue_trampoline_addr uintptr //go:cgo_import_dynamic libc_kqueue kqueue "/usr/lib/libSystem.B.dylib" @@ -1428,14 +1428,14 @@ func Lchown(path string, uid int, gid int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_lchown_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + _, _, e1 := syscall_syscall(libc_lchown_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_lchown_trampoline() +var libc_lchown_trampoline_addr uintptr //go:cgo_import_dynamic libc_lchown lchown "/usr/lib/libSystem.B.dylib" @@ -1452,14 +1452,14 @@ func Link(path string, link string) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_link_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + _, _, e1 := syscall_syscall(libc_link_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_link_trampoline() +var libc_link_trampoline_addr uintptr //go:cgo_import_dynamic libc_link link "/usr/lib/libSystem.B.dylib" @@ -1476,28 +1476,28 @@ func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err er if err != nil { return } - _, _, e1 := syscall_syscall6(funcPC(libc_linkat_trampoline), uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + _, _, e1 := syscall_syscall6(libc_linkat_trampoline_addr, uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_linkat_trampoline() +var libc_linkat_trampoline_addr uintptr //go:cgo_import_dynamic libc_linkat linkat "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Listen(s int, backlog int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_listen_trampoline), uintptr(s), uintptr(backlog), 0) + _, _, e1 := syscall_syscall(libc_listen_trampoline_addr, uintptr(s), uintptr(backlog), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_listen_trampoline() +var libc_listen_trampoline_addr uintptr //go:cgo_import_dynamic libc_listen listen "/usr/lib/libSystem.B.dylib" @@ -1509,14 +1509,14 @@ func Mkdir(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_mkdir_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(libc_mkdir_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_mkdir_trampoline() +var libc_mkdir_trampoline_addr uintptr //go:cgo_import_dynamic libc_mkdir mkdir "/usr/lib/libSystem.B.dylib" @@ -1528,14 +1528,14 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_mkdirat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + _, _, e1 := syscall_syscall(libc_mkdirat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_mkdirat_trampoline() +var libc_mkdirat_trampoline_addr uintptr //go:cgo_import_dynamic libc_mkdirat mkdirat "/usr/lib/libSystem.B.dylib" @@ -1547,14 +1547,14 @@ func Mkfifo(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_mkfifo_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(libc_mkfifo_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_mkfifo_trampoline() +var libc_mkfifo_trampoline_addr uintptr //go:cgo_import_dynamic libc_mkfifo mkfifo "/usr/lib/libSystem.B.dylib" @@ -1566,14 +1566,14 @@ func Mknod(path string, mode uint32, dev int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_mknod_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + _, _, e1 := syscall_syscall(libc_mknod_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_mknod_trampoline() +var libc_mknod_trampoline_addr uintptr //go:cgo_import_dynamic libc_mknod mknod "/usr/lib/libSystem.B.dylib" @@ -1585,7 +1585,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { if err != nil { return } - r0, _, e1 := syscall_syscall(funcPC(libc_open_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + r0, _, e1 := syscall_syscall(libc_open_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1593,7 +1593,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { return } -func libc_open_trampoline() +var libc_open_trampoline_addr uintptr //go:cgo_import_dynamic libc_open open "/usr/lib/libSystem.B.dylib" @@ -1605,7 +1605,7 @@ func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { if err != nil { return } - r0, _, e1 := syscall_syscall6(funcPC(libc_openat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) + r0, _, e1 := syscall_syscall6(libc_openat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1613,7 +1613,7 @@ func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { return } -func libc_openat_trampoline() +var libc_openat_trampoline_addr uintptr //go:cgo_import_dynamic libc_openat openat "/usr/lib/libSystem.B.dylib" @@ -1625,7 +1625,7 @@ func Pathconf(path string, name int) (val int, err error) { if err != nil { return } - r0, _, e1 := syscall_syscall(funcPC(libc_pathconf_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + r0, _, e1 := syscall_syscall(libc_pathconf_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) val = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1633,7 +1633,7 @@ func Pathconf(path string, name int) (val int, err error) { return } -func libc_pathconf_trampoline() +var libc_pathconf_trampoline_addr uintptr //go:cgo_import_dynamic libc_pathconf pathconf "/usr/lib/libSystem.B.dylib" @@ -1646,7 +1646,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := syscall_syscall6(funcPC(libc_pread_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0) + r0, _, e1 := syscall_syscall6(libc_pread_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1654,7 +1654,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) { return } -func libc_pread_trampoline() +var libc_pread_trampoline_addr uintptr //go:cgo_import_dynamic libc_pread pread "/usr/lib/libSystem.B.dylib" @@ -1667,7 +1667,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := syscall_syscall6(funcPC(libc_pwrite_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0) + r0, _, e1 := syscall_syscall6(libc_pwrite_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1675,7 +1675,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { return } -func libc_pwrite_trampoline() +var libc_pwrite_trampoline_addr uintptr //go:cgo_import_dynamic libc_pwrite pwrite "/usr/lib/libSystem.B.dylib" @@ -1688,7 +1688,7 @@ func read(fd int, p []byte) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := syscall_syscall(funcPC(libc_read_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p))) + r0, _, e1 := syscall_syscall(libc_read_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(p))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1696,7 +1696,7 @@ func read(fd int, p []byte) (n int, err error) { return } -func libc_read_trampoline() +var libc_read_trampoline_addr uintptr //go:cgo_import_dynamic libc_read read "/usr/lib/libSystem.B.dylib" @@ -1714,7 +1714,7 @@ func Readlink(path string, buf []byte) (n int, err error) { } else { _p1 = unsafe.Pointer(&_zero) } - r0, _, e1 := syscall_syscall(funcPC(libc_readlink_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + r0, _, e1 := syscall_syscall(libc_readlink_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1722,7 +1722,7 @@ func Readlink(path string, buf []byte) (n int, err error) { return } -func libc_readlink_trampoline() +var libc_readlink_trampoline_addr uintptr //go:cgo_import_dynamic libc_readlink readlink "/usr/lib/libSystem.B.dylib" @@ -1740,7 +1740,7 @@ func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { } else { _p1 = unsafe.Pointer(&_zero) } - r0, _, e1 := syscall_syscall6(funcPC(libc_readlinkat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) + r0, _, e1 := syscall_syscall6(libc_readlinkat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1748,7 +1748,7 @@ func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { return } -func libc_readlinkat_trampoline() +var libc_readlinkat_trampoline_addr uintptr //go:cgo_import_dynamic libc_readlinkat readlinkat "/usr/lib/libSystem.B.dylib" @@ -1765,14 +1765,14 @@ func Rename(from string, to string) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_rename_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + _, _, e1 := syscall_syscall(libc_rename_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_rename_trampoline() +var libc_rename_trampoline_addr uintptr //go:cgo_import_dynamic libc_rename rename "/usr/lib/libSystem.B.dylib" @@ -1789,14 +1789,14 @@ func Renameat(fromfd int, from string, tofd int, to string) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall6(funcPC(libc_renameat_trampoline), uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) + _, _, e1 := syscall_syscall6(libc_renameat_trampoline_addr, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_renameat_trampoline() +var libc_renameat_trampoline_addr uintptr //go:cgo_import_dynamic libc_renameat renameat "/usr/lib/libSystem.B.dylib" @@ -1808,14 +1808,14 @@ func Revoke(path string) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_revoke_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(libc_revoke_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_revoke_trampoline() +var libc_revoke_trampoline_addr uintptr //go:cgo_import_dynamic libc_revoke revoke "/usr/lib/libSystem.B.dylib" @@ -1827,21 +1827,21 @@ func Rmdir(path string) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_rmdir_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(libc_rmdir_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_rmdir_trampoline() +var libc_rmdir_trampoline_addr uintptr //go:cgo_import_dynamic libc_rmdir rmdir "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_lseek_trampoline), uintptr(fd), uintptr(offset), uintptr(whence)) + r0, _, e1 := syscall_syscall(libc_lseek_trampoline_addr, uintptr(fd), uintptr(offset), uintptr(whence)) newoffset = int64(r0) if e1 != 0 { err = errnoErr(e1) @@ -1849,14 +1849,14 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { return } -func libc_lseek_trampoline() +var libc_lseek_trampoline_addr uintptr //go:cgo_import_dynamic libc_lseek lseek "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) { - r0, _, e1 := syscall_syscall6(funcPC(libc_select_trampoline), uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) + r0, _, e1 := syscall_syscall6(libc_select_trampoline_addr, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1864,49 +1864,49 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err return } -func libc_select_trampoline() +var libc_select_trampoline_addr uintptr //go:cgo_import_dynamic libc_select select "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setegid(egid int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_setegid_trampoline), uintptr(egid), 0, 0) + _, _, e1 := syscall_syscall(libc_setegid_trampoline_addr, uintptr(egid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setegid_trampoline() +var libc_setegid_trampoline_addr uintptr //go:cgo_import_dynamic libc_setegid setegid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Seteuid(euid int) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_seteuid_trampoline), uintptr(euid), 0, 0) + _, _, e1 := syscall_rawSyscall(libc_seteuid_trampoline_addr, uintptr(euid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_seteuid_trampoline() +var libc_seteuid_trampoline_addr uintptr //go:cgo_import_dynamic libc_seteuid seteuid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setgid(gid int) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setgid_trampoline), uintptr(gid), 0, 0) + _, _, e1 := syscall_rawSyscall(libc_setgid_trampoline_addr, uintptr(gid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setgid_trampoline() +var libc_setgid_trampoline_addr uintptr //go:cgo_import_dynamic libc_setgid setgid "/usr/lib/libSystem.B.dylib" @@ -1918,105 +1918,105 @@ func Setlogin(name string) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_setlogin_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(libc_setlogin_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setlogin_trampoline() +var libc_setlogin_trampoline_addr uintptr //go:cgo_import_dynamic libc_setlogin setlogin "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setpgid(pid int, pgid int) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setpgid_trampoline), uintptr(pid), uintptr(pgid), 0) + _, _, e1 := syscall_rawSyscall(libc_setpgid_trampoline_addr, uintptr(pid), uintptr(pgid), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setpgid_trampoline() +var libc_setpgid_trampoline_addr uintptr //go:cgo_import_dynamic libc_setpgid setpgid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setpriority(which int, who int, prio int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_setpriority_trampoline), uintptr(which), uintptr(who), uintptr(prio)) + _, _, e1 := syscall_syscall(libc_setpriority_trampoline_addr, uintptr(which), uintptr(who), uintptr(prio)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setpriority_trampoline() +var libc_setpriority_trampoline_addr uintptr //go:cgo_import_dynamic libc_setpriority setpriority "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setprivexec(flag int) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_setprivexec_trampoline), uintptr(flag), 0, 0) + _, _, e1 := syscall_syscall(libc_setprivexec_trampoline_addr, uintptr(flag), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setprivexec_trampoline() +var libc_setprivexec_trampoline_addr uintptr //go:cgo_import_dynamic libc_setprivexec setprivexec "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setregid(rgid int, egid int) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setregid_trampoline), uintptr(rgid), uintptr(egid), 0) + _, _, e1 := syscall_rawSyscall(libc_setregid_trampoline_addr, uintptr(rgid), uintptr(egid), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setregid_trampoline() +var libc_setregid_trampoline_addr uintptr //go:cgo_import_dynamic libc_setregid setregid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setreuid(ruid int, euid int) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setreuid_trampoline), uintptr(ruid), uintptr(euid), 0) + _, _, e1 := syscall_rawSyscall(libc_setreuid_trampoline_addr, uintptr(ruid), uintptr(euid), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setreuid_trampoline() +var libc_setreuid_trampoline_addr uintptr //go:cgo_import_dynamic libc_setreuid setreuid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setrlimit(which int, lim *Rlimit) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setrlimit_trampoline), uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + _, _, e1 := syscall_rawSyscall(libc_setrlimit_trampoline_addr, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setrlimit_trampoline() +var libc_setrlimit_trampoline_addr uintptr //go:cgo_import_dynamic libc_setrlimit setrlimit "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setsid() (pid int, err error) { - r0, _, e1 := syscall_rawSyscall(funcPC(libc_setsid_trampoline), 0, 0, 0) + r0, _, e1 := syscall_rawSyscall(libc_setsid_trampoline_addr, 0, 0, 0) pid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -2024,35 +2024,35 @@ func Setsid() (pid int, err error) { return } -func libc_setsid_trampoline() +var libc_setsid_trampoline_addr uintptr //go:cgo_import_dynamic libc_setsid setsid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Settimeofday(tp *Timeval) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_settimeofday_trampoline), uintptr(unsafe.Pointer(tp)), 0, 0) + _, _, e1 := syscall_rawSyscall(libc_settimeofday_trampoline_addr, uintptr(unsafe.Pointer(tp)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_settimeofday_trampoline() +var libc_settimeofday_trampoline_addr uintptr //go:cgo_import_dynamic libc_settimeofday settimeofday "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setuid(uid int) (err error) { - _, _, e1 := syscall_rawSyscall(funcPC(libc_setuid_trampoline), uintptr(uid), 0, 0) + _, _, e1 := syscall_rawSyscall(libc_setuid_trampoline_addr, uintptr(uid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_setuid_trampoline() +var libc_setuid_trampoline_addr uintptr //go:cgo_import_dynamic libc_setuid setuid "/usr/lib/libSystem.B.dylib" @@ -2069,14 +2069,14 @@ func Symlink(path string, link string) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_symlink_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + _, _, e1 := syscall_syscall(libc_symlink_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_symlink_trampoline() +var libc_symlink_trampoline_addr uintptr //go:cgo_import_dynamic libc_symlink symlink "/usr/lib/libSystem.B.dylib" @@ -2093,28 +2093,28 @@ func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_symlinkat_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) + _, _, e1 := syscall_syscall(libc_symlinkat_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) if e1 != 0 { err = errnoErr(e1) } return } -func libc_symlinkat_trampoline() +var libc_symlinkat_trampoline_addr uintptr //go:cgo_import_dynamic libc_symlinkat symlinkat "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Sync() (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_sync_trampoline), 0, 0, 0) + _, _, e1 := syscall_syscall(libc_sync_trampoline_addr, 0, 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_sync_trampoline() +var libc_sync_trampoline_addr uintptr //go:cgo_import_dynamic libc_sync sync "/usr/lib/libSystem.B.dylib" @@ -2126,26 +2126,26 @@ func Truncate(path string, length int64) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_truncate_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(length), 0) + _, _, e1 := syscall_syscall(libc_truncate_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_truncate_trampoline() +var libc_truncate_trampoline_addr uintptr //go:cgo_import_dynamic libc_truncate truncate "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(newmask int) (oldmask int) { - r0, _, _ := syscall_syscall(funcPC(libc_umask_trampoline), uintptr(newmask), 0, 0) + r0, _, _ := syscall_syscall(libc_umask_trampoline_addr, uintptr(newmask), 0, 0) oldmask = int(r0) return } -func libc_umask_trampoline() +var libc_umask_trampoline_addr uintptr //go:cgo_import_dynamic libc_umask umask "/usr/lib/libSystem.B.dylib" @@ -2157,14 +2157,14 @@ func Undelete(path string) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_undelete_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(libc_undelete_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_undelete_trampoline() +var libc_undelete_trampoline_addr uintptr //go:cgo_import_dynamic libc_undelete undelete "/usr/lib/libSystem.B.dylib" @@ -2176,14 +2176,14 @@ func Unlink(path string) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_unlink_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(libc_unlink_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_unlink_trampoline() +var libc_unlink_trampoline_addr uintptr //go:cgo_import_dynamic libc_unlink unlink "/usr/lib/libSystem.B.dylib" @@ -2195,14 +2195,14 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_unlinkat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + _, _, e1 := syscall_syscall(libc_unlinkat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) if e1 != 0 { err = errnoErr(e1) } return } -func libc_unlinkat_trampoline() +var libc_unlinkat_trampoline_addr uintptr //go:cgo_import_dynamic libc_unlinkat unlinkat "/usr/lib/libSystem.B.dylib" @@ -2214,14 +2214,14 @@ func Unmount(path string, flags int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_unmount_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + _, _, e1 := syscall_syscall(libc_unmount_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_unmount_trampoline() +var libc_unmount_trampoline_addr uintptr //go:cgo_import_dynamic libc_unmount unmount "/usr/lib/libSystem.B.dylib" @@ -2234,7 +2234,7 @@ func write(fd int, p []byte) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := syscall_syscall(funcPC(libc_write_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p))) + r0, _, e1 := syscall_syscall(libc_write_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(p))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -2242,14 +2242,14 @@ func write(fd int, p []byte) (n int, err error) { return } -func libc_write_trampoline() +var libc_write_trampoline_addr uintptr //go:cgo_import_dynamic libc_write write "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) { - r0, _, e1 := syscall_syscall6(funcPC(libc_mmap_trampoline), uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos)) + r0, _, e1 := syscall_syscall6(libc_mmap_trampoline_addr, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos)) ret = uintptr(r0) if e1 != 0 { err = errnoErr(e1) @@ -2257,28 +2257,28 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) ( return } -func libc_mmap_trampoline() +var libc_mmap_trampoline_addr uintptr //go:cgo_import_dynamic libc_mmap mmap "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func munmap(addr uintptr, length uintptr) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_munmap_trampoline), uintptr(addr), uintptr(length), 0) + _, _, e1 := syscall_syscall(libc_munmap_trampoline_addr, uintptr(addr), uintptr(length), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_munmap_trampoline() +var libc_munmap_trampoline_addr uintptr //go:cgo_import_dynamic libc_munmap munmap "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func readlen(fd int, buf *byte, nbuf int) (n int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_read_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + r0, _, e1 := syscall_syscall(libc_read_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -2289,7 +2289,7 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func writelen(fd int, buf *byte, nbuf int) (n int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_write_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + r0, _, e1 := syscall_syscall(libc_write_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -2300,14 +2300,14 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fstat(fd int, stat *Stat_t) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fstat_trampoline), uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + _, _, e1 := syscall_syscall(libc_fstat_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fstat_trampoline() +var libc_fstat_trampoline_addr uintptr //go:cgo_import_dynamic libc_fstat fstat "/usr/lib/libSystem.B.dylib" @@ -2319,35 +2319,35 @@ func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall6(funcPC(libc_fstatat_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall6(libc_fstatat_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fstatat_trampoline() +var libc_fstatat_trampoline_addr uintptr //go:cgo_import_dynamic libc_fstatat fstatat "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fstatfs(fd int, stat *Statfs_t) (err error) { - _, _, e1 := syscall_syscall(funcPC(libc_fstatfs_trampoline), uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + _, _, e1 := syscall_syscall(libc_fstatfs_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_fstatfs_trampoline() +var libc_fstatfs_trampoline_addr uintptr //go:cgo_import_dynamic libc_fstatfs fstatfs "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) { - r0, _, e1 := syscall_syscall(funcPC(libc_getfsstat_trampoline), uintptr(buf), uintptr(size), uintptr(flags)) + r0, _, e1 := syscall_syscall(libc_getfsstat_trampoline_addr, uintptr(buf), uintptr(size), uintptr(flags)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -2355,7 +2355,7 @@ func getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) { return } -func libc_getfsstat_trampoline() +var libc_getfsstat_trampoline_addr uintptr //go:cgo_import_dynamic libc_getfsstat getfsstat "/usr/lib/libSystem.B.dylib" @@ -2367,28 +2367,28 @@ func Lstat(path string, stat *Stat_t) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_lstat_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + _, _, e1 := syscall_syscall(libc_lstat_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_lstat_trampoline() +var libc_lstat_trampoline_addr uintptr //go:cgo_import_dynamic libc_lstat lstat "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func ptrace1(request int, pid int, addr uintptr, data uintptr) (err error) { - _, _, e1 := syscall_syscall6(funcPC(libc_ptrace_trampoline), uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) + _, _, e1 := syscall_syscall6(libc_ptrace_trampoline_addr, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_ptrace_trampoline() +var libc_ptrace_trampoline_addr uintptr //go:cgo_import_dynamic libc_ptrace ptrace "/usr/lib/libSystem.B.dylib" @@ -2400,14 +2400,14 @@ func Stat(path string, stat *Stat_t) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_stat_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + _, _, e1 := syscall_syscall(libc_stat_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_stat_trampoline() +var libc_stat_trampoline_addr uintptr //go:cgo_import_dynamic libc_stat stat "/usr/lib/libSystem.B.dylib" @@ -2419,13 +2419,13 @@ func Statfs(path string, stat *Statfs_t) (err error) { if err != nil { return } - _, _, e1 := syscall_syscall(funcPC(libc_statfs_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + _, _, e1 := syscall_syscall(libc_statfs_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) } return } -func libc_statfs_trampoline() +var libc_statfs_trampoline_addr uintptr //go:cgo_import_dynamic libc_statfs statfs "/usr/lib/libSystem.B.dylib" diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s index e30a6974071..33e19776db4 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s @@ -5,287 +5,855 @@ // +build go1.12 #include "textflag.h" -TEXT ·libc_getgroups_trampoline(SB),NOSPLIT,$0-0 + +TEXT libc_getgroups_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getgroups(SB) -TEXT ·libc_setgroups_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getgroups_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getgroups_trampoline_addr(SB)/8, $libc_getgroups_trampoline<>(SB) + +TEXT libc_setgroups_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setgroups(SB) -TEXT ·libc_wait4_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setgroups_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setgroups_trampoline_addr(SB)/8, $libc_setgroups_trampoline<>(SB) + +TEXT libc_wait4_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_wait4(SB) -TEXT ·libc_accept_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_wait4_trampoline_addr(SB), RODATA, $8 +DATA ·libc_wait4_trampoline_addr(SB)/8, $libc_wait4_trampoline<>(SB) + +TEXT libc_accept_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_accept(SB) -TEXT ·libc_bind_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_accept_trampoline_addr(SB), RODATA, $8 +DATA ·libc_accept_trampoline_addr(SB)/8, $libc_accept_trampoline<>(SB) + +TEXT libc_bind_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_bind(SB) -TEXT ·libc_connect_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_bind_trampoline_addr(SB), RODATA, $8 +DATA ·libc_bind_trampoline_addr(SB)/8, $libc_bind_trampoline<>(SB) + +TEXT libc_connect_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_connect(SB) -TEXT ·libc_socket_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_connect_trampoline_addr(SB), RODATA, $8 +DATA ·libc_connect_trampoline_addr(SB)/8, $libc_connect_trampoline<>(SB) + +TEXT libc_socket_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_socket(SB) -TEXT ·libc_getsockopt_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_socket_trampoline_addr(SB), RODATA, $8 +DATA ·libc_socket_trampoline_addr(SB)/8, $libc_socket_trampoline<>(SB) + +TEXT libc_getsockopt_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getsockopt(SB) -TEXT ·libc_setsockopt_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getsockopt_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getsockopt_trampoline_addr(SB)/8, $libc_getsockopt_trampoline<>(SB) + +TEXT libc_setsockopt_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setsockopt(SB) -TEXT ·libc_getpeername_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setsockopt_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setsockopt_trampoline_addr(SB)/8, $libc_setsockopt_trampoline<>(SB) + +TEXT libc_getpeername_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getpeername(SB) -TEXT ·libc_getsockname_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getpeername_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getpeername_trampoline_addr(SB)/8, $libc_getpeername_trampoline<>(SB) + +TEXT libc_getsockname_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getsockname(SB) -TEXT ·libc_shutdown_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getsockname_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getsockname_trampoline_addr(SB)/8, $libc_getsockname_trampoline<>(SB) + +TEXT libc_shutdown_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_shutdown(SB) -TEXT ·libc_socketpair_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_shutdown_trampoline_addr(SB), RODATA, $8 +DATA ·libc_shutdown_trampoline_addr(SB)/8, $libc_shutdown_trampoline<>(SB) + +TEXT libc_socketpair_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_socketpair(SB) -TEXT ·libc_recvfrom_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_socketpair_trampoline_addr(SB), RODATA, $8 +DATA ·libc_socketpair_trampoline_addr(SB)/8, $libc_socketpair_trampoline<>(SB) + +TEXT libc_recvfrom_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_recvfrom(SB) -TEXT ·libc_sendto_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_recvfrom_trampoline_addr(SB), RODATA, $8 +DATA ·libc_recvfrom_trampoline_addr(SB)/8, $libc_recvfrom_trampoline<>(SB) + +TEXT libc_sendto_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_sendto(SB) -TEXT ·libc_recvmsg_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_sendto_trampoline_addr(SB), RODATA, $8 +DATA ·libc_sendto_trampoline_addr(SB)/8, $libc_sendto_trampoline<>(SB) + +TEXT libc_recvmsg_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_recvmsg(SB) -TEXT ·libc_sendmsg_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_recvmsg_trampoline_addr(SB), RODATA, $8 +DATA ·libc_recvmsg_trampoline_addr(SB)/8, $libc_recvmsg_trampoline<>(SB) + +TEXT libc_sendmsg_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_sendmsg(SB) -TEXT ·libc_kevent_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_sendmsg_trampoline_addr(SB), RODATA, $8 +DATA ·libc_sendmsg_trampoline_addr(SB)/8, $libc_sendmsg_trampoline<>(SB) + +TEXT libc_kevent_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_kevent(SB) -TEXT ·libc_utimes_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_kevent_trampoline_addr(SB), RODATA, $8 +DATA ·libc_kevent_trampoline_addr(SB)/8, $libc_kevent_trampoline<>(SB) + +TEXT libc_utimes_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_utimes(SB) -TEXT ·libc_futimes_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_utimes_trampoline_addr(SB), RODATA, $8 +DATA ·libc_utimes_trampoline_addr(SB)/8, $libc_utimes_trampoline<>(SB) + +TEXT libc_futimes_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_futimes(SB) -TEXT ·libc_poll_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_futimes_trampoline_addr(SB), RODATA, $8 +DATA ·libc_futimes_trampoline_addr(SB)/8, $libc_futimes_trampoline<>(SB) + +TEXT libc_poll_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_poll(SB) -TEXT ·libc_madvise_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_poll_trampoline_addr(SB), RODATA, $8 +DATA ·libc_poll_trampoline_addr(SB)/8, $libc_poll_trampoline<>(SB) + +TEXT libc_madvise_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_madvise(SB) -TEXT ·libc_mlock_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_madvise_trampoline_addr(SB), RODATA, $8 +DATA ·libc_madvise_trampoline_addr(SB)/8, $libc_madvise_trampoline<>(SB) + +TEXT libc_mlock_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_mlock(SB) -TEXT ·libc_mlockall_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_mlock_trampoline_addr(SB), RODATA, $8 +DATA ·libc_mlock_trampoline_addr(SB)/8, $libc_mlock_trampoline<>(SB) + +TEXT libc_mlockall_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_mlockall(SB) -TEXT ·libc_mprotect_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_mlockall_trampoline_addr(SB), RODATA, $8 +DATA ·libc_mlockall_trampoline_addr(SB)/8, $libc_mlockall_trampoline<>(SB) + +TEXT libc_mprotect_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_mprotect(SB) -TEXT ·libc_msync_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_mprotect_trampoline_addr(SB), RODATA, $8 +DATA ·libc_mprotect_trampoline_addr(SB)/8, $libc_mprotect_trampoline<>(SB) + +TEXT libc_msync_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_msync(SB) -TEXT ·libc_munlock_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_msync_trampoline_addr(SB), RODATA, $8 +DATA ·libc_msync_trampoline_addr(SB)/8, $libc_msync_trampoline<>(SB) + +TEXT libc_munlock_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_munlock(SB) -TEXT ·libc_munlockall_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_munlock_trampoline_addr(SB), RODATA, $8 +DATA ·libc_munlock_trampoline_addr(SB)/8, $libc_munlock_trampoline<>(SB) + +TEXT libc_munlockall_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_munlockall(SB) -TEXT ·libc_pipe_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_munlockall_trampoline_addr(SB), RODATA, $8 +DATA ·libc_munlockall_trampoline_addr(SB)/8, $libc_munlockall_trampoline<>(SB) + +TEXT libc_pipe_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_pipe(SB) -TEXT ·libc_getxattr_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_pipe_trampoline_addr(SB), RODATA, $8 +DATA ·libc_pipe_trampoline_addr(SB)/8, $libc_pipe_trampoline<>(SB) + +TEXT libc_getxattr_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getxattr(SB) -TEXT ·libc_fgetxattr_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getxattr_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getxattr_trampoline_addr(SB)/8, $libc_getxattr_trampoline<>(SB) + +TEXT libc_fgetxattr_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fgetxattr(SB) -TEXT ·libc_setxattr_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fgetxattr_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fgetxattr_trampoline_addr(SB)/8, $libc_fgetxattr_trampoline<>(SB) + +TEXT libc_setxattr_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setxattr(SB) -TEXT ·libc_fsetxattr_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setxattr_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setxattr_trampoline_addr(SB)/8, $libc_setxattr_trampoline<>(SB) + +TEXT libc_fsetxattr_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fsetxattr(SB) -TEXT ·libc_removexattr_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fsetxattr_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fsetxattr_trampoline_addr(SB)/8, $libc_fsetxattr_trampoline<>(SB) + +TEXT libc_removexattr_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_removexattr(SB) -TEXT ·libc_fremovexattr_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_removexattr_trampoline_addr(SB), RODATA, $8 +DATA ·libc_removexattr_trampoline_addr(SB)/8, $libc_removexattr_trampoline<>(SB) + +TEXT libc_fremovexattr_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fremovexattr(SB) -TEXT ·libc_listxattr_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fremovexattr_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fremovexattr_trampoline_addr(SB)/8, $libc_fremovexattr_trampoline<>(SB) + +TEXT libc_listxattr_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_listxattr(SB) -TEXT ·libc_flistxattr_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_listxattr_trampoline_addr(SB), RODATA, $8 +DATA ·libc_listxattr_trampoline_addr(SB)/8, $libc_listxattr_trampoline<>(SB) + +TEXT libc_flistxattr_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_flistxattr(SB) -TEXT ·libc_setattrlist_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_flistxattr_trampoline_addr(SB), RODATA, $8 +DATA ·libc_flistxattr_trampoline_addr(SB)/8, $libc_flistxattr_trampoline<>(SB) + +TEXT libc_setattrlist_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setattrlist(SB) -TEXT ·libc_fcntl_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setattrlist_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setattrlist_trampoline_addr(SB)/8, $libc_setattrlist_trampoline<>(SB) + +TEXT libc_fcntl_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fcntl(SB) -TEXT ·libc_kill_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fcntl_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fcntl_trampoline_addr(SB)/8, $libc_fcntl_trampoline<>(SB) + +TEXT libc_kill_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_kill(SB) -TEXT ·libc_ioctl_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_kill_trampoline_addr(SB), RODATA, $8 +DATA ·libc_kill_trampoline_addr(SB)/8, $libc_kill_trampoline<>(SB) + +TEXT libc_ioctl_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_ioctl(SB) -TEXT ·libc_sysctl_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_ioctl_trampoline_addr(SB), RODATA, $8 +DATA ·libc_ioctl_trampoline_addr(SB)/8, $libc_ioctl_trampoline<>(SB) + +TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_sysctl(SB) -TEXT ·libc_sendfile_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $8 +DATA ·libc_sysctl_trampoline_addr(SB)/8, $libc_sysctl_trampoline<>(SB) + +TEXT libc_sendfile_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_sendfile(SB) -TEXT ·libc_access_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_sendfile_trampoline_addr(SB), RODATA, $8 +DATA ·libc_sendfile_trampoline_addr(SB)/8, $libc_sendfile_trampoline<>(SB) + +TEXT libc_access_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_access(SB) -TEXT ·libc_adjtime_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_access_trampoline_addr(SB), RODATA, $8 +DATA ·libc_access_trampoline_addr(SB)/8, $libc_access_trampoline<>(SB) + +TEXT libc_adjtime_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_adjtime(SB) -TEXT ·libc_chdir_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_adjtime_trampoline_addr(SB), RODATA, $8 +DATA ·libc_adjtime_trampoline_addr(SB)/8, $libc_adjtime_trampoline<>(SB) + +TEXT libc_chdir_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_chdir(SB) -TEXT ·libc_chflags_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_chdir_trampoline_addr(SB), RODATA, $8 +DATA ·libc_chdir_trampoline_addr(SB)/8, $libc_chdir_trampoline<>(SB) + +TEXT libc_chflags_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_chflags(SB) -TEXT ·libc_chmod_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_chflags_trampoline_addr(SB), RODATA, $8 +DATA ·libc_chflags_trampoline_addr(SB)/8, $libc_chflags_trampoline<>(SB) + +TEXT libc_chmod_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_chmod(SB) -TEXT ·libc_chown_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_chmod_trampoline_addr(SB), RODATA, $8 +DATA ·libc_chmod_trampoline_addr(SB)/8, $libc_chmod_trampoline<>(SB) + +TEXT libc_chown_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_chown(SB) -TEXT ·libc_chroot_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_chown_trampoline_addr(SB), RODATA, $8 +DATA ·libc_chown_trampoline_addr(SB)/8, $libc_chown_trampoline<>(SB) + +TEXT libc_chroot_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_chroot(SB) -TEXT ·libc_clock_gettime_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_chroot_trampoline_addr(SB), RODATA, $8 +DATA ·libc_chroot_trampoline_addr(SB)/8, $libc_chroot_trampoline<>(SB) + +TEXT libc_clock_gettime_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_clock_gettime(SB) -TEXT ·libc_close_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_clock_gettime_trampoline_addr(SB), RODATA, $8 +DATA ·libc_clock_gettime_trampoline_addr(SB)/8, $libc_clock_gettime_trampoline<>(SB) + +TEXT libc_close_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_close(SB) -TEXT ·libc_clonefile_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_close_trampoline_addr(SB), RODATA, $8 +DATA ·libc_close_trampoline_addr(SB)/8, $libc_close_trampoline<>(SB) + +TEXT libc_clonefile_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_clonefile(SB) -TEXT ·libc_clonefileat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_clonefile_trampoline_addr(SB), RODATA, $8 +DATA ·libc_clonefile_trampoline_addr(SB)/8, $libc_clonefile_trampoline<>(SB) + +TEXT libc_clonefileat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_clonefileat(SB) -TEXT ·libc_dup_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_clonefileat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_clonefileat_trampoline_addr(SB)/8, $libc_clonefileat_trampoline<>(SB) + +TEXT libc_dup_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_dup(SB) -TEXT ·libc_dup2_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_dup_trampoline_addr(SB), RODATA, $8 +DATA ·libc_dup_trampoline_addr(SB)/8, $libc_dup_trampoline<>(SB) + +TEXT libc_dup2_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_dup2(SB) -TEXT ·libc_exchangedata_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_dup2_trampoline_addr(SB), RODATA, $8 +DATA ·libc_dup2_trampoline_addr(SB)/8, $libc_dup2_trampoline<>(SB) + +TEXT libc_exchangedata_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_exchangedata(SB) -TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_exchangedata_trampoline_addr(SB), RODATA, $8 +DATA ·libc_exchangedata_trampoline_addr(SB)/8, $libc_exchangedata_trampoline<>(SB) + +TEXT libc_exit_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_exit(SB) -TEXT ·libc_faccessat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_exit_trampoline_addr(SB), RODATA, $8 +DATA ·libc_exit_trampoline_addr(SB)/8, $libc_exit_trampoline<>(SB) + +TEXT libc_faccessat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_faccessat(SB) -TEXT ·libc_fchdir_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_faccessat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_faccessat_trampoline_addr(SB)/8, $libc_faccessat_trampoline<>(SB) + +TEXT libc_fchdir_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fchdir(SB) -TEXT ·libc_fchflags_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fchdir_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fchdir_trampoline_addr(SB)/8, $libc_fchdir_trampoline<>(SB) + +TEXT libc_fchflags_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fchflags(SB) -TEXT ·libc_fchmod_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fchflags_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fchflags_trampoline_addr(SB)/8, $libc_fchflags_trampoline<>(SB) + +TEXT libc_fchmod_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fchmod(SB) -TEXT ·libc_fchmodat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fchmod_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fchmod_trampoline_addr(SB)/8, $libc_fchmod_trampoline<>(SB) + +TEXT libc_fchmodat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fchmodat(SB) -TEXT ·libc_fchown_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fchmodat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fchmodat_trampoline_addr(SB)/8, $libc_fchmodat_trampoline<>(SB) + +TEXT libc_fchown_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fchown(SB) -TEXT ·libc_fchownat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fchown_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fchown_trampoline_addr(SB)/8, $libc_fchown_trampoline<>(SB) + +TEXT libc_fchownat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fchownat(SB) -TEXT ·libc_fclonefileat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fchownat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fchownat_trampoline_addr(SB)/8, $libc_fchownat_trampoline<>(SB) + +TEXT libc_fclonefileat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fclonefileat(SB) -TEXT ·libc_flock_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fclonefileat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fclonefileat_trampoline_addr(SB)/8, $libc_fclonefileat_trampoline<>(SB) + +TEXT libc_flock_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_flock(SB) -TEXT ·libc_fpathconf_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_flock_trampoline_addr(SB), RODATA, $8 +DATA ·libc_flock_trampoline_addr(SB)/8, $libc_flock_trampoline<>(SB) + +TEXT libc_fpathconf_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fpathconf(SB) -TEXT ·libc_fsync_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fpathconf_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fpathconf_trampoline_addr(SB)/8, $libc_fpathconf_trampoline<>(SB) + +TEXT libc_fsync_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fsync(SB) -TEXT ·libc_ftruncate_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fsync_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fsync_trampoline_addr(SB)/8, $libc_fsync_trampoline<>(SB) + +TEXT libc_ftruncate_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_ftruncate(SB) -TEXT ·libc_getcwd_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_ftruncate_trampoline_addr(SB), RODATA, $8 +DATA ·libc_ftruncate_trampoline_addr(SB)/8, $libc_ftruncate_trampoline<>(SB) + +TEXT libc_getcwd_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getcwd(SB) -TEXT ·libc_getdtablesize_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getcwd_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getcwd_trampoline_addr(SB)/8, $libc_getcwd_trampoline<>(SB) + +TEXT libc_getdtablesize_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getdtablesize(SB) -TEXT ·libc_getegid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getdtablesize_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getdtablesize_trampoline_addr(SB)/8, $libc_getdtablesize_trampoline<>(SB) + +TEXT libc_getegid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getegid(SB) -TEXT ·libc_geteuid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getegid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getegid_trampoline_addr(SB)/8, $libc_getegid_trampoline<>(SB) + +TEXT libc_geteuid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_geteuid(SB) -TEXT ·libc_getgid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_geteuid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_geteuid_trampoline_addr(SB)/8, $libc_geteuid_trampoline<>(SB) + +TEXT libc_getgid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getgid(SB) -TEXT ·libc_getpgid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getgid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getgid_trampoline_addr(SB)/8, $libc_getgid_trampoline<>(SB) + +TEXT libc_getpgid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getpgid(SB) -TEXT ·libc_getpgrp_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getpgid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getpgid_trampoline_addr(SB)/8, $libc_getpgid_trampoline<>(SB) + +TEXT libc_getpgrp_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getpgrp(SB) -TEXT ·libc_getpid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getpgrp_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getpgrp_trampoline_addr(SB)/8, $libc_getpgrp_trampoline<>(SB) + +TEXT libc_getpid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getpid(SB) -TEXT ·libc_getppid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getpid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getpid_trampoline_addr(SB)/8, $libc_getpid_trampoline<>(SB) + +TEXT libc_getppid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getppid(SB) -TEXT ·libc_getpriority_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getppid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getppid_trampoline_addr(SB)/8, $libc_getppid_trampoline<>(SB) + +TEXT libc_getpriority_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getpriority(SB) -TEXT ·libc_getrlimit_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getpriority_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getpriority_trampoline_addr(SB)/8, $libc_getpriority_trampoline<>(SB) + +TEXT libc_getrlimit_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getrlimit(SB) -TEXT ·libc_getrusage_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getrlimit_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getrlimit_trampoline_addr(SB)/8, $libc_getrlimit_trampoline<>(SB) + +TEXT libc_getrusage_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getrusage(SB) -TEXT ·libc_getsid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getrusage_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getrusage_trampoline_addr(SB)/8, $libc_getrusage_trampoline<>(SB) + +TEXT libc_getsid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getsid(SB) -TEXT ·libc_gettimeofday_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getsid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getsid_trampoline_addr(SB)/8, $libc_getsid_trampoline<>(SB) + +TEXT libc_gettimeofday_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_gettimeofday(SB) -TEXT ·libc_getuid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_gettimeofday_trampoline_addr(SB), RODATA, $8 +DATA ·libc_gettimeofday_trampoline_addr(SB)/8, $libc_gettimeofday_trampoline<>(SB) + +TEXT libc_getuid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getuid(SB) -TEXT ·libc_issetugid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getuid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getuid_trampoline_addr(SB)/8, $libc_getuid_trampoline<>(SB) + +TEXT libc_issetugid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_issetugid(SB) -TEXT ·libc_kqueue_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_issetugid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_issetugid_trampoline_addr(SB)/8, $libc_issetugid_trampoline<>(SB) + +TEXT libc_kqueue_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_kqueue(SB) -TEXT ·libc_lchown_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_kqueue_trampoline_addr(SB), RODATA, $8 +DATA ·libc_kqueue_trampoline_addr(SB)/8, $libc_kqueue_trampoline<>(SB) + +TEXT libc_lchown_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_lchown(SB) -TEXT ·libc_link_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_lchown_trampoline_addr(SB), RODATA, $8 +DATA ·libc_lchown_trampoline_addr(SB)/8, $libc_lchown_trampoline<>(SB) + +TEXT libc_link_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_link(SB) -TEXT ·libc_linkat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_link_trampoline_addr(SB), RODATA, $8 +DATA ·libc_link_trampoline_addr(SB)/8, $libc_link_trampoline<>(SB) + +TEXT libc_linkat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_linkat(SB) -TEXT ·libc_listen_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_linkat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_linkat_trampoline_addr(SB)/8, $libc_linkat_trampoline<>(SB) + +TEXT libc_listen_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_listen(SB) -TEXT ·libc_mkdir_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_listen_trampoline_addr(SB), RODATA, $8 +DATA ·libc_listen_trampoline_addr(SB)/8, $libc_listen_trampoline<>(SB) + +TEXT libc_mkdir_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_mkdir(SB) -TEXT ·libc_mkdirat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_mkdir_trampoline_addr(SB), RODATA, $8 +DATA ·libc_mkdir_trampoline_addr(SB)/8, $libc_mkdir_trampoline<>(SB) + +TEXT libc_mkdirat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_mkdirat(SB) -TEXT ·libc_mkfifo_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_mkdirat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_mkdirat_trampoline_addr(SB)/8, $libc_mkdirat_trampoline<>(SB) + +TEXT libc_mkfifo_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_mkfifo(SB) -TEXT ·libc_mknod_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_mkfifo_trampoline_addr(SB), RODATA, $8 +DATA ·libc_mkfifo_trampoline_addr(SB)/8, $libc_mkfifo_trampoline<>(SB) + +TEXT libc_mknod_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_mknod(SB) -TEXT ·libc_open_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_mknod_trampoline_addr(SB), RODATA, $8 +DATA ·libc_mknod_trampoline_addr(SB)/8, $libc_mknod_trampoline<>(SB) + +TEXT libc_open_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_open(SB) -TEXT ·libc_openat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_open_trampoline_addr(SB), RODATA, $8 +DATA ·libc_open_trampoline_addr(SB)/8, $libc_open_trampoline<>(SB) + +TEXT libc_openat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_openat(SB) -TEXT ·libc_pathconf_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_openat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_openat_trampoline_addr(SB)/8, $libc_openat_trampoline<>(SB) + +TEXT libc_pathconf_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_pathconf(SB) -TEXT ·libc_pread_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_pathconf_trampoline_addr(SB), RODATA, $8 +DATA ·libc_pathconf_trampoline_addr(SB)/8, $libc_pathconf_trampoline<>(SB) + +TEXT libc_pread_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_pread(SB) -TEXT ·libc_pwrite_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_pread_trampoline_addr(SB), RODATA, $8 +DATA ·libc_pread_trampoline_addr(SB)/8, $libc_pread_trampoline<>(SB) + +TEXT libc_pwrite_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_pwrite(SB) -TEXT ·libc_read_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_pwrite_trampoline_addr(SB), RODATA, $8 +DATA ·libc_pwrite_trampoline_addr(SB)/8, $libc_pwrite_trampoline<>(SB) + +TEXT libc_read_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_read(SB) -TEXT ·libc_readlink_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_read_trampoline_addr(SB), RODATA, $8 +DATA ·libc_read_trampoline_addr(SB)/8, $libc_read_trampoline<>(SB) + +TEXT libc_readlink_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_readlink(SB) -TEXT ·libc_readlinkat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_readlink_trampoline_addr(SB), RODATA, $8 +DATA ·libc_readlink_trampoline_addr(SB)/8, $libc_readlink_trampoline<>(SB) + +TEXT libc_readlinkat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_readlinkat(SB) -TEXT ·libc_rename_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_readlinkat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_readlinkat_trampoline_addr(SB)/8, $libc_readlinkat_trampoline<>(SB) + +TEXT libc_rename_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_rename(SB) -TEXT ·libc_renameat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_rename_trampoline_addr(SB), RODATA, $8 +DATA ·libc_rename_trampoline_addr(SB)/8, $libc_rename_trampoline<>(SB) + +TEXT libc_renameat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_renameat(SB) -TEXT ·libc_revoke_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_renameat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_renameat_trampoline_addr(SB)/8, $libc_renameat_trampoline<>(SB) + +TEXT libc_revoke_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_revoke(SB) -TEXT ·libc_rmdir_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_revoke_trampoline_addr(SB), RODATA, $8 +DATA ·libc_revoke_trampoline_addr(SB)/8, $libc_revoke_trampoline<>(SB) + +TEXT libc_rmdir_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_rmdir(SB) -TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_rmdir_trampoline_addr(SB), RODATA, $8 +DATA ·libc_rmdir_trampoline_addr(SB)/8, $libc_rmdir_trampoline<>(SB) + +TEXT libc_lseek_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_lseek(SB) -TEXT ·libc_select_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_lseek_trampoline_addr(SB), RODATA, $8 +DATA ·libc_lseek_trampoline_addr(SB)/8, $libc_lseek_trampoline<>(SB) + +TEXT libc_select_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_select(SB) -TEXT ·libc_setegid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_select_trampoline_addr(SB), RODATA, $8 +DATA ·libc_select_trampoline_addr(SB)/8, $libc_select_trampoline<>(SB) + +TEXT libc_setegid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setegid(SB) -TEXT ·libc_seteuid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setegid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setegid_trampoline_addr(SB)/8, $libc_setegid_trampoline<>(SB) + +TEXT libc_seteuid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_seteuid(SB) -TEXT ·libc_setgid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_seteuid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_seteuid_trampoline_addr(SB)/8, $libc_seteuid_trampoline<>(SB) + +TEXT libc_setgid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setgid(SB) -TEXT ·libc_setlogin_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setgid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setgid_trampoline_addr(SB)/8, $libc_setgid_trampoline<>(SB) + +TEXT libc_setlogin_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setlogin(SB) -TEXT ·libc_setpgid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setlogin_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setlogin_trampoline_addr(SB)/8, $libc_setlogin_trampoline<>(SB) + +TEXT libc_setpgid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setpgid(SB) -TEXT ·libc_setpriority_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setpgid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setpgid_trampoline_addr(SB)/8, $libc_setpgid_trampoline<>(SB) + +TEXT libc_setpriority_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setpriority(SB) -TEXT ·libc_setprivexec_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setpriority_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setpriority_trampoline_addr(SB)/8, $libc_setpriority_trampoline<>(SB) + +TEXT libc_setprivexec_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setprivexec(SB) -TEXT ·libc_setregid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setprivexec_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setprivexec_trampoline_addr(SB)/8, $libc_setprivexec_trampoline<>(SB) + +TEXT libc_setregid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setregid(SB) -TEXT ·libc_setreuid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setregid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setregid_trampoline_addr(SB)/8, $libc_setregid_trampoline<>(SB) + +TEXT libc_setreuid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setreuid(SB) -TEXT ·libc_setrlimit_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setreuid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setreuid_trampoline_addr(SB)/8, $libc_setreuid_trampoline<>(SB) + +TEXT libc_setrlimit_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setrlimit(SB) -TEXT ·libc_setsid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setrlimit_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setrlimit_trampoline_addr(SB)/8, $libc_setrlimit_trampoline<>(SB) + +TEXT libc_setsid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setsid(SB) -TEXT ·libc_settimeofday_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setsid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setsid_trampoline_addr(SB)/8, $libc_setsid_trampoline<>(SB) + +TEXT libc_settimeofday_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_settimeofday(SB) -TEXT ·libc_setuid_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_settimeofday_trampoline_addr(SB), RODATA, $8 +DATA ·libc_settimeofday_trampoline_addr(SB)/8, $libc_settimeofday_trampoline<>(SB) + +TEXT libc_setuid_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_setuid(SB) -TEXT ·libc_symlink_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_setuid_trampoline_addr(SB), RODATA, $8 +DATA ·libc_setuid_trampoline_addr(SB)/8, $libc_setuid_trampoline<>(SB) + +TEXT libc_symlink_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_symlink(SB) -TEXT ·libc_symlinkat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_symlink_trampoline_addr(SB), RODATA, $8 +DATA ·libc_symlink_trampoline_addr(SB)/8, $libc_symlink_trampoline<>(SB) + +TEXT libc_symlinkat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_symlinkat(SB) -TEXT ·libc_sync_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_symlinkat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_symlinkat_trampoline_addr(SB)/8, $libc_symlinkat_trampoline<>(SB) + +TEXT libc_sync_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_sync(SB) -TEXT ·libc_truncate_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_sync_trampoline_addr(SB), RODATA, $8 +DATA ·libc_sync_trampoline_addr(SB)/8, $libc_sync_trampoline<>(SB) + +TEXT libc_truncate_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_truncate(SB) -TEXT ·libc_umask_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_truncate_trampoline_addr(SB), RODATA, $8 +DATA ·libc_truncate_trampoline_addr(SB)/8, $libc_truncate_trampoline<>(SB) + +TEXT libc_umask_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_umask(SB) -TEXT ·libc_undelete_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_umask_trampoline_addr(SB), RODATA, $8 +DATA ·libc_umask_trampoline_addr(SB)/8, $libc_umask_trampoline<>(SB) + +TEXT libc_undelete_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_undelete(SB) -TEXT ·libc_unlink_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_undelete_trampoline_addr(SB), RODATA, $8 +DATA ·libc_undelete_trampoline_addr(SB)/8, $libc_undelete_trampoline<>(SB) + +TEXT libc_unlink_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_unlink(SB) -TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_unlink_trampoline_addr(SB), RODATA, $8 +DATA ·libc_unlink_trampoline_addr(SB)/8, $libc_unlink_trampoline<>(SB) + +TEXT libc_unlinkat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_unlinkat(SB) -TEXT ·libc_unmount_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_unlinkat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_unlinkat_trampoline_addr(SB)/8, $libc_unlinkat_trampoline<>(SB) + +TEXT libc_unmount_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_unmount(SB) -TEXT ·libc_write_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_unmount_trampoline_addr(SB), RODATA, $8 +DATA ·libc_unmount_trampoline_addr(SB)/8, $libc_unmount_trampoline<>(SB) + +TEXT libc_write_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_write(SB) -TEXT ·libc_mmap_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_write_trampoline_addr(SB), RODATA, $8 +DATA ·libc_write_trampoline_addr(SB)/8, $libc_write_trampoline<>(SB) + +TEXT libc_mmap_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_mmap(SB) -TEXT ·libc_munmap_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_mmap_trampoline_addr(SB), RODATA, $8 +DATA ·libc_mmap_trampoline_addr(SB)/8, $libc_mmap_trampoline<>(SB) + +TEXT libc_munmap_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_munmap(SB) -TEXT ·libc_fstat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_munmap_trampoline_addr(SB), RODATA, $8 +DATA ·libc_munmap_trampoline_addr(SB)/8, $libc_munmap_trampoline<>(SB) + +TEXT libc_fstat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fstat(SB) -TEXT ·libc_fstatat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fstat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fstat_trampoline_addr(SB)/8, $libc_fstat_trampoline<>(SB) + +TEXT libc_fstatat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fstatat(SB) -TEXT ·libc_fstatfs_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fstatat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fstatat_trampoline_addr(SB)/8, $libc_fstatat_trampoline<>(SB) + +TEXT libc_fstatfs_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fstatfs(SB) -TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_fstatfs_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fstatfs_trampoline_addr(SB)/8, $libc_fstatfs_trampoline<>(SB) + +TEXT libc_getfsstat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getfsstat(SB) -TEXT ·libc_lstat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_getfsstat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_getfsstat_trampoline_addr(SB)/8, $libc_getfsstat_trampoline<>(SB) + +TEXT libc_lstat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_lstat(SB) -TEXT ·libc_ptrace_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_lstat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_lstat_trampoline_addr(SB)/8, $libc_lstat_trampoline<>(SB) + +TEXT libc_ptrace_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_ptrace(SB) -TEXT ·libc_stat_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_ptrace_trampoline_addr(SB), RODATA, $8 +DATA ·libc_ptrace_trampoline_addr(SB)/8, $libc_ptrace_trampoline<>(SB) + +TEXT libc_stat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_stat(SB) -TEXT ·libc_statfs_trampoline(SB),NOSPLIT,$0-0 + +GLOBL ·libc_stat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_stat_trampoline_addr(SB)/8, $libc_stat_trampoline<>(SB) + +TEXT libc_statfs_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_statfs(SB) + +GLOBL ·libc_statfs_trampoline_addr(SB), RODATA, $8 +DATA ·libc_statfs_trampoline_addr(SB)/8, $libc_statfs_trampoline<>(SB) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_darwin_386.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_darwin_386.go deleted file mode 100644 index 1794ffc9245..00000000000 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_darwin_386.go +++ /dev/null @@ -1,438 +0,0 @@ -// go run mksysnum.go /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include/sys/syscall.h -// Code generated by the command above; see README.md. DO NOT EDIT. - -//go:build 386 && darwin -// +build 386,darwin - -package unix - -// Deprecated: Use libSystem wrappers instead of direct syscalls. -const ( - SYS_SYSCALL = 0 - SYS_EXIT = 1 - SYS_FORK = 2 - SYS_READ = 3 - SYS_WRITE = 4 - SYS_OPEN = 5 - SYS_CLOSE = 6 - SYS_WAIT4 = 7 - SYS_LINK = 9 - SYS_UNLINK = 10 - SYS_CHDIR = 12 - SYS_FCHDIR = 13 - SYS_MKNOD = 14 - SYS_CHMOD = 15 - SYS_CHOWN = 16 - SYS_GETFSSTAT = 18 - SYS_GETPID = 20 - SYS_SETUID = 23 - SYS_GETUID = 24 - SYS_GETEUID = 25 - SYS_PTRACE = 26 - SYS_RECVMSG = 27 - SYS_SENDMSG = 28 - SYS_RECVFROM = 29 - SYS_ACCEPT = 30 - SYS_GETPEERNAME = 31 - SYS_GETSOCKNAME = 32 - SYS_ACCESS = 33 - SYS_CHFLAGS = 34 - SYS_FCHFLAGS = 35 - SYS_SYNC = 36 - SYS_KILL = 37 - SYS_GETPPID = 39 - SYS_DUP = 41 - SYS_PIPE = 42 - SYS_GETEGID = 43 - SYS_SIGACTION = 46 - SYS_GETGID = 47 - SYS_SIGPROCMASK = 48 - SYS_GETLOGIN = 49 - SYS_SETLOGIN = 50 - SYS_ACCT = 51 - SYS_SIGPENDING = 52 - SYS_SIGALTSTACK = 53 - SYS_IOCTL = 54 - SYS_REBOOT = 55 - SYS_REVOKE = 56 - SYS_SYMLINK = 57 - SYS_READLINK = 58 - SYS_EXECVE = 59 - SYS_UMASK = 60 - SYS_CHROOT = 61 - SYS_MSYNC = 65 - SYS_VFORK = 66 - SYS_MUNMAP = 73 - SYS_MPROTECT = 74 - SYS_MADVISE = 75 - SYS_MINCORE = 78 - SYS_GETGROUPS = 79 - SYS_SETGROUPS = 80 - SYS_GETPGRP = 81 - SYS_SETPGID = 82 - SYS_SETITIMER = 83 - SYS_SWAPON = 85 - SYS_GETITIMER = 86 - SYS_GETDTABLESIZE = 89 - SYS_DUP2 = 90 - SYS_FCNTL = 92 - SYS_SELECT = 93 - SYS_FSYNC = 95 - SYS_SETPRIORITY = 96 - SYS_SOCKET = 97 - SYS_CONNECT = 98 - SYS_GETPRIORITY = 100 - SYS_BIND = 104 - SYS_SETSOCKOPT = 105 - SYS_LISTEN = 106 - SYS_SIGSUSPEND = 111 - SYS_GETTIMEOFDAY = 116 - SYS_GETRUSAGE = 117 - SYS_GETSOCKOPT = 118 - SYS_READV = 120 - SYS_WRITEV = 121 - SYS_SETTIMEOFDAY = 122 - SYS_FCHOWN = 123 - SYS_FCHMOD = 124 - SYS_SETREUID = 126 - SYS_SETREGID = 127 - SYS_RENAME = 128 - SYS_FLOCK = 131 - SYS_MKFIFO = 132 - SYS_SENDTO = 133 - SYS_SHUTDOWN = 134 - SYS_SOCKETPAIR = 135 - SYS_MKDIR = 136 - SYS_RMDIR = 137 - SYS_UTIMES = 138 - SYS_FUTIMES = 139 - SYS_ADJTIME = 140 - SYS_GETHOSTUUID = 142 - SYS_SETSID = 147 - SYS_GETPGID = 151 - SYS_SETPRIVEXEC = 152 - SYS_PREAD = 153 - SYS_PWRITE = 154 - SYS_NFSSVC = 155 - SYS_STATFS = 157 - SYS_FSTATFS = 158 - SYS_UNMOUNT = 159 - SYS_GETFH = 161 - SYS_QUOTACTL = 165 - SYS_MOUNT = 167 - SYS_CSOPS = 169 - SYS_CSOPS_AUDITTOKEN = 170 - SYS_WAITID = 173 - SYS_KDEBUG_TYPEFILTER = 177 - SYS_KDEBUG_TRACE_STRING = 178 - SYS_KDEBUG_TRACE64 = 179 - SYS_KDEBUG_TRACE = 180 - SYS_SETGID = 181 - SYS_SETEGID = 182 - SYS_SETEUID = 183 - SYS_SIGRETURN = 184 - SYS_THREAD_SELFCOUNTS = 186 - SYS_FDATASYNC = 187 - SYS_STAT = 188 - SYS_FSTAT = 189 - SYS_LSTAT = 190 - SYS_PATHCONF = 191 - SYS_FPATHCONF = 192 - SYS_GETRLIMIT = 194 - SYS_SETRLIMIT = 195 - SYS_GETDIRENTRIES = 196 - SYS_MMAP = 197 - SYS_LSEEK = 199 - SYS_TRUNCATE = 200 - SYS_FTRUNCATE = 201 - SYS_SYSCTL = 202 - SYS_MLOCK = 203 - SYS_MUNLOCK = 204 - SYS_UNDELETE = 205 - SYS_OPEN_DPROTECTED_NP = 216 - SYS_GETATTRLIST = 220 - SYS_SETATTRLIST = 221 - SYS_GETDIRENTRIESATTR = 222 - SYS_EXCHANGEDATA = 223 - SYS_SEARCHFS = 225 - SYS_DELETE = 226 - SYS_COPYFILE = 227 - SYS_FGETATTRLIST = 228 - SYS_FSETATTRLIST = 229 - SYS_POLL = 230 - SYS_WATCHEVENT = 231 - SYS_WAITEVENT = 232 - SYS_MODWATCH = 233 - SYS_GETXATTR = 234 - SYS_FGETXATTR = 235 - SYS_SETXATTR = 236 - SYS_FSETXATTR = 237 - SYS_REMOVEXATTR = 238 - SYS_FREMOVEXATTR = 239 - SYS_LISTXATTR = 240 - SYS_FLISTXATTR = 241 - SYS_FSCTL = 242 - SYS_INITGROUPS = 243 - SYS_POSIX_SPAWN = 244 - SYS_FFSCTL = 245 - SYS_NFSCLNT = 247 - SYS_FHOPEN = 248 - SYS_MINHERIT = 250 - SYS_SEMSYS = 251 - SYS_MSGSYS = 252 - SYS_SHMSYS = 253 - SYS_SEMCTL = 254 - SYS_SEMGET = 255 - SYS_SEMOP = 256 - SYS_MSGCTL = 258 - SYS_MSGGET = 259 - SYS_MSGSND = 260 - SYS_MSGRCV = 261 - SYS_SHMAT = 262 - SYS_SHMCTL = 263 - SYS_SHMDT = 264 - SYS_SHMGET = 265 - SYS_SHM_OPEN = 266 - SYS_SHM_UNLINK = 267 - SYS_SEM_OPEN = 268 - SYS_SEM_CLOSE = 269 - SYS_SEM_UNLINK = 270 - SYS_SEM_WAIT = 271 - SYS_SEM_TRYWAIT = 272 - SYS_SEM_POST = 273 - SYS_SYSCTLBYNAME = 274 - SYS_OPEN_EXTENDED = 277 - SYS_UMASK_EXTENDED = 278 - SYS_STAT_EXTENDED = 279 - SYS_LSTAT_EXTENDED = 280 - SYS_FSTAT_EXTENDED = 281 - SYS_CHMOD_EXTENDED = 282 - SYS_FCHMOD_EXTENDED = 283 - SYS_ACCESS_EXTENDED = 284 - SYS_SETTID = 285 - SYS_GETTID = 286 - SYS_SETSGROUPS = 287 - SYS_GETSGROUPS = 288 - SYS_SETWGROUPS = 289 - SYS_GETWGROUPS = 290 - SYS_MKFIFO_EXTENDED = 291 - SYS_MKDIR_EXTENDED = 292 - SYS_IDENTITYSVC = 293 - SYS_SHARED_REGION_CHECK_NP = 294 - SYS_VM_PRESSURE_MONITOR = 296 - SYS_PSYNCH_RW_LONGRDLOCK = 297 - SYS_PSYNCH_RW_YIELDWRLOCK = 298 - SYS_PSYNCH_RW_DOWNGRADE = 299 - SYS_PSYNCH_RW_UPGRADE = 300 - SYS_PSYNCH_MUTEXWAIT = 301 - SYS_PSYNCH_MUTEXDROP = 302 - SYS_PSYNCH_CVBROAD = 303 - SYS_PSYNCH_CVSIGNAL = 304 - SYS_PSYNCH_CVWAIT = 305 - SYS_PSYNCH_RW_RDLOCK = 306 - SYS_PSYNCH_RW_WRLOCK = 307 - SYS_PSYNCH_RW_UNLOCK = 308 - SYS_PSYNCH_RW_UNLOCK2 = 309 - SYS_GETSID = 310 - SYS_SETTID_WITH_PID = 311 - SYS_PSYNCH_CVCLRPREPOST = 312 - SYS_AIO_FSYNC = 313 - SYS_AIO_RETURN = 314 - SYS_AIO_SUSPEND = 315 - SYS_AIO_CANCEL = 316 - SYS_AIO_ERROR = 317 - SYS_AIO_READ = 318 - SYS_AIO_WRITE = 319 - SYS_LIO_LISTIO = 320 - SYS_IOPOLICYSYS = 322 - SYS_PROCESS_POLICY = 323 - SYS_MLOCKALL = 324 - SYS_MUNLOCKALL = 325 - SYS_ISSETUGID = 327 - SYS___PTHREAD_KILL = 328 - SYS___PTHREAD_SIGMASK = 329 - SYS___SIGWAIT = 330 - SYS___DISABLE_THREADSIGNAL = 331 - SYS___PTHREAD_MARKCANCEL = 332 - SYS___PTHREAD_CANCELED = 333 - SYS___SEMWAIT_SIGNAL = 334 - SYS_PROC_INFO = 336 - SYS_SENDFILE = 337 - SYS_STAT64 = 338 - SYS_FSTAT64 = 339 - SYS_LSTAT64 = 340 - SYS_STAT64_EXTENDED = 341 - SYS_LSTAT64_EXTENDED = 342 - SYS_FSTAT64_EXTENDED = 343 - SYS_GETDIRENTRIES64 = 344 - SYS_STATFS64 = 345 - SYS_FSTATFS64 = 346 - SYS_GETFSSTAT64 = 347 - SYS___PTHREAD_CHDIR = 348 - SYS___PTHREAD_FCHDIR = 349 - SYS_AUDIT = 350 - SYS_AUDITON = 351 - SYS_GETAUID = 353 - SYS_SETAUID = 354 - SYS_GETAUDIT_ADDR = 357 - SYS_SETAUDIT_ADDR = 358 - SYS_AUDITCTL = 359 - SYS_BSDTHREAD_CREATE = 360 - SYS_BSDTHREAD_TERMINATE = 361 - SYS_KQUEUE = 362 - SYS_KEVENT = 363 - SYS_LCHOWN = 364 - SYS_BSDTHREAD_REGISTER = 366 - SYS_WORKQ_OPEN = 367 - SYS_WORKQ_KERNRETURN = 368 - SYS_KEVENT64 = 369 - SYS___OLD_SEMWAIT_SIGNAL = 370 - SYS___OLD_SEMWAIT_SIGNAL_NOCANCEL = 371 - SYS_THREAD_SELFID = 372 - SYS_LEDGER = 373 - SYS_KEVENT_QOS = 374 - SYS_KEVENT_ID = 375 - SYS___MAC_EXECVE = 380 - SYS___MAC_SYSCALL = 381 - SYS___MAC_GET_FILE = 382 - SYS___MAC_SET_FILE = 383 - SYS___MAC_GET_LINK = 384 - SYS___MAC_SET_LINK = 385 - SYS___MAC_GET_PROC = 386 - SYS___MAC_SET_PROC = 387 - SYS___MAC_GET_FD = 388 - SYS___MAC_SET_FD = 389 - SYS___MAC_GET_PID = 390 - SYS_PSELECT = 394 - SYS_PSELECT_NOCANCEL = 395 - SYS_READ_NOCANCEL = 396 - SYS_WRITE_NOCANCEL = 397 - SYS_OPEN_NOCANCEL = 398 - SYS_CLOSE_NOCANCEL = 399 - SYS_WAIT4_NOCANCEL = 400 - SYS_RECVMSG_NOCANCEL = 401 - SYS_SENDMSG_NOCANCEL = 402 - SYS_RECVFROM_NOCANCEL = 403 - SYS_ACCEPT_NOCANCEL = 404 - SYS_MSYNC_NOCANCEL = 405 - SYS_FCNTL_NOCANCEL = 406 - SYS_SELECT_NOCANCEL = 407 - SYS_FSYNC_NOCANCEL = 408 - SYS_CONNECT_NOCANCEL = 409 - SYS_SIGSUSPEND_NOCANCEL = 410 - SYS_READV_NOCANCEL = 411 - SYS_WRITEV_NOCANCEL = 412 - SYS_SENDTO_NOCANCEL = 413 - SYS_PREAD_NOCANCEL = 414 - SYS_PWRITE_NOCANCEL = 415 - SYS_WAITID_NOCANCEL = 416 - SYS_POLL_NOCANCEL = 417 - SYS_MSGSND_NOCANCEL = 418 - SYS_MSGRCV_NOCANCEL = 419 - SYS_SEM_WAIT_NOCANCEL = 420 - SYS_AIO_SUSPEND_NOCANCEL = 421 - SYS___SIGWAIT_NOCANCEL = 422 - SYS___SEMWAIT_SIGNAL_NOCANCEL = 423 - SYS___MAC_MOUNT = 424 - SYS___MAC_GET_MOUNT = 425 - SYS___MAC_GETFSSTAT = 426 - SYS_FSGETPATH = 427 - SYS_AUDIT_SESSION_SELF = 428 - SYS_AUDIT_SESSION_JOIN = 429 - SYS_FILEPORT_MAKEPORT = 430 - SYS_FILEPORT_MAKEFD = 431 - SYS_AUDIT_SESSION_PORT = 432 - SYS_PID_SUSPEND = 433 - SYS_PID_RESUME = 434 - SYS_PID_HIBERNATE = 435 - SYS_PID_SHUTDOWN_SOCKETS = 436 - SYS_SHARED_REGION_MAP_AND_SLIDE_NP = 438 - SYS_KAS_INFO = 439 - SYS_MEMORYSTATUS_CONTROL = 440 - SYS_GUARDED_OPEN_NP = 441 - SYS_GUARDED_CLOSE_NP = 442 - SYS_GUARDED_KQUEUE_NP = 443 - SYS_CHANGE_FDGUARD_NP = 444 - SYS_USRCTL = 445 - SYS_PROC_RLIMIT_CONTROL = 446 - SYS_CONNECTX = 447 - SYS_DISCONNECTX = 448 - SYS_PEELOFF = 449 - SYS_SOCKET_DELEGATE = 450 - SYS_TELEMETRY = 451 - SYS_PROC_UUID_POLICY = 452 - SYS_MEMORYSTATUS_GET_LEVEL = 453 - SYS_SYSTEM_OVERRIDE = 454 - SYS_VFS_PURGE = 455 - SYS_SFI_CTL = 456 - SYS_SFI_PIDCTL = 457 - SYS_COALITION = 458 - SYS_COALITION_INFO = 459 - SYS_NECP_MATCH_POLICY = 460 - SYS_GETATTRLISTBULK = 461 - SYS_CLONEFILEAT = 462 - SYS_OPENAT = 463 - SYS_OPENAT_NOCANCEL = 464 - SYS_RENAMEAT = 465 - SYS_FACCESSAT = 466 - SYS_FCHMODAT = 467 - SYS_FCHOWNAT = 468 - SYS_FSTATAT = 469 - SYS_FSTATAT64 = 470 - SYS_LINKAT = 471 - SYS_UNLINKAT = 472 - SYS_READLINKAT = 473 - SYS_SYMLINKAT = 474 - SYS_MKDIRAT = 475 - SYS_GETATTRLISTAT = 476 - SYS_PROC_TRACE_LOG = 477 - SYS_BSDTHREAD_CTL = 478 - SYS_OPENBYID_NP = 479 - SYS_RECVMSG_X = 480 - SYS_SENDMSG_X = 481 - SYS_THREAD_SELFUSAGE = 482 - SYS_CSRCTL = 483 - SYS_GUARDED_OPEN_DPROTECTED_NP = 484 - SYS_GUARDED_WRITE_NP = 485 - SYS_GUARDED_PWRITE_NP = 486 - SYS_GUARDED_WRITEV_NP = 487 - SYS_RENAMEATX_NP = 488 - SYS_MREMAP_ENCRYPTED = 489 - SYS_NETAGENT_TRIGGER = 490 - SYS_STACK_SNAPSHOT_WITH_CONFIG = 491 - SYS_MICROSTACKSHOT = 492 - SYS_GRAB_PGO_DATA = 493 - SYS_PERSONA = 494 - SYS_WORK_INTERVAL_CTL = 499 - SYS_GETENTROPY = 500 - SYS_NECP_OPEN = 501 - SYS_NECP_CLIENT_ACTION = 502 - SYS___NEXUS_OPEN = 503 - SYS___NEXUS_REGISTER = 504 - SYS___NEXUS_DEREGISTER = 505 - SYS___NEXUS_CREATE = 506 - SYS___NEXUS_DESTROY = 507 - SYS___NEXUS_GET_OPT = 508 - SYS___NEXUS_SET_OPT = 509 - SYS___CHANNEL_OPEN = 510 - SYS___CHANNEL_GET_INFO = 511 - SYS___CHANNEL_SYNC = 512 - SYS___CHANNEL_GET_OPT = 513 - SYS___CHANNEL_SET_OPT = 514 - SYS_ULOCK_WAIT = 515 - SYS_ULOCK_WAKE = 516 - SYS_FCLONEFILEAT = 517 - SYS_FS_SNAPSHOT = 518 - SYS_TERMINATE_WITH_PAYLOAD = 520 - SYS_ABORT_WITH_PAYLOAD = 521 - SYS_NECP_SESSION_OPEN = 522 - SYS_NECP_SESSION_ACTION = 523 - SYS_SETATTRLISTAT = 524 - SYS_NET_QOS_GUIDELINE = 525 - SYS_FMOUNT = 526 - SYS_NTP_ADJTIME = 527 - SYS_NTP_GETTIME = 528 - SYS_OS_FAULT_WITH_PAYLOAD = 529 - SYS_MAXSYSCALL = 530 - SYS_INVALID = 63 -) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_darwin_arm.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_darwin_arm.go deleted file mode 100644 index 6dc736449a5..00000000000 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_darwin_arm.go +++ /dev/null @@ -1,438 +0,0 @@ -// go run mksysnum.go /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.1.sdk/usr/include/sys/syscall.h -// Code generated by the command above; see README.md. DO NOT EDIT. - -//go:build arm && darwin -// +build arm,darwin - -package unix - -// Deprecated: Use libSystem wrappers instead of direct syscalls. -const ( - SYS_SYSCALL = 0 - SYS_EXIT = 1 - SYS_FORK = 2 - SYS_READ = 3 - SYS_WRITE = 4 - SYS_OPEN = 5 - SYS_CLOSE = 6 - SYS_WAIT4 = 7 - SYS_LINK = 9 - SYS_UNLINK = 10 - SYS_CHDIR = 12 - SYS_FCHDIR = 13 - SYS_MKNOD = 14 - SYS_CHMOD = 15 - SYS_CHOWN = 16 - SYS_GETFSSTAT = 18 - SYS_GETPID = 20 - SYS_SETUID = 23 - SYS_GETUID = 24 - SYS_GETEUID = 25 - SYS_PTRACE = 26 - SYS_RECVMSG = 27 - SYS_SENDMSG = 28 - SYS_RECVFROM = 29 - SYS_ACCEPT = 30 - SYS_GETPEERNAME = 31 - SYS_GETSOCKNAME = 32 - SYS_ACCESS = 33 - SYS_CHFLAGS = 34 - SYS_FCHFLAGS = 35 - SYS_SYNC = 36 - SYS_KILL = 37 - SYS_GETPPID = 39 - SYS_DUP = 41 - SYS_PIPE = 42 - SYS_GETEGID = 43 - SYS_SIGACTION = 46 - SYS_GETGID = 47 - SYS_SIGPROCMASK = 48 - SYS_GETLOGIN = 49 - SYS_SETLOGIN = 50 - SYS_ACCT = 51 - SYS_SIGPENDING = 52 - SYS_SIGALTSTACK = 53 - SYS_IOCTL = 54 - SYS_REBOOT = 55 - SYS_REVOKE = 56 - SYS_SYMLINK = 57 - SYS_READLINK = 58 - SYS_EXECVE = 59 - SYS_UMASK = 60 - SYS_CHROOT = 61 - SYS_MSYNC = 65 - SYS_VFORK = 66 - SYS_MUNMAP = 73 - SYS_MPROTECT = 74 - SYS_MADVISE = 75 - SYS_MINCORE = 78 - SYS_GETGROUPS = 79 - SYS_SETGROUPS = 80 - SYS_GETPGRP = 81 - SYS_SETPGID = 82 - SYS_SETITIMER = 83 - SYS_SWAPON = 85 - SYS_GETITIMER = 86 - SYS_GETDTABLESIZE = 89 - SYS_DUP2 = 90 - SYS_FCNTL = 92 - SYS_SELECT = 93 - SYS_FSYNC = 95 - SYS_SETPRIORITY = 96 - SYS_SOCKET = 97 - SYS_CONNECT = 98 - SYS_GETPRIORITY = 100 - SYS_BIND = 104 - SYS_SETSOCKOPT = 105 - SYS_LISTEN = 106 - SYS_SIGSUSPEND = 111 - SYS_GETTIMEOFDAY = 116 - SYS_GETRUSAGE = 117 - SYS_GETSOCKOPT = 118 - SYS_READV = 120 - SYS_WRITEV = 121 - SYS_SETTIMEOFDAY = 122 - SYS_FCHOWN = 123 - SYS_FCHMOD = 124 - SYS_SETREUID = 126 - SYS_SETREGID = 127 - SYS_RENAME = 128 - SYS_FLOCK = 131 - SYS_MKFIFO = 132 - SYS_SENDTO = 133 - SYS_SHUTDOWN = 134 - SYS_SOCKETPAIR = 135 - SYS_MKDIR = 136 - SYS_RMDIR = 137 - SYS_UTIMES = 138 - SYS_FUTIMES = 139 - SYS_ADJTIME = 140 - SYS_GETHOSTUUID = 142 - SYS_SETSID = 147 - SYS_GETPGID = 151 - SYS_SETPRIVEXEC = 152 - SYS_PREAD = 153 - SYS_PWRITE = 154 - SYS_NFSSVC = 155 - SYS_STATFS = 157 - SYS_FSTATFS = 158 - SYS_UNMOUNT = 159 - SYS_GETFH = 161 - SYS_QUOTACTL = 165 - SYS_MOUNT = 167 - SYS_CSOPS = 169 - SYS_CSOPS_AUDITTOKEN = 170 - SYS_WAITID = 173 - SYS_KDEBUG_TYPEFILTER = 177 - SYS_KDEBUG_TRACE_STRING = 178 - SYS_KDEBUG_TRACE64 = 179 - SYS_KDEBUG_TRACE = 180 - SYS_SETGID = 181 - SYS_SETEGID = 182 - SYS_SETEUID = 183 - SYS_SIGRETURN = 184 - SYS_THREAD_SELFCOUNTS = 186 - SYS_FDATASYNC = 187 - SYS_STAT = 188 - SYS_FSTAT = 189 - SYS_LSTAT = 190 - SYS_PATHCONF = 191 - SYS_FPATHCONF = 192 - SYS_GETRLIMIT = 194 - SYS_SETRLIMIT = 195 - SYS_GETDIRENTRIES = 196 - SYS_MMAP = 197 - SYS_LSEEK = 199 - SYS_TRUNCATE = 200 - SYS_FTRUNCATE = 201 - SYS_SYSCTL = 202 - SYS_MLOCK = 203 - SYS_MUNLOCK = 204 - SYS_UNDELETE = 205 - SYS_OPEN_DPROTECTED_NP = 216 - SYS_GETATTRLIST = 220 - SYS_SETATTRLIST = 221 - SYS_GETDIRENTRIESATTR = 222 - SYS_EXCHANGEDATA = 223 - SYS_SEARCHFS = 225 - SYS_DELETE = 226 - SYS_COPYFILE = 227 - SYS_FGETATTRLIST = 228 - SYS_FSETATTRLIST = 229 - SYS_POLL = 230 - SYS_WATCHEVENT = 231 - SYS_WAITEVENT = 232 - SYS_MODWATCH = 233 - SYS_GETXATTR = 234 - SYS_FGETXATTR = 235 - SYS_SETXATTR = 236 - SYS_FSETXATTR = 237 - SYS_REMOVEXATTR = 238 - SYS_FREMOVEXATTR = 239 - SYS_LISTXATTR = 240 - SYS_FLISTXATTR = 241 - SYS_FSCTL = 242 - SYS_INITGROUPS = 243 - SYS_POSIX_SPAWN = 244 - SYS_FFSCTL = 245 - SYS_NFSCLNT = 247 - SYS_FHOPEN = 248 - SYS_MINHERIT = 250 - SYS_SEMSYS = 251 - SYS_MSGSYS = 252 - SYS_SHMSYS = 253 - SYS_SEMCTL = 254 - SYS_SEMGET = 255 - SYS_SEMOP = 256 - SYS_MSGCTL = 258 - SYS_MSGGET = 259 - SYS_MSGSND = 260 - SYS_MSGRCV = 261 - SYS_SHMAT = 262 - SYS_SHMCTL = 263 - SYS_SHMDT = 264 - SYS_SHMGET = 265 - SYS_SHM_OPEN = 266 - SYS_SHM_UNLINK = 267 - SYS_SEM_OPEN = 268 - SYS_SEM_CLOSE = 269 - SYS_SEM_UNLINK = 270 - SYS_SEM_WAIT = 271 - SYS_SEM_TRYWAIT = 272 - SYS_SEM_POST = 273 - SYS_SYSCTLBYNAME = 274 - SYS_OPEN_EXTENDED = 277 - SYS_UMASK_EXTENDED = 278 - SYS_STAT_EXTENDED = 279 - SYS_LSTAT_EXTENDED = 280 - SYS_FSTAT_EXTENDED = 281 - SYS_CHMOD_EXTENDED = 282 - SYS_FCHMOD_EXTENDED = 283 - SYS_ACCESS_EXTENDED = 284 - SYS_SETTID = 285 - SYS_GETTID = 286 - SYS_SETSGROUPS = 287 - SYS_GETSGROUPS = 288 - SYS_SETWGROUPS = 289 - SYS_GETWGROUPS = 290 - SYS_MKFIFO_EXTENDED = 291 - SYS_MKDIR_EXTENDED = 292 - SYS_IDENTITYSVC = 293 - SYS_SHARED_REGION_CHECK_NP = 294 - SYS_VM_PRESSURE_MONITOR = 296 - SYS_PSYNCH_RW_LONGRDLOCK = 297 - SYS_PSYNCH_RW_YIELDWRLOCK = 298 - SYS_PSYNCH_RW_DOWNGRADE = 299 - SYS_PSYNCH_RW_UPGRADE = 300 - SYS_PSYNCH_MUTEXWAIT = 301 - SYS_PSYNCH_MUTEXDROP = 302 - SYS_PSYNCH_CVBROAD = 303 - SYS_PSYNCH_CVSIGNAL = 304 - SYS_PSYNCH_CVWAIT = 305 - SYS_PSYNCH_RW_RDLOCK = 306 - SYS_PSYNCH_RW_WRLOCK = 307 - SYS_PSYNCH_RW_UNLOCK = 308 - SYS_PSYNCH_RW_UNLOCK2 = 309 - SYS_GETSID = 310 - SYS_SETTID_WITH_PID = 311 - SYS_PSYNCH_CVCLRPREPOST = 312 - SYS_AIO_FSYNC = 313 - SYS_AIO_RETURN = 314 - SYS_AIO_SUSPEND = 315 - SYS_AIO_CANCEL = 316 - SYS_AIO_ERROR = 317 - SYS_AIO_READ = 318 - SYS_AIO_WRITE = 319 - SYS_LIO_LISTIO = 320 - SYS_IOPOLICYSYS = 322 - SYS_PROCESS_POLICY = 323 - SYS_MLOCKALL = 324 - SYS_MUNLOCKALL = 325 - SYS_ISSETUGID = 327 - SYS___PTHREAD_KILL = 328 - SYS___PTHREAD_SIGMASK = 329 - SYS___SIGWAIT = 330 - SYS___DISABLE_THREADSIGNAL = 331 - SYS___PTHREAD_MARKCANCEL = 332 - SYS___PTHREAD_CANCELED = 333 - SYS___SEMWAIT_SIGNAL = 334 - SYS_PROC_INFO = 336 - SYS_SENDFILE = 337 - SYS_STAT64 = 338 - SYS_FSTAT64 = 339 - SYS_LSTAT64 = 340 - SYS_STAT64_EXTENDED = 341 - SYS_LSTAT64_EXTENDED = 342 - SYS_FSTAT64_EXTENDED = 343 - SYS_GETDIRENTRIES64 = 344 - SYS_STATFS64 = 345 - SYS_FSTATFS64 = 346 - SYS_GETFSSTAT64 = 347 - SYS___PTHREAD_CHDIR = 348 - SYS___PTHREAD_FCHDIR = 349 - SYS_AUDIT = 350 - SYS_AUDITON = 351 - SYS_GETAUID = 353 - SYS_SETAUID = 354 - SYS_GETAUDIT_ADDR = 357 - SYS_SETAUDIT_ADDR = 358 - SYS_AUDITCTL = 359 - SYS_BSDTHREAD_CREATE = 360 - SYS_BSDTHREAD_TERMINATE = 361 - SYS_KQUEUE = 362 - SYS_KEVENT = 363 - SYS_LCHOWN = 364 - SYS_BSDTHREAD_REGISTER = 366 - SYS_WORKQ_OPEN = 367 - SYS_WORKQ_KERNRETURN = 368 - SYS_KEVENT64 = 369 - SYS___OLD_SEMWAIT_SIGNAL = 370 - SYS___OLD_SEMWAIT_SIGNAL_NOCANCEL = 371 - SYS_THREAD_SELFID = 372 - SYS_LEDGER = 373 - SYS_KEVENT_QOS = 374 - SYS_KEVENT_ID = 375 - SYS___MAC_EXECVE = 380 - SYS___MAC_SYSCALL = 381 - SYS___MAC_GET_FILE = 382 - SYS___MAC_SET_FILE = 383 - SYS___MAC_GET_LINK = 384 - SYS___MAC_SET_LINK = 385 - SYS___MAC_GET_PROC = 386 - SYS___MAC_SET_PROC = 387 - SYS___MAC_GET_FD = 388 - SYS___MAC_SET_FD = 389 - SYS___MAC_GET_PID = 390 - SYS_PSELECT = 394 - SYS_PSELECT_NOCANCEL = 395 - SYS_READ_NOCANCEL = 396 - SYS_WRITE_NOCANCEL = 397 - SYS_OPEN_NOCANCEL = 398 - SYS_CLOSE_NOCANCEL = 399 - SYS_WAIT4_NOCANCEL = 400 - SYS_RECVMSG_NOCANCEL = 401 - SYS_SENDMSG_NOCANCEL = 402 - SYS_RECVFROM_NOCANCEL = 403 - SYS_ACCEPT_NOCANCEL = 404 - SYS_MSYNC_NOCANCEL = 405 - SYS_FCNTL_NOCANCEL = 406 - SYS_SELECT_NOCANCEL = 407 - SYS_FSYNC_NOCANCEL = 408 - SYS_CONNECT_NOCANCEL = 409 - SYS_SIGSUSPEND_NOCANCEL = 410 - SYS_READV_NOCANCEL = 411 - SYS_WRITEV_NOCANCEL = 412 - SYS_SENDTO_NOCANCEL = 413 - SYS_PREAD_NOCANCEL = 414 - SYS_PWRITE_NOCANCEL = 415 - SYS_WAITID_NOCANCEL = 416 - SYS_POLL_NOCANCEL = 417 - SYS_MSGSND_NOCANCEL = 418 - SYS_MSGRCV_NOCANCEL = 419 - SYS_SEM_WAIT_NOCANCEL = 420 - SYS_AIO_SUSPEND_NOCANCEL = 421 - SYS___SIGWAIT_NOCANCEL = 422 - SYS___SEMWAIT_SIGNAL_NOCANCEL = 423 - SYS___MAC_MOUNT = 424 - SYS___MAC_GET_MOUNT = 425 - SYS___MAC_GETFSSTAT = 426 - SYS_FSGETPATH = 427 - SYS_AUDIT_SESSION_SELF = 428 - SYS_AUDIT_SESSION_JOIN = 429 - SYS_FILEPORT_MAKEPORT = 430 - SYS_FILEPORT_MAKEFD = 431 - SYS_AUDIT_SESSION_PORT = 432 - SYS_PID_SUSPEND = 433 - SYS_PID_RESUME = 434 - SYS_PID_HIBERNATE = 435 - SYS_PID_SHUTDOWN_SOCKETS = 436 - SYS_SHARED_REGION_MAP_AND_SLIDE_NP = 438 - SYS_KAS_INFO = 439 - SYS_MEMORYSTATUS_CONTROL = 440 - SYS_GUARDED_OPEN_NP = 441 - SYS_GUARDED_CLOSE_NP = 442 - SYS_GUARDED_KQUEUE_NP = 443 - SYS_CHANGE_FDGUARD_NP = 444 - SYS_USRCTL = 445 - SYS_PROC_RLIMIT_CONTROL = 446 - SYS_CONNECTX = 447 - SYS_DISCONNECTX = 448 - SYS_PEELOFF = 449 - SYS_SOCKET_DELEGATE = 450 - SYS_TELEMETRY = 451 - SYS_PROC_UUID_POLICY = 452 - SYS_MEMORYSTATUS_GET_LEVEL = 453 - SYS_SYSTEM_OVERRIDE = 454 - SYS_VFS_PURGE = 455 - SYS_SFI_CTL = 456 - SYS_SFI_PIDCTL = 457 - SYS_COALITION = 458 - SYS_COALITION_INFO = 459 - SYS_NECP_MATCH_POLICY = 460 - SYS_GETATTRLISTBULK = 461 - SYS_CLONEFILEAT = 462 - SYS_OPENAT = 463 - SYS_OPENAT_NOCANCEL = 464 - SYS_RENAMEAT = 465 - SYS_FACCESSAT = 466 - SYS_FCHMODAT = 467 - SYS_FCHOWNAT = 468 - SYS_FSTATAT = 469 - SYS_FSTATAT64 = 470 - SYS_LINKAT = 471 - SYS_UNLINKAT = 472 - SYS_READLINKAT = 473 - SYS_SYMLINKAT = 474 - SYS_MKDIRAT = 475 - SYS_GETATTRLISTAT = 476 - SYS_PROC_TRACE_LOG = 477 - SYS_BSDTHREAD_CTL = 478 - SYS_OPENBYID_NP = 479 - SYS_RECVMSG_X = 480 - SYS_SENDMSG_X = 481 - SYS_THREAD_SELFUSAGE = 482 - SYS_CSRCTL = 483 - SYS_GUARDED_OPEN_DPROTECTED_NP = 484 - SYS_GUARDED_WRITE_NP = 485 - SYS_GUARDED_PWRITE_NP = 486 - SYS_GUARDED_WRITEV_NP = 487 - SYS_RENAMEATX_NP = 488 - SYS_MREMAP_ENCRYPTED = 489 - SYS_NETAGENT_TRIGGER = 490 - SYS_STACK_SNAPSHOT_WITH_CONFIG = 491 - SYS_MICROSTACKSHOT = 492 - SYS_GRAB_PGO_DATA = 493 - SYS_PERSONA = 494 - SYS_WORK_INTERVAL_CTL = 499 - SYS_GETENTROPY = 500 - SYS_NECP_OPEN = 501 - SYS_NECP_CLIENT_ACTION = 502 - SYS___NEXUS_OPEN = 503 - SYS___NEXUS_REGISTER = 504 - SYS___NEXUS_DEREGISTER = 505 - SYS___NEXUS_CREATE = 506 - SYS___NEXUS_DESTROY = 507 - SYS___NEXUS_GET_OPT = 508 - SYS___NEXUS_SET_OPT = 509 - SYS___CHANNEL_OPEN = 510 - SYS___CHANNEL_GET_INFO = 511 - SYS___CHANNEL_SYNC = 512 - SYS___CHANNEL_GET_OPT = 513 - SYS___CHANNEL_SET_OPT = 514 - SYS_ULOCK_WAIT = 515 - SYS_ULOCK_WAKE = 516 - SYS_FCLONEFILEAT = 517 - SYS_FS_SNAPSHOT = 518 - SYS_TERMINATE_WITH_PAYLOAD = 520 - SYS_ABORT_WITH_PAYLOAD = 521 - SYS_NECP_SESSION_OPEN = 522 - SYS_NECP_SESSION_ACTION = 523 - SYS_SETATTRLISTAT = 524 - SYS_NET_QOS_GUIDELINE = 525 - SYS_FMOUNT = 526 - SYS_NTP_ADJTIME = 527 - SYS_NTP_GETTIME = 528 - SYS_OS_FAULT_WITH_PAYLOAD = 529 - SYS_MAXSYSCALL = 530 - SYS_INVALID = 63 -) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_darwin_386.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_darwin_386.go deleted file mode 100644 index 883b64a2723..00000000000 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_darwin_386.go +++ /dev/null @@ -1,524 +0,0 @@ -// cgo -godefs types_darwin.go | go run mkpost.go -// Code generated by the command above; see README.md. DO NOT EDIT. - -//go:build 386 && darwin -// +build 386,darwin - -package unix - -const ( - SizeofPtr = 0x4 - SizeofShort = 0x2 - SizeofInt = 0x4 - SizeofLong = 0x4 - SizeofLongLong = 0x8 -) - -type ( - _C_short int16 - _C_int int32 - _C_long int32 - _C_long_long int64 -) - -type Timespec struct { - Sec int32 - Nsec int32 -} - -type Timeval struct { - Sec int32 - Usec int32 -} - -type Timeval32 struct{} - -type Rusage struct { - Utime Timeval - Stime Timeval - Maxrss int32 - Ixrss int32 - Idrss int32 - Isrss int32 - Minflt int32 - Majflt int32 - Nswap int32 - Inblock int32 - Oublock int32 - Msgsnd int32 - Msgrcv int32 - Nsignals int32 - Nvcsw int32 - Nivcsw int32 -} - -type Rlimit struct { - Cur uint64 - Max uint64 -} - -type _Gid_t uint32 - -type Stat_t struct { - Dev int32 - Mode uint16 - Nlink uint16 - Ino uint64 - Uid uint32 - Gid uint32 - Rdev int32 - Atim Timespec - Mtim Timespec - Ctim Timespec - Btim Timespec - Size int64 - Blocks int64 - Blksize int32 - Flags uint32 - Gen uint32 - Lspare int32 - Qspare [2]int64 -} - -type Statfs_t struct { - Bsize uint32 - Iosize int32 - Blocks uint64 - Bfree uint64 - Bavail uint64 - Files uint64 - Ffree uint64 - Fsid Fsid - Owner uint32 - Type uint32 - Flags uint32 - Fssubtype uint32 - Fstypename [16]byte - Mntonname [1024]byte - Mntfromname [1024]byte - Reserved [8]uint32 -} - -type Flock_t struct { - Start int64 - Len int64 - Pid int32 - Type int16 - Whence int16 -} - -type Fstore_t struct { - Flags uint32 - Posmode int32 - Offset int64 - Length int64 - Bytesalloc int64 -} - -type Radvisory_t struct { - Offset int64 - Count int32 -} - -type Fbootstraptransfer_t struct { - Offset int64 - Length uint32 - Buffer *byte -} - -type Log2phys_t struct { - Flags uint32 - Contigbytes int64 - Devoffset int64 -} - -type Fsid struct { - Val [2]int32 -} - -type Dirent struct { - Ino uint64 - Seekoff uint64 - Reclen uint16 - Namlen uint16 - Type uint8 - Name [1024]int8 - _ [3]byte -} - -const ( - PathMax = 0x400 -) - -type RawSockaddrInet4 struct { - Len uint8 - Family uint8 - Port uint16 - Addr [4]byte /* in_addr */ - Zero [8]int8 -} - -type RawSockaddrInet6 struct { - Len uint8 - Family uint8 - Port uint16 - Flowinfo uint32 - Addr [16]byte /* in6_addr */ - Scope_id uint32 -} - -type RawSockaddrUnix struct { - Len uint8 - Family uint8 - Path [104]int8 -} - -type RawSockaddrDatalink struct { - Len uint8 - Family uint8 - Index uint16 - Type uint8 - Nlen uint8 - Alen uint8 - Slen uint8 - Data [12]int8 -} - -type RawSockaddr struct { - Len uint8 - Family uint8 - Data [14]int8 -} - -type RawSockaddrAny struct { - Addr RawSockaddr - Pad [92]int8 -} - -type RawSockaddrCtl struct { - Sc_len uint8 - Sc_family uint8 - Ss_sysaddr uint16 - Sc_id uint32 - Sc_unit uint32 - Sc_reserved [5]uint32 -} - -type _Socklen uint32 - -type Linger struct { - Onoff int32 - Linger int32 -} - -type Iovec struct { - Base *byte - Len uint32 -} - -type IPMreq struct { - Multiaddr [4]byte /* in_addr */ - Interface [4]byte /* in_addr */ -} - -type IPMreqn struct { - Multiaddr [4]byte /* in_addr */ - Address [4]byte /* in_addr */ - Ifindex int32 -} - -type IPv6Mreq struct { - Multiaddr [16]byte /* in6_addr */ - Interface uint32 -} - -type Msghdr struct { - Name *byte - Namelen uint32 - Iov *Iovec - Iovlen int32 - Control *byte - Controllen uint32 - Flags int32 -} - -type Cmsghdr struct { - Len uint32 - Level int32 - Type int32 -} - -type Inet4Pktinfo struct { - Ifindex uint32 - Spec_dst [4]byte /* in_addr */ - Addr [4]byte /* in_addr */ -} - -type Inet6Pktinfo struct { - Addr [16]byte /* in6_addr */ - Ifindex uint32 -} - -type IPv6MTUInfo struct { - Addr RawSockaddrInet6 - Mtu uint32 -} - -type ICMPv6Filter struct { - Filt [8]uint32 -} - -const ( - SizeofSockaddrInet4 = 0x10 - SizeofSockaddrInet6 = 0x1c - SizeofSockaddrAny = 0x6c - SizeofSockaddrUnix = 0x6a - SizeofSockaddrDatalink = 0x14 - SizeofSockaddrCtl = 0x20 - SizeofLinger = 0x8 - SizeofIovec = 0x8 - SizeofIPMreq = 0x8 - SizeofIPMreqn = 0xc - SizeofIPv6Mreq = 0x14 - SizeofMsghdr = 0x1c - SizeofCmsghdr = 0xc - SizeofInet4Pktinfo = 0xc - SizeofInet6Pktinfo = 0x14 - SizeofIPv6MTUInfo = 0x20 - SizeofICMPv6Filter = 0x20 -) - -const ( - PTRACE_TRACEME = 0x0 - PTRACE_CONT = 0x7 - PTRACE_KILL = 0x8 -) - -type Kevent_t struct { - Ident uint32 - Filter int16 - Flags uint16 - Fflags uint32 - Data int32 - Udata *byte -} - -type FdSet struct { - Bits [32]int32 -} - -const ( - SizeofIfMsghdr = 0x70 - SizeofIfData = 0x60 - SizeofIfaMsghdr = 0x14 - SizeofIfmaMsghdr = 0x10 - SizeofIfmaMsghdr2 = 0x14 - SizeofRtMsghdr = 0x5c - SizeofRtMetrics = 0x38 -) - -type IfMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Data IfData -} - -type IfData struct { - Type uint8 - Typelen uint8 - Physical uint8 - Addrlen uint8 - Hdrlen uint8 - Recvquota uint8 - Xmitquota uint8 - Unused1 uint8 - Mtu uint32 - Metric uint32 - Baudrate uint32 - Ipackets uint32 - Ierrors uint32 - Opackets uint32 - Oerrors uint32 - Collisions uint32 - Ibytes uint32 - Obytes uint32 - Imcasts uint32 - Omcasts uint32 - Iqdrops uint32 - Noproto uint32 - Recvtiming uint32 - Xmittiming uint32 - Lastchange Timeval - Unused2 uint32 - Hwassist uint32 - Reserved1 uint32 - Reserved2 uint32 -} - -type IfaMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Metric int32 -} - -type IfmaMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - _ [2]byte -} - -type IfmaMsghdr2 struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Refcount int32 -} - -type RtMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Index uint16 - Flags int32 - Addrs int32 - Pid int32 - Seq int32 - Errno int32 - Use int32 - Inits uint32 - Rmx RtMetrics -} - -type RtMetrics struct { - Locks uint32 - Mtu uint32 - Hopcount uint32 - Expire int32 - Recvpipe uint32 - Sendpipe uint32 - Ssthresh uint32 - Rtt uint32 - Rttvar uint32 - Pksent uint32 - State uint32 - Filler [3]uint32 -} - -const ( - SizeofBpfVersion = 0x4 - SizeofBpfStat = 0x8 - SizeofBpfProgram = 0x8 - SizeofBpfInsn = 0x8 - SizeofBpfHdr = 0x14 -) - -type BpfVersion struct { - Major uint16 - Minor uint16 -} - -type BpfStat struct { - Recv uint32 - Drop uint32 -} - -type BpfProgram struct { - Len uint32 - Insns *BpfInsn -} - -type BpfInsn struct { - Code uint16 - Jt uint8 - Jf uint8 - K uint32 -} - -type BpfHdr struct { - Tstamp Timeval - Caplen uint32 - Datalen uint32 - Hdrlen uint16 - _ [2]byte -} - -type Termios struct { - Iflag uint32 - Oflag uint32 - Cflag uint32 - Lflag uint32 - Cc [20]uint8 - Ispeed uint32 - Ospeed uint32 -} - -type Winsize struct { - Row uint16 - Col uint16 - Xpixel uint16 - Ypixel uint16 -} - -const ( - AT_FDCWD = -0x2 - AT_REMOVEDIR = 0x80 - AT_SYMLINK_FOLLOW = 0x40 - AT_SYMLINK_NOFOLLOW = 0x20 -) - -type PollFd struct { - Fd int32 - Events int16 - Revents int16 -} - -const ( - POLLERR = 0x8 - POLLHUP = 0x10 - POLLIN = 0x1 - POLLNVAL = 0x20 - POLLOUT = 0x4 - POLLPRI = 0x2 - POLLRDBAND = 0x80 - POLLRDNORM = 0x40 - POLLWRBAND = 0x100 - POLLWRNORM = 0x4 -) - -type Utsname struct { - Sysname [256]byte - Nodename [256]byte - Release [256]byte - Version [256]byte - Machine [256]byte -} - -const SizeofClockinfo = 0x14 - -type Clockinfo struct { - Hz int32 - Tick int32 - Tickadj int32 - Stathz int32 - Profhz int32 -} - -type CtlInfo struct { - Id uint32 - Name [96]byte -} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go deleted file mode 100644 index eef51338574..00000000000 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go +++ /dev/null @@ -1,524 +0,0 @@ -// cgo -godefs types_darwin.go | go run mkpost.go -// Code generated by the command above; see README.md. DO NOT EDIT. - -//go:build arm && darwin -// +build arm,darwin - -package unix - -const ( - SizeofPtr = 0x4 - SizeofShort = 0x2 - SizeofInt = 0x4 - SizeofLong = 0x4 - SizeofLongLong = 0x8 -) - -type ( - _C_short int16 - _C_int int32 - _C_long int32 - _C_long_long int64 -) - -type Timespec struct { - Sec int32 - Nsec int32 -} - -type Timeval struct { - Sec int32 - Usec int32 -} - -type Timeval32 struct{} - -type Rusage struct { - Utime Timeval - Stime Timeval - Maxrss int32 - Ixrss int32 - Idrss int32 - Isrss int32 - Minflt int32 - Majflt int32 - Nswap int32 - Inblock int32 - Oublock int32 - Msgsnd int32 - Msgrcv int32 - Nsignals int32 - Nvcsw int32 - Nivcsw int32 -} - -type Rlimit struct { - Cur uint64 - Max uint64 -} - -type _Gid_t uint32 - -type Stat_t struct { - Dev int32 - Mode uint16 - Nlink uint16 - Ino uint64 - Uid uint32 - Gid uint32 - Rdev int32 - Atim Timespec - Mtim Timespec - Ctim Timespec - Btim Timespec - Size int64 - Blocks int64 - Blksize int32 - Flags uint32 - Gen uint32 - Lspare int32 - Qspare [2]int64 -} - -type Statfs_t struct { - Bsize uint32 - Iosize int32 - Blocks uint64 - Bfree uint64 - Bavail uint64 - Files uint64 - Ffree uint64 - Fsid Fsid - Owner uint32 - Type uint32 - Flags uint32 - Fssubtype uint32 - Fstypename [16]byte - Mntonname [1024]byte - Mntfromname [1024]byte - Reserved [8]uint32 -} - -type Flock_t struct { - Start int64 - Len int64 - Pid int32 - Type int16 - Whence int16 -} - -type Fstore_t struct { - Flags uint32 - Posmode int32 - Offset int64 - Length int64 - Bytesalloc int64 -} - -type Radvisory_t struct { - Offset int64 - Count int32 -} - -type Fbootstraptransfer_t struct { - Offset int64 - Length uint32 - Buffer *byte -} - -type Log2phys_t struct { - Flags uint32 - Contigbytes int64 - Devoffset int64 -} - -type Fsid struct { - Val [2]int32 -} - -type Dirent struct { - Ino uint64 - Seekoff uint64 - Reclen uint16 - Namlen uint16 - Type uint8 - Name [1024]int8 - _ [3]byte -} - -const ( - PathMax = 0x400 -) - -type RawSockaddrInet4 struct { - Len uint8 - Family uint8 - Port uint16 - Addr [4]byte /* in_addr */ - Zero [8]int8 -} - -type RawSockaddrInet6 struct { - Len uint8 - Family uint8 - Port uint16 - Flowinfo uint32 - Addr [16]byte /* in6_addr */ - Scope_id uint32 -} - -type RawSockaddrUnix struct { - Len uint8 - Family uint8 - Path [104]int8 -} - -type RawSockaddrDatalink struct { - Len uint8 - Family uint8 - Index uint16 - Type uint8 - Nlen uint8 - Alen uint8 - Slen uint8 - Data [12]int8 -} - -type RawSockaddr struct { - Len uint8 - Family uint8 - Data [14]int8 -} - -type RawSockaddrAny struct { - Addr RawSockaddr - Pad [92]int8 -} - -type RawSockaddrCtl struct { - Sc_len uint8 - Sc_family uint8 - Ss_sysaddr uint16 - Sc_id uint32 - Sc_unit uint32 - Sc_reserved [5]uint32 -} - -type _Socklen uint32 - -type Linger struct { - Onoff int32 - Linger int32 -} - -type Iovec struct { - Base *byte - Len uint32 -} - -type IPMreq struct { - Multiaddr [4]byte /* in_addr */ - Interface [4]byte /* in_addr */ -} - -type IPMreqn struct { - Multiaddr [4]byte /* in_addr */ - Address [4]byte /* in_addr */ - Ifindex int32 -} - -type IPv6Mreq struct { - Multiaddr [16]byte /* in6_addr */ - Interface uint32 -} - -type Msghdr struct { - Name *byte - Namelen uint32 - Iov *Iovec - Iovlen int32 - Control *byte - Controllen uint32 - Flags int32 -} - -type Cmsghdr struct { - Len uint32 - Level int32 - Type int32 -} - -type Inet4Pktinfo struct { - Ifindex uint32 - Spec_dst [4]byte /* in_addr */ - Addr [4]byte /* in_addr */ -} - -type Inet6Pktinfo struct { - Addr [16]byte /* in6_addr */ - Ifindex uint32 -} - -type IPv6MTUInfo struct { - Addr RawSockaddrInet6 - Mtu uint32 -} - -type ICMPv6Filter struct { - Filt [8]uint32 -} - -const ( - SizeofSockaddrInet4 = 0x10 - SizeofSockaddrInet6 = 0x1c - SizeofSockaddrAny = 0x6c - SizeofSockaddrUnix = 0x6a - SizeofSockaddrDatalink = 0x14 - SizeofSockaddrCtl = 0x20 - SizeofLinger = 0x8 - SizeofIovec = 0x8 - SizeofIPMreq = 0x8 - SizeofIPMreqn = 0xc - SizeofIPv6Mreq = 0x14 - SizeofMsghdr = 0x1c - SizeofCmsghdr = 0xc - SizeofInet4Pktinfo = 0xc - SizeofInet6Pktinfo = 0x14 - SizeofIPv6MTUInfo = 0x20 - SizeofICMPv6Filter = 0x20 -) - -const ( - PTRACE_TRACEME = 0x0 - PTRACE_CONT = 0x7 - PTRACE_KILL = 0x8 -) - -type Kevent_t struct { - Ident uint32 - Filter int16 - Flags uint16 - Fflags uint32 - Data int32 - Udata *byte -} - -type FdSet struct { - Bits [32]int32 -} - -const ( - SizeofIfMsghdr = 0x70 - SizeofIfData = 0x60 - SizeofIfaMsghdr = 0x14 - SizeofIfmaMsghdr = 0x10 - SizeofIfmaMsghdr2 = 0x14 - SizeofRtMsghdr = 0x5c - SizeofRtMetrics = 0x38 -) - -type IfMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Data IfData -} - -type IfData struct { - Type uint8 - Typelen uint8 - Physical uint8 - Addrlen uint8 - Hdrlen uint8 - Recvquota uint8 - Xmitquota uint8 - Unused1 uint8 - Mtu uint32 - Metric uint32 - Baudrate uint32 - Ipackets uint32 - Ierrors uint32 - Opackets uint32 - Oerrors uint32 - Collisions uint32 - Ibytes uint32 - Obytes uint32 - Imcasts uint32 - Omcasts uint32 - Iqdrops uint32 - Noproto uint32 - Recvtiming uint32 - Xmittiming uint32 - Lastchange Timeval - Unused2 uint32 - Hwassist uint32 - Reserved1 uint32 - Reserved2 uint32 -} - -type IfaMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Metric int32 -} - -type IfmaMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - _ [2]byte -} - -type IfmaMsghdr2 struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Refcount int32 -} - -type RtMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Index uint16 - Flags int32 - Addrs int32 - Pid int32 - Seq int32 - Errno int32 - Use int32 - Inits uint32 - Rmx RtMetrics -} - -type RtMetrics struct { - Locks uint32 - Mtu uint32 - Hopcount uint32 - Expire int32 - Recvpipe uint32 - Sendpipe uint32 - Ssthresh uint32 - Rtt uint32 - Rttvar uint32 - Pksent uint32 - State uint32 - Filler [3]uint32 -} - -const ( - SizeofBpfVersion = 0x4 - SizeofBpfStat = 0x8 - SizeofBpfProgram = 0x8 - SizeofBpfInsn = 0x8 - SizeofBpfHdr = 0x14 -) - -type BpfVersion struct { - Major uint16 - Minor uint16 -} - -type BpfStat struct { - Recv uint32 - Drop uint32 -} - -type BpfProgram struct { - Len uint32 - Insns *BpfInsn -} - -type BpfInsn struct { - Code uint16 - Jt uint8 - Jf uint8 - K uint32 -} - -type BpfHdr struct { - Tstamp Timeval - Caplen uint32 - Datalen uint32 - Hdrlen uint16 - _ [2]byte -} - -type Termios struct { - Iflag uint32 - Oflag uint32 - Cflag uint32 - Lflag uint32 - Cc [20]uint8 - Ispeed uint32 - Ospeed uint32 -} - -type Winsize struct { - Row uint16 - Col uint16 - Xpixel uint16 - Ypixel uint16 -} - -const ( - AT_FDCWD = -0x2 - AT_REMOVEDIR = 0x80 - AT_SYMLINK_FOLLOW = 0x40 - AT_SYMLINK_NOFOLLOW = 0x20 -) - -type PollFd struct { - Fd int32 - Events int16 - Revents int16 -} - -const ( - POLLERR = 0x8 - POLLHUP = 0x10 - POLLIN = 0x1 - POLLNVAL = 0x20 - POLLOUT = 0x4 - POLLPRI = 0x2 - POLLRDBAND = 0x80 - POLLRDNORM = 0x40 - POLLWRBAND = 0x100 - POLLWRNORM = 0x4 -) - -type Utsname struct { - Sysname [256]byte - Nodename [256]byte - Release [256]byte - Version [256]byte - Machine [256]byte -} - -const SizeofClockinfo = 0x14 - -type Clockinfo struct { - Hz int32 - Tick int32 - Tickadj int32 - Stathz int32 - Profhz int32 -} - -type CtlInfo struct { - Id uint32 - Name [96]byte -} diff --git a/src/cmd/vendor/golang.org/x/sys/windows/empty.s b/src/cmd/vendor/golang.org/x/sys/windows/empty.s index 69309e4da55..fdbbbcd3171 100644 --- a/src/cmd/vendor/golang.org/x/sys/windows/empty.s +++ b/src/cmd/vendor/golang.org/x/sys/windows/empty.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !go1.12 // +build !go1.12 // This file is here to allow bodyless functions with go:linkname for Go 1.11 diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt index 5fb1c25acee..10591f8041b 100644 --- a/src/cmd/vendor/modules.txt +++ b/src/cmd/vendor/modules.txt @@ -39,7 +39,7 @@ golang.org/x/mod/sumdb/dirhash golang.org/x/mod/sumdb/note golang.org/x/mod/sumdb/tlog golang.org/x/mod/zip -# golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 +# golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 ## explicit; go 1.17 golang.org/x/sys/internal/unsafeheader golang.org/x/sys/plan9 From a63cded5e413ffad1ec8088ef7abd10abb7b5252 Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Wed, 12 May 2021 11:03:48 -0400 Subject: [PATCH 039/940] debug/dwarf: delay array type fixup to handle type cycles A user encountered a debug/dwarf crash when running the dwarf2json tool (https://github.com/volatilityfoundation/dwarf2json) on a debug-built copy of the linux kernel. In this crash, the DWARF type reader was trying to examine the contents of an array type while that array type was still in the process of being constructed (due to cycles in the type graph). To avoid such situations, this patch extends the mechanism introduced in https://go-review.googlesource.com/18459 (which handles typedef types) to delay fixup of array types as well. Change-Id: I303f6ce5db1ca4bd79da3581957dfc2bfc17cc01 Reviewed-on: https://go-review.googlesource.com/c/go/+/319329 Trust: Than McIntosh Run-TryBot: Than McIntosh Reviewed-by: Cherry Mui Reviewed-by: Yi Chou TryBot-Result: Go Bot --- src/debug/dwarf/type.go | 59 +++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/src/debug/dwarf/type.go b/src/debug/dwarf/type.go index 316db258f65..eb5a666ed38 100644 --- a/src/debug/dwarf/type.go +++ b/src/debug/dwarf/type.go @@ -292,11 +292,35 @@ func (d *Data) Type(off Offset) (Type, error) { return d.readType("info", d.Reader(), off, d.typeCache, nil) } +type typeFixer struct { + typedefs []*TypedefType + arraytypes []*Type +} + +func (tf *typeFixer) recordArrayType(t *Type) { + if t == nil { + return + } + _, ok := (*t).(*ArrayType) + if ok { + tf.arraytypes = append(tf.arraytypes, t) + } +} + +func (tf *typeFixer) apply() { + for _, t := range tf.typedefs { + t.Common().ByteSize = t.Type.Size() + } + for _, t := range tf.arraytypes { + zeroArray(t) + } +} + // readType reads a type from r at off of name. It adds types to the // type cache, appends new typedef types to typedefs, and computes the // sizes of types. Callers should pass nil for typedefs; this is used // for internal recursion. -func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Offset]Type, typedefs *[]*TypedefType) (Type, error) { +func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Offset]Type, fixups *typeFixer) (Type, error) { if t, ok := typeCache[off]; ok { return t, nil } @@ -311,18 +335,16 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off } // If this is the root of the recursion, prepare to resolve - // typedef sizes once the recursion is done. This must be done - // after the type graph is constructed because it may need to - // resolve cycles in a different order than readType - // encounters them. - if typedefs == nil { - var typedefList []*TypedefType + // typedef sizes and perform other fixups once the recursion is + // done. This must be done after the type graph is constructed + // because it may need to resolve cycles in a different order than + // readType encounters them. + if fixups == nil { + var fixer typeFixer defer func() { - for _, t := range typedefList { - t.Common().ByteSize = t.Type.Size() - } + fixer.apply() }() - typedefs = &typedefList + fixups = &fixer } // Parse type from Entry. @@ -376,7 +398,7 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off var t Type switch toff := tval.(type) { case Offset: - if t, err = d.readType(name, r.clone(), toff, typeCache, typedefs); err != nil { + if t, err = d.readType(name, r.clone(), toff, typeCache, fixups); err != nil { return nil } case uint64: @@ -567,7 +589,7 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off if bito == lastFieldBitOffset && t.Kind != "union" { // Last field was zero width. Fix array length. // (DWARF writes out 0-length arrays as if they were 1-length arrays.) - zeroArray(lastFieldType) + fixups.recordArrayType(lastFieldType) } lastFieldType = &f.Type lastFieldBitOffset = bito @@ -576,7 +598,7 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off b, ok := e.Val(AttrByteSize).(int64) if ok && b*8 == lastFieldBitOffset { // Final field must be zero width. Fix array length. - zeroArray(lastFieldType) + fixups.recordArrayType(lastFieldType) } } @@ -719,7 +741,7 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off // Record that we need to resolve this // type's size once the type graph is // constructed. - *typedefs = append(*typedefs, t) + fixups.typedefs = append(fixups.typedefs, t) case *PtrType: b = int64(addressSize) } @@ -737,11 +759,8 @@ Error: } func zeroArray(t *Type) { - if t == nil { - return - } - at, ok := (*t).(*ArrayType) - if !ok || at.Type.Size() == 0 { + at := (*t).(*ArrayType) + if at.Type.Size() == 0 { return } // Make a copy to avoid invalidating typeCache. From fd4631e24f53cf836a67b00e82e2159854ec31d0 Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Tue, 11 May 2021 11:29:27 -0400 Subject: [PATCH 040/940] cmd/compile/internal/dwarfgen: fix DWARF param DIE ordering The DWARF standard requires that the DIEs in a subprogram corresponding to input and output parameters appear in declaration order; this patch adds some new code in dwarfgen to enforce this ordering (relying on the existing fn.Dcl ordering is not sufficient). Prior to the register ABI, it was easy to keep vars/decls sorted during DWARF generation since you could always rely on frame offset; with the ABI sorting by frame offset no longer gives you the original declaration order in all cases. Fixes #46055. Change-Id: I0e070cb781d6453caba896e5d3bee7cd5388050d Reviewed-on: https://go-review.googlesource.com/c/go/+/318829 Trust: Than McIntosh Run-TryBot: Than McIntosh TryBot-Result: Go Bot Reviewed-by: Alessandro Arzilli Reviewed-by: Cherry Mui --- src/cmd/compile/internal/dwarfgen/dwarf.go | 55 ++++++++++++++++++++++ src/cmd/link/internal/ld/dwarf_test.go | 30 +++++++----- 2 files changed, 72 insertions(+), 13 deletions(-) diff --git a/src/cmd/compile/internal/dwarfgen/dwarf.go b/src/cmd/compile/internal/dwarfgen/dwarf.go index 422c7e66c47..5d7dc320aa8 100644 --- a/src/cmd/compile/internal/dwarfgen/dwarf.go +++ b/src/cmd/compile/internal/dwarfgen/dwarf.go @@ -222,9 +222,64 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir fnsym.Func().RecordAutoType(reflectdata.TypeLinksym(n.Type())) } + // Sort decls and vars. + sortDeclsAndVars(fn, decls, vars) + return decls, vars } +// sortDeclsAndVars sorts the decl and dwarf var lists according to +// parameter declaration order, so as to insure that when a subprogram +// DIE is emitted, its parameter children appear in declaration order. +// Prior to the advent of the register ABI, sorting by frame offset +// would achieve this; with the register we now need to go back to the +// original function signature. +func sortDeclsAndVars(fn *ir.Func, decls []*ir.Name, vars []*dwarf.Var) { + paramOrder := make(map[*ir.Name]int) + idx := 1 + for _, selfn := range types.RecvsParamsResults { + fsl := selfn(fn.Type()).FieldSlice() + for _, f := range fsl { + if n, ok := f.Nname.(*ir.Name); ok { + paramOrder[n] = idx + idx++ + } + } + } + sort.Stable(varsAndDecls{decls, vars, paramOrder}) +} + +type varsAndDecls struct { + decls []*ir.Name + vars []*dwarf.Var + paramOrder map[*ir.Name]int +} + +func (v varsAndDecls) Len() int { + return len(v.decls) +} + +func (v varsAndDecls) Less(i, j int) bool { + nameLT := func(ni, nj *ir.Name) bool { + oi, foundi := v.paramOrder[ni] + oj, foundj := v.paramOrder[nj] + if foundi { + if foundj { + return oi < oj + } else { + return true + } + } + return false + } + return nameLT(v.decls[i], v.decls[j]) +} + +func (v varsAndDecls) Swap(i, j int) { + v.vars[i], v.vars[j] = v.vars[j], v.vars[i] + v.decls[i], v.decls[j] = v.decls[j], v.decls[i] +} + // Given a function that was inlined at some point during the // compilation, return a sorted list of nodes corresponding to the // autos/locals in that function prior to inlining. If this is a diff --git a/src/cmd/link/internal/ld/dwarf_test.go b/src/cmd/link/internal/ld/dwarf_test.go index 5cc4800e2a3..2f59c2fe0aa 100644 --- a/src/cmd/link/internal/ld/dwarf_test.go +++ b/src/cmd/link/internal/ld/dwarf_test.go @@ -1660,16 +1660,16 @@ func TestOutputParamAbbrevAndAttr(t *testing.T) { package main //go:noinline -func ABC(p1, p2, p3 int, f1, f2, f3 float32, b1 [1024]int) (r1 int, r2 int, r3 [1024]int, r4 byte) { - b1[0] = 6 - r1, r2, r3, r4 = p3, p2, b1, 'a' +func ABC(c1, c2, c3 int, d1, d2, d3, d4 string, f1, f2, f3 float32, g1 [1024]int) (r1 int, r2 int, r3 [1024]int, r4 byte, r5 string, r6 float32) { + g1[0] = 6 + r1, r2, r3, r4, r5, r6 = c3, c2+c1, g1, 'a', d1+d2+d3+d4, f1+f2+f3 return } func main() { a := [1024]int{} - v1, v2, v3, v4 := ABC(1, 2, 3, 1.0, 2.0, 1.0, a) - println(v1, v2, v3[0], v4) + v1, v2, v3, v4, v5, v6 := ABC(1, 2, 3, "a", "b", "c", "d", 1.0, 2.0, 1.0, a) + println(v1, v2, v3[0], v4, v5, v6) } ` dir := t.TempDir() @@ -1708,18 +1708,20 @@ func main() { // OK to have it missing for input parameters, but for the moment // we verify that the attr is present but set to false. - // Values in this map: + // Values in this map are of the form : + // where order is the order within the child DIE list of the param, + // and is an integer: // - // 0: // -1: varparm attr not found // 1: varparm found with value false // 2: varparm found with value true // - foundParams := make(map[string]int) + foundParams := make(map[string]string) // Walk ABCs's children looking for params. abcIdx := ex.idxFromOffset(abcdie.Offset) childDies := ex.Children(abcIdx) + idx := 0 for _, child := range childDies { if child.Tag == dwarf.TagFormalParameter { st := -1 @@ -1731,7 +1733,8 @@ func main() { } } if name, ok := child.Val(dwarf.AttrName).(string); ok { - foundParams[name] = st + foundParams[name] = fmt.Sprintf("%d:%d", idx, st) + idx++ } } } @@ -1739,13 +1742,14 @@ func main() { // Digest the result. found := make([]string, 0, len(foundParams)) for k, v := range foundParams { - found = append(found, fmt.Sprintf("%s:%d", k, v)) + found = append(found, fmt.Sprintf("%s:%s", k, v)) } sort.Strings(found) - // Make sure we see all of the expected params, that they have - // the varparam attr, and the varparm is set for the returns. - expected := "[b1:1 f1:1 f2:1 f3:1 p1:1 p2:1 p3:1 r1:2 r2:2 r3:2 r4:2]" + // Make sure we see all of the expected params in the proper + // order, that they have the varparam attr, and the varparm is set + // for the returns. + expected := "[c1:0:1 c2:1:1 c3:2:1 d1:3:1 d2:4:1 d3:5:1 d4:6:1 f1:7:1 f2:8:1 f3:9:1 g1:10:1 r1:11:2 r2:12:2 r3:13:2 r4:14:2 r5:15:2 r6:16:2]" if fmt.Sprintf("%+v", found) != expected { t.Errorf("param check failed, wanted %s got %s\n", expected, found) From 2a61b3c59088115245d084d5ae07dd4be5fbe1b0 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 11 May 2021 10:52:44 -0400 Subject: [PATCH 041/940] regexp: fix repeat of preferred empty match MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In Perl mode, (|a)* should match an empty string at the start of the input. Instead it matches as many a's as possible. Because (|a)+ is handled correctly, matching only an empty string, this leads to the paradox that e* can match more text than e+ (for e = (|a)) and that e+ is sometimes different from ee*. This is a very old bug that ultimately derives from the picture I drew for e* in https://swtch.com/~rsc/regexp/regexp1.html. The picture is correct for longest-match (POSIX) regexps but subtly wrong for preferred-match (Perl) regexps in the case where e has a preferred empty match. Pointed out by Andrew Gallant in private mail. The current code treats e* and e+ as the same structure, with different entry points. In the case of e* the preference list ends up not quite in the right order, in part because the “before e” and “after e” states are the same state. Splitting them apart fixes the preference list, and that can be done by compiling e* as if it were (e+)?. Like with any bug fix, there is a very low chance of breaking a program that accidentally depends on the buggy behavior. RE2, Go, and Rust all have this bug, and we've all agreed to fix it, to keep the implementations in sync. Fixes #46123. Change-Id: I70e742e71e0a23b626593b16ddef3c1e73b413b0 Reviewed-on: https://go-review.googlesource.com/c/go/+/318750 Trust: Russ Cox Run-TryBot: Russ Cox Reviewed-by: Rob Pike TryBot-Result: Go Bot --- src/regexp/find_test.go | 1 + src/regexp/onepass_test.go | 2 +- src/regexp/syntax/compile.go | 29 ++++- src/regexp/syntax/prog_test.go | 15 +++ src/regexp/testdata/basic.dat | 12 +- src/regexp/testdata/nullsubexpr.dat | 18 +-- src/regexp/testdata/re2-exhaustive.txt.bz2 | Bin 394016 -> 428262 bytes src/regexp/testdata/re2-search.txt | 145 ++++++++++++++++++--- 8 files changed, 176 insertions(+), 46 deletions(-) diff --git a/src/regexp/find_test.go b/src/regexp/find_test.go index 87c49b074fa..64c2239d905 100644 --- a/src/regexp/find_test.go +++ b/src/regexp/find_test.go @@ -97,6 +97,7 @@ var findTests = []FindTest{ {`\B`, "xx", build(1, 1, 1)}, {`\B`, "x y", nil}, {`\B`, "xx yy", build(2, 1, 1, 4, 4)}, + {`(|a)*`, "aa", build(3, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2)}, // RE2 tests {`[^\S\s]`, "abcd", nil}, diff --git a/src/regexp/onepass_test.go b/src/regexp/onepass_test.go index 32264d5f1ef..6a42eda391c 100644 --- a/src/regexp/onepass_test.go +++ b/src/regexp/onepass_test.go @@ -142,7 +142,7 @@ var onePassTests = []struct { {`^(?:(a)|(?:a*))$`, false}, {`^(?:(?:(?:.(?:$))?))$`, true}, {`^abcd$`, true}, - {`^(?:(?:a{0,})*?)$`, true}, + {`^(?:(?:a{0,})*?)$`, false}, {`^(?:(?:a+)*)$`, true}, {`^(?:(?:a|(?:aa)))$`, true}, {`^(?:[^\s\S])$`, true}, diff --git a/src/regexp/syntax/compile.go b/src/regexp/syntax/compile.go index 7524d628fe1..c9f9fa024bf 100644 --- a/src/regexp/syntax/compile.go +++ b/src/regexp/syntax/compile.go @@ -57,8 +57,9 @@ func (l1 patchList) append(p *Prog, l2 patchList) patchList { // A frag represents a compiled program fragment. type frag struct { - i uint32 // index of first instruction - out patchList // where to record end instruction + i uint32 // index of first instruction + out patchList // where to record end instruction + nullable bool // whether fragment can match empty string } type compiler struct { @@ -159,7 +160,7 @@ func (c *compiler) compile(re *Regexp) frag { func (c *compiler) inst(op InstOp) frag { // TODO: impose length limit - f := frag{i: uint32(len(c.p.Inst))} + f := frag{i: uint32(len(c.p.Inst)), nullable: true} c.p.Inst = append(c.p.Inst, Inst{Op: op}) return f } @@ -194,7 +195,7 @@ func (c *compiler) cat(f1, f2 frag) frag { // TODO: elide nop f1.out.patch(c.p, f2.i) - return frag{f1.i, f2.out} + return frag{f1.i, f2.out, f1.nullable && f2.nullable} } func (c *compiler) alt(f1, f2 frag) frag { @@ -211,6 +212,7 @@ func (c *compiler) alt(f1, f2 frag) frag { i.Out = f1.i i.Arg = f2.i f.out = f1.out.append(c.p, f2.out) + f.nullable = f1.nullable || f2.nullable return f } @@ -228,7 +230,12 @@ func (c *compiler) quest(f1 frag, nongreedy bool) frag { return f } -func (c *compiler) star(f1 frag, nongreedy bool) frag { +// loop returns the fragment for the main loop of a plus or star. +// For plus, it can be used after changing the entry to f1.i. +// For star, it can be used directly when f1 can't match an empty string. +// (When f1 can match an empty string, f1* must be implemented as (f1+)? +// to get the priority match order correct.) +func (c *compiler) loop(f1 frag, nongreedy bool) frag { f := c.inst(InstAlt) i := &c.p.Inst[f.i] if nongreedy { @@ -242,8 +249,17 @@ func (c *compiler) star(f1 frag, nongreedy bool) frag { return f } +func (c *compiler) star(f1 frag, nongreedy bool) frag { + if f1.nullable { + // Use (f1+)? to get priority match order correct. + // See golang.org/issue/46123. + return c.quest(c.plus(f1, nongreedy), nongreedy) + } + return c.loop(f1, nongreedy) +} + func (c *compiler) plus(f1 frag, nongreedy bool) frag { - return frag{f1.i, c.star(f1, nongreedy).out} + return frag{f1.i, c.loop(f1, nongreedy).out, f1.nullable} } func (c *compiler) empty(op EmptyOp) frag { @@ -255,6 +271,7 @@ func (c *compiler) empty(op EmptyOp) frag { func (c *compiler) rune(r []rune, flags Flags) frag { f := c.inst(InstRune) + f.nullable = false i := &c.p.Inst[f.i] i.Rune = r flags &= FoldCase // only relevant flag is FoldCase diff --git a/src/regexp/syntax/prog_test.go b/src/regexp/syntax/prog_test.go index 50bfa3d4bef..5603aea2289 100644 --- a/src/regexp/syntax/prog_test.go +++ b/src/regexp/syntax/prog_test.go @@ -88,6 +88,21 @@ var compileTests = []struct { 1* empty 4 -> 2 2 anynotnl -> 3 3 match +`}, + {"(?:|a)+", ` 0 fail + 1 nop -> 4 + 2 rune1 "a" -> 4 + 3* alt -> 1, 2 + 4 alt -> 3, 5 + 5 match +`}, + {"(?:|a)*", ` 0 fail + 1 nop -> 4 + 2 rune1 "a" -> 4 + 3 alt -> 1, 2 + 4 alt -> 3, 6 + 5* alt -> 3, 6 + 6 match `}, } diff --git a/src/regexp/testdata/basic.dat b/src/regexp/testdata/basic.dat index 7859290ba1d..1776b1ff96b 100644 --- a/src/regexp/testdata/basic.dat +++ b/src/regexp/testdata/basic.dat @@ -124,24 +124,20 @@ E ((a)) abc (0,1)(0,1)(0,1) E (a)b(c) abc (0,3)(0,1)(2,3) E a+b+c aabbabc (4,7) E a* aaa (0,3) -#E (a*)* - (0,0)(0,0) -E (a*)* - (0,0)(?,?) RE2/Go +E (a*)* - (0,0)(0,0) E (a*)+ - (0,0)(0,0) -#E (a*|b)* - (0,0)(0,0) -E (a*|b)* - (0,0)(?,?) RE2/Go +E (a*|b)* - (0,0)(0,0) E (a+|b)* ab (0,2)(1,2) E (a+|b)+ ab (0,2)(1,2) E (a+|b)? ab (0,1)(0,1) BE [^ab]* cde (0,3) -#E (^)* - (0,0)(0,0) -E (^)* - (0,0)(?,?) RE2/Go +E (^)* - (0,0)(0,0) BE a* NULL (0,0) E ([abc])*d abbbcd (0,6)(4,5) E ([abc])*bcd abcd (0,4)(0,1) E a|b|c|d|e e (0,1) E (a|b|c|d|e)f ef (0,2)(0,1) -#E ((a*|b))* - (0,0)(0,0)(0,0) -E ((a*|b))* - (0,0)(?,?)(?,?) RE2/Go +E ((a*|b))* - (0,0)(0,0)(0,0) BE abcd*efg abcdefg (0,7) BE ab* xabyabbbz (1,3) BE ab* xayabbbz (1,2) diff --git a/src/regexp/testdata/nullsubexpr.dat b/src/regexp/testdata/nullsubexpr.dat index 2e18fbb9170..68d9c99996a 100644 --- a/src/regexp/testdata/nullsubexpr.dat +++ b/src/regexp/testdata/nullsubexpr.dat @@ -1,8 +1,7 @@ NOTE null subexpression matches : 2002-06-06 E (a*)* a (0,1)(0,1) -#E SAME x (0,0)(0,0) -E SAME x (0,0)(?,?) RE2/Go +E SAME x (0,0)(0,0) E SAME aaaaaa (0,6)(0,6) E SAME aaaaaax (0,6)(0,6) E (a*)+ a (0,1)(0,1) @@ -19,8 +18,7 @@ E SAME aaaaaa (0,6)(0,6) E SAME aaaaaax (0,6)(0,6) E ([a]*)* a (0,1)(0,1) -#E SAME x (0,0)(0,0) -E SAME x (0,0)(?,?) RE2/Go +E SAME x (0,0)(0,0) E SAME aaaaaa (0,6)(0,6) E SAME aaaaaax (0,6)(0,6) E ([a]*)+ a (0,1)(0,1) @@ -28,8 +26,7 @@ E SAME x (0,0)(0,0) E SAME aaaaaa (0,6)(0,6) E SAME aaaaaax (0,6)(0,6) E ([^b]*)* a (0,1)(0,1) -#E SAME b (0,0)(0,0) -E SAME b (0,0)(?,?) RE2/Go +E SAME b (0,0)(0,0) E SAME aaaaaa (0,6)(0,6) E SAME aaaaaab (0,6)(0,6) E ([ab]*)* a (0,1)(0,1) @@ -41,11 +38,9 @@ E SAME bbbbbb (0,6)(0,6) E SAME aaaabcde (0,5)(0,5) E ([^a]*)* b (0,1)(0,1) E SAME bbbbbb (0,6)(0,6) -#E SAME aaaaaa (0,0)(0,0) -E SAME aaaaaa (0,0)(?,?) RE2/Go +E SAME aaaaaa (0,0)(0,0) E ([^ab]*)* ccccxx (0,6)(0,6) -#E SAME ababab (0,0)(0,0) -E SAME ababab (0,0)(?,?) RE2/Go +E SAME ababab (0,0)(0,0) E ((z)+|a)* zabcde (0,2)(1,2) @@ -65,8 +60,7 @@ B \(a*\)*\(x\)\(\1\) axa (0,3)(0,1)(1,2)(2,3) B \(a*\)*\(x\)\(\1\)\(x\) axax (0,4)(0,1)(1,2)(2,3)(3,4) B \(a*\)*\(x\)\(\1\)\(x\) axxa (0,3)(1,1)(1,2)(2,2)(2,3) -#E (a*)*(x) x (0,1)(0,0)(0,1) -E (a*)*(x) x (0,1)(?,?)(0,1) RE2/Go +E (a*)*(x) x (0,1)(0,0)(0,1) E (a*)*(x) ax (0,2)(0,1)(1,2) E (a*)*(x) axa (0,2)(0,1)(1,2) diff --git a/src/regexp/testdata/re2-exhaustive.txt.bz2 b/src/regexp/testdata/re2-exhaustive.txt.bz2 index a357f280169150b1d351c3fd5ed9a9eeff4ce66f..6638476dec0ae8eb102fff1d339d99b1a3e9f412 100644 GIT binary patch literal 428262 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

Tq22c8L;1f?a9&MZjq*YPsNs? zuZ19q&gYeRlc(ZK?=FY)_*YI!Wi}?UA4UL-*{?i_AF(;oF&gkMH%8TJS7>&~d-%#aO=cZvC&bE$m|jDh3NFyK3?`h!{fu zyiw!B+L_fQV$FwW6@x2#G1uM#{4t&Ng4cbf8e*r8PqiN*13>ix|NNhd*D6IagEg0e zi%kb&G$hx<6ld%Jyd@&#$^@XhHZ8oizgZNy(az*yYv~x1>0aL}>RSYCo;xvGXSV0v zmGGLi|A@>^0ZykJYC5hk4Z1fk0Jxs`kXz6H<|T1q#`PZNJV7B^I-_$(W2x(Him;O% z0zk-b`a9Vb7k4OqD5&QzNCRRHC;>hc25hQmvAF&&GW@yFIBNH1)+5htAA4ps>BD?_ z=8RL`(bbdNg*Zy}zrLP0^GaT8Viik z1O7$EoYdHTSL^XUt+ln>1qIxi&V%$zo>szfxRCy;=vq;&CYhC%XGD5B0JEW=1&l5UiNlEU%2hYXBZ zj~-JdJAIQZ9mMzGWeMs2W)?9W_-u{4gMLr4F~E`j$3Bxlvjm`N&}mp*EQ_2|YJoD5 z>@QXAU4G0jue+20)TUHvn8GAc3*mu8zn4LzQx0BG2NehPC+s9groAJ+jMCTDppsQ@ zGaMOd!N^XKit9RB5-8UTQhkB!)70^YM(F0zF^+hu38IYULT@vmA?;t}@jA>S-w}DM ztDoRKOpEZ-2g?>jT%K1n1UBwqemW245PD$%<~v~B;7&={Ug=nGi_l`vvfnx(V=v^3{qvAsS!lXJzLMmkJd>B5n;Su z zjWMZg#2m(fF}V7a)`>CDZRBL%*-?{SzSVTllYte!6;oj5U&Q51=jrS562Jw>aY>ij z@c!~J-~p9b4G$P)7Yiu?T{)zZf!YOKs&f-!Q`1` zp{p?su_`Sbh90k#O>}XqRUjSnzT$Q`w{ir=1CQd9TZ)?&XKb?_aehbXq}I7wYicnb zx7UKvjcS|cEz^p1k|60pD>B((YGwzhW*Q})^o9mEP#??14R#Sc5LF>KfTwsuN24dJ zah3=Hvs=>Di*8^n{7?_?KqS#ddy|K6?J>ka8`CC%aksB*w7sWP?)T8Gn~|X5$A#`|Jg&>^v~` zQvOT+p{or?SE4d^7yN0T>FlN6EORRpBC)N_9;L76<*opvCnC7I>CV75139)0lPk+?bMayP za{lAacl(L^3F~hvaM@uGgWvvUcK>r&`qa9+^do{Qq9y%ZVFK$H`y-U&ymVPSIs0AB zZ=TcK0t{DA%sQhZqQ_yHP`0wN6e%|Ob6~i!SNxMnceu63gYXkdzi)x;5Bp6OSiEdc z`z;`&xyV&i+@`rGASP*B6|ihTTR9eS7@o?E>!iim0*|I4-SiXVGMzIs5x1S0GO;dx zvCcP`2%REk>LcYC#+NO-Um`FV6xN^Y3+Qz2^5ikC5UgKx`?mefirwv7_XONb z01i3$k#TxtXu8e>NWU7*QgBRwCT%}#2z8iKQFf<*`54_NTxdCrh*DPozqrN zh~GjTX8Ev;6N*G_Of+Ql)ULWGFqCh&%?z!(QI1p061e310ma? z$AIl){1P9ZiD6JVG@U4!CZ?q&hgD+Q__N9Fc5*{;Kqb>+qa0d~VV3Z#QvXB>OS0WK zzMVnQFflN*?{SGkqj~x`Z%)lb2_YG_EjDLThBB()fH58>LWVtLeB`Qi3OyvmGd0?y zIc1LC$wfC;wO4h&WYja1A9F=d`Bm~qvoo=vOk5=voihTyEm~5=P|`6f_J_bT4_79G z0!?72q=&&&8+>ooP?t2vRgN_z-G>zICihCIta{Y=1?rXrP%ymx;cAY<#A1 z8^vYYCwZ|sE}?2{6d*bVkl=|5unv+g_&w+`xWB%BqaFDdz4eiA3palK<@md(*<_8} zyoB(_gR}SUCayYgd4fQY{|0(OVHX;90Mt#NYt=Ns#}8E72QUTVoE36#1#< z_=wi1%0**)OYGwih+v&>SN6YUaGB0byLZin{WiK${O)rt+4#^~x^%YmT*74JiYqY% zPjJZ}qgcMq94g*BXmfG;?)vt8g0snE>+GJnrsJnFwgT3h{7&s4uWFz+R`1 z?$sPiqQMVNhVJ645HoPl2=ZPRHb|Al$IW~{RBh6Du_0D~GBt6fJBR{abq%;9?d`S5M6M$3LZ2%?x zv;3=Or$<}1+P^wn)%>U`=Q&WX%D3+DhRC`_plXG>r+#Ivy+k$wvNFQHQ93}n2}sDD z7>S>Jm3Z`3yZ;WX`WTFAl;QPTOflL+Mf5;a| z8Sa6Tu4Thw+t=#Z^pQycttTe?=J9_ka*+tImJ;@vmC7~$>_zbm_P}|>s zBHOHUY&5)901HcP=&43&7+__MKX2ckCX@B5pjBB6RTs4grjF*lDWT?L2t-T8_Zv1rf`++VV%6|6g0sp;<14Se?*IFmd#@hN_B>g>8vJa%{KK~phW`42X2tX| z)+hr1tDeHsxkqPj+ve|W&EMOyT5litvOv(-xp8Lp-p02lPv1y6#0oI| z@;wxP^7QT2%X5uwf!deKn}%pf)Axe{x+i`)DVbT?6%m@HITr_+*1U&pk{)^>yUFxX zhAdK=*H{2e_D9@rYD~=~u%ZB1BU4a!tr!_i z>a#9Z9Zc)rK0=UL^|{|FT^mpt_WRx{)(Ac-g7rc>lR3GsaqScM_6TB)IKNl4P2el+ z3)Uvfl1G^?S{?wW+GU9>h01WLv7iFTk!X!5Ns&)C3XAffH)5F~m3}uOeM2i4zF~zf zSf)*{YJI}K!3rj!KlU+e9hy=HWyMgpjbxt8!1as`0~Ai(Uc5iRiHRLB9F}RYEa|$9 zIxP6OeWsn#s&3eJ-N_^m1KXQtsCp+YAH`>kyqG?$ys&!1!o9VI`J~Ha;L?ixXfE&4 z@->HB?iPg#XM<(aPU@l}Z{1!|<6hgLo6mlK(Sy099K8oF54=P>wS#0ix_euj?djr? zw%v*N?N@(DqrGpvM4DMNd%7|qrhi9U*J=9-%4Nk}R|lp-Vd5c?l}iNUl;J`KJ)>CI zNOr;-XXfi`x;RwODM0Womk^;7zHX40x#Ctr!RSzF%b4N>p5;Q~xc~_II(!94E?^HfmJ7CkWJ$A{r`9f=41^bjJymtg4#;@uEyH z#$*MITr96OC}GmehWlu?C{8WvVqgTb1fi&s*A*5nnJm zCJBtq|Qp!Nij=dcE>@Z9YIf6)-8*65xDSWO*~97CDx9pPZPsJU z@9Eqriboi0WY9oEhJx9>OvC-*VUrky5T;b`f*)O8M#m>`ZcfPCT|2)OIJp&->g2R8D}JXYMt$5 zxt%Ud9?R?~gj?Y?=8RlNY-6rp3x#K}j;&V=oFWwC2UD&aWvA*WAuKh6uW-?%sgj>~6<`pV@4J2D+Fvs0(lrNCLtFgK>168hlP|NdiTpbjwo5 z9IFS25kx*;Ug7P1$uJKZIe^1*QyoD0hssc25_S8&ecMzdtf1gZU^u&Evq=e;X~oa9 zcEWg$k5*bul&*5WTEw|&QiH0dD5EGg9I`Ic-m;R-*0-0w_Cnzo8zYi6aR5u5j@y(1 z$5#>&=!q%dnuNM|RxP+UuQO`1gEs0Ze#+)4d4;@(AQGy7=r7rsCLC^h@a}PL=RWHY z{4;7@TbUoy?B?1KU!V}roUnm+splcDJHr8#A4f*sQG1x5B!3S~#MVFDst2e=9$;fK zDt32zlhrO#nVQ#P4Ri5Krmd~D>@gj#9nw%NwyUeci95P91hK22m5otM=MtKQsV7w4 z=z_`|_q(2k78S4wW@)tnQ){y6{69*pN{}O7+2Q$BhWt~>)=w9CoVZgJ{N&vFgHvp8 z&8U+hAb1g{?s!w-cinFg9UHqDR7(;ZoVxAm*bU+sP%WK3W>X##uhj0A(yD~xPcc*a z>x)hpl~!#F^Y;AlBbv zR&E~R5>-_vs|sANP*#aW5*5CZ5_J`egQaP}x;bJIU?+ zV0&vl<79tAaZ7&! z(ez_tCFX$qMG$sft>5RFnK!Qvw>G~46|#7}Z&w?x*hmg~^zjz5ovG-Sr2~GQ?4^t( z7caXsbH0|EmeDUHq-Cw3@LJH~7;g@;6Go7F)YY)6BnDu2%!>kT2$5BH#z-_$JB*iz zlKJ+Rq>0`}ju(M2!`S>goW&SS>XfOYad5-K_$R*0B7BR}P3VSvK^_ygw7Hw_fWz86 zTm4`iL`g4ipj1w%CAs8GC|!E=>nPUT4yj>Q0KmcW2ZBL`P{Zm>Ee3lD5|e{Tt?{+u zj8Nea1?feznhBwHCy7)mdbXp6w4({AO#)A=mbbSMR-9yLrda?HL(tdiOoE1om+GjH z%4v`#VReQN8GOT@1Z1RK{|4g5>0d1KEaN(Ntwx2tY*1oJnZ(AEv94OBu|F*fF`E9# zmS^GM7uWoz)S^F58{oq%dWYmV_p`2UZxcEcdI_mhoZD_)c0Hm@fgjm1h~SJdZ|ryH zo0vOrv^{k!POVV1q&jf014QZ#>_CRCp%VXMA2sb_sNAxk%XH7{1M62L*gfevDetW! zXH~D|mqsGpo^8Id;^_LV#s_JIF}f2?$avkp$!)It_RQ3mX(6Om6ZNbY^@f>Il_;-P z9&$+d2;+kYY=*jdZ(x&KNOOIwusG-h zGY=T(9#!gf-DnG0e?Po&15gswXB3uFjoOL+`s;-OAp}XW7d04HR7H`?N3s@s=opQSEyV<} z05MFS1tl6Z+Gt7*)!ChfW^DB&h(g{e7K`Y}I{-^g26cInOENo=N?h^gR|X)U(&S8~ zp_MRuF>F{Y8>FLUErrZ;zv7A7_>?!+D+^hQ@n4kGc{fi{z&=dFmi_*(4bs7){i2ux5;4G#bFkWQy)^aK1rrzuEA*1WwAp&(N)QXDT zlzBPBQ-NBnTpMBJQ|o*j-Crcvwdpe>G*&sLW;Xih{_yCro@Ix_>jwW@%3c-3`-#2E z^$UfNAL9)Na^S-Y)!Abf0vF%`vh3rA{Q0_}%s&Nmy{i{8g|hSQE6n~B;Hzj&>^}5o zt(rBv66!AnT&i7nX@2i72oFe{h?e9b2z(xkH zW4RN3#cWST9Ti0BDey=*k{zSLlmV`fozjJcOcq2<#>^Moa5VAe!@J2cXF4W4<>iOh zACv&UC~!%JP0uZQckS1G+aM^#$Q5?iOMNBq#hY%jVZ(-B1)q(s0M#m@Ur1>>i_KS)My#&M~W{J2^YmSU$rMD;7`An-pAj4HGRMR}Fc1E$P|MBfR@eYu`9rs`h zxW_hc?=sDVzq-AC{p^kAn;B|aA7&=|JJ(dc|8hj%NCkS_5Z;aWymrQIBCBos#MuLD znp(H_cMe|qymRO2hbs$bv?nGZ4?k`18kk)BpqKZHk@I?btbk`4^3xGx7u}I#_uI3Y zpZ^BFej!?458i5E4%#x1XjyCOD13kCdQ{?xG{sJ(&keWTRzDn-^+)oBTW8cFQzlCioa}a;*O}8hu}aW{iuw?1 z=y+DYU$S*=g2Q-&$w|kve|AEeEa^{PHm{}*%cgzYmrsOG01Ma z&Lumk@bL7au!cZ_OI~ClE%|~d*SXTc2fiL3RGKHr=yq^(vtn2v9_14p_;8C3fej`N zr|?^cE7wNj5cxwgaPW=s@!H<)^^2pLaV9ReGbe(@#dVm2xfuI?2NV%vRlbzVKK#Dy;=Bb-=Wx9=~P0Z%hr<6 zOOi7P-Tdopc4;>rjUhyqw;{ObC*iOD{46Z3AI;F(!| zl|Ba3zZ$>YG@~xxRlvng2-}pD*8F?9O*Zw3q4h7<-dsp>Ba_6=XtmU~RtFo?FRN|! zZ}=~drF9w<>hLI^50CBk%JkG~At#80GedQpAD#?+I0obAR%yj9X$W|flM+kb_JY|e zd4XIx*<`0&@kI=C84PT|9p15sV)LM^H z?m}(8sJpB?$T)WUE99LoI96tf41w=ibik|G!Cd5c`Cm= zCVc@F{=NNG!B>-(i|7?=Qo?Xi$C2LG^Kbg7;E93{#f)bg9y$*ig_oDbKAqWpc6Rlg z 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ⅇYDU;`R1-c9fzCN!g9roHxD0 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%0Ag@+`R_Fu>{5 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℞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 Q#WZtd^J?C!UtNIy564dJJ^%m! delta 344814 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

?IYek5w!Q>ZeVEc zOx$g=q_nN~ws?l#-u?9bF(>iFlhNjz?Det-?{{U08V@XYx&36gXzt1Q!7+|OYe(&_ z>IEP}IBnZ4bd*`6UTI{QYQzjlL^km{>}dhL1#`7~6IUfu6Q-Z_zPr1ksp5Pa{``FC z2G)nedv{k%E!wj8Y~F0jfy=iKY&om-^fP3;NIpGVv47r}9khL>b}qLq<>}m;kxMU^ zMo?}|mu)HBv~t@#mN)jr?0gbT8@zY49!KedfQU~`0EhuA=AQ6^E-d{9Ik)T$+;%m2 zFNg<&i)Rv!%zid}ckt4?DUdS$ z{W&1;*0pFFcH#!e8&3fl-7;-*6F`>ZZ@`76Y7d3^M59B4QWWlNC*`43V$7i7Ftc

Rt;@qk*a+4vuR+=E%9V^rKq|&y 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ⅆm_GY0K;TFg;Lvabh1Yc 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%0AKSo#4mD#YnjDL!^fj-BoF6|=q%F|A`Zb0Pae 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

Q5<~w7vaSj4rNu>UQ3~sJGF6R~wtPs_~PbDDB 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 Date: Thu, 6 May 2021 14:01:20 -0400 Subject: [PATCH 042/940] cmd/go: be less strict about go version syntax in dependency go.mod files It is unclear what the future holds for the go line in go.mod files. Perhaps at some point we will switch to semver numbering. Perhaps at some point we will allow specifying minor versions or even betas and release candidates. Those kinds of changes are difficult today because the go line is parsed in dependency modules, meaning that older versions of the Go toolchain need to understand newer go lines. This CL makes that case - parsing a go line in a dependency's go.mod file - a bit more lax about how to find the version. It allows a leading v and any trailing non-digit-prefixed string after the MAJOR.MINOR section. There are no concrete plans to make use of any of these changes, but if in the future we want to make them, having a few Go releases under out belt that will accept the syntax in dependencies will make any changes significantly easier. Change-Id: I79bb84bba4b769048ac4b14d5c275eb9a3f270c4 Reviewed-on: https://go-review.googlesource.com/c/go/+/317690 Trust: Russ Cox Run-TryBot: Russ Cox TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills --- src/cmd/go.mod | 2 +- src/cmd/go.sum | 4 +- src/cmd/go/testdata/script/badgo.txt | 50 +++++++++++++++++++ .../vendor/golang.org/x/mod/modfile/rule.go | 14 +++++- src/cmd/vendor/modules.txt | 2 +- 5 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 src/cmd/go/testdata/script/badgo.txt diff --git a/src/cmd/go.mod b/src/cmd/go.mod index c3617eea0b1..88f5f2883a6 100644 --- a/src/cmd/go.mod +++ b/src/cmd/go.mod @@ -7,7 +7,7 @@ require ( github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 // indirect golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e // indirect - golang.org/x/mod v0.4.3-0.20210504181020-67f1c1edc27a + golang.org/x/mod v0.4.3-0.20210512182355-6088ed88cecd golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 // indirect golang.org/x/term v0.0.0-20210503060354-a79de5458b56 golang.org/x/tools v0.1.1-0.20210505014545-7cab0ef2e9a5 diff --git a/src/cmd/go.sum b/src/cmd/go.sum index f42aac70d69..73750802bc1 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -9,8 +9,8 @@ golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e h1:pv3V0NlNSh5Q6AX/StwGLBjc golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI= golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/mod v0.4.3-0.20210504181020-67f1c1edc27a h1:wbpC/7Wbo5WFVox32n+KjhRRLmTLq8YW/wRlL2iVAhk= -golang.org/x/mod v0.4.3-0.20210504181020-67f1c1edc27a/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.4.3-0.20210512182355-6088ed88cecd h1:CuRnpyMrCCBulv0d/y0CswR4K0vGydgE3DZ2wYPIOo8= +golang.org/x/mod v0.4.3-0.20210512182355-6088ed88cecd/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 h1:yhBbb4IRs2HS9PPlAg6DMC6mUOKexJBNsLf4Z+6En1Q= golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/src/cmd/go/testdata/script/badgo.txt b/src/cmd/go/testdata/script/badgo.txt new file mode 100644 index 00000000000..cf4e2584d65 --- /dev/null +++ b/src/cmd/go/testdata/script/badgo.txt @@ -0,0 +1,50 @@ +go get example.net/badgo@v1.0.0 +go get example.net/badgo@v1.1.0 +go get example.net/badgo@v1.2.0 +go get example.net/badgo@v1.3.0 +go get example.net/badgo@v1.4.0 +go get example.net/badgo@v1.5.0 +! go get example.net/badgo@v1.6.0 +stderr 'invalid go version .X.Y.: must match format 1.23' + +-- go.mod -- +module m + +replace ( + example.net/badgo v1.0.0 => ./v1.0.0 + example.net/badgo v1.1.0 => ./v1.1.0 + example.net/badgo v1.2.0 => ./v1.2.0 + example.net/badgo v1.3.0 => ./v1.3.0 + example.net/badgo v1.4.0 => ./v1.4.0 + example.net/badgo v1.5.0 => ./v1.5.0 + example.net/badgo v1.6.0 => ./v1.6.0 +) + +-- v1.0.0/go.mod -- +module example.net/badgo +go 1.17.0 + +-- v1.1.0/go.mod -- +module example.net/badgo +go 1.17rc2 + +-- v1.2.0/go.mod -- +module example.net/badgo +go 1.17.1 + +-- v1.3.0/go.mod -- +module example.net/badgo +go v1.17.0 + +-- v1.4.0/go.mod -- +module example.net/badgo +go v1.17.0-rc.2 + +-- v1.5.0/go.mod -- +module example.net/badgo +go v1.17.1 + +-- v1.6.0/go.mod -- +module example.net/badgo +go X.Y + diff --git a/src/cmd/vendor/golang.org/x/mod/modfile/rule.go b/src/cmd/vendor/golang.org/x/mod/modfile/rule.go index d8242de2806..7299e15500a 100644 --- a/src/cmd/vendor/golang.org/x/mod/modfile/rule.go +++ b/src/cmd/vendor/golang.org/x/mod/modfile/rule.go @@ -217,6 +217,7 @@ func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (parse } var GoVersionRE = lazyregexp.New(`^([1-9][0-9]*)\.(0|[1-9][0-9]*)$`) +var laxGoVersionRE = lazyregexp.New(`^v?(([1-9][0-9]*)\.(0|[1-9][0-9]*))([^0-9].*)$`) func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, args []string, fix VersionFixer, strict bool) { // If strict is false, this module is a dependency. @@ -267,8 +268,17 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a errorf("go directive expects exactly one argument") return } else if !GoVersionRE.MatchString(args[0]) { - errorf("invalid go version '%s': must match format 1.23", args[0]) - return + fixed := false + if !strict { + if m := laxGoVersionRE.FindStringSubmatch(args[0]); m != nil { + args[0] = m[1] + fixed = true + } + } + if !fixed { + errorf("invalid go version '%s': must match format 1.23", args[0]) + return + } } f.Go = &Go{Syntax: line} diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt index 10591f8041b..016ec011a97 100644 --- a/src/cmd/vendor/modules.txt +++ b/src/cmd/vendor/modules.txt @@ -28,7 +28,7 @@ golang.org/x/arch/x86/x86asm ## explicit; go 1.17 golang.org/x/crypto/ed25519 golang.org/x/crypto/ed25519/internal/edwards25519 -# golang.org/x/mod v0.4.3-0.20210504181020-67f1c1edc27a +# golang.org/x/mod v0.4.3-0.20210512182355-6088ed88cecd ## explicit; go 1.17 golang.org/x/mod/internal/lazyregexp golang.org/x/mod/modfile From 7a7624a3fa4665e8d75919746b6d762d3984d471 Mon Sep 17 00:00:00 2001 From: Kevin Albertson Date: Tue, 16 Feb 2021 14:40:49 +0000 Subject: [PATCH 043/940] cmd/go: permit .tbd files as a linker flag A .tbd file is a macOS text-based stub library and is a valid input to the macOS linker. This change adds .tbd to the allow-list for acceptable linker flags. Fixes golang/go#44263 Change-Id: Ie5439a13325dbc908e42f95ec70aca518bb549f9 GitHub-Last-Rev: 6055c3b5fa8c8146c0c5c976aa8e1d219e01e414 GitHub-Pull-Request: golang/go#44276 Reviewed-on: https://go-review.googlesource.com/c/go/+/292269 Reviewed-by: Cherry Mui Reviewed-by: Bryan C. Mills Run-TryBot: Cherry Mui TryBot-Result: Go Bot Trust: Ian Lance Taylor --- src/cmd/go/internal/work/security.go | 4 ++-- src/cmd/go/internal/work/security_test.go | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go index 36bbab37ee2..e9b9f6c6c0f 100644 --- a/src/cmd/go/internal/work/security.go +++ b/src/cmd/go/internal/work/security.go @@ -208,8 +208,8 @@ var validLinkerFlags = []*lazyregexp.Regexp{ re(`-Wl,-z,(no)?execstack`), re(`-Wl,-z,relro`), - re(`[a-zA-Z0-9_/].*\.(a|o|obj|dll|dylib|so)`), // direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o) - re(`\./.*\.(a|o|obj|dll|dylib|so)`), + re(`[a-zA-Z0-9_/].*\.(a|o|obj|dll|dylib|so|tbd)`), // direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o) + re(`\./.*\.(a|o|obj|dll|dylib|so|tbd)`), } var validLinkerFlagsWithNextArg = []string{ diff --git a/src/cmd/go/internal/work/security_test.go b/src/cmd/go/internal/work/security_test.go index 4f2e0eb21ab..8d4be0abfc0 100644 --- a/src/cmd/go/internal/work/security_test.go +++ b/src/cmd/go/internal/work/security_test.go @@ -164,6 +164,8 @@ var goodLinkerFlags = [][]string{ {"-Wl,-framework", "-Wl,Chocolate"}, {"-Wl,-framework,Chocolate"}, {"-Wl,-unresolved-symbols=ignore-all"}, + {"libcgotbdtest.tbd"}, + {"./libcgotbdtest.tbd"}, } var badLinkerFlags = [][]string{ From 9daf3cca8245a156b02da7bafef42637f8196f88 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Wed, 12 May 2021 09:26:45 -0700 Subject: [PATCH 044/940] [dev.typeparams] cmd/compile: keep instantiated method as a method, rather than converting to function Previously, we were converting an instantitated method to a function, by moving the receiver arg to the regular args, etc. But that made the type of the method signature inconsistent with the signature on the method fields, which leads to some problems with more complex programs with instantiations. And things work fine if we leave the instantiated method as a method. So, make the change to keep instantiated methods as real methods (until they are transformed much later in the compiler). Change-Id: If34be9e88c1b0ff819d557cf8dfbb31196542e7c Reviewed-on: https://go-review.googlesource.com/c/go/+/319490 Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall Trust: Dan Scales --- src/cmd/compile/internal/noder/stencil.go | 51 ++++++++++++++--------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 751a6282566..adcea2c087d 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -87,19 +87,20 @@ func (g *irgen) stencil() { call := n.(*ir.CallExpr) inst := call.X.(*ir.InstExpr) st := g.getInstantiationForNode(inst) - // Replace the OFUNCINST with a direct reference to the - // new stenciled function - call.X = st.Nname if inst.X.Op() == ir.OCALLPART { - // When we create an instantiation of a method - // call, we make it a function. So, move the - // receiver to be the first arg of the function - // call. - withRecv := make([]ir.Node, len(call.Args)+1) - dot := inst.X.(*ir.SelectorExpr) - withRecv[0] = dot.X - copy(withRecv[1:], call.Args) - call.Args = withRecv + // Replace the OFUNCINST with the selector + // expression, and update the selector expression + // to refer to the new stenciled function. + call.X = inst.X + se := call.X.(*ir.SelectorExpr) + se.Selection = types.NewField(se.Pos(), se.Sel, st.Type()) + se.Selection.Nname = st.Nname + se.SetOp(ir.ODOTMETH) + se.SetType(st.Type()) + } else { + // Replace the OFUNCINST with a direct reference to the + // new stenciled function + call.X = st.Nname } // Transform the Call now, which changes OCALL // to OCALLFUNC and does typecheckaste/assignconvfn. @@ -165,13 +166,13 @@ func (g *irgen) instantiateMethods() { baseSym := typ.Sym().Pkg.Lookup(genericTypeName(typ.Sym())) baseType := baseSym.Def.(*ir.Name).Type() for j, m := range typ.Methods().Slice() { - name := m.Nname.(*ir.Name) targs := make([]ir.Node, len(typ.RParams())) for k, targ := range typ.RParams() { targs[k] = ir.TypeNode(targ) } baseNname := baseType.Methods().Slice()[j].Nname.(*ir.Name) - name.Func = g.getInstantiation(baseNname, targs, true) + f := g.getInstantiation(baseNname, targs, true) + m.Nname = f.Nname } } g.instTypeList = nil @@ -315,15 +316,25 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []ir.No newf.Dcl[i] = subst.node(n).(*ir.Name) } - // Ugly: we have to insert the Name nodes of the parameters/results into + // Replace the types in the function signature. + // Ugly: also, we have to insert the Name nodes of the parameters/results into // the function type. The current function type has no Nname fields set, // because it came via conversion from the types2 type. oldt := nameNode.Type() - // We also transform a generic method type to the corresponding - // instantiated function type where the receiver is the first parameter. - newt := types.NewSignature(oldt.Pkg(), nil, nil, - subst.fields(ir.PPARAM, append(oldt.Recvs().FieldSlice(), oldt.Params().FieldSlice()...), newf.Dcl), - subst.fields(ir.PPARAMOUT, oldt.Results().FieldSlice(), newf.Dcl)) + dcl := newf.Dcl + var newrecv *types.Field + if oldt.Recv() != nil { + newrecv = subst.fields(ir.PPARAM, oldt.Recvs().FieldSlice(), dcl)[0] + if newrecv.Nname != nil { + // If we found the receiver in the dcl list, then skip it + // when we scan for the remaining params below. + assert(newrecv.Nname == dcl[0]) + dcl = dcl[1:] + } + } + newt := types.NewSignature(oldt.Pkg(), newrecv, nil, + subst.fields(ir.PPARAM, oldt.Params().FieldSlice(), dcl), + subst.fields(ir.PPARAMOUT, oldt.Results().FieldSlice(), dcl)) newf.Nname.SetType(newt) ir.MarkFunc(newf.Nname) From 92c189f2117415ff7a4bd9652422ba9af1745cb9 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 13 May 2021 16:36:32 -0400 Subject: [PATCH 045/940] cmd/link: resolve ABI alias for runtime.unreachableMethod We redirect references to unreachable methods to runtime.unreachableMethod. We choose to use ABIInternal symbol for this, because runtime.unreachableMethod is a defined Go function. When linking against shared libraries, and ABI wrappers are not enabled, the imported function symbols are all ABI0 and aliased to ABIInternal. We need to resolve ABI alias in this case. Change-Id: Idd64ef46ce0b5f54882ea0069ce0d59dc9b7a599 Reviewed-on: https://go-review.googlesource.com/c/go/+/319891 Trust: Cherry Mui Run-TryBot: Cherry Mui Reviewed-by: Jeremy Faller Reviewed-by: David Chase Reviewed-by: Than McIntosh TryBot-Result: Go Bot --- src/cmd/link/internal/ld/data.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 6659e95cc1f..223df63d9df 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -340,6 +340,7 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) { if weak && !ldr.AttrReachable(rs) { // Redirect it to runtime.unreachableMethod, which will throw if called. rs = syms.unreachableMethod + rs = ldr.ResolveABIAlias(rs) } if target.IsExternal() { nExtReloc++ @@ -623,6 +624,7 @@ func extreloc(ctxt *Link, ldr *loader.Loader, s loader.Sym, r loader.Reloc) (loa rs := ldr.ResolveABIAlias(r.Sym()) if r.Weak() && !ldr.AttrReachable(rs) { rs = ctxt.ArchSyms.unreachableMethod + rs = ldr.ResolveABIAlias(rs) } rs, off := FoldSubSymbolOffset(ldr, rs) rr.Xadd = r.Add() + off From b4833f7c06c332ad2ef30666144a20fb7838aba1 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 13 May 2021 16:48:50 -0400 Subject: [PATCH 046/940] cmd/link: always mark runtime.unreachableMethod symbol In the deadcode path we mark runtime.unreachableMethod symbol, which is a special symbol used for redirecting unreachable methods. Currently this code is conditioned on not -linkshared. This is wrong. It should be marked with -linkshared mode as well. In fact, -linkshared should only affect the entry symbol. Change the code accordingly. Change-Id: I252abf850212a930f275589ef0035a43e52cb9cc Reviewed-on: https://go-review.googlesource.com/c/go/+/319893 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Jeremy Faller --- src/cmd/link/internal/ld/deadcode.go | 38 ++++++++++++++-------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go index 1ed5598c99d..416e5da3983 100644 --- a/src/cmd/link/internal/ld/deadcode.go +++ b/src/cmd/link/internal/ld/deadcode.go @@ -65,26 +65,26 @@ func (d *deadcodePass) init() { } } names = append(names, *flagEntrySymbol) - // runtime.unreachableMethod is a function that will throw if called. - // We redirect unreachable methods to it. - names = append(names, "runtime.unreachableMethod") - if !d.ctxt.linkShared && d.ctxt.BuildMode != BuildModePlugin { - // runtime.buildVersion and runtime.modinfo are referenced in .go.buildinfo section - // (see function buildinfo in data.go). They should normally be reachable from the - // runtime. Just make it explicit, in case. - names = append(names, "runtime.buildVersion", "runtime.modinfo") - } - if d.ctxt.BuildMode == BuildModePlugin { - names = append(names, objabi.PathToPrefix(*flagPluginPath)+"..inittask", objabi.PathToPrefix(*flagPluginPath)+".main", "go.plugin.tabs") + } + // runtime.unreachableMethod is a function that will throw if called. + // We redirect unreachable methods to it. + names = append(names, "runtime.unreachableMethod") + if !d.ctxt.linkShared && d.ctxt.BuildMode != BuildModePlugin { + // runtime.buildVersion and runtime.modinfo are referenced in .go.buildinfo section + // (see function buildinfo in data.go). They should normally be reachable from the + // runtime. Just make it explicit, in case. + names = append(names, "runtime.buildVersion", "runtime.modinfo") + } + if d.ctxt.BuildMode == BuildModePlugin { + names = append(names, objabi.PathToPrefix(*flagPluginPath)+"..inittask", objabi.PathToPrefix(*flagPluginPath)+".main", "go.plugin.tabs") - // We don't keep the go.plugin.exports symbol, - // but we do keep the symbols it refers to. - exportsIdx := d.ldr.Lookup("go.plugin.exports", 0) - if exportsIdx != 0 { - relocs := d.ldr.Relocs(exportsIdx) - for i := 0; i < relocs.Count(); i++ { - d.mark(relocs.At(i).Sym(), 0) - } + // We don't keep the go.plugin.exports symbol, + // but we do keep the symbols it refers to. + exportsIdx := d.ldr.Lookup("go.plugin.exports", 0) + if exportsIdx != 0 { + relocs := d.ldr.Relocs(exportsIdx) + for i := 0; i < relocs.Count(); i++ { + d.mark(relocs.At(i).Sym(), 0) } } } From c3fa51c9a2288ae6441f54e3a59d82015f0b7728 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Thu, 6 May 2021 14:21:47 -0700 Subject: [PATCH 047/940] cmd/compile: changed representation of typeparam bound in types1 Especially with typesets, we should be able to fully represent a typeparam bound as just another type (actually an interface type). Change the representation of a typeparam in types1 to include a bound, which is just a type. Changed the signature for NewTypeParam() to take a sym, and not a package, since we always set the sym (name) of the typeparam when creating it. No need for an extra pkg field in Typeparam. Also added index field in the types1 representation of typeparam. This is especially needed to correctly export the typeparam, and re-import it as a types2 type (which requires the index to be set correctly). Change-Id: I50200e2489a97898c37d292b2bd025df790b0277 Reviewed-on: https://go-review.googlesource.com/c/go/+/319929 Reviewed-by: Robert Griesemer Trust: Robert Griesemer Trust: Dan Scales Run-TryBot: Dan Scales TryBot-Result: Go Bot --- src/cmd/compile/internal/noder/types.go | 7 ++--- src/cmd/compile/internal/types/type.go | 38 +++++++++++++++++++++---- src/cmd/compile/internal/types2/type.go | 5 ++++ 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go index 8680559a412..8a2c023a1a3 100644 --- a/src/cmd/compile/internal/noder/types.go +++ b/src/cmd/compile/internal/noder/types.go @@ -204,18 +204,15 @@ func (g *irgen) typ0(typ types2.Type) *types.Type { return types.NewInterface(g.tpkg(typ), append(embeddeds, methods...)) case *types2.TypeParam: - tp := types.NewTypeParam(g.tpkg(typ)) // Save the name of the type parameter in the sym of the type. // Include the types2 subscript in the sym name sym := g.pkg(typ.Obj().Pkg()).Lookup(types2.TypeString(typ, func(*types2.Package) string { return "" })) - tp.SetSym(sym) + tp := types.NewTypeParam(sym, typ.Index()) // Set g.typs[typ] in case the bound methods reference typ. g.typs[typ] = tp - // TODO(danscales): we don't currently need to use the bounds - // anywhere, so eventually we can probably remove. bound := g.typ1(typ.Bound()) - *tp.Methods() = *bound.Methods() + tp.SetBound(bound) return tp case *types2.Tuple: diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index 1a9aa6916a2..d3c02fc56d3 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -151,7 +151,7 @@ type Type struct { // TARRAY: *Array // TSLICE: Slice // TSSA: string - // TTYPEPARAM: *Interface (though we may not need to store/use the Interface info) + // TTYPEPARAM: *Typeparam Extra interface{} // Width is the width of this Type in bytes. @@ -377,6 +377,12 @@ type Interface struct { pkg *Pkg } +// Typeparam contains Type fields specific to typeparam types. +type Typeparam struct { + index int // type parameter index in source order, starting at 0 + bound *Type +} + // Ptr contains Type fields specific to pointer types. type Ptr struct { Elem *Type // element type @@ -558,7 +564,7 @@ func New(et Kind) *Type { case TRESULTS: t.Extra = new(Results) case TTYPEPARAM: - t.Extra = new(Interface) + t.Extra = new(Typeparam) } return t } @@ -825,6 +831,8 @@ func (t *Type) copy() *Type { case TARRAY: x := *t.Extra.(*Array) nt.Extra = &x + case TTYPEPARAM: + base.Fatalf("typeparam types cannot be copied") case TTUPLE, TSSA, TRESULTS: base.Fatalf("ssa types cannot be copied") } @@ -1766,14 +1774,34 @@ func NewInterface(pkg *Pkg, methods []*Field) *Type { return t } -// NewTypeParam returns a new type param. -func NewTypeParam(pkg *Pkg) *Type { +// NewTypeParam returns a new type param with the specified sym (package and name) +// and specified index within the typeparam list. +func NewTypeParam(sym *Sym, index int) *Type { t := New(TTYPEPARAM) - t.Extra.(*Interface).pkg = pkg + t.sym = sym + t.Extra.(*Typeparam).index = index t.SetHasTParam(true) return t } +// Index returns the index of the type param within its param list. +func (t *Type) Index() int { + t.wantEtype(TTYPEPARAM) + return t.Extra.(*Typeparam).index +} + +// SetBound sets the bound of a typeparam. +func (t *Type) SetBound(bound *Type) { + t.wantEtype(TTYPEPARAM) + t.Extra.(*Typeparam).bound = bound +} + +// Bound returns the bound of a typeparam. +func (t *Type) Bound() *Type { + t.wantEtype(TTYPEPARAM) + return t.Extra.(*Typeparam).bound +} + const BOGUS_FUNARG_OFFSET = -1000000000 func unzeroFieldOffsets(f []*Field) { diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index e6c260ff679..88dedbad452 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -760,6 +760,11 @@ func (check *Checker) NewTypeParam(obj *TypeName, index int, bound Type) *TypePa return typ } +// Index returns the index of the type param within its param list. +func (t *TypeParam) Index() int { + return t.index +} + func (t *TypeParam) Bound() *Interface { iface := asInterface(t.bound) // use the type bound position if we have one From 3a0453514a80b001e6135f98ec4e0da5a78ab267 Mon Sep 17 00:00:00 2001 From: John Bampton Date: Fri, 7 May 2021 10:47:28 +0000 Subject: [PATCH 048/940] all: fix spelling Change-Id: Id991d8e81e04835cabfb02d07a2199bfb553726c GitHub-Last-Rev: 5d0b55d49127a2e2ba3148d20a58c52debcae12b GitHub-Pull-Request: golang/go#44802 Reviewed-on: https://go-review.googlesource.com/c/go/+/299069 Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor Trust: Heschi Kreinick --- src/net/http/httputil/reverseproxy_test.go | 2 +- src/net/http/socks_bundle.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/net/http/httputil/reverseproxy_test.go b/src/net/http/httputil/reverseproxy_test.go index b89eb90ad64..22720caf930 100644 --- a/src/net/http/httputil/reverseproxy_test.go +++ b/src/net/http/httputil/reverseproxy_test.go @@ -1209,7 +1209,7 @@ func TestReverseProxyWebSocket(t *testing.T) { } } -func TestReverseProxyWebSocketCancelation(t *testing.T) { +func TestReverseProxyWebSocketCancellation(t *testing.T) { n := 5 triggerCancelCh := make(chan bool, n) nthResponse := func(i int) string { diff --git a/src/net/http/socks_bundle.go b/src/net/http/socks_bundle.go index e4466695899..e6db1c7640f 100644 --- a/src/net/http/socks_bundle.go +++ b/src/net/http/socks_bundle.go @@ -453,7 +453,7 @@ func (up *socksUsernamePassword) Authenticate(ctx context.Context, rw io.ReadWri b = append(b, up.Username...) b = append(b, byte(len(up.Password))) b = append(b, up.Password...) - // TODO(mikio): handle IO deadlines and cancelation if + // TODO(mikio): handle IO deadlines and cancellation if // necessary if _, err := rw.Write(b); err != nil { return err From 12d383c7c7406dda2cb969a89ce3801c220614c5 Mon Sep 17 00:00:00 2001 From: itchyny Date: Thu, 13 May 2021 04:03:18 +0000 Subject: [PATCH 049/940] debug/macho: fix a typo in macho.go Change-Id: Ica47b53decf6690fbd37e666e9de5098117b82de GitHub-Last-Rev: 6aabb208a6499e29fe32a2f0d928c4e027d556b2 GitHub-Pull-Request: golang/go#46147 Reviewed-on: https://go-review.googlesource.com/c/go/+/319592 Reviewed-by: Brad Fitzpatrick Trust: Brad Fitzpatrick Trust: Heschi Kreinick --- src/debug/macho/macho.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debug/macho/macho.go b/src/debug/macho/macho.go index 49e107eed3d..9fa9f957529 100644 --- a/src/debug/macho/macho.go +++ b/src/debug/macho/macho.go @@ -4,7 +4,7 @@ // Mach-O header data structures // Originally at: -// http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html (since deleted by Apply) +// http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html (since deleted by Apple) // Archived copy at: // https://web.archive.org/web/20090819232456/http://developer.apple.com/documentation/DeveloperTools/Conceptual/MachORuntime/index.html // For cloned PDF see: From c925e1546ee72e40ca5351f3773379e99a6b8cdf Mon Sep 17 00:00:00 2001 From: eric fang Date: Fri, 7 May 2021 05:48:18 +0000 Subject: [PATCH 050/940] cmd/internal/obj/arm64: disable AL and NV for some condition operation instructions According to the armv8-a reference manual, conditions AL and NV are not allowed for instructions CINC, CINV, CNEG, CSET and CSETM. This CL adds this check and the corresponding test cases. Change-Id: Icb496b7b13a353f41491f2de4d939a5cd88abb04 Reviewed-on: https://go-review.googlesource.com/c/go/+/317912 Reviewed-by: eric fang Reviewed-by: Cherry Mui Trust: eric fang Run-TryBot: eric fang TryBot-Result: Go Bot --- .../asm/internal/asm/testdata/arm64error.s | 10 ++++++++ src/cmd/internal/obj/arm64/asm7.go | 24 +++++++++---------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/cmd/asm/internal/asm/testdata/arm64error.s b/src/cmd/asm/internal/asm/testdata/arm64error.s index 66fc9107594..cf57179e430 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64error.s +++ b/src/cmd/asm/internal/asm/testdata/arm64error.s @@ -52,6 +52,16 @@ TEXT errors(SB),$0 NEGSW R7@>2, R5 // ERROR "unsupported shift operator" CINC CS, R2, R3, R4 // ERROR "illegal combination" CSEL LT, R1, R2 // ERROR "illegal combination" + CINC AL, R2, R3 // ERROR "invalid condition" + CINC NV, R2, R3 // ERROR "invalid condition" + CINVW AL, R2, R3 // ERROR "invalid condition" + CINV NV, R2, R3 // ERROR "invalid condition" + CNEG AL, R2, R3 // ERROR "invalid condition" + CNEGW NV, R2, R3 // ERROR "invalid condition" + CSET AL, R2 // ERROR "invalid condition" + CSET NV, R2 // ERROR "invalid condition" + CSETMW AL, R2 // ERROR "invalid condition" + CSETM NV, R2 // ERROR "invalid condition" LDP.P 8(R2), (R2, R3) // ERROR "constrained unpredictable behavior" LDP.W 8(R3), (R2, R3) // ERROR "constrained unpredictable behavior" LDP (R1), (R2, R2) // ERROR "constrained unpredictable behavior" diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go index 575436d764a..b8c3cd97c76 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -3536,27 +3536,25 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { o1 = c.oprrr(p, p.As) cond := int(p.From.Reg) - if cond < COND_EQ || cond > COND_NV { + // AL and NV are not allowed for CINC/CINV/CNEG/CSET/CSETM instructions + if cond < COND_EQ || cond > COND_NV || (cond == COND_AL || cond == COND_NV) && p.From3Type() == obj.TYPE_NONE { c.ctxt.Diag("invalid condition: %v", p) } else { cond -= COND_EQ } r := int(p.Reg) - var rf int - if r != 0 { - if p.From3Type() == obj.TYPE_NONE { - /* CINC/CINV/CNEG */ - rf = r - cond ^= 1 - } else { - rf = int(p.GetFrom3().Reg) /* CSEL */ + var rf int = r + if p.From3Type() == obj.TYPE_NONE { + /* CINC/CINV/CNEG or CSET/CSETM*/ + if r == 0 { + /* CSET/CSETM */ + rf = REGZERO + r = rf } - } else { - /* CSET */ - rf = REGZERO - r = rf cond ^= 1 + } else { + rf = int(p.GetFrom3().Reg) /* CSEL */ } rt := int(p.To.Reg) From d137b745398e8313c0f086d4d044751295be6163 Mon Sep 17 00:00:00 2001 From: Ben Hoyt Date: Fri, 14 May 2021 09:59:20 +1200 Subject: [PATCH 051/940] cmd/go: fix spacing in help text of -overlay flag There was a space missing in the first line shown below, and an extra space in the second line shown. Thanks Peter Bourgon for noting this. BEFORE: $ go help build | grep -A1 'has some limitations' has some limitations:importantly, cgo files included from outside the include path must be in the same directory as the Go package they are AFTER: $ go help build | grep -A1 'has some limitations' has some limitations: importantly, cgo files included from outside the include path must be in the same directory as the Go package they are Note that I edited alldocs.go by hand here, as the mkalldocs.sh script produces a lot more changes, for example adding the -insecure flag documentation in. Not sure what's wrong there. Change-Id: I303f6d6b42b0e24cec0748a949dc23beec64b917 Reviewed-on: https://go-review.googlesource.com/c/go/+/319949 Reviewed-by: Jay Conrod Reviewed-by: Bryan C. Mills Trust: Jay Conrod Run-TryBot: Jay Conrod TryBot-Result: Go Bot --- src/cmd/go/alldocs.go | 4 ++-- src/cmd/go/internal/work/build.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index 052b61c03dd..fcc7f36335e 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -174,8 +174,8 @@ // a build will run as if the disk file path exists with the contents // given by the backing file paths, or as if the disk file path does not // exist if its backing file path is empty. Support for the -overlay flag -// has some limitations:importantly, cgo files included from outside the -// include path must be in the same directory as the Go package they are +// has some limitations: importantly, cgo files included from outside the +// include path must be in the same directory as the Go package they are // included from, and overlays will not appear when binaries and tests are // run through go run and go test respectively. // -pkgdir dir diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go index 1babbda8899..0ed2389cd5a 100644 --- a/src/cmd/go/internal/work/build.go +++ b/src/cmd/go/internal/work/build.go @@ -128,8 +128,8 @@ and test commands: a build will run as if the disk file path exists with the contents given by the backing file paths, or as if the disk file path does not exist if its backing file path is empty. Support for the -overlay flag - has some limitations:importantly, cgo files included from outside the - include path must be in the same directory as the Go package they are + has some limitations: importantly, cgo files included from outside the + include path must be in the same directory as the Go package they are included from, and overlays will not appear when binaries and tests are run through go run and go test respectively. -pkgdir dir From a938e529861215d9721f5e2590d5166bfbf2d271 Mon Sep 17 00:00:00 2001 From: Manlio Perillo Date: Thu, 13 May 2021 16:08:59 +0200 Subject: [PATCH 052/940] cmd/go: fix a portability issue in the cd script command Currently all script tests use the UNIX path separator with the cd command, causing the PWD environment variable to have the incorrect path separator on Windows. Call filepath.FromSlash on the cd command argument. Update the testdata/script/README to document that the cd argument must use slashes. Add a regression test. To reproduce this issue, a test must use the cd command followed by a stdout or stderr command containing the pattern $PWD. Change-Id: Ib2dc5f185cc2476451402787996d14df91f7dddb Reviewed-on: https://go-review.googlesource.com/c/go/+/319311 Reviewed-by: Jay Conrod Reviewed-by: Bryan C. Mills Trust: Jay Conrod Run-TryBot: Jay Conrod TryBot-Result: Go Bot --- src/cmd/go/script_test.go | 2 +- src/cmd/go/testdata/script/README | 1 + src/cmd/go/testdata/script/test_script_cmdcd.txt | 13 +++++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 src/cmd/go/testdata/script/test_script_cmdcd.txt diff --git a/src/cmd/go/script_test.go b/src/cmd/go/script_test.go index 327eaff4450..639e907db07 100644 --- a/src/cmd/go/script_test.go +++ b/src/cmd/go/script_test.go @@ -517,7 +517,7 @@ func (ts *testScript) cmdCd(want simpleStatus, args []string) { ts.fatalf("usage: cd dir") } - dir := args[0] + dir := filepath.FromSlash(args[0]) if !filepath.IsAbs(dir) { dir = filepath.Join(ts.cd, dir) } diff --git a/src/cmd/go/testdata/script/README b/src/cmd/go/testdata/script/README index d7e67bb7b60..48e4055b0bd 100644 --- a/src/cmd/go/testdata/script/README +++ b/src/cmd/go/testdata/script/README @@ -102,6 +102,7 @@ The commands are: - cd dir Change to the given directory for future commands. + The directory must use slashes as path separator. - chmod perm path... Change the permissions of the files or directories named by the path arguments diff --git a/src/cmd/go/testdata/script/test_script_cmdcd.txt b/src/cmd/go/testdata/script/test_script_cmdcd.txt new file mode 100644 index 00000000000..6e6f67e13d0 --- /dev/null +++ b/src/cmd/go/testdata/script/test_script_cmdcd.txt @@ -0,0 +1,13 @@ +# Tests that after a cd command, where usually the UNIX path separator is used, +# a match against $PWD does not fail on Windows. + +cd $WORK/a/b/c/pkg + +go list -find -f {{.Root}} +stdout $PWD + +-- $WORK/a/b/c/pkg/go.mod -- +module pkg + +-- $WORK/a/b/c/pkg/pkg.go -- +package pkg From 0eb38f2b164ec5b0094c5895cfe1b3a40c183d50 Mon Sep 17 00:00:00 2001 From: Manlio Perillo Date: Wed, 12 May 2021 12:09:18 +0200 Subject: [PATCH 053/940] cmd/go/internal/load: override Package.Root in module mode The Context.ImportDir method in the go/build package sets Package.Root to $GOPATH, if a package is inside a GOPATH workspace. The loadPackageData function keeps this value even when modules are enabled. Override Package.Root when modules are enabled, instead of just set its value when Context.ImportDir was unable to set it. Add a regression test. Fixes #46119 Change-Id: I900a33fe13a445cb771e2952d0d830f1b4a5921f Reviewed-on: https://go-review.googlesource.com/c/go/+/319209 Reviewed-by: Bryan C. Mills Trust: Bryan C. Mills Trust: Jay Conrod Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot --- src/cmd/go/internal/load/pkg.go | 4 +++- .../testdata/script/list_gomod_in_gopath.txt | 23 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/cmd/go/testdata/script/list_gomod_in_gopath.txt diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index a3b96702ce5..738904865e2 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -849,7 +849,9 @@ func loadPackageData(ctx context.Context, path, parentPath, parentDir, parentRoo buildMode = build.ImportComment } data.p, data.err = cfg.BuildContext.ImportDir(r.dir, buildMode) - if data.p.Root == "" && cfg.ModulesEnabled { + if cfg.ModulesEnabled { + // Override data.p.Root, since ImportDir sets it to $GOPATH, if + // the module is inside $GOPATH/src. if info := modload.PackageModuleInfo(ctx, path); info != nil { data.p.Root = info.Dir } diff --git a/src/cmd/go/testdata/script/list_gomod_in_gopath.txt b/src/cmd/go/testdata/script/list_gomod_in_gopath.txt new file mode 100644 index 00000000000..064f33adc36 --- /dev/null +++ b/src/cmd/go/testdata/script/list_gomod_in_gopath.txt @@ -0,0 +1,23 @@ +# Issue 46119 + +# When a module is inside a GOPATH workspace, Package.Root should be set to +# Module.Dir instead of $GOPATH/src. + +env GOPATH=$WORK/tmp +cd $WORK/tmp/src/test + +go list -f {{.Root}} +stdout ^$PWD$ + +# Were we really inside a GOPATH workspace? +env GO111MODULE=off +go list -f {{.Root}} +stdout ^$WORK/tmp$ + +-- $WORK/tmp/src/test/go.mod -- +module test + +-- $WORK/tmp/src/test/main.go -- +package main + +func main() {} From 3d324f127dbb916f38d7476e9c4ff106e5d54f99 Mon Sep 17 00:00:00 2001 From: Michael Fraenkel Date: Thu, 13 May 2021 09:41:45 -0600 Subject: [PATCH 054/940] net/http: prevent infinite wait during TestMissingStatusNoPanic If the client request never makes it to the server, the outstanding accept is never broken. Change the test to always close the listening socket when the client request completes. Updates #45358 Change-Id: I744a91dfa11704e7e528163d7669c394e90456dc Reviewed-on: https://go-review.googlesource.com/c/go/+/319275 Trust: Heschi Kreinick Reviewed-by: Bryan C. Mills --- src/net/http/transport_test.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index 5b6a5aa9925..dcaacece617 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -5322,7 +5322,6 @@ func TestMissingStatusNoPanic(t *testing.T) { ln := newLocalListener(t) addr := ln.Addr().String() - shutdown := make(chan bool, 1) done := make(chan bool) fullAddrURL := fmt.Sprintf("http://%s", addr) raw := "HTTP/1.1 400\r\n" + @@ -5334,10 +5333,7 @@ func TestMissingStatusNoPanic(t *testing.T) { "Aloha Olaa" go func() { - defer func() { - ln.Close() - close(done) - }() + defer close(done) conn, _ := ln.Accept() if conn != nil { @@ -5368,7 +5364,7 @@ func TestMissingStatusNoPanic(t *testing.T) { t.Errorf("got=%v want=%q", err, want) } - close(shutdown) + ln.Close() <-done } From 02699f810a05215060ba2181f394d551819ad7d4 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 13 May 2021 18:19:42 -0400 Subject: [PATCH 055/940] runtime: mark osyield nosplit on OpenBSD osyield is called in code paths that are not allowed to split stack, e.g. casgstatus called from entersyscall/exitsyscall. It is nosplit on all other platforms. Mark it nosplit on OpenBSD as well. Change-Id: I3fed5d7f58b3d50610beca6eed2c7e902b8ec52c Reviewed-on: https://go-review.googlesource.com/c/go/+/319969 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Joel Sing --- src/runtime/sys_openbsd1.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/runtime/sys_openbsd1.go b/src/runtime/sys_openbsd1.go index 6f9ad356d44..cb5d35879cd 100644 --- a/src/runtime/sys_openbsd1.go +++ b/src/runtime/sys_openbsd1.go @@ -23,6 +23,7 @@ func thrwakeup(ident uintptr, n int32) int32 { } func thrwakeup_trampoline() +//go:nosplit func osyield() { libcCall(unsafe.Pointer(funcPC(sched_yield_trampoline)), unsafe.Pointer(nil)) } From 03ed590e517980afc9c48816aced517fce2996ca Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 6 May 2021 16:04:05 -0700 Subject: [PATCH 056/940] [dev.typeparams] cmd/compile/internal/types2: use Checker-provided type parameter IDs when possible This is a port of https://golang.org/cl/317472. For #46003. Change-Id: Ie7b8880d43d459527b981ed4f60ee4d80a3cd17a Reviewed-on: https://go-review.googlesource.com/c/go/+/320149 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/api_test.go | 1 - src/cmd/compile/internal/types2/check.go | 1 + src/cmd/compile/internal/types2/type.go | 14 ++++++++++---- src/cmd/compile/internal/types2/types_test.go | 8 -------- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/cmd/compile/internal/types2/api_test.go b/src/cmd/compile/internal/types2/api_test.go index 873390c1e92..e1020a12194 100644 --- a/src/cmd/compile/internal/types2/api_test.go +++ b/src/cmd/compile/internal/types2/api_test.go @@ -349,7 +349,6 @@ func TestTypesInfo(t *testing.T) { } for _, test := range tests { - ResetId() // avoid renumbering of type parameter ids when adding tests info := Info{Types: make(map[syntax.Expr]TypeAndValue)} var name string if strings.HasPrefix(test.src, brokenPkg) { diff --git a/src/cmd/compile/internal/types2/check.go b/src/cmd/compile/internal/types2/check.go index 8d6cd1edab9..f80a918467e 100644 --- a/src/cmd/compile/internal/types2/check.go +++ b/src/cmd/compile/internal/types2/check.go @@ -83,6 +83,7 @@ type Checker struct { pkg *Package *Info version version // accepted language version + nextID uint64 // unique Id for type parameters (first valid Id is 1) objMap map[Object]*declInfo // maps package-level objects and (non-interface) methods to declaration info impMap map[importKey]*Package // maps (import path, source directory) to (complete or fake) package posMap map[*Interface][]syntax.Pos // maps interface types to lists of embedded interface positions diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index 88dedbad452..cf119a1b23b 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -732,11 +732,11 @@ func (t *Named) AddMethod(m *Func) { // Note: This is a uint32 rather than a uint64 because the // respective 64 bit atomic instructions are not available // on all platforms. -var lastId uint32 +var lastID uint32 -// nextId returns a value increasing monotonically by 1 with +// nextID returns a value increasing monotonically by 1 with // each call, starting with 1. It may be called concurrently. -func nextId() uint64 { return uint64(atomic.AddUint32(&lastId, 1)) } +func nextID() uint64 { return uint64(atomic.AddUint32(&lastID, 1)) } // A TypeParam represents a type parameter type. type TypeParam struct { @@ -753,7 +753,13 @@ func (t *TypeParam) Obj() *TypeName { return t.obj } // NewTypeParam returns a new TypeParam. func (check *Checker) NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam { assert(bound != nil) - typ := &TypeParam{check: check, id: nextId(), obj: obj, index: index, bound: bound} + // Always increment lastID, even if it is not used. + id := nextID() + if check != nil { + check.nextID++ + id = check.nextID + } + typ := &TypeParam{check: check, id: id, obj: obj, index: index, bound: bound} if obj.typ == nil { obj.typ = typ } diff --git a/src/cmd/compile/internal/types2/types_test.go b/src/cmd/compile/internal/types2/types_test.go index 096402148d3..11dca0b53de 100644 --- a/src/cmd/compile/internal/types2/types_test.go +++ b/src/cmd/compile/internal/types2/types_test.go @@ -4,14 +4,6 @@ package types2 -import "sync/atomic" - func init() { acceptMethodTypeParams = true } - -// Upon calling ResetId, nextId starts with 1 again. -// It may be called concurrently. This is only needed -// for tests where we may want to have a consistent -// numbering for each individual test case. -func ResetId() { atomic.StoreUint32(&lastId, 0) } From 0d1e293b2329a013f03ea3f742f1716098ee282c Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 14 May 2021 10:05:16 -0700 Subject: [PATCH 057/940] [dev.typeparams] cmd/compile/internal/types2: print "incomplete" for interfaces in debug mode only The /* incomplete */ comment printed for interfaces that have not been "completed" yet is not useful for end-users; it's here for type-checker debugging. Rather than trying to pass through a debug flag through all print routines (which may require new exported API), simply don't print the comment unless we have the debug flag set inside the type-checker. For #46167. Change-Id: Ibd22edfe63001dfd2b814eeb94c2d54d35afd88c Reviewed-on: https://go-review.googlesource.com/c/go/+/320150 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/types_test.go | 3 +++ src/cmd/compile/internal/types2/typestring.go | 2 +- src/cmd/compile/internal/types2/typestring_test.go | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/types2/types_test.go b/src/cmd/compile/internal/types2/types_test.go index 11dca0b53de..1525844f2df 100644 --- a/src/cmd/compile/internal/types2/types_test.go +++ b/src/cmd/compile/internal/types2/types_test.go @@ -7,3 +7,6 @@ package types2 func init() { acceptMethodTypeParams = true } + +// Debug is set if types2 is built with debug mode enabled. +const Debug = debug diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go index 40016697b7c..e85cc8ed358 100644 --- a/src/cmd/compile/internal/types2/typestring.go +++ b/src/cmd/compile/internal/types2/typestring.go @@ -226,7 +226,7 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { empty = false } } - if t.allMethods == nil || len(t.methods) > len(t.allMethods) { + if debug && (t.allMethods == nil || len(t.methods) > len(t.allMethods)) { if !empty { buf.WriteByte(' ') } diff --git a/src/cmd/compile/internal/types2/typestring_test.go b/src/cmd/compile/internal/types2/typestring_test.go index d98e9a5ade6..618fdc0757d 100644 --- a/src/cmd/compile/internal/types2/typestring_test.go +++ b/src/cmd/compile/internal/types2/typestring_test.go @@ -138,6 +138,10 @@ func TestTypeString(t *testing.T) { var nopos syntax.Pos func TestIncompleteInterfaces(t *testing.T) { + if !Debug { + t.Skip("requires type checker to be compiled with debug = true") + } + sig := NewSignature(nil, nil, nil, false) m := NewFunc(nopos, nil, "m", sig) for _, test := range []struct { From ce92a2023ccd77ca609126aa8a6e881c9def57f0 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Thu, 13 May 2021 09:48:40 -0400 Subject: [PATCH 058/940] cmd/go: error out of 'go mod tidy' if the go version is newer than supported Fixes #46142 Change-Id: Ib7a0a159e53cbe476be6aa9a050add10cc750dec Reviewed-on: https://go-review.googlesource.com/c/go/+/319669 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Jay Conrod --- src/cmd/go/internal/modload/load.go | 8 ++- .../go/testdata/script/mod_tidy_too_new.txt | 57 +++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 src/cmd/go/testdata/script/mod_tidy_too_new.txt diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go index f30ac6e0c8b..83fc7c09c37 100644 --- a/src/cmd/go/internal/modload/load.go +++ b/src/cmd/go/internal/modload/load.go @@ -922,7 +922,8 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader { } if params.GoVersion != "" { - if semver.Compare("v"+params.GoVersion, narrowAllVersionV) < 0 && !ld.UseVendorAll { + goVersionV := "v" + params.GoVersion + if semver.Compare(goVersionV, narrowAllVersionV) < 0 && !ld.UseVendorAll { // The module's go version explicitly predates the change in "all" for lazy // loading, so continue to use the older interpretation. // (If params.GoVersion is empty, we are probably not in any module at all @@ -930,6 +931,11 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader { ld.allClosesOverTests = true } + if ld.Tidy && semver.Compare(goVersionV, "v"+latestGoVersion()) > 0 { + ld.errorf("go mod tidy: go.mod file indicates go %s, but maximum supported version is %s\n", params.GoVersion, latestGoVersion()) + base.ExitIfErrors() + } + var err error ld.requirements, err = convertDepth(ctx, ld.requirements, modDepthFromGoVersion(params.GoVersion)) if err != nil { diff --git a/src/cmd/go/testdata/script/mod_tidy_too_new.txt b/src/cmd/go/testdata/script/mod_tidy_too_new.txt new file mode 100644 index 00000000000..b9c53b510da --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_too_new.txt @@ -0,0 +1,57 @@ +# https://golang.org/issue/46142: 'go mod tidy' should error out if the version +# in the go.mod file is newer than the most recent supported version. + +cp go.mod go.mod.orig + + +# If the go.mod file specifies an unsupported Go version, 'go mod tidy' should +# refuse to edit it: we don't know what a tidy go.mod file for that version +# would look like. + +! go mod tidy +stderr 'go mod tidy: go.mod file indicates go 2000.0, but maximum supported version is '$goversion'$' +cmp go.mod go.mod.orig + + +# The -e flag should push past the error and edit the file anyway, +# but preserve the too-high version. + +cp go.mod.orig go.mod +go mod tidy -e +stderr 'go mod tidy: go.mod file indicates go 2000.0, but maximum supported version is '$goversion'$' +cmp go.mod go.mod.tidy + + +# Explicitly switching to a supported version should suppress the error completely. + +cp go.mod.orig go.mod +go mod tidy -go=1.17 +! stderr 'maximum supported version' +go mod edit -go=1.17 go.mod.tidy +cmp go.mod go.mod.tidy + + +-- go.mod -- +module example.net/from/the/future + +go 2000.0 + +replace example.net/m v0.0.0 => ./m +-- go.mod.tidy -- +module example.net/from/the/future + +go 2000.0 + +replace example.net/m v0.0.0 => ./m + +require example.net/m v0.0.0 +-- x.go -- +package x + +import "example.net/m" +-- m/go.mod -- +module example.net/m + +go 1.17 +-- m/m.go -- +package m From bade680867c9b1eecc7b5d177ed94c455a72e50a Mon Sep 17 00:00:00 2001 From: Lynn Boger Date: Wed, 12 May 2021 12:11:03 -0500 Subject: [PATCH 059/940] runtime/cgo: fix crosscall2 on ppc64x Some uses of crosscall2 did not work on ppc64le and probably aix-ppc64. In particular, if there was a main program compiled with -buildmode=pie and used a plugin which invoked crosscall2, then failures could occur due to R2 getting set incorrectly along the way. The problem was due to R2 being saved on the caller's stack; it is now saved on the crosscall2 stack. More details can be found in the issue. This adds a testcase where the main program is built with pie and the plugin invokes crosscall2. This also changes the save of the CR bits from MOVD to MOVW as it should be. Fixes #43228 Change-Id: Ib5673e25a2ec5ee46bf9a1ffb0cb1f3ef5449086 Reviewed-on: https://go-review.googlesource.com/c/go/+/319489 Run-TryBot: Lynn Boger Reviewed-by: Cherry Mui Trust: Heschi Kreinick --- misc/cgo/testplugin/plugin_test.go | 7 +++++++ src/runtime/cgo/asm_ppc64x.s | 12 ++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/misc/cgo/testplugin/plugin_test.go b/misc/cgo/testplugin/plugin_test.go index 28a8c669c07..a6accc1dfbb 100644 --- a/misc/cgo/testplugin/plugin_test.go +++ b/misc/cgo/testplugin/plugin_test.go @@ -263,6 +263,13 @@ func TestIssue25756(t *testing.T) { } } +// Test with main using -buildmode=pie with plugin for issue #43228 +func TestIssue25756pie(t *testing.T) { + goCmd(t, "build", "-buildmode=plugin", "-o", "life.so", "./issue25756/plugin") + goCmd(t, "build", "-buildmode=pie", "-o", "issue25756pie.exe", "./issue25756/main.go") + run(t, "./issue25756pie.exe") +} + func TestMethod(t *testing.T) { // Exported symbol's method must be live. goCmd(t, "build", "-buildmode=plugin", "-o", "plugin.so", "./method/plugin.go") diff --git a/src/runtime/cgo/asm_ppc64x.s b/src/runtime/cgo/asm_ppc64x.s index 9dec8d04ce1..187b2d42f63 100644 --- a/src/runtime/cgo/asm_ppc64x.s +++ b/src/runtime/cgo/asm_ppc64x.s @@ -12,17 +12,20 @@ // func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr) // Saves C callee-saved registers and calls cgocallback with three arguments. // fn is the PC of a func(a unsafe.Pointer) function. +// The value of R2 is saved on the new stack frame, and not +// the caller's frame due to issue #43228. TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0 // Start with standard C stack frame layout and linkage MOVD LR, R0 MOVD R0, 16(R1) // Save LR in caller's frame MOVW CR, R0 // Save CR in caller's frame - MOVD R0, 8(R1) - MOVD R2, 24(R1) // Save TOC in caller's frame + MOVW R0, 8(R1) BL saveregs2<>(SB) MOVDU R1, (-288-3*8-FIXED_FRAME)(R1) + // Save the caller's R2 + MOVD R2, 24(R1) // Initialize Go ABI environment BL runtime·reginit(SB) @@ -41,12 +44,13 @@ TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0 MOVD R6, FIXED_FRAME+16(R1) // ctxt uintptr BL runtime·cgocallback(SB) + // Restore the caller's R2 + MOVD 24(R1), R2 ADD $(288+3*8+FIXED_FRAME), R1 BL restoreregs2<>(SB) - MOVD 24(R1), R2 - MOVD 8(R1), R0 + MOVW 8(R1), R0 MOVFL R0, $0xff MOVD 16(R1), R0 MOVD R0, LR From b1aff42900133e4fbc9b7d7c1af13c77e4f647b0 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Mon, 10 May 2021 17:19:50 -0400 Subject: [PATCH 060/940] cmd/go: don't print 'go get' deprecation notices in the main module If a user runs 'go get example.com/cmd' for a package in the main module, it's more likely they intend to fill in missing dependencies for that package (especially with -u). If the intent were only to build and install, 'go install example.com/cmd' would be a better choice. For #43684 Resolving a comment on CL 305670. Change-Id: I5c80ffdcdb3425b448f2f49cc20b07a18cb2bbe9 Reviewed-on: https://go-review.googlesource.com/c/go/+/318570 Trust: Jay Conrod Run-TryBot: Jay Conrod TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills --- src/cmd/go/internal/modget/get.go | 8 +++---- .../script/mod_get_deprecate_install.txt | 21 +++++++++++++++++-- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go index 3a24b6a2f7e..2a7fe5226fd 100644 --- a/src/cmd/go/internal/modget/get.go +++ b/src/cmd/go/internal/modget/get.go @@ -386,14 +386,14 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) { } load.CheckPackageErrors(pkgs) - haveExe := false + haveExternalExe := false for _, pkg := range pkgs { - if pkg.Name == "main" { - haveExe = true + if pkg.Name == "main" && pkg.Module != nil && pkg.Module.Path != modload.Target.Path { + haveExternalExe = true break } } - if haveExe { + if haveExternalExe { fmt.Fprint(os.Stderr, "go get: installing executables with 'go get' in module mode is deprecated.") var altMsg string if modload.HasModRoot() { diff --git a/src/cmd/go/testdata/script/mod_get_deprecate_install.txt b/src/cmd/go/testdata/script/mod_get_deprecate_install.txt index d832b5f2e80..63cd27a42d2 100644 --- a/src/cmd/go/testdata/script/mod_get_deprecate_install.txt +++ b/src/cmd/go/testdata/script/mod_get_deprecate_install.txt @@ -7,16 +7,33 @@ go get example.com/cmd/a stderr '^go get: installing executables with ''go get'' in module mode is deprecated.$' stderr 'Use ''go install pkg@version'' instead.' - -go mod init m +cp go.mod.orig go.mod # 'go get' inside a module with a non-main package does not print a message. # This will stop building in the future, but it's the command we want to use. go get rsc.io/quote ! stderr deprecated +cp go.mod.orig go.mod # 'go get' inside a module with an executable prints a different # deprecation message. go get example.com/cmd/a stderr '^go get: installing executables with ''go get'' in module mode is deprecated.$' stderr 'To adjust and download dependencies of the current module, use ''go get -d''' +cp go.mod.orig go.mod + +# 'go get' should not print a warning for a main package inside the main module. +# The intent is most likely to update the dependencies of that package. +# 'go install' would be used otherwise. +go get m +! stderr . +cp go.mod.orig go.mod + +-- go.mod.orig -- +module m + +go 1.17 +-- main.go -- +package main + +func main() {} From b9b2bed8933a467dcc48eedeec83dfea7ff3148a Mon Sep 17 00:00:00 2001 From: "Andrew G. Morgan" Date: Wed, 12 May 2021 20:41:26 -0700 Subject: [PATCH 061/940] syscall: some containers may fail syscall.TestSetuidEtc The test previously had the hardcoded assumption that /proc/self/status files had "Groups:" lines containing numerical IDs in ascending order. Because of the possibility of non-monotonic ordering of GIDs in user namespaces, this assumption was not universally true for all /proc/self/gid_map setups. To ensure this test can pass in those setups, sanity check failed "Groups:" line matches with a string sorted version of the expected values. (For the test cases here, numerical and string sorted order are guaranteed to match.) Fixes #46145 Change-Id: Ia060e80b123604bc394a15c02582fc406f944d36 Reviewed-on: https://go-review.googlesource.com/c/go/+/319591 Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor Trust: Tobias Klauser --- misc/cgo/test/issue1435.go | 21 +++++++++++++++++---- src/syscall/syscall_linux_test.go | 21 +++++++++++++++++---- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/misc/cgo/test/issue1435.go b/misc/cgo/test/issue1435.go index cf34ce8db6c..92c6b998465 100644 --- a/misc/cgo/test/issue1435.go +++ b/misc/cgo/test/issue1435.go @@ -9,6 +9,7 @@ package cgotest import ( "fmt" "os" + "sort" "strings" "syscall" "testing" @@ -105,11 +106,23 @@ func compareStatus(filter, expect string) error { // "Pid:\t". } if strings.HasPrefix(line, filter) { - if line != expected { - return fmt.Errorf("%q got:%q want:%q (bad) [pid=%d file:'%s' %v]\n", tf, line, expected, pid, string(d), expectedProc) + if line == expected { + foundAThread = true + break } - foundAThread = true - break + if filter == "Groups:" && strings.HasPrefix(line, "Groups:\t") { + // https://github.com/golang/go/issues/46145 + // Containers don't reliably output this line in sorted order so manually sort and compare that. + a := strings.Split(line[8:], " ") + sort.Strings(a) + got := strings.Join(a, " ") + if got == expected[8:] { + foundAThread = true + break + } + + } + return fmt.Errorf("%q got:%q want:%q (bad) [pid=%d file:'%s' %v]\n", tf, line, expected, pid, string(d), expectedProc) } } } diff --git a/src/syscall/syscall_linux_test.go b/src/syscall/syscall_linux_test.go index adeb7c9ebbf..442dc9f10eb 100644 --- a/src/syscall/syscall_linux_test.go +++ b/src/syscall/syscall_linux_test.go @@ -14,6 +14,7 @@ import ( "os/signal" "path/filepath" "runtime" + "sort" "strconv" "strings" "syscall" @@ -583,11 +584,23 @@ func compareStatus(filter, expect string) error { // "Pid:\t". } if strings.HasPrefix(line, filter) { - if line != expected { - return fmt.Errorf("%q got:%q want:%q (bad) [pid=%d file:'%s' %v]\n", tf, line, expected, pid, string(d), expectedProc) + if line == expected { + foundAThread = true + break } - foundAThread = true - break + if filter == "Groups:" && strings.HasPrefix(line, "Groups:\t") { + // https://github.com/golang/go/issues/46145 + // Containers don't reliably output this line in sorted order so manually sort and compare that. + a := strings.Split(line[8:], " ") + sort.Strings(a) + got := strings.Join(a, " ") + if got == expected[8:] { + foundAThread = true + break + } + + } + return fmt.Errorf("%q got:%q want:%q (bad) [pid=%d file:'%s' %v]\n", tf, line, expected, pid, string(d), expectedProc) } } } From a2c07a9a1a445c28fa4db9bd1472b28cad3ca818 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 17 May 2021 12:18:12 +0200 Subject: [PATCH 062/940] all: update golang.org/x/net to latest To pull in CL 318309. For #41184 Change-Id: I99adb0478e71dbd72e13551a87ed09eae2a0ef2c Reviewed-on: https://go-review.googlesource.com/c/go/+/320312 Trust: Tobias Klauser Run-TryBot: Tobias Klauser TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/go.mod | 2 +- src/go.sum | 4 ++-- src/vendor/golang.org/x/net/route/empty.s | 1 + src/vendor/modules.txt | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/go.mod b/src/go.mod index a3ceb05890e..93ff2d8d3c1 100644 --- a/src/go.mod +++ b/src/go.mod @@ -4,7 +4,7 @@ go 1.17 require ( golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e - golang.org/x/net v0.0.0-20210505024714-0287a6fb4125 + golang.org/x/net v0.0.0-20210510120150-4163338589ed golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 // indirect golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f // indirect ) diff --git a/src/go.sum b/src/go.sum index 27513a350dd..1390ce6d458 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,7 +1,7 @@ golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI= golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/net v0.0.0-20210505024714-0287a6fb4125 h1:Ugb8sMTWuWRC3+sz5WeN/4kejDx9BvIwnPUiJBjJE+8= -golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I= +golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 h1:cdsMqa2nXzqlgs183pHxtvoVwU7CyzaCTAUOg94af4c= golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f h1:yQJrRE0hDxDFmZLlRaw+3vusO4fwNHgHIjUOMO7bHYI= diff --git a/src/vendor/golang.org/x/net/route/empty.s b/src/vendor/golang.org/x/net/route/empty.s index bff0231c7d5..90ab4ca3d8e 100644 --- a/src/vendor/golang.org/x/net/route/empty.s +++ b/src/vendor/golang.org/x/net/route/empty.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin && go1.12 // +build darwin,go1.12 // This exists solely so we can linkname in symbols from syscall. diff --git a/src/vendor/modules.txt b/src/vendor/modules.txt index 5b939af60db..1b850342a5a 100644 --- a/src/vendor/modules.txt +++ b/src/vendor/modules.txt @@ -8,7 +8,7 @@ golang.org/x/crypto/curve25519 golang.org/x/crypto/hkdf golang.org/x/crypto/internal/subtle golang.org/x/crypto/poly1305 -# golang.org/x/net v0.0.0-20210505024714-0287a6fb4125 +# golang.org/x/net v0.0.0-20210510120150-4163338589ed ## explicit; go 1.17 golang.org/x/net/dns/dnsmessage golang.org/x/net/http/httpguts From f39200b037e022d0f79ed478a45492306aaf5629 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 17 May 2021 11:49:53 -0700 Subject: [PATCH 063/940] [dev.typeparams] go/constant: implement Kind.String Fixes #46211. Change-Id: I7e373be5ccf9c6b53d58ed942addd17d28c3efa1 Reviewed-on: https://go-review.googlesource.com/c/go/+/320491 Trust: Robert Griesemer Run-TryBot: Robert Griesemer Reviewed-by: Matthew Dempsky TryBot-Result: Go Bot --- src/go/constant/kind_string.go | 28 ++++++++++++++++++++++++++++ src/go/constant/value.go | 2 ++ 2 files changed, 30 insertions(+) create mode 100644 src/go/constant/kind_string.go diff --git a/src/go/constant/kind_string.go b/src/go/constant/kind_string.go new file mode 100644 index 00000000000..700332511d8 --- /dev/null +++ b/src/go/constant/kind_string.go @@ -0,0 +1,28 @@ +// Code generated by "stringer -type Kind"; DO NOT EDIT. + +package constant + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[Unknown-0] + _ = x[Bool-1] + _ = x[String-2] + _ = x[Int-3] + _ = x[Float-4] + _ = x[Complex-5] +} + +const _Kind_name = "UnknownBoolStringIntFloatComplex" + +var _Kind_index = [...]uint8{0, 7, 11, 17, 20, 25, 32} + +func (i Kind) String() string { + if i < 0 || i >= Kind(len(_Kind_index)-1) { + return "Kind(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _Kind_name[_Kind_index[i]:_Kind_index[i+1]] +} diff --git a/src/go/constant/value.go b/src/go/constant/value.go index 78cb3f896f5..014e873100d 100644 --- a/src/go/constant/value.go +++ b/src/go/constant/value.go @@ -24,6 +24,8 @@ import ( "unicode/utf8" ) +//go:generate stringer -type Kind + // Kind specifies the kind of value represented by a Value. type Kind int From bfe3573d58d7c49c4d58e0ab392eb0b5a660d262 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Mon, 17 May 2021 16:11:51 -0400 Subject: [PATCH 064/940] go/token: correct the interval notation used in some panic messages Fix an apparent typo for the right-hand bound in a couple panic messages, where '[' was used instead of ']'. Fixes #46215 Change-Id: Ie419c404ca72ed085a83a2c38ea1a5d6ed326cca Reviewed-on: https://go-review.googlesource.com/c/go/+/320510 Trust: Robert Findley Trust: Robert Griesemer Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/token/position.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/go/token/position.go b/src/go/token/position.go index bbcd8b022b6..0d7982c6705 100644 --- a/src/go/token/position.go +++ b/src/go/token/position.go @@ -278,7 +278,7 @@ func (f *File) Pos(offset int) Pos { // func (f *File) Offset(p Pos) int { if int(p) < f.base || int(p) > f.base+f.size { - panic(fmt.Sprintf("invalid Pos value %d (should be in [%d, %d[)", p, f.base, f.base+f.size)) + panic(fmt.Sprintf("invalid Pos value %d (should be in [%d, %d])", p, f.base, f.base+f.size)) } return int(p) - f.base } @@ -346,7 +346,7 @@ func (f *File) position(p Pos, adjusted bool) (pos Position) { func (f *File) PositionFor(p Pos, adjusted bool) (pos Position) { if p != NoPos { if int(p) < f.base || int(p) > f.base+f.size { - panic(fmt.Sprintf("invalid Pos value %d (should be in [%d, %d[)", p, f.base, f.base+f.size)) + panic(fmt.Sprintf("invalid Pos value %d (should be in [%d, %d])", p, f.base, f.base+f.size)) } pos = f.position(p, adjusted) } From 5e191f8f4885cac105b6d7069e02c0c8d149c22c Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Mon, 17 May 2021 10:30:01 +1000 Subject: [PATCH 065/940] time: rewrite the documentation for layout strings People continue to be confused by how these work. Address that by some rejiggering. Introduce a constant called Layout that both defines the time and provides a reference point for Parse and Format to refer to. We can then delete much redundancy, especially for Format's comments, but Parse tightens a bit too. Then change the way the concept of the layout string is introduced, and provide a clearer catalog of what its elements are. Fixes #38871 Change-Id: Ib967ae70c7d5798a97b865cdda1fda4daed8a99a Reviewed-on: https://go-review.googlesource.com/c/go/+/320252 Trust: Rob Pike Run-TryBot: Rob Pike TryBot-Result: Go Bot Reviewed-by: Russ Cox --- src/time/format.go | 165 +++++++++++++++++++++++---------------------- 1 file changed, 86 insertions(+), 79 deletions(-) diff --git a/src/time/format.go b/src/time/format.go index f6dc8ee621b..6040ed5aebc 100644 --- a/src/time/format.go +++ b/src/time/format.go @@ -7,58 +7,18 @@ package time import "errors" // These are predefined layouts for use in Time.Format and time.Parse. -// The reference time used in the layouts is the specific time: -// Mon Jan 2 15:04:05 MST 2006 -// which is Unix time 1136239445. Since MST is GMT-0700, -// the reference time can be thought of as +// The reference time used in these layouts is the specific time stamp: // 01/02 03:04:05PM '06 -0700 -// To define your own format, write down what the reference time would look -// like formatted your way; see the values of constants like ANSIC, -// StampMicro or Kitchen for examples. The model is to demonstrate what the -// reference time looks like so that the Format and Parse methods can apply -// the same transformation to a general time value. +// (January 2, 15:04:05, 2006, in time zone seven hours west of GMT). +// That value is recorded as the constant named Layout, listed below. As a Unix +// time, this is 1136239445. Since MST is GMT-0700, the reference would be +// printed by the Unix date command as: +// Mon Jan 2 15:04:05 MST 2006 +// It is a regrettable historic error that the date uses the American convention +// of putting the numerical month before the day. // -// Some valid layouts are invalid time values for time.Parse, due to formats -// such as _ for space padding and Z for zone information. -// -// Within the format string, an underscore _ represents a space that may be -// replaced by a digit if the following number (a day) has two digits; for -// compatibility with fixed-width Unix time formats. -// -// A decimal point followed by one or more zeros represents a fractional -// second, printed to the given number of decimal places. -// Either a comma or decimal point followed by one or more nines represents -// a fractional second, printed to the given number of decimal places, with -// trailing zeros removed. -// When parsing (only), the input may contain a fractional second -// field immediately after the seconds field, even if the layout does not -// signify its presence. In that case either a comma or a decimal point -// followed by a maximal series of digits is parsed as a fractional second. -// -// Numeric time zone offsets format as follows: -// -0700 ±hhmm -// -07:00 ±hh:mm -// -07 ±hh -// Replacing the sign in the format with a Z triggers -// the ISO 8601 behavior of printing Z instead of an -// offset for the UTC zone. Thus: -// Z0700 Z or ±hhmm -// Z07:00 Z or ±hh:mm -// Z07 Z or ±hh -// -// The recognized day of week formats are "Mon" and "Monday". -// The recognized month formats are "Jan" and "January". -// -// The formats 2, _2, and 02 are unpadded, space-padded, and zero-padded -// day of month. The formats __2 and 002 are space-padded and zero-padded -// three-character day of year; there is no unpadded day of year format. -// -// Text in the format string that is not recognized as part of the reference -// time is echoed verbatim during Format and expected to appear verbatim -// in the input to Parse. -// -// The executable example for Time.Format demonstrates the working -// of the layout string in detail and is a good reference. +// The example for Time.Format demonstrates the working of the layout string +// in detail and is a good reference. // // Note that the RFC822, RFC850, and RFC1123 formats should be applied // only to local times. Applying them to UTC times will use "UTC" as the @@ -71,7 +31,65 @@ import "errors" // permitted by the RFCs and they do accept time formats not formally defined. // The RFC3339Nano format removes trailing zeros from the seconds field // and thus may not sort correctly once formatted. +// +// Most programs can use one of the defined constants as the layout passed to +// Format or Parse. The rest of this comment can be ignored unless you are +// creating a custom layout string. +// +// To define your own format, write down what the reference time would look like +// formatted your way; see the values of constants like ANSIC, StampMicro or +// Kitchen for examples. The model is to demonstrate what the reference time +// looks like so that the Format and Parse methods can apply the same +// transformation to a general time value. +// +// Here is a summary of the components of a layout string. Each element shows by +// example the formatting of an element of the reference time. Only these values +// are recognized. Text in the layout string that is not recognized as part of +// the reference time is echoed verbatim during Format and expected to appear +// verbatim in the input to Parse. +// +// Year: "2006" "06" +// Month: "Jan" "January" +// Textual day of the week: "Mon" "Monday" +// Numeric day of the month: "2" "_2" "02" +// Numeric day of the year: "__2" "002" +// Hour: "15" "3" "03" (PM or AM) +// Minute: "4" "04" +// Second: "5" "05" +// AM/PM mark: "PM" +// +// Numeric time zone offsets format as follows: +// "-0700" ±hhmm +// "-07:00" ±hh:mm +// "-07" ±hh +// Replacing the sign in the format with a Z triggers +// the ISO 8601 behavior of printing Z instead of an +// offset for the UTC zone. Thus: +// "Z0700" Z or ±hhmm +// "Z07:00" Z or ±hh:mm +// "Z07" Z or ±hh +// +// Within the format string, the underscores in "_2" and "__2" represent spaces +// that may be replaced by digits if the following number has multiple digits, +// for compatibility with fixed-width Unix time formats. A leading zero represents +// a zero-padded value. +// +// The formats and 002 are space-padded and zero-padded +// three-character day of year; there is no unpadded day of year format. +// +// A decimal point followed by one or more zeros represents a fractional +// second, printed to the given number of decimal places. +// Either a comma or decimal point followed by one or more nines represents +// a fractional second, printed to the given number of decimal places, with +// trailing zeros removed. +// For example "15:04:05,000" or "15:04:05.000" formats or parses with +// millisecond precision. +// +// Some valid layouts are invalid time values for time.Parse, due to formats +// such as _ for space padding and Z for zone information. +// const ( + Layout = "01/02 03:04:05PM '06 -0700" // The reference time, in numerical order. ANSIC = "Mon Jan _2 15:04:05 2006" UnixDate = "Mon Jan _2 15:04:05 MST 2006" RubyDate = "Mon Jan 02 15:04:05 -0700 2006" @@ -531,23 +549,12 @@ func (t Time) GoString() string { return string(buf) } -// Format returns a textual representation of the time value formatted -// according to layout, which defines the format by showing how the reference -// time, defined to be -// Mon Jan 2 15:04:05 -0700 MST 2006 -// would be displayed if it were the value; it serves as an example of the -// desired output. The same display rules will then be applied to the time -// value. +// Format returns a textual representation of the time value formatted according +// to the layout defined by the argument. See the documentation for the +// constant called Layout to see how to represent the layout format. // -// A fractional second is represented by adding either a comma or a -// period and zeros to the end of the seconds section of layout string, -// as in "15:04:05,000" or "15:04:05.000" to format a time stamp with -// millisecond precision. -// -// Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard -// and convenient representations of the reference time. For more information -// about the formats and the definition of the reference time, see the -// documentation for ANSIC and the other constants defined by this package. +// The executable example for Time.Format demonstrates the working +// of the layout string in detail and is a good reference. func (t Time) Format(layout string) string { const bufSize = 64 var b []byte @@ -855,21 +862,19 @@ func skip(value, prefix string) (string, error) { } // Parse parses a formatted string and returns the time value it represents. -// The layout defines the format by showing how the reference time, -// defined to be -// Mon Jan 2 15:04:05 -0700 MST 2006 -// would be interpreted if it were the value; it serves as an example of -// the input format. The same interpretation will then be made to the -// input string. +// See the documentation for the constant called Layout to see how to +// represent the format. The second argument must be parseable using +// the format string (layout) provided as the first argument. // -// Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard -// and convenient representations of the reference time. For more information -// about the formats and the definition of the reference time, see the -// documentation for ANSIC and the other constants defined by this package. -// Also, the executable example for Time.Format demonstrates the working -// of the layout string in detail and is a good reference. +// The example for Time.Format demonstrates the working of the layout string +// in detail and is a good reference. // -// Elements omitted from the value are assumed to be zero or, when +// When parsing (only), the input may contain a fractional second +// field immediately after the seconds field, even if the layout does not +// signify its presence. In that case either a comma or a decimal point +// followed by a maximal series of digits is parsed as a fractional second. +// +// Elements omitted from the layout are assumed to be zero or, when // zero is impossible, one, so parsing "3:04pm" returns the time // corresponding to Jan 1, year 0, 15:04:00 UTC (note that because the year is // 0, this time is before the zero Time). @@ -879,6 +884,8 @@ func skip(value, prefix string) (string, error) { // For layouts specifying the two-digit year 06, a value NN >= 69 will be treated // as 19NN and a value NN < 69 will be treated as 20NN. // +// The remainder of this comment describes the handling of time zones. +// // In the absence of a time zone indicator, Parse returns a time in UTC. // // When parsing a time with a zone offset like -0700, if the offset corresponds From 8b0901fd32aa9c29a1fa4ed8cd517914920a1509 Mon Sep 17 00:00:00 2001 From: Jeff Widman Date: Tue, 18 May 2021 06:09:20 +0000 Subject: [PATCH 066/940] doc/go1.17: fix typo "avoding" -> "avoiding" Change-Id: Ice4a6e7ec8175caf3f049ac1ca39929059f90e9c GitHub-Last-Rev: a2d59d55511ac7825cbeca6651a79b1060d90de3 GitHub-Pull-Request: golang/go#46227 Reviewed-on: https://go-review.googlesource.com/c/go/+/320729 Reviewed-by: Keith Randall Reviewed-by: Alberto Donizetti Trust: Alberto Donizetti --- doc/go1.17.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index cf856a1e735..4b2f4bce796 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -60,7 +60,7 @@ Do not send CLs removing the interior tags from such phrases.

If a module specifies go 1.17 or higher in its go.mod file, its transitive requirements are now loaded lazily, - avoding the need to download or read go.mod files for + avoiding the need to download or read go.mod files for otherwise-irrelevant dependencies. To support lazy loading, in Go 1.17 modules the go command maintains explicit requirements in the go.mod file for every dependency that provides any package From 690a8c3fb136431d4f22894c545ea99278758570 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 13 May 2021 19:22:57 -0400 Subject: [PATCH 067/940] make.bash: fix misuse of continue Apparently, in bash, the "continue" keyword can only be used inside of a loop, not in an if block. If readelf exists but $CC does not, make.bash emits a warning: ./make.bash: line 135: continue: only meaningful in a `for', `while', or `until' loop Change it to a conditional. Change-Id: I00a0940ed99bc0c565094e506705961b6b3d362e Reviewed-on: https://go-review.googlesource.com/c/go/+/320170 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor Reviewed-by: Cuong Manh Le --- src/make.bash | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/make.bash b/src/make.bash index 3d1b0c87e75..4fb13f62758 100755 --- a/src/make.bash +++ b/src/make.bash @@ -132,10 +132,11 @@ fi # Test which linker/loader our system is using if type readelf >/dev/null 2>&1; then - echo "int main() { return 0; }" | ${CC:-cc} -o ./test-musl-ldso -x c - || continue - LDSO=$(readelf -l ./test-musl-ldso | grep 'interpreter:' | sed -e 's/^.*interpreter: \(.*\)[]]/\1/') >/dev/null 2>&1 - [ -z "$LDSO" ] || export GO_LDSO="$LDSO" - rm -f ./test-musl-ldso + if echo "int main() { return 0; }" | ${CC:-cc} -o ./test-musl-ldso -x c - >/dev/null 2>&1; then + LDSO=$(readelf -l ./test-musl-ldso | grep 'interpreter:' | sed -e 's/^.*interpreter: \(.*\)[]]/\1/') >/dev/null 2>&1 + [ -z "$LDSO" ] || export GO_LDSO="$LDSO" + rm -f ./test-musl-ldso + fi fi # Clean old generated file that will cause problems in the build. From 077f03f4d878f3b62e4aa15cdbd7cabc9dd08a11 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 18 May 2021 12:47:30 -0400 Subject: [PATCH 068/940] [dev.typeparams] runtime: use internal/abi.FuncPCABI0 for sigtramp PC on FreeBSD Same as CL 313230, for FreeBSD. sigtramp is the only one we need. Change-Id: Iefc00c1cb7e70b08a07c3bc3604b2114fd86563d Reviewed-on: https://go-review.googlesource.com/c/go/+/320912 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- src/runtime/os_freebsd2.go | 4 +++- src/runtime/os_freebsd_amd64.go | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/runtime/os_freebsd2.go b/src/runtime/os_freebsd2.go index fde6fbf1b14..53ba23b64cf 100644 --- a/src/runtime/os_freebsd2.go +++ b/src/runtime/os_freebsd2.go @@ -7,6 +7,8 @@ package runtime +import "internal/abi" + //go:nosplit //go:nowritebarrierrec func setsig(i uint32, fn uintptr) { @@ -14,7 +16,7 @@ func setsig(i uint32, fn uintptr) { sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART sa.sa_mask = sigset_all if fn == funcPC(sighandler) { - fn = funcPC(sigtramp) + fn = abi.FuncPCABI0(sigtramp) } sa.sa_handler = fn sigaction(i, &sa, nil) diff --git a/src/runtime/os_freebsd_amd64.go b/src/runtime/os_freebsd_amd64.go index dc0bb9ff96f..7ae80c25060 100644 --- a/src/runtime/os_freebsd_amd64.go +++ b/src/runtime/os_freebsd_amd64.go @@ -4,6 +4,8 @@ package runtime +import "internal/abi" + func cgoSigtramp() //go:nosplit @@ -14,9 +16,9 @@ func setsig(i uint32, fn uintptr) { sa.sa_mask = sigset_all if fn == funcPC(sighandler) { if iscgo { - fn = funcPC(cgoSigtramp) + fn = abi.FuncPCABI0(cgoSigtramp) } else { - fn = funcPC(sigtramp) + fn = abi.FuncPCABI0(sigtramp) } } sa.sa_handler = fn From 048cb4ceee652e358d84fbca260fc93d7a0dfbe3 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Mon, 10 May 2021 09:59:07 -0700 Subject: [PATCH 069/940] crypto/x509: remove duplicate import Change-Id: I86742ae7aa4ff49a38f8e3bc1d64fb223feae73e Reviewed-on: https://go-review.googlesource.com/c/go/+/318409 Trust: Roland Shoemaker Trust: Katie Hockman Run-TryBot: Roland Shoemaker TryBot-Result: Go Bot Reviewed-by: Katie Hockman --- src/crypto/x509/parser.go | 115 +++++++++++++++++++------------------- 1 file changed, 57 insertions(+), 58 deletions(-) diff --git a/src/crypto/x509/parser.go b/src/crypto/x509/parser.go index 578227ab8eb..3d51ddd7f57 100644 --- a/src/crypto/x509/parser.go +++ b/src/crypto/x509/parser.go @@ -24,7 +24,6 @@ import ( "unicode/utf8" "golang.org/x/crypto/cryptobyte" - cbasn1 "golang.org/x/crypto/cryptobyte/asn1" cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1" ) @@ -55,23 +54,23 @@ func isPrintable(b byte) bool { // UTF8String, BMPString, and IA5String. This is mostly copied from the // respective encoding/asn1.parse... methods, rather than just increasing // the API surface of that package. -func parseASN1String(tag cbasn1.Tag, value []byte) (string, error) { +func parseASN1String(tag cryptobyte_asn1.Tag, value []byte) (string, error) { switch tag { - case cbasn1.T61String: + case cryptobyte_asn1.T61String: return string(value), nil - case cbasn1.PrintableString: + case cryptobyte_asn1.PrintableString: for _, b := range value { if !isPrintable(b) { return "", errors.New("invalid PrintableString") } } return string(value), nil - case cbasn1.UTF8String: + case cryptobyte_asn1.UTF8String: if !utf8.Valid(value) { return "", errors.New("invalid UTF-8 string") } return string(value), nil - case cbasn1.Tag(asn1.TagBMPString): + case cryptobyte_asn1.Tag(asn1.TagBMPString): if len(value)%2 != 0 { return "", errors.New("invalid BMPString") } @@ -88,7 +87,7 @@ func parseASN1String(tag cbasn1.Tag, value []byte) (string, error) { } return string(utf16.Decode(s)), nil - case cbasn1.IA5String: + case cryptobyte_asn1.IA5String: s := string(value) if isIA5String(s) != nil { return "", errors.New("invalid IA5String") @@ -101,7 +100,7 @@ func parseASN1String(tag cbasn1.Tag, value []byte) (string, error) { // parseName parses a DER encoded Name as defined in RFC 5280. We may // want to export this function in the future for use in crypto/tls. func parseName(raw cryptobyte.String) (*pkix.RDNSequence, error) { - if !raw.ReadASN1(&raw, cbasn1.SEQUENCE) { + if !raw.ReadASN1(&raw, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: invalid RDNSequence") } @@ -109,12 +108,12 @@ func parseName(raw cryptobyte.String) (*pkix.RDNSequence, error) { for !raw.Empty() { var rdnSet pkix.RelativeDistinguishedNameSET var set cryptobyte.String - if !raw.ReadASN1(&set, cbasn1.SET) { + if !raw.ReadASN1(&set, cryptobyte_asn1.SET) { return nil, errors.New("x509: invalid RDNSequence") } for !set.Empty() { var atav cryptobyte.String - if !set.ReadASN1(&atav, cbasn1.SEQUENCE) { + if !set.ReadASN1(&atav, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: invalid RDNSequence: invalid attribute") } var attr pkix.AttributeTypeAndValue @@ -122,7 +121,7 @@ func parseName(raw cryptobyte.String) (*pkix.RDNSequence, error) { return nil, errors.New("x509: invalid RDNSequence: invalid attribute type") } var rawValue cryptobyte.String - var valueTag cbasn1.Tag + var valueTag cryptobyte_asn1.Tag if !atav.ReadAnyASN1(&rawValue, &valueTag) { return nil, errors.New("x509: invalid RDNSequence: invalid attribute value") } @@ -149,7 +148,7 @@ func parseAI(der cryptobyte.String) (pkix.AlgorithmIdentifier, error) { return ai, nil } var params cryptobyte.String - var tag cbasn1.Tag + var tag cryptobyte_asn1.Tag if !der.ReadAnyASN1Element(¶ms, &tag) { return ai, errors.New("x509: malformed parameters") } @@ -162,11 +161,11 @@ func parseValidity(der cryptobyte.String) (time.Time, time.Time, error) { extract := func() (time.Time, error) { var t time.Time switch { - case der.PeekASN1Tag(cbasn1.UTCTime): + case der.PeekASN1Tag(cryptobyte_asn1.UTCTime): // TODO(rolandshoemaker): once #45411 is fixed, the following code // should be replaced with a call to der.ReadASN1UTCTime. var utc cryptobyte.String - if !der.ReadASN1(&utc, cbasn1.UTCTime) { + if !der.ReadASN1(&utc, cryptobyte_asn1.UTCTime) { return t, errors.New("x509: malformed UTCTime") } s := string(utc) @@ -190,7 +189,7 @@ func parseValidity(der cryptobyte.String) (time.Time, time.Time, error) { // UTCTime only encodes times prior to 2050. See https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1 t = t.AddDate(-100, 0, 0) } - case der.PeekASN1Tag(cbasn1.GeneralizedTime): + case der.PeekASN1Tag(cryptobyte_asn1.GeneralizedTime): if !der.ReadASN1GeneralizedTime(&t) { return t, errors.New("x509: malformed GeneralizedTime") } @@ -217,13 +216,13 @@ func parseExtension(der cryptobyte.String) (pkix.Extension, error) { if !der.ReadASN1ObjectIdentifier(&ext.Id) { return ext, errors.New("x509: malformed extention OID field") } - if der.PeekASN1Tag(cbasn1.BOOLEAN) { + if der.PeekASN1Tag(cryptobyte_asn1.BOOLEAN) { if !der.ReadASN1Boolean(&ext.Critical) { return ext, errors.New("x509: malformed extention critical field") } } var val cryptobyte.String - if !der.ReadASN1(&val, cbasn1.OCTET_STRING) { + if !der.ReadASN1(&val, cryptobyte_asn1.OCTET_STRING) { return ext, errors.New("x509: malformed extention value field") } ext.Value = val @@ -241,7 +240,7 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{ } p := &pkcs1PublicKey{N: new(big.Int)} - if !der.ReadASN1(&der, cbasn1.SEQUENCE) { + if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: invalid RSA public key") } if !der.ReadASN1Integer(p.N) { @@ -307,7 +306,7 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{ }, } paramsDer := cryptobyte.String(keyData.Algorithm.Parameters.FullBytes) - if !paramsDer.ReadASN1(¶msDer, cbasn1.SEQUENCE) || + if !paramsDer.ReadASN1(¶msDer, cryptobyte_asn1.SEQUENCE) || !paramsDer.ReadASN1Integer(pub.Parameters.P) || !paramsDer.ReadASN1Integer(pub.Parameters.Q) || !paramsDer.ReadASN1Integer(pub.Parameters.G) { @@ -340,16 +339,16 @@ func parseKeyUsageExtension(der cryptobyte.String) (KeyUsage, error) { func parseBasicConstraintsExtension(der cryptobyte.String) (bool, int, error) { var isCA bool - if !der.ReadASN1(&der, cbasn1.SEQUENCE) { + if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { return false, 0, errors.New("x509: invalid basic constraints a") } - if der.PeekASN1Tag(cbasn1.BOOLEAN) { + if der.PeekASN1Tag(cryptobyte_asn1.BOOLEAN) { if !der.ReadASN1Boolean(&isCA) { return false, 0, errors.New("x509: invalid basic constraints b") } } maxPathLen := -1 - if !der.Empty() && der.PeekASN1Tag(cbasn1.INTEGER) { + if !der.Empty() && der.PeekASN1Tag(cryptobyte_asn1.INTEGER) { if !der.ReadASN1Integer(&maxPathLen) { return false, 0, errors.New("x509: invalid basic constraints c") } @@ -360,12 +359,12 @@ func parseBasicConstraintsExtension(der cryptobyte.String) (bool, int, error) { } func forEachSAN(der cryptobyte.String, callback func(tag int, data []byte) error) error { - if !der.ReadASN1(&der, cbasn1.SEQUENCE) { + if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { return errors.New("x509: invalid subject alternative names") } for !der.Empty() { var san cryptobyte.String - var tag cbasn1.Tag + var tag cryptobyte_asn1.Tag if !der.ReadAnyASN1(&san, &tag) { return errors.New("x509: invalid subject alternative name") } @@ -425,7 +424,7 @@ func parseSANExtension(der cryptobyte.String) (dnsNames, emailAddresses []string func parseExtKeyUsageExtension(der cryptobyte.String) ([]ExtKeyUsage, []asn1.ObjectIdentifier, error) { var extKeyUsages []ExtKeyUsage var unknownUsages []asn1.ObjectIdentifier - if !der.ReadASN1(&der, cbasn1.SEQUENCE) { + if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { return nil, nil, errors.New("x509: invalid extended key usages") } for !der.Empty() { @@ -444,12 +443,12 @@ func parseExtKeyUsageExtension(der cryptobyte.String) ([]ExtKeyUsage, []asn1.Obj func parseCertificatePoliciesExtension(der cryptobyte.String) ([]asn1.ObjectIdentifier, error) { var oids []asn1.ObjectIdentifier - if !der.ReadASN1(&der, cbasn1.SEQUENCE) { + if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: invalid certificate policies") } for !der.Empty() { var cp cryptobyte.String - if !der.ReadASN1(&cp, cbasn1.SEQUENCE) { + if !der.ReadASN1(&cp, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: invalid certificate policies") } var oid asn1.ObjectIdentifier @@ -697,31 +696,31 @@ func processExtensions(out *Certificate) error { // fullName [0] GeneralNames, // nameRelativeToCRLIssuer [1] RelativeDistinguishedName } val := cryptobyte.String(e.Value) - if !val.ReadASN1(&val, cbasn1.SEQUENCE) { + if !val.ReadASN1(&val, cryptobyte_asn1.SEQUENCE) { return errors.New("x509: invalid CRL distribution points") } for !val.Empty() { var dpDER cryptobyte.String - if !val.ReadASN1(&dpDER, cbasn1.SEQUENCE) { + if !val.ReadASN1(&dpDER, cryptobyte_asn1.SEQUENCE) { return errors.New("x509: invalid CRL distribution point") } var dpNameDER cryptobyte.String var dpNamePresent bool - if !dpDER.ReadOptionalASN1(&dpNameDER, &dpNamePresent, cbasn1.Tag(0).Constructed().ContextSpecific()) { + if !dpDER.ReadOptionalASN1(&dpNameDER, &dpNamePresent, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific()) { return errors.New("x509: invalid CRL distribution point") } if !dpNamePresent { continue } - if !dpNameDER.ReadASN1(&dpNameDER, cbasn1.Tag(0).Constructed().ContextSpecific()) { + if !dpNameDER.ReadASN1(&dpNameDER, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific()) { return errors.New("x509: invalid CRL distribution point") } for !dpNameDER.Empty() { - if !dpNameDER.PeekASN1Tag(cbasn1.Tag(6).ContextSpecific()) { + if !dpNameDER.PeekASN1Tag(cryptobyte_asn1.Tag(6).ContextSpecific()) { break } var uri cryptobyte.String - if !dpNameDER.ReadASN1(&uri, cbasn1.Tag(6).ContextSpecific()) { + if !dpNameDER.ReadASN1(&uri, cryptobyte_asn1.Tag(6).ContextSpecific()) { return errors.New("x509: invalid CRL distribution point") } out.CRLDistributionPoints = append(out.CRLDistributionPoints, string(uri)) @@ -732,10 +731,10 @@ func processExtensions(out *Certificate) error { // RFC 5280, 4.2.1.1 val := cryptobyte.String(e.Value) var akid cryptobyte.String - if !val.ReadASN1(&akid, cbasn1.SEQUENCE) { + if !val.ReadASN1(&akid, cryptobyte_asn1.SEQUENCE) { return errors.New("x509: invalid authority key identifier") } - if !akid.ReadASN1(&akid, cbasn1.Tag(0).ContextSpecific()) { + if !akid.ReadASN1(&akid, cryptobyte_asn1.Tag(0).ContextSpecific()) { return errors.New("x509: invalid authority key identifier") } out.AuthorityKeyId = akid @@ -748,7 +747,7 @@ func processExtensions(out *Certificate) error { // RFC 5280, 4.2.1.2 val := cryptobyte.String(e.Value) var skid cryptobyte.String - if !val.ReadASN1(&skid, cbasn1.OCTET_STRING) { + if !val.ReadASN1(&skid, cryptobyte_asn1.OCTET_STRING) { return errors.New("x509: invalid subject key identifier") } out.SubjectKeyId = skid @@ -764,22 +763,22 @@ func processExtensions(out *Certificate) error { } else if e.Id.Equal(oidExtensionAuthorityInfoAccess) { // RFC 5280 4.2.2.1: Authority Information Access val := cryptobyte.String(e.Value) - if !val.ReadASN1(&val, cbasn1.SEQUENCE) { + if !val.ReadASN1(&val, cryptobyte_asn1.SEQUENCE) { return errors.New("x509: invalid authority info access") } for !val.Empty() { var aiaDER cryptobyte.String - if !val.ReadASN1(&aiaDER, cbasn1.SEQUENCE) { + if !val.ReadASN1(&aiaDER, cryptobyte_asn1.SEQUENCE) { return errors.New("x509: invalid authority info access") } var method asn1.ObjectIdentifier if !aiaDER.ReadASN1ObjectIdentifier(&method) { return errors.New("x509: invalid authority info access") } - if !aiaDER.PeekASN1Tag(cbasn1.Tag(6).ContextSpecific()) { + if !aiaDER.PeekASN1Tag(cryptobyte_asn1.Tag(6).ContextSpecific()) { continue } - if !aiaDER.ReadASN1(&aiaDER, cbasn1.Tag(6).ContextSpecific()) { + if !aiaDER.ReadASN1(&aiaDER, cryptobyte_asn1.Tag(6).ContextSpecific()) { return errors.New("x509: invalid authority info access") } switch { @@ -809,26 +808,26 @@ func parseCertificate(der []byte) (*Certificate, error) { // we read the SEQUENCE including length and tag bytes so that // we can populate Certificate.Raw, before unwrapping the // SEQUENCE so it can be operated on - if !input.ReadASN1Element(&input, cbasn1.SEQUENCE) { + if !input.ReadASN1Element(&input, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed certificate") } cert.Raw = input - if !input.ReadASN1(&input, cbasn1.SEQUENCE) { + if !input.ReadASN1(&input, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed certificate") } var tbs cryptobyte.String // do the same trick again as above to extract the raw // bytes for Certificate.RawTBSCertificate - if !input.ReadASN1Element(&tbs, cbasn1.SEQUENCE) { + if !input.ReadASN1Element(&tbs, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed tbs certificate") } cert.RawTBSCertificate = tbs - if !tbs.ReadASN1(&tbs, cbasn1.SEQUENCE) { + if !tbs.ReadASN1(&tbs, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed tbs certificate") } - if !tbs.ReadOptionalASN1Integer(&cert.Version, cbasn1.Tag(0).Constructed().ContextSpecific(), 0) { + if !tbs.ReadOptionalASN1Integer(&cert.Version, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific(), 0) { return nil, errors.New("x509: malformed version") } if cert.Version < 0 { @@ -853,14 +852,14 @@ func parseCertificate(der []byte) (*Certificate, error) { cert.SerialNumber = serial var sigAISeq cryptobyte.String - if !tbs.ReadASN1(&sigAISeq, cbasn1.SEQUENCE) { + if !tbs.ReadASN1(&sigAISeq, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed signature algorithm identifier") } // Before parsing the inner algorithm identifier, extract // the outer algorithm identifier and make sure that they // match. var outerSigAISeq cryptobyte.String - if !input.ReadASN1(&outerSigAISeq, cbasn1.SEQUENCE) { + if !input.ReadASN1(&outerSigAISeq, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed algorithm identifier") } if !bytes.Equal(outerSigAISeq, sigAISeq) { @@ -873,7 +872,7 @@ func parseCertificate(der []byte) (*Certificate, error) { cert.SignatureAlgorithm = getSignatureAlgorithmFromAI(sigAI) var issuerSeq cryptobyte.String - if !tbs.ReadASN1Element(&issuerSeq, cbasn1.SEQUENCE) { + if !tbs.ReadASN1Element(&issuerSeq, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed issuer") } cert.RawIssuer = issuerSeq @@ -884,7 +883,7 @@ func parseCertificate(der []byte) (*Certificate, error) { cert.Issuer.FillFromRDNSequence(issuerRDNs) var validity cryptobyte.String - if !tbs.ReadASN1(&validity, cbasn1.SEQUENCE) { + if !tbs.ReadASN1(&validity, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed validity") } cert.NotBefore, cert.NotAfter, err = parseValidity(validity) @@ -893,7 +892,7 @@ func parseCertificate(der []byte) (*Certificate, error) { } var subjectSeq cryptobyte.String - if !tbs.ReadASN1Element(&subjectSeq, cbasn1.SEQUENCE) { + if !tbs.ReadASN1Element(&subjectSeq, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed issuer") } cert.RawSubject = subjectSeq @@ -904,15 +903,15 @@ func parseCertificate(der []byte) (*Certificate, error) { cert.Subject.FillFromRDNSequence(subjectRDNs) var spki cryptobyte.String - if !tbs.ReadASN1Element(&spki, cbasn1.SEQUENCE) { + if !tbs.ReadASN1Element(&spki, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed spki") } cert.RawSubjectPublicKeyInfo = spki - if !spki.ReadASN1(&spki, cbasn1.SEQUENCE) { + if !spki.ReadASN1(&spki, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed spki") } var pkAISeq cryptobyte.String - if !spki.ReadASN1(&pkAISeq, cbasn1.SEQUENCE) { + if !spki.ReadASN1(&pkAISeq, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed public key algorithm identifier") } pkAI, err := parseAI(pkAISeq) @@ -933,25 +932,25 @@ func parseCertificate(der []byte) (*Certificate, error) { } if cert.Version > 1 { - if !tbs.SkipOptionalASN1(cbasn1.Tag(1).Constructed().ContextSpecific()) { + if !tbs.SkipOptionalASN1(cryptobyte_asn1.Tag(1).Constructed().ContextSpecific()) { return nil, errors.New("x509: malformed issuerUniqueID") } - if !tbs.SkipOptionalASN1(cbasn1.Tag(2).Constructed().ContextSpecific()) { + if !tbs.SkipOptionalASN1(cryptobyte_asn1.Tag(2).Constructed().ContextSpecific()) { return nil, errors.New("x509: malformed subjectUniqueID") } if cert.Version == 3 { var extensions cryptobyte.String var present bool - if !tbs.ReadOptionalASN1(&extensions, &present, cbasn1.Tag(3).Constructed().ContextSpecific()) { + if !tbs.ReadOptionalASN1(&extensions, &present, cryptobyte_asn1.Tag(3).Constructed().ContextSpecific()) { return nil, errors.New("x509: malformed extensions") } if present { - if !extensions.ReadASN1(&extensions, cbasn1.SEQUENCE) { + if !extensions.ReadASN1(&extensions, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed extensions") } for !extensions.Empty() { var extension cryptobyte.String - if !extensions.ReadASN1(&extension, cbasn1.SEQUENCE) { + if !extensions.ReadASN1(&extension, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed extension") } ext, err := parseExtension(extension) From 6d2ef2ef2a3ed375b5c782e6c8b0f8a59c3d3c8c Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Tue, 18 May 2021 12:58:02 -0400 Subject: [PATCH 070/940] cmd/compile: don't emit inltree for closure within body of inlined func When inlining functions with closures, ensure that we don't mark the body of the closure with a src.Pos marker that reflects the inline, since this will result in the generation of an inltree table for the closure itself (as opposed to the routine that the func-with-closure was inlined into). Fixes #46234. Change-Id: I348296de6504fc4745d99adab436640f50be299a Reviewed-on: https://go-review.googlesource.com/c/go/+/320913 Reviewed-by: Cherry Mui Reviewed-by: Matthew Dempsky Run-TryBot: Cherry Mui TryBot-Result: Go Bot Trust: Than McIntosh --- src/cmd/compile/internal/inline/inl.go | 16 +++- test/closure3.dir/main.go | 8 +- test/fixedbugs/issue46234.go | 103 +++++++++++++++++++++++++ test/inline.go | 4 +- 4 files changed, 124 insertions(+), 7 deletions(-) create mode 100644 test/fixedbugs/issue46234.go diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go index a6829e9835f..d6b4ced4e15 100644 --- a/src/cmd/compile/internal/inline/inl.go +++ b/src/cmd/compile/internal/inline/inl.go @@ -1124,6 +1124,10 @@ type inlsubst struct { newclofn *ir.Func fn *ir.Func // For debug -- the func that is being inlined + + // If true, then don't update source positions during substitution + // (retain old source positions). + noPosUpdate bool } // list inlines a list of nodes. @@ -1219,7 +1223,14 @@ func (subst *inlsubst) clovar(n *ir.Name) *ir.Name { // closure node. func (subst *inlsubst) closure(n *ir.ClosureExpr) ir.Node { m := ir.Copy(n) - m.SetPos(subst.updatedPos(m.Pos())) + + // Prior to the subst edit, set a flag in the inlsubst to + // indicated that we don't want to update the source positions in + // the new closure. If we do this, it will appear that the closure + // itself has things inlined into it, which is not the case. See + // issue #46234 for more details. + defer func(prev bool) { subst.noPosUpdate = prev }(subst.noPosUpdate) + subst.noPosUpdate = true ir.EditChildren(m, subst.edit) //fmt.Printf("Inlining func %v with closure into %v\n", subst.fn, ir.FuncName(ir.CurFunc)) @@ -1445,6 +1456,9 @@ func (subst *inlsubst) node(n ir.Node) ir.Node { } func (subst *inlsubst) updatedPos(xpos src.XPos) src.XPos { + if subst.noPosUpdate { + return xpos + } pos := base.Ctxt.PosTable.Pos(xpos) oldbase := pos.Base() // can be nil newbase := subst.bases[oldbase] diff --git a/test/closure3.dir/main.go b/test/closure3.dir/main.go index 2fc33753ed7..662a2e967bb 100644 --- a/test/closure3.dir/main.go +++ b/test/closure3.dir/main.go @@ -94,10 +94,10 @@ func main() { return x + 2 } y, sink = func() (func(int) int, int) { // ERROR "can inline main.func12" - return func(x int) int { // ERROR "can inline main.func12" + return func(x int) int { // ERROR "func literal does not escape" "can inline main.func12" return x + 1 }, 42 - }() // ERROR "func literal does not escape" "inlining call to main.func12" + }() // ERROR "inlining call to main.func12" if y(40) != 41 { ppanic("y(40) != 41") } @@ -109,10 +109,10 @@ func main() { return x + 2 } y, sink = func() (func(int) int, int) { // ERROR "can inline main.func13.2" - return func(x int) int { // ERROR "can inline main.func13.2" + return func(x int) int { // ERROR "func literal does not escape" "can inline main.func13.2" return x + 1 }, 42 - }() // ERROR "inlining call to main.func13.2" "func literal does not escape" + }() // ERROR "inlining call to main.func13.2" if y(40) != 41 { ppanic("y(40) != 41") } diff --git a/test/fixedbugs/issue46234.go b/test/fixedbugs/issue46234.go new file mode 100644 index 00000000000..c669cc01a60 --- /dev/null +++ b/test/fixedbugs/issue46234.go @@ -0,0 +1,103 @@ +// buildrun -t 30 + +// +build !js + +// Copyright 2021 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. + +// Ensure that runtime traceback does not infinite loop for +// the testcase below. + +package main + +import ( + "bytes" + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" +) + +const prog = ` + +package main + +import "context" + +var gpi *int + +type nAO struct { + eE bool +} + +type NAO func(*nAO) + +func WEA() NAO { + return func(o *nAO) { o.eE = true } +} + +type R struct { + cM *CM +} + +type CM int + +type A string + +func (m *CM) NewA(ctx context.Context, cN string, nn *nAO, opts ...NAO) (*A, error) { + for _, o := range opts { + o(nn) + } + s := A("foo") + return &s, nil +} + +func (r *R) CA(ctx context.Context, cN string, nn *nAO) (*int, error) { + cA, err := r.cM.NewA(ctx, cN, nn, WEA(), WEA()) + if err == nil { + return nil, err + } + println(cA) + x := int(42) + return &x, nil +} + +func main() { + c := CM(1) + r := R{cM: &c} + var ctx context.Context + nnr := nAO{} + pi, err := r.CA(ctx, "foo", nil) + if err != nil { + panic("bad") + } + println(nnr.eE) + gpi = pi +} +` + +func main() { + dir, err := ioutil.TempDir("", "46234") + if err != nil { + log.Fatal(err) + } + defer os.RemoveAll(dir) + + file := filepath.Join(dir, "main.go") + if err := ioutil.WriteFile(file, []byte(prog), 0655); err != nil { + log.Fatalf("Write error %v", err) + } + + cmd := exec.Command("go", "run", file) + output, err := cmd.CombinedOutput() + if err == nil { + log.Fatalf("Passed, expected an error") + } + + want := []byte("segmentation violation") + if !bytes.Contains(output, want) { + log.Fatalf("Unmatched error message %q:\nin\n%s\nError: %v", want, output, err) + } +} diff --git a/test/inline.go b/test/inline.go index bc23768d016..472a941dca3 100644 --- a/test/inline.go +++ b/test/inline.go @@ -92,9 +92,9 @@ func o() int { foo := func() int { return 1 } // ERROR "can inline o.func1" "func literal does not escape" func(x int) { // ERROR "can inline o.func2" if x > 10 { - foo = func() int { return 2 } // ERROR "can inline o.func2" + foo = func() int { return 2 } // ERROR "func literal does not escape" "can inline o.func2" } - }(11) // ERROR "func literal does not escape" "inlining call to o.func2" + }(11) // ERROR "inlining call to o.func2" return foo() } From f208f1ac993b0b47ebf9bb247a4bc16bc53ad0fd Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 17 May 2021 11:40:21 -0700 Subject: [PATCH 071/940] [dev.typeparams] cmd/compile/internal/ir: more useful Fatalfs This CL just adds some additional details to existing Fatalf messages that make them more useful for identifying what went wrong. Change-Id: Icba0d943ccfb1b810a1ede0977cc8cf22b2afde5 Reviewed-on: https://go-review.googlesource.com/c/go/+/320612 Trust: Matthew Dempsky Trust: Dan Scales Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/ir/func.go | 2 +- src/cmd/compile/internal/ir/node.go | 2 +- src/cmd/compile/internal/ir/val.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cmd/compile/internal/ir/func.go b/src/cmd/compile/internal/ir/func.go index 20fe965711d..a4231a1bcb6 100644 --- a/src/cmd/compile/internal/ir/func.go +++ b/src/cmd/compile/internal/ir/func.go @@ -279,7 +279,7 @@ func FuncSymName(s *types.Sym) string { // MarkFunc marks a node as a function. func MarkFunc(n *Name) { if n.Op() != ONAME || n.Class != Pxxx { - base.Fatalf("expected ONAME/Pxxx node, got %v", n) + base.FatalfAt(n.Pos(), "expected ONAME/Pxxx node, got %v (%v/%v)", n, n.Op(), n.Class) } n.Class = PFUNC diff --git a/src/cmd/compile/internal/ir/node.go b/src/cmd/compile/internal/ir/node.go index af559cc0820..9191eeb1d6c 100644 --- a/src/cmd/compile/internal/ir/node.go +++ b/src/cmd/compile/internal/ir/node.go @@ -563,7 +563,7 @@ func OuterValue(n Node) Node { for { switch nn := n; nn.Op() { case OXDOT: - base.Fatalf("OXDOT in walk") + base.FatalfAt(n.Pos(), "OXDOT in walk: %v", n) case ODOT: nn := nn.(*SelectorExpr) n = nn.X diff --git a/src/cmd/compile/internal/ir/val.go b/src/cmd/compile/internal/ir/val.go index 03c320e205d..af9f95b29d7 100644 --- a/src/cmd/compile/internal/ir/val.go +++ b/src/cmd/compile/internal/ir/val.go @@ -66,7 +66,7 @@ func Float64Val(v constant.Value) float64 { func AssertValidTypeForConst(t *types.Type, v constant.Value) { if !ValidTypeForConst(t, v) { - base.Fatalf("%v does not represent %v", t, v) + base.Fatalf("%v does not represent %v (%v)", t, v, v.Kind()) } } From bbc0059b037c22c27fe42ed0a97d1400ebd7785d Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 17 May 2021 13:59:25 -0700 Subject: [PATCH 072/940] [dev.typeparams] test: run more tests with -G=3 This CL expands the current logic for re-running "errorcheck" tests with -G=3 to run (almost) all regress tests that way. This exposes a handful of additional failures, so the excluded-files list is expanded accordingly. (The next CL addresses several of the easy test cases.) Change-Id: Ia5ce399f225d83e817a046a3bd1a41b9681be3af Reviewed-on: https://go-review.googlesource.com/c/go/+/320609 Run-TryBot: Matthew Dempsky Trust: Matthew Dempsky Trust: Dan Scales TryBot-Result: Go Bot Reviewed-by: Dan Scales --- test/run.go | 295 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 200 insertions(+), 95 deletions(-) diff --git a/test/run.go b/test/run.go index 5e60de76248..fc4e89fc64c 100644 --- a/test/run.go +++ b/test/run.go @@ -42,6 +42,7 @@ var ( linkshared = flag.Bool("linkshared", false, "") updateErrors = flag.Bool("update_errors", false, "update error messages in test file based on compiler output") runoutputLimit = flag.Int("l", defaultRunOutputLimit(), "number of parallel runoutput tests to run") + generics = flag.String("G", "0,3", "a comma-separated list of -G compiler flags to test with") shard = flag.Int("shard", 0, "shard index to run. Only applicable if -shards is non-zero.") shards = flag.Int("shards", 0, "number of shards. If 0, all tests are run. This is used by the continuous build.") @@ -82,6 +83,15 @@ const maxTests = 5000 func main() { flag.Parse() + var glevels []int + for _, s := range strings.Split(*generics, ",") { + glevel, err := strconv.Atoi(s) + if err != nil { + log.Fatalf("invalid -G flag: %v", err) + } + glevels = append(glevels, glevel) + } + goos = getenv("GOOS", runtime.GOOS) goarch = getenv("GOARCH", runtime.GOARCH) cgoEnv, err := exec.Command(goTool(), "env", "CGO_ENABLED").Output() @@ -113,11 +123,11 @@ func main() { } if fi, err := os.Stat(arg); err == nil && fi.IsDir() { for _, baseGoFile := range goFiles(arg) { - tests = append(tests, startTest(arg, baseGoFile)) + tests = append(tests, startTests(arg, baseGoFile, glevels)...) } } else if strings.HasSuffix(arg, ".go") { dir, file := filepath.Split(arg) - tests = append(tests, startTest(dir, file)) + tests = append(tests, startTests(dir, file, glevels)...) } else { log.Fatalf("can't yet deal with non-directory and non-go file %q", arg) } @@ -125,7 +135,7 @@ func main() { } else { for _, dir := range dirs { for _, baseGoFile := range goFiles(dir) { - tests = append(tests, startTest(dir, baseGoFile)) + tests = append(tests, startTests(dir, baseGoFile, glevels)...) } } } @@ -151,7 +161,8 @@ func main() { resCount[status]++ dt := fmt.Sprintf("%.3fs", test.dt.Seconds()) if status == "FAIL" { - fmt.Printf("# go run run.go -- %s\n%s\nFAIL\t%s\t%s\n", + fmt.Printf("# go run run.go -G=%v %s\n%s\nFAIL\t%s\t%s\n", + test.glevel, path.Join(test.dir, test.gofile), errStr, test.goFileName(), dt) continue @@ -270,6 +281,7 @@ type test struct { dir, gofile string donec chan bool // closed when done dt time.Duration + glevel int // what -G level this test should use src string @@ -277,23 +289,27 @@ type test struct { err error } -// startTest -func startTest(dir, gofile string) *test { - t := &test{ - dir: dir, - gofile: gofile, - donec: make(chan bool, 1), +func startTests(dir, gofile string, glevels []int) []*test { + tests := make([]*test, len(glevels)) + for i, glevel := range glevels { + t := &test{ + dir: dir, + gofile: gofile, + glevel: glevel, + donec: make(chan bool, 1), + } + if toRun == nil { + toRun = make(chan *test, maxTests) + go runTests() + } + select { + case toRun <- t: + default: + panic("toRun buffer size (maxTests) is too small") + } + tests[i] = t } - if toRun == nil { - toRun = make(chan *test, maxTests) - go runTests() - } - select { - case toRun <- t: - default: - panic("toRun buffer size (maxTests) is too small") - } - return t + return tests } // runTests runs tests in parallel, but respecting the order they @@ -480,12 +496,16 @@ func init() { checkShouldTest() } // This must match the flags used for building the standard library, // or else the commands will rebuild any needed packages (like runtime) // over and over. -func goGcflags() string { - return "-gcflags=all=" + os.Getenv("GO_GCFLAGS") +func (t *test) goGcflags() string { + flags := os.Getenv("GO_GCFLAGS") + if t.glevel != 0 { + flags = fmt.Sprintf("%s -G=%v", flags, t.glevel) + } + return "-gcflags=all=" + flags } -func goGcflagsIsEmpty() bool { - return "" == os.Getenv("GO_GCFLAGS") +func (t *test) goGcflagsIsEmpty() bool { + return "" == os.Getenv("GO_GCFLAGS") && t.glevel == 0 } var errTimeout = errors.New("command exceeded time limit") @@ -498,6 +518,17 @@ func (t *test) run() { close(t.donec) }() + if t.glevel > 0 { + // Files excluded from generics testing. + filename := strings.Replace(t.goFileName(), "\\", "/", -1) // goFileName() uses \ on Windows + if excludedFiles[filename] { + if *verbose { + fmt.Printf("excl\t%s\n", filename) + } + return + } + } + srcBytes, err := ioutil.ReadFile(t.goFileName()) if err != nil { t.err = err @@ -616,6 +647,49 @@ func (t *test) run() { } } + type Tool int + + const ( + _ Tool = iota + AsmCheck + Build + Run + Compile + ) + + // checkFlags reports whether the current test configuration should + // be skipped because flags (which should be an arguments list for + // "go tool compile", not "go build") contains an excluded flag. + // It will also update flags as appropriate. + checkFlags := func(tool Tool) bool { + if t.glevel > 0 { + return true + } + + switch tool { + case Build, Run: + // ok; handled in goGcflags + + case Compile: + for _, flag := range flags { + for _, pattern := range excludedFlags { + if strings.Contains(flag, pattern) { + if *verbose { + fmt.Printf("excl\t%s\t%s\n", t.goFileName(), flags) + } + return true // cannot handle flag + } + } + } + flags = append(flags, fmt.Sprintf("-G=%v", t.glevel)) + + default: + return false + } + + return true + } + t.makeTempDir() if !*keep { defer os.RemoveAll(t.tempDir) @@ -692,6 +766,10 @@ func (t *test) run() { t.err = fmt.Errorf("unimplemented action %q", action) case "asmcheck": + if !checkFlags(AsmCheck) { + return + } + // Compile Go file and match the generated assembly // against a set of regexps in comments. ops := t.wantedAsmOpcodes(long) @@ -746,6 +824,10 @@ func (t *test) run() { return case "errorcheck": + if !checkFlags(Compile) { + return + } + // Compile Go file. // Fail if wantError is true and compilation was successful and vice versa. // Match errors produced by gc against errors in comments. @@ -774,72 +856,20 @@ func (t *test) run() { t.updateErrors(string(out), long) } t.err = t.errorCheck(string(out), wantAuto, long, t.gofile) - if t.err != nil { - return // don't hide error if run below succeeds - } - - // The following is temporary scaffolding to get types2 typechecker - // up and running against the existing test cases. The explicitly - // listed files don't pass yet, usually because the error messages - // are slightly different (this list is not complete). Any errorcheck - // tests that require output from analysis phases past initial type- - // checking are also excluded since these phases are not running yet. - // We can get rid of this code once types2 is fully plugged in. - - // For now we're done when we can't handle the file or some of the flags. - // The first goal is to eliminate the excluded list; the second goal is to - // eliminate the flag list. - - // Excluded files. - filename := strings.Replace(t.goFileName(), "\\", "/", -1) // goFileName() uses \ on Windows - if excluded[filename] { - if *verbose { - fmt.Printf("excl\t%s\n", filename) - } - return // cannot handle file yet - } - - // Excluded flags. - for _, flag := range flags { - for _, pattern := range []string{ - "-m", - } { - if strings.Contains(flag, pattern) { - if *verbose { - fmt.Printf("excl\t%s\t%s\n", filename, flags) - } - return // cannot handle flag - } - } - } - - // Run errorcheck again with -G option (new typechecker). - cmdline = []string{goTool(), "tool", "compile", "-G=3", "-C", "-e", "-o", "a.o"} - // No need to add -dynlink even if linkshared if we're just checking for errors... - cmdline = append(cmdline, flags...) - cmdline = append(cmdline, long) - out, err = runcmd(cmdline...) - if wantError { - if err == nil { - t.err = fmt.Errorf("compilation succeeded unexpectedly\n%s", out) - return - } - } else { - if err != nil { - t.err = err - return - } - } - if *updateErrors { - t.updateErrors(string(out), long) - } - t.err = t.errorCheck(string(out), wantAuto, long, t.gofile) case "compile": + if !checkFlags(Compile) { + return + } + // Compile Go file. _, t.err = compileFile(runcmd, long, flags) case "compiledir": + if !checkFlags(Compile) { + return + } + // Compile all files in the directory as packages in lexicographic order. longdir := filepath.Join(cwd, t.goDirName()) pkgs, err := goDirPackages(longdir, singlefilepkgs) @@ -855,6 +885,10 @@ func (t *test) run() { } case "errorcheckdir", "errorcheckandrundir": + if !checkFlags(Compile) { + return + } + flags = append(flags, "-d=panic") // Compile and errorCheck all files in the directory as packages in lexicographic order. // If errorcheckdir and wantError, compilation of the last package must fail. @@ -900,6 +934,10 @@ func (t *test) run() { fallthrough case "rundir": + if !checkFlags(Run) { + return + } + // Compile all files in the directory as packages in lexicographic order. // In case of errorcheckandrundir, ignore failed compilation of the package before the last. // Link as if the last file is the main package, run it. @@ -958,6 +996,10 @@ func (t *test) run() { } case "runindir": + if !checkFlags(Run) { + return + } + // Make a shallow copy of t.goDirName() in its own module and GOPATH, and // run "go run ." in it. The module path (and hence import path prefix) of // the copy is equal to the basename of the source directory. @@ -983,7 +1025,7 @@ func (t *test) run() { return } - cmd := []string{goTool(), "run", goGcflags()} + cmd := []string{goTool(), "run", t.goGcflags()} if *linkshared { cmd = append(cmd, "-linkshared") } @@ -997,13 +1039,21 @@ func (t *test) run() { t.checkExpectedOutput(out) case "build": + if !checkFlags(Build) { + return + } + // Build Go file. - _, err := runcmd(goTool(), "build", goGcflags(), "-o", "a.exe", long) + _, err := runcmd(goTool(), "build", t.goGcflags(), "-o", "a.exe", long) if err != nil { t.err = err } case "builddir", "buildrundir": + if !checkFlags(Build) { + return + } + // Build an executable from all the .go and .s files in a subdirectory. // Run it and verify its output in the buildrundir case. longdir := filepath.Join(cwd, t.goDirName()) @@ -1083,10 +1133,14 @@ func (t *test) run() { } case "buildrun": + if !checkFlags(Build) { + return + } + // Build an executable from Go file, then run it, verify its output. // Useful for timeout tests where failure mode is infinite loop. // TODO: not supported on NaCl - cmd := []string{goTool(), "build", goGcflags(), "-o", "a.exe"} + cmd := []string{goTool(), "build", t.goGcflags(), "-o", "a.exe"} if *linkshared { cmd = append(cmd, "-linkshared") } @@ -1108,13 +1162,17 @@ func (t *test) run() { t.checkExpectedOutput(out) case "run": + if !checkFlags(Run) { + return + } + // Run Go file if no special go command flags are provided; // otherwise build an executable and run it. // Verify the output. runInDir = "" var out []byte var err error - if len(flags)+len(args) == 0 && goGcflagsIsEmpty() && !*linkshared && goarch == runtime.GOARCH && goos == runtime.GOOS { + if len(flags)+len(args) == 0 && t.goGcflagsIsEmpty() && !*linkshared && goarch == runtime.GOARCH && goos == runtime.GOOS { // If we're not using special go command flags, // skip all the go command machinery. // This avoids any time the go command would @@ -1136,7 +1194,7 @@ func (t *test) run() { } out, err = runcmd(append([]string{exe}, args...)...) } else { - cmd := []string{goTool(), "run", goGcflags()} + cmd := []string{goTool(), "run", t.goGcflags()} if *linkshared { cmd = append(cmd, "-linkshared") } @@ -1151,6 +1209,10 @@ func (t *test) run() { t.checkExpectedOutput(out) case "runoutput": + if !checkFlags(Run) { + return + } + // Run Go file and write its output into temporary Go file. // Run generated Go file and verify its output. rungatec <- true @@ -1158,7 +1220,7 @@ func (t *test) run() { <-rungatec }() runInDir = "" - cmd := []string{goTool(), "run", goGcflags()} + cmd := []string{goTool(), "run", t.goGcflags()} if *linkshared { cmd = append(cmd, "-linkshared") } @@ -1173,7 +1235,7 @@ func (t *test) run() { t.err = fmt.Errorf("write tempfile:%s", err) return } - cmd = []string{goTool(), "run", goGcflags()} + cmd = []string{goTool(), "run", t.goGcflags()} if *linkshared { cmd = append(cmd, "-linkshared") } @@ -1186,10 +1248,14 @@ func (t *test) run() { t.checkExpectedOutput(out) case "errorcheckoutput": + if !checkFlags(Compile) { + return + } + // Run Go file and write its output into temporary Go file. // Compile and errorCheck generated Go file. runInDir = "" - cmd := []string{goTool(), "run", goGcflags()} + cmd := []string{goTool(), "run", t.goGcflags()} if *linkshared { cmd = append(cmd, "-linkshared") } @@ -1941,9 +2007,26 @@ func overlayDir(dstRoot, srcRoot string) error { }) } +// The following is temporary scaffolding to get types2 typechecker +// up and running against the existing test cases. The explicitly +// listed files don't pass yet, usually because the error messages +// are slightly different (this list is not complete). Any errorcheck +// tests that require output from analysis phases past initial type- +// checking are also excluded since these phases are not running yet. +// We can get rid of this code once types2 is fully plugged in. + +// For now we skip tests when we can't handle the file or some of the flags. +// The first goal is to eliminate the excluded list; the second goal is to +// eliminate the flag list. + +var excludedFlags = []string{ + "-G", // skip redundant testing + "-m", +} + // List of files that the compiler cannot errorcheck with the new typechecker (compiler -G option). // Temporary scaffolding until we pass all the tests at which point this map can be removed. -var excluded = map[string]bool{ +var excludedFiles = map[string]bool{ "complit1.go": true, // types2 reports extra errors "const2.go": true, // types2 not run after syntax errors "ddd1.go": true, // issue #42987 @@ -1955,51 +2038,73 @@ var excluded = map[string]bool{ "initializerr.go": true, // types2 reports extra errors "linkname2.go": true, // error reported by noder (not running for types2 errorcheck test) "notinheap.go": true, // types2 doesn't report errors about conversions that are invalid due to //go:notinheap + "printbig.go": true, // large untyped int passed to print (32-bit) "shift1.go": true, // issue #42989 + "shift2.go": true, // bad code generation; constant.Value of the wrong kind? "typecheck.go": true, // invalid function is not causing errors when called "writebarrier.go": true, // correct diagnostics, but different lines (probably irgen's fault) + "interface/private.go": true, // types2 phrases errors differently (doesn't use non-spec "private" term) + + "fixedbugs/bug114.go": true, // large untyped int passed to println (32-bit) "fixedbugs/bug176.go": true, // types2 reports all errors (pref: types2) "fixedbugs/bug195.go": true, // types2 reports slightly different (but correct) bugs - "fixedbugs/bug228.go": true, // types2 not run after syntax errors + "fixedbugs/bug228.go": true, // types2 doesn't run when there are syntax errors "fixedbugs/bug231.go": true, // types2 bug? (same error reported twice) + "fixedbugs/bug248.go": true, // types2 reports different (but ok) error message "fixedbugs/bug255.go": true, // types2 reports extra errors + "fixedbugs/bug345.go": true, // types2 reports different (but ok) error message "fixedbugs/bug351.go": true, // types2 reports extra errors "fixedbugs/bug374.go": true, // types2 reports extra errors "fixedbugs/bug385_32.go": true, // types2 doesn't produce missing error "type .* too large" (32-bit specific) "fixedbugs/bug388.go": true, // types2 not run due to syntax errors "fixedbugs/bug412.go": true, // types2 produces a follow-on error + "fixedbugs/bug420.go": true, // ICE in irgen + "fixedbugs/bug460.go": true, // types2 reports different (but probably ok) error message + "fixedbugs/issue10700.go": true, // types2 reports ok hint, but does not match regexp "fixedbugs/issue11590.go": true, // types2 doesn't report a follow-on error (pref: types2) "fixedbugs/issue11610.go": true, // types2 not run after syntax errors "fixedbugs/issue11614.go": true, // types2 reports an extra error "fixedbugs/issue13415.go": true, // declared but not used conflict "fixedbugs/issue14520.go": true, // missing import path error by types2 + "fixedbugs/issue16133.go": true, // types2 doesn't use package path for qualified identifiers when package name is ambiguous "fixedbugs/issue16428.go": true, // types2 reports two instead of one error "fixedbugs/issue17038.go": true, // types2 doesn't report a follow-on error (pref: types2) + "fixedbugs/issue17270.go": true, // ICE in irgen "fixedbugs/issue17645.go": true, // multiple errors on same line "fixedbugs/issue18331.go": true, // missing error about misuse of //go:noescape (irgen needs code from noder) "fixedbugs/issue18393.go": true, // types2 not run after syntax errors + "fixedbugs/issue18419.go": true, // types2 reports "fixedbugs/issue19012.go": true, // multiple errors on same line + "fixedbugs/issue20174.go": true, // ICE due to width not calculated (probably irgen's fault) "fixedbugs/issue20233.go": true, // types2 reports two instead of one error (pref: compiler) "fixedbugs/issue20245.go": true, // types2 reports two instead of one error (pref: compiler) "fixedbugs/issue20250.go": true, // correct diagnostics, but different lines (probably irgen's fault) "fixedbugs/issue21979.go": true, // types2 doesn't report a follow-on error (pref: types2) + "fixedbugs/issue23305.go": true, // large untyped int passed to println (32-bit) "fixedbugs/issue23732.go": true, // types2 reports different (but ok) line numbers "fixedbugs/issue25958.go": true, // types2 doesn't report a follow-on error (pref: types2) "fixedbugs/issue28079b.go": true, // types2 reports follow-on errors "fixedbugs/issue28268.go": true, // types2 reports follow-on errors + "fixedbugs/issue31053.go": true, // types2 reports "unknown field" instead of "cannot refer to unexported field" "fixedbugs/issue33460.go": true, // types2 reports alternative positions in separate error "fixedbugs/issue41575.go": true, // types2 reports alternative positions in separate error "fixedbugs/issue42058a.go": true, // types2 doesn't report "channel element type too large" "fixedbugs/issue42058b.go": true, // types2 doesn't report "channel element type too large" "fixedbugs/issue4232.go": true, // types2 reports (correct) extra errors + "fixedbugs/issue43479.go": true, // ICE in iexport due to Syms from the wrong package + "fixedbugs/issue43962.go": true, // types2 panics when importing package named "init" + "fixedbugs/issue44432.go": true, // types2 reports different (but ok) error message "fixedbugs/issue4452.go": true, // types2 reports (correct) extra errors + "fixedbugs/issue4510.go": true, // types2 reports different (but ok) line numbers + "fixedbugs/issue4909b.go": true, // types2 reports different (but ok) error message "fixedbugs/issue5609.go": true, // types2 needs a better error message "fixedbugs/issue6889.go": true, // types2 can handle this without constant overflow - "fixedbugs/issue7525.go": true, // types2 reports init cycle error on different line - ok otherwise "fixedbugs/issue7525b.go": true, // types2 reports init cycle error on different line - ok otherwise "fixedbugs/issue7525c.go": true, // types2 reports init cycle error on different line - ok otherwise "fixedbugs/issue7525d.go": true, // types2 reports init cycle error on different line - ok otherwise "fixedbugs/issue7525e.go": true, // types2 reports init cycle error on different line - ok otherwise + "fixedbugs/issue7525.go": true, // types2 reports init cycle error on different line - ok otherwise + "fixedbugs/issue9691.go": true, // "cannot assign to int(.autotmp_4)" (probably irgen's fault) } From 140cd7c1d3f1f37ae332d504897a98800a80e0e6 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 13 May 2021 18:07:57 -0400 Subject: [PATCH 073/940] [dev.typeparams] runtime: use internal/abi.FuncPCABI0 for syscall wrappers on OpenBSD Same as CL 313230, for OpenBSD. Change-Id: I56f4a8a368e1a17615a01db4e2b6c53e4ed263bd Reviewed-on: https://go-review.googlesource.com/c/go/+/320889 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Than McIntosh Reviewed-by: Michael Knyszek --- src/runtime/os_openbsd.go | 3 +- src/runtime/os_openbsd_libc.go | 3 +- src/runtime/sys_openbsd.go | 15 ++++++---- src/runtime/sys_openbsd1.go | 13 ++++---- src/runtime/sys_openbsd2.go | 53 +++++++++++++++++---------------- src/runtime/sys_openbsd3.go | 25 +++++++++------- src/runtime/sys_openbsd_amd64.s | 2 +- 7 files changed, 64 insertions(+), 50 deletions(-) diff --git a/src/runtime/os_openbsd.go b/src/runtime/os_openbsd.go index 6259b96c22b..35995e7035f 100644 --- a/src/runtime/os_openbsd.go +++ b/src/runtime/os_openbsd.go @@ -5,6 +5,7 @@ package runtime import ( + "internal/abi" "runtime/internal/atomic" "unsafe" ) @@ -192,7 +193,7 @@ func setsig(i uint32, fn uintptr) { sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART sa.sa_mask = uint32(sigset_all) if fn == funcPC(sighandler) { - fn = funcPC(sigtramp) + fn = abi.FuncPCABI0(sigtramp) } sa.sa_sigaction = fn sigaction(i, &sa, nil) diff --git a/src/runtime/os_openbsd_libc.go b/src/runtime/os_openbsd_libc.go index 0a342e55339..981e49827fb 100644 --- a/src/runtime/os_openbsd_libc.go +++ b/src/runtime/os_openbsd_libc.go @@ -8,6 +8,7 @@ package runtime import ( + "internal/abi" "unsafe" ) @@ -48,7 +49,7 @@ func newosproc(mp *m) { // setup and then calls mstart. var oset sigset sigprocmask(_SIG_SETMASK, &sigset_all, &oset) - err := pthread_create(&attr, funcPC(mstart_stub), unsafe.Pointer(mp)) + err := pthread_create(&attr, abi.FuncPCABI0(mstart_stub), unsafe.Pointer(mp)) sigprocmask(_SIG_SETMASK, &oset, nil) if err != 0 { write(2, unsafe.Pointer(&failThreadCreate[0]), int32(len(failThreadCreate))) diff --git a/src/runtime/sys_openbsd.go b/src/runtime/sys_openbsd.go index ab3149558b3..15888619b17 100644 --- a/src/runtime/sys_openbsd.go +++ b/src/runtime/sys_openbsd.go @@ -7,7 +7,10 @@ package runtime -import "unsafe" +import ( + "internal/abi" + "unsafe" +) // The *_trampoline functions convert from the Go calling convention to the C calling convention // and then call the underlying libc function. These are defined in sys_openbsd_$ARCH.s. @@ -15,35 +18,35 @@ import "unsafe" //go:nosplit //go:cgo_unsafe_args func pthread_attr_init(attr *pthreadattr) int32 { - return libcCall(unsafe.Pointer(funcPC(pthread_attr_init_trampoline)), unsafe.Pointer(&attr)) + return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_attr_init_trampoline)), unsafe.Pointer(&attr)) } func pthread_attr_init_trampoline() //go:nosplit //go:cgo_unsafe_args func pthread_attr_destroy(attr *pthreadattr) int32 { - return libcCall(unsafe.Pointer(funcPC(pthread_attr_destroy_trampoline)), unsafe.Pointer(&attr)) + return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_attr_destroy_trampoline)), unsafe.Pointer(&attr)) } func pthread_attr_destroy_trampoline() //go:nosplit //go:cgo_unsafe_args func pthread_attr_getstacksize(attr *pthreadattr, size *uintptr) int32 { - return libcCall(unsafe.Pointer(funcPC(pthread_attr_getstacksize_trampoline)), unsafe.Pointer(&attr)) + return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_attr_getstacksize_trampoline)), unsafe.Pointer(&attr)) } func pthread_attr_getstacksize_trampoline() //go:nosplit //go:cgo_unsafe_args func pthread_attr_setdetachstate(attr *pthreadattr, state int) int32 { - return libcCall(unsafe.Pointer(funcPC(pthread_attr_setdetachstate_trampoline)), unsafe.Pointer(&attr)) + return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_attr_setdetachstate_trampoline)), unsafe.Pointer(&attr)) } func pthread_attr_setdetachstate_trampoline() //go:nosplit //go:cgo_unsafe_args func pthread_create(attr *pthreadattr, start uintptr, arg unsafe.Pointer) int32 { - return libcCall(unsafe.Pointer(funcPC(pthread_create_trampoline)), unsafe.Pointer(&attr)) + return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_create_trampoline)), unsafe.Pointer(&attr)) } func pthread_create_trampoline() diff --git a/src/runtime/sys_openbsd1.go b/src/runtime/sys_openbsd1.go index cb5d35879cd..b4e9f54538e 100644 --- a/src/runtime/sys_openbsd1.go +++ b/src/runtime/sys_openbsd1.go @@ -7,31 +7,34 @@ package runtime -import "unsafe" +import ( + "internal/abi" + "unsafe" +) //go:nosplit //go:cgo_unsafe_args func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort *uint32) int32 { - return libcCall(unsafe.Pointer(funcPC(thrsleep_trampoline)), unsafe.Pointer(&ident)) + return libcCall(unsafe.Pointer(abi.FuncPCABI0(thrsleep_trampoline)), unsafe.Pointer(&ident)) } func thrsleep_trampoline() //go:nosplit //go:cgo_unsafe_args func thrwakeup(ident uintptr, n int32) int32 { - return libcCall(unsafe.Pointer(funcPC(thrwakeup_trampoline)), unsafe.Pointer(&ident)) + return libcCall(unsafe.Pointer(abi.FuncPCABI0(thrwakeup_trampoline)), unsafe.Pointer(&ident)) } func thrwakeup_trampoline() //go:nosplit func osyield() { - libcCall(unsafe.Pointer(funcPC(sched_yield_trampoline)), unsafe.Pointer(nil)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(sched_yield_trampoline)), unsafe.Pointer(nil)) } func sched_yield_trampoline() //go:nosplit func osyield_no_g() { - asmcgocall_no_g(unsafe.Pointer(funcPC(sched_yield_trampoline)), unsafe.Pointer(nil)) + asmcgocall_no_g(unsafe.Pointer(abi.FuncPCABI0(sched_yield_trampoline)), unsafe.Pointer(nil)) } //go:cgo_import_dynamic libc_thrsleep __thrsleep "libc.so" diff --git a/src/runtime/sys_openbsd2.go b/src/runtime/sys_openbsd2.go index cd1a4e879fb..190ee4716a6 100644 --- a/src/runtime/sys_openbsd2.go +++ b/src/runtime/sys_openbsd2.go @@ -7,21 +7,24 @@ package runtime -import "unsafe" +import ( + "internal/abi" + "unsafe" +) // This is exported via linkname to assembly in runtime/cgo. //go:linkname exit //go:nosplit //go:cgo_unsafe_args func exit(code int32) { - libcCall(unsafe.Pointer(funcPC(exit_trampoline)), unsafe.Pointer(&code)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(exit_trampoline)), unsafe.Pointer(&code)) } func exit_trampoline() //go:nosplit //go:cgo_unsafe_args func getthrid() (tid int32) { - libcCall(unsafe.Pointer(funcPC(getthrid_trampoline)), unsafe.Pointer(&tid)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(getthrid_trampoline)), unsafe.Pointer(&tid)) return } func getthrid_trampoline() @@ -29,14 +32,14 @@ func getthrid_trampoline() //go:nosplit //go:cgo_unsafe_args func raiseproc(sig uint32) { - libcCall(unsafe.Pointer(funcPC(raiseproc_trampoline)), unsafe.Pointer(&sig)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(raiseproc_trampoline)), unsafe.Pointer(&sig)) } func raiseproc_trampoline() //go:nosplit //go:cgo_unsafe_args func thrkill(tid int32, sig int) { - libcCall(unsafe.Pointer(funcPC(thrkill_trampoline)), unsafe.Pointer(&tid)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(thrkill_trampoline)), unsafe.Pointer(&tid)) } func thrkill_trampoline() @@ -53,7 +56,7 @@ func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) (un ret1 unsafe.Pointer ret2 int }{addr, n, prot, flags, fd, off, nil, 0} - libcCall(unsafe.Pointer(funcPC(mmap_trampoline)), unsafe.Pointer(&args)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(mmap_trampoline)), unsafe.Pointer(&args)) return args.ret1, args.ret2 } func mmap_trampoline() @@ -61,42 +64,42 @@ func mmap_trampoline() //go:nosplit //go:cgo_unsafe_args func munmap(addr unsafe.Pointer, n uintptr) { - libcCall(unsafe.Pointer(funcPC(munmap_trampoline)), unsafe.Pointer(&addr)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(munmap_trampoline)), unsafe.Pointer(&addr)) } func munmap_trampoline() //go:nosplit //go:cgo_unsafe_args func madvise(addr unsafe.Pointer, n uintptr, flags int32) { - libcCall(unsafe.Pointer(funcPC(madvise_trampoline)), unsafe.Pointer(&addr)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(madvise_trampoline)), unsafe.Pointer(&addr)) } func madvise_trampoline() //go:nosplit //go:cgo_unsafe_args func open(name *byte, mode, perm int32) (ret int32) { - return libcCall(unsafe.Pointer(funcPC(open_trampoline)), unsafe.Pointer(&name)) + return libcCall(unsafe.Pointer(abi.FuncPCABI0(open_trampoline)), unsafe.Pointer(&name)) } func open_trampoline() //go:nosplit //go:cgo_unsafe_args func closefd(fd int32) int32 { - return libcCall(unsafe.Pointer(funcPC(close_trampoline)), unsafe.Pointer(&fd)) + return libcCall(unsafe.Pointer(abi.FuncPCABI0(close_trampoline)), unsafe.Pointer(&fd)) } func close_trampoline() //go:nosplit //go:cgo_unsafe_args func read(fd int32, p unsafe.Pointer, n int32) int32 { - return libcCall(unsafe.Pointer(funcPC(read_trampoline)), unsafe.Pointer(&fd)) + return libcCall(unsafe.Pointer(abi.FuncPCABI0(read_trampoline)), unsafe.Pointer(&fd)) } func read_trampoline() //go:nosplit //go:cgo_unsafe_args func write1(fd uintptr, p unsafe.Pointer, n int32) int32 { - return libcCall(unsafe.Pointer(funcPC(write_trampoline)), unsafe.Pointer(&fd)) + return libcCall(unsafe.Pointer(abi.FuncPCABI0(write_trampoline)), unsafe.Pointer(&fd)) } func write_trampoline() @@ -110,7 +113,7 @@ func pipe2(flags int32) (r, w int32, errno int32) { p unsafe.Pointer flags int32 }{noescape(unsafe.Pointer(&p)), flags} - errno = libcCall(unsafe.Pointer(funcPC(pipe2_trampoline)), unsafe.Pointer(&args)) + errno = libcCall(unsafe.Pointer(abi.FuncPCABI0(pipe2_trampoline)), unsafe.Pointer(&args)) return p[0], p[1], errno } func pipe2_trampoline() @@ -118,34 +121,34 @@ func pipe2_trampoline() //go:nosplit //go:cgo_unsafe_args func setitimer(mode int32, new, old *itimerval) { - libcCall(unsafe.Pointer(funcPC(setitimer_trampoline)), unsafe.Pointer(&mode)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(setitimer_trampoline)), unsafe.Pointer(&mode)) } func setitimer_trampoline() //go:nosplit //go:cgo_unsafe_args func usleep(usec uint32) { - libcCall(unsafe.Pointer(funcPC(usleep_trampoline)), unsafe.Pointer(&usec)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(usleep_trampoline)), unsafe.Pointer(&usec)) } func usleep_trampoline() //go:nosplit //go:cgo_unsafe_args func usleep_no_g(usec uint32) { - asmcgocall_no_g(unsafe.Pointer(funcPC(usleep_trampoline)), unsafe.Pointer(&usec)) + asmcgocall_no_g(unsafe.Pointer(abi.FuncPCABI0(usleep_trampoline)), unsafe.Pointer(&usec)) } //go:nosplit //go:cgo_unsafe_args func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 { - return libcCall(unsafe.Pointer(funcPC(sysctl_trampoline)), unsafe.Pointer(&mib)) + return libcCall(unsafe.Pointer(abi.FuncPCABI0(sysctl_trampoline)), unsafe.Pointer(&mib)) } func sysctl_trampoline() //go:nosplit //go:cgo_unsafe_args func fcntl(fd, cmd, arg int32) int32 { - return libcCall(unsafe.Pointer(funcPC(fcntl_trampoline)), unsafe.Pointer(&fd)) + return libcCall(unsafe.Pointer(abi.FuncPCABI0(fcntl_trampoline)), unsafe.Pointer(&fd)) } func fcntl_trampoline() @@ -156,7 +159,7 @@ func nanotime1() int64 { clock_id int32 tp unsafe.Pointer }{_CLOCK_MONOTONIC, unsafe.Pointer(&ts)} - libcCall(unsafe.Pointer(funcPC(clock_gettime_trampoline)), unsafe.Pointer(&args)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(clock_gettime_trampoline)), unsafe.Pointer(&args)) return ts.tv_sec*1e9 + int64(ts.tv_nsec) } func clock_gettime_trampoline() @@ -168,42 +171,42 @@ func walltime() (int64, int32) { clock_id int32 tp unsafe.Pointer }{_CLOCK_REALTIME, unsafe.Pointer(&ts)} - libcCall(unsafe.Pointer(funcPC(clock_gettime_trampoline)), unsafe.Pointer(&args)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(clock_gettime_trampoline)), unsafe.Pointer(&args)) return ts.tv_sec, int32(ts.tv_nsec) } //go:nosplit //go:cgo_unsafe_args func kqueue() int32 { - return libcCall(unsafe.Pointer(funcPC(kqueue_trampoline)), nil) + return libcCall(unsafe.Pointer(abi.FuncPCABI0(kqueue_trampoline)), nil) } func kqueue_trampoline() //go:nosplit //go:cgo_unsafe_args func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32 { - return libcCall(unsafe.Pointer(funcPC(kevent_trampoline)), unsafe.Pointer(&kq)) + return libcCall(unsafe.Pointer(abi.FuncPCABI0(kevent_trampoline)), unsafe.Pointer(&kq)) } func kevent_trampoline() //go:nosplit //go:cgo_unsafe_args func sigaction(sig uint32, new *sigactiont, old *sigactiont) { - libcCall(unsafe.Pointer(funcPC(sigaction_trampoline)), unsafe.Pointer(&sig)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(sigaction_trampoline)), unsafe.Pointer(&sig)) } func sigaction_trampoline() //go:nosplit //go:cgo_unsafe_args func sigprocmask(how uint32, new *sigset, old *sigset) { - libcCall(unsafe.Pointer(funcPC(sigprocmask_trampoline)), unsafe.Pointer(&how)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(sigprocmask_trampoline)), unsafe.Pointer(&how)) } func sigprocmask_trampoline() //go:nosplit //go:cgo_unsafe_args func sigaltstack(new *stackt, old *stackt) { - libcCall(unsafe.Pointer(funcPC(sigaltstack_trampoline)), unsafe.Pointer(&new)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(sigaltstack_trampoline)), unsafe.Pointer(&new)) } func sigaltstack_trampoline() diff --git a/src/runtime/sys_openbsd3.go b/src/runtime/sys_openbsd3.go index 8d77a4b216e..a917ebde610 100644 --- a/src/runtime/sys_openbsd3.go +++ b/src/runtime/sys_openbsd3.go @@ -7,7 +7,10 @@ package runtime -import "unsafe" +import ( + "internal/abi" + "unsafe" +) // The X versions of syscall expect the libc call to return a 64-bit result. // Otherwise (the non-X version) expects a 32-bit result. @@ -20,7 +23,7 @@ import "unsafe" //go:cgo_unsafe_args func syscall_syscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { entersyscall() - libcCall(unsafe.Pointer(funcPC(syscall)), unsafe.Pointer(&fn)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall)), unsafe.Pointer(&fn)) exitsyscall() return } @@ -31,7 +34,7 @@ func syscall() //go:cgo_unsafe_args func syscall_syscallX(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { entersyscall() - libcCall(unsafe.Pointer(funcPC(syscallX)), unsafe.Pointer(&fn)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(syscallX)), unsafe.Pointer(&fn)) exitsyscall() return } @@ -42,7 +45,7 @@ func syscallX() //go:cgo_unsafe_args func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) { entersyscall() - libcCall(unsafe.Pointer(funcPC(syscall6)), unsafe.Pointer(&fn)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall6)), unsafe.Pointer(&fn)) exitsyscall() return } @@ -53,7 +56,7 @@ func syscall6() //go:cgo_unsafe_args func syscall_syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) { entersyscall() - libcCall(unsafe.Pointer(funcPC(syscall6X)), unsafe.Pointer(&fn)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall6X)), unsafe.Pointer(&fn)) exitsyscall() return } @@ -64,7 +67,7 @@ func syscall6X() //go:cgo_unsafe_args func syscall_syscall10(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 uintptr) (r1, r2, err uintptr) { entersyscall() - libcCall(unsafe.Pointer(funcPC(syscall10)), unsafe.Pointer(&fn)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall10)), unsafe.Pointer(&fn)) exitsyscall() return } @@ -75,7 +78,7 @@ func syscall10() //go:cgo_unsafe_args func syscall_syscall10X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 uintptr) (r1, r2, err uintptr) { entersyscall() - libcCall(unsafe.Pointer(funcPC(syscall10X)), unsafe.Pointer(&fn)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall10X)), unsafe.Pointer(&fn)) exitsyscall() return } @@ -85,7 +88,7 @@ func syscall10X() //go:nosplit //go:cgo_unsafe_args func syscall_rawSyscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { - libcCall(unsafe.Pointer(funcPC(syscall)), unsafe.Pointer(&fn)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall)), unsafe.Pointer(&fn)) return } @@ -93,7 +96,7 @@ func syscall_rawSyscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { //go:nosplit //go:cgo_unsafe_args func syscall_rawSyscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) { - libcCall(unsafe.Pointer(funcPC(syscall6)), unsafe.Pointer(&fn)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall6)), unsafe.Pointer(&fn)) return } @@ -101,7 +104,7 @@ func syscall_rawSyscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintpt //go:nosplit //go:cgo_unsafe_args func syscall_rawSyscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) { - libcCall(unsafe.Pointer(funcPC(syscall6X)), unsafe.Pointer(&fn)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall6X)), unsafe.Pointer(&fn)) return } @@ -109,6 +112,6 @@ func syscall_rawSyscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintp //go:nosplit //go:cgo_unsafe_args func syscall_rawSyscall10X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 uintptr) (r1, r2, err uintptr) { - libcCall(unsafe.Pointer(funcPC(syscall10X)), unsafe.Pointer(&fn)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall10X)), unsafe.Pointer(&fn)) return } diff --git a/src/runtime/sys_openbsd_amd64.s b/src/runtime/sys_openbsd_amd64.s index 522e98cf4f5..fc89ee6cbbd 100644 --- a/src/runtime/sys_openbsd_amd64.s +++ b/src/runtime/sys_openbsd_amd64.s @@ -58,7 +58,7 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-32 RET // Called using C ABI. -TEXT runtime·sigtramp(SB),NOSPLIT,$0 +TEXT runtime·sigtramp(SB),NOSPLIT,$0 // Transition from C ABI to Go ABI. PUSH_REGS_HOST_TO_ABI0() From f3fc8b5779314bae827b868deb916c7a8e748907 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 17 May 2021 11:40:02 -0700 Subject: [PATCH 074/940] [dev.typeparams] cmd/compile: simplify type alias handling for export Currently the exporter uses types.IsDotAlias(n.Sym()) to recognize that n is a type alias, but IsDotAlias is actually meant for recognizing aliases introduced by dot imports. Translated to go/types, the current logic amounts recognizing type aliases as if by: var n *types.TypeName typ, ok := n.Pkg().Scope().Lookup(n.Name()).Type().(*types.Named) isAlias := !ok || typ.Obj().Pkg() != n.Pkg() || typ.Obj().Name() != n.Name() But we can instead just check n.Alias() (eqv. n.IsAlias() in go/types). In addition to being much simpler, this is also actually correct for recognizing function-scoped type declarations (though we don't currently support those anyway, nor would they go through this exact code path). To avoid possible future misuse of IsDotAlias, this CL also inlines its trivial definition into its only call site. Passes toolstash -cmp, also w/ -gcflags=all=-G=3. Change-Id: I7c6283f4b58d5311aa683f8229bbf62f8bab2ff9 Reviewed-on: https://go-review.googlesource.com/c/go/+/320613 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Trust: Matthew Dempsky Trust: Dan Scales Reviewed-by: Dan Scales --- src/cmd/compile/internal/noder/decl.go | 8 +------- src/cmd/compile/internal/noder/import.go | 2 +- src/cmd/compile/internal/noder/object.go | 1 + src/cmd/compile/internal/typecheck/iexport.go | 2 +- src/cmd/compile/internal/typecheck/typecheck.go | 5 ----- src/cmd/compile/internal/types/pkg.go | 4 ---- 6 files changed, 4 insertions(+), 18 deletions(-) diff --git a/src/cmd/compile/internal/noder/decl.go b/src/cmd/compile/internal/noder/decl.go index 4ca2eb4740a..3e55437afab 100644 --- a/src/cmd/compile/internal/noder/decl.go +++ b/src/cmd/compile/internal/noder/decl.go @@ -104,13 +104,7 @@ func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) { if decl.Alias { name, _ := g.def(decl.Name) g.pragmaFlags(decl.Pragma, 0) - - // TODO(mdempsky): This matches how typecheckdef marks aliases for - // export, but this won't generalize to exporting function-scoped - // type aliases. We should maybe just use n.Alias() instead. - if ir.CurFunc == nil { - name.Sym().Def = ir.TypeNode(name.Type()) - } + assert(name.Alias()) // should be set by irgen.obj out.Append(ir.NewDecl(g.pos(decl), ir.ODCLTYPE, name)) return diff --git a/src/cmd/compile/internal/noder/import.go b/src/cmd/compile/internal/noder/import.go index 701e9001c85..c4a57806ebf 100644 --- a/src/cmd/compile/internal/noder/import.go +++ b/src/cmd/compile/internal/noder/import.go @@ -431,7 +431,7 @@ func clearImports() { s.Def = nil continue } - if types.IsDotAlias(s) { + if s.Def != nil && s.Def.Sym() != s { // throw away top-level name left over // from previous import . "x" // We'll report errors after type checking in CheckDotImports. diff --git a/src/cmd/compile/internal/noder/object.go b/src/cmd/compile/internal/noder/object.go index 82cce1ace0f..7af2fe6715e 100644 --- a/src/cmd/compile/internal/noder/object.go +++ b/src/cmd/compile/internal/noder/object.go @@ -101,6 +101,7 @@ func (g *irgen) obj(obj types2.Object) *ir.Name { case *types2.TypeName: if obj.IsAlias() { name = g.objCommon(pos, ir.OTYPE, g.sym(obj), class, g.typ(obj.Type())) + name.SetAlias(true) } else { name = ir.NewDeclNameAt(pos, ir.OTYPE, g.sym(obj)) g.objFinish(name, class, types.NewNamed(name)) diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index 64d68ef6255..3538c4d5a66 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -479,7 +479,7 @@ func (p *iexporter) doDecl(n *ir.Name) { w.constExt(n) case ir.OTYPE: - if types.IsDotAlias(n.Sym()) { + if n.Alias() { // Alias. w.tag('A') w.pos(n.Pos()) diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go index 95f7b50259f..9868c2d9a92 100644 --- a/src/cmd/compile/internal/typecheck/typecheck.go +++ b/src/cmd/compile/internal/typecheck/typecheck.go @@ -1889,11 +1889,6 @@ func typecheckdef(n *ir.Name) { n.SetDiag(true) goto ret } - // For package-level type aliases, set n.Sym.Def so we can identify - // it as a type alias during export. See also #31959. - if n.Curfn == nil { - n.Sym().Def = n.Ntype - } } break } diff --git a/src/cmd/compile/internal/types/pkg.go b/src/cmd/compile/internal/types/pkg.go index a6d2e2007b0..f63a357f0d0 100644 --- a/src/cmd/compile/internal/types/pkg.go +++ b/src/cmd/compile/internal/types/pkg.go @@ -137,7 +137,3 @@ func CleanroomDo(f func()) { f() pkgMap = saved } - -func IsDotAlias(sym *Sym) bool { - return sym.Def != nil && sym.Def.Sym() != sym -} From eeadce2d871358306f2a95b0cfbe809ea017932a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 18 May 2021 11:16:38 -0400 Subject: [PATCH 075/940] go/build/constraint: fix parsing of "// +build" (with no args) "// +build" by itself was like "// +build !" - unsatisfiable. Make it so again (right now it panics). Fixes #44487. Change-Id: Iacbc1398af6f988ef011f9f438e792eb62f8f434 Reviewed-on: https://go-review.googlesource.com/c/go/+/320829 Trust: Russ Cox Run-TryBot: Russ Cox TryBot-Result: Go Bot Reviewed-by: Jay Conrod --- src/go/build/constraint/expr.go | 3 +++ src/go/build/constraint/expr_test.go | 32 ++++++++++++++++------------ 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/go/build/constraint/expr.go b/src/go/build/constraint/expr.go index 1ef707ceacf..957eb9b5279 100644 --- a/src/go/build/constraint/expr.go +++ b/src/go/build/constraint/expr.go @@ -426,6 +426,9 @@ func parsePlusBuildExpr(text string) Expr { x = or(x, y) } } + if x == nil { + x = tag("ignore") + } return x } diff --git a/src/go/build/constraint/expr_test.go b/src/go/build/constraint/expr_test.go index 4979f8b5f28..15d189012ef 100644 --- a/src/go/build/constraint/expr_test.go +++ b/src/go/build/constraint/expr_test.go @@ -216,6 +216,7 @@ var parsePlusBuildExprTests = []struct { {"!!x", tag("ignore")}, {"!x", not(tag("x"))}, {"!", tag("ignore")}, + {"", tag("ignore")}, } func TestParsePlusBuildExpr(t *testing.T) { @@ -232,19 +233,22 @@ func TestParsePlusBuildExpr(t *testing.T) { var constraintTests = []struct { in string x Expr - err error + err string }{ - {"//+build x y", or(tag("x"), tag("y")), nil}, - {"// +build x y \n", or(tag("x"), tag("y")), nil}, - {"// +build x y \n ", nil, errNotConstraint}, - {"// +build x y \nmore", nil, errNotConstraint}, - {" //+build x y", nil, errNotConstraint}, + {"//+build !", tag("ignore"), ""}, + {"//+build", tag("ignore"), ""}, + {"//+build x y", or(tag("x"), tag("y")), ""}, + {"// +build x y \n", or(tag("x"), tag("y")), ""}, + {"// +build x y \n ", nil, "not a build constraint"}, + {"// +build x y \nmore", nil, "not a build constraint"}, + {" //+build x y", nil, "not a build constraint"}, - {"//go:build x && y", and(tag("x"), tag("y")), nil}, - {"//go:build x && y\n", and(tag("x"), tag("y")), nil}, - {"//go:build x && y\n ", nil, errNotConstraint}, - {"//go:build x && y\nmore", nil, errNotConstraint}, - {" //go:build x && y", nil, errNotConstraint}, + {"//go:build x && y", and(tag("x"), tag("y")), ""}, + {"//go:build x && y\n", and(tag("x"), tag("y")), ""}, + {"//go:build x && y\n ", nil, "not a build constraint"}, + {"//go:build x && y\nmore", nil, "not a build constraint"}, + {" //go:build x && y", nil, "not a build constraint"}, + {"//go:build\n", nil, "unexpected end of expression"}, } func TestParse(t *testing.T) { @@ -252,14 +256,14 @@ func TestParse(t *testing.T) { t.Run(fmt.Sprint(i), func(t *testing.T) { x, err := Parse(tt.in) if err != nil { - if tt.err == nil { + if tt.err == "" { t.Errorf("Constraint(%q): unexpected error: %v", tt.in, err) - } else if tt.err != err { + } else if !strings.Contains(err.Error(), tt.err) { t.Errorf("Constraint(%q): error %v, want %v", tt.in, err, tt.err) } return } - if tt.err != nil { + if tt.err != "" { t.Errorf("Constraint(%q) = %v, want error %v", tt.in, x, tt.err) return } From 15a374d5c1336e9cc2f8b615477d5917e9477440 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 18 May 2021 18:25:44 -0400 Subject: [PATCH 076/940] test: check portable error message on issue46234.go issue46234.go expects an error output "segmentation violation", which is UNIX-specific. Check for "nil pointer dereference" instead, which is emitted by the Go runtime and should work on all platforms. Should fix Windows builders. Change-Id: I3f5a66a687d43cae5eaf6a9e942b877e5a248900 Reviewed-on: https://go-review.googlesource.com/c/go/+/321072 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- test/fixedbugs/issue46234.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fixedbugs/issue46234.go b/test/fixedbugs/issue46234.go index c669cc01a60..8e7eb8bf8d2 100644 --- a/test/fixedbugs/issue46234.go +++ b/test/fixedbugs/issue46234.go @@ -96,7 +96,7 @@ func main() { log.Fatalf("Passed, expected an error") } - want := []byte("segmentation violation") + want := []byte("nil pointer dereference") if !bytes.Contains(output, want) { log.Fatalf("Unmatched error message %q:\nin\n%s\nError: %v", want, output, err) } From 81b22480cfd66dc5d95f8cadfadc4ac2c16074e6 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 18 May 2021 17:37:54 -0700 Subject: [PATCH 077/940] [dev.typeparams] cmd/compile/internal/syntax: accept embedded type literals The parser accepted embedded elements but the first term of an element had to be a ~-term or a type name. This CL fixes that. Change-Id: I013b6cdc5963fb228867ca6597f9139db2be7ec5 Reviewed-on: https://go-review.googlesource.com/c/go/+/321109 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/syntax/parser.go | 12 +++++ .../internal/syntax/testdata/interface.go2 | 46 ++++++++++++++++++- 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go index e7b8840b337..0e711a0113f 100644 --- a/src/cmd/compile/internal/syntax/parser.go +++ b/src/cmd/compile/internal/syntax/parser.go @@ -1443,6 +1443,18 @@ func (p *parser) interfaceType() *InterfaceType { } return false } + + default: + if p.mode&AllowGenerics != 0 { + pos := p.pos() + if t := p.typeOrNil(); t != nil { + f := new(Field) + f.pos = pos + f.Type = t + typ.MethodList = append(typ.MethodList, p.embeddedElem(f)) + return false + } + } } if p.mode&AllowGenerics != 0 { diff --git a/src/cmd/compile/internal/syntax/testdata/interface.go2 b/src/cmd/compile/internal/syntax/testdata/interface.go2 index a817327a43f..b399d751488 100644 --- a/src/cmd/compile/internal/syntax/testdata/interface.go2 +++ b/src/cmd/compile/internal/syntax/testdata/interface.go2 @@ -25,7 +25,6 @@ type _ interface { ~int | ~string } - type _ interface { m() ~int @@ -34,3 +33,48 @@ type _ interface { ~int | ~string type bool, int, float64 } + +type _ interface { + int + []byte + [10]int + struct{} + *int + func() + interface{} + map[string]int + chan T + chan<- T + <-chan T + T[int] +} + +type _ interface { + int | string + []byte | string + [10]int | string + struct{} | string + *int | string + func() | string + interface{} | string + map[string]int | string + chan T | string + chan<- T | string + <-chan T | string + T[int] | string +} + +type _ interface { + ~int | string + ~[]byte | string + ~[10]int | string + ~struct{} | string + ~*int | string + ~func() | string + ~interface{} | string + ~map[string]int | string + ~chan T | string + ~chan<- T | string + ~<-chan T | string + ~T[int] | string +} From c81562d99f8945a38da9a302731e6ac08f72825f Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 17 May 2021 11:41:20 -0700 Subject: [PATCH 078/940] [dev.typeparams] test: update regress tests for types2 Followup to previous commit that extended test/run.go to run more tests with -G=3. This CL updates a handful of easy test cases for types2 compatibility. Change-Id: I58a6f9ce6f9172d61dc25411536ee489ccb03ae0 Reviewed-on: https://go-review.googlesource.com/c/go/+/320610 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Trust: Matthew Dempsky Trust: Dan Scales Reviewed-by: Dan Scales Reviewed-by: Robert Griesemer --- test/fixedbugs/bug248.dir/bug2.go | 4 ++-- test/fixedbugs/bug345.dir/main.go | 4 ++-- test/fixedbugs/bug460.dir/b.go | 10 +++++----- test/fixedbugs/issue44432.go | 4 ++-- test/fixedbugs/issue4909b.go | 2 +- test/run.go | 5 ----- 6 files changed, 12 insertions(+), 17 deletions(-) diff --git a/test/fixedbugs/bug248.dir/bug2.go b/test/fixedbugs/bug248.dir/bug2.go index c0fdecfdb7b..92a7974679e 100644 --- a/test/fixedbugs/bug248.dir/bug2.go +++ b/test/fixedbugs/bug248.dir/bug2.go @@ -50,8 +50,8 @@ var p0i2 p1.I = t0(0) // ERROR "does not implement|incompatible" func foobar() { // check that cannot assign one to the other, // but can convert. - v0 = v1 // ERROR "assign" - v1 = v0 // ERROR "assign" + v0 = v1 // ERROR "assign|cannot use" + v1 = v0 // ERROR "assign|cannot use" v0 = p0.T(v1) v1 = p1.T(v0) diff --git a/test/fixedbugs/bug345.dir/main.go b/test/fixedbugs/bug345.dir/main.go index b77a2fad5fb..a53d3e8586e 100644 --- a/test/fixedbugs/bug345.dir/main.go +++ b/test/fixedbugs/bug345.dir/main.go @@ -23,7 +23,7 @@ func main() { // main.go:27: cannot use &x (type *"io".SectionReader) as type *"/Users/rsc/g/go/test/fixedbugs/bug345.dir/io".SectionReader in function argument var w io.Writer - bufio.NewWriter(w) // ERROR "[\w.]+[^.]/io|has incompatible type" + bufio.NewWriter(w) // ERROR "[\w.]+[^.]/io|has incompatible type|cannot use" var x goio.SectionReader - io.SR(&x) // ERROR "[\w.]+[^.]/io|has incompatible type" + io.SR(&x) // ERROR "[\w.]+[^.]/io|has incompatible type|cannot use" } diff --git a/test/fixedbugs/bug460.dir/b.go b/test/fixedbugs/bug460.dir/b.go index ef646946cf1..5d388fc413f 100644 --- a/test/fixedbugs/bug460.dir/b.go +++ b/test/fixedbugs/bug460.dir/b.go @@ -9,9 +9,9 @@ import "./a" var x a.Foo func main() { - x.int = 20 // ERROR "unexported field" - x.int8 = 20 // ERROR "unexported field" - x.error = nil // ERROR "unexported field" - x.rune = 'a' // ERROR "unexported field" - x.byte = 20 // ERROR "unexported field" + x.int = 20 // ERROR "unexported field|undefined" + x.int8 = 20 // ERROR "unexported field|undefined" + x.error = nil // ERROR "unexported field|undefined" + x.rune = 'a' // ERROR "unexported field|undefined" + x.byte = 20 // ERROR "unexported field|undefined" } diff --git a/test/fixedbugs/issue44432.go b/test/fixedbugs/issue44432.go index c5fb67e0d78..eec53f30008 100644 --- a/test/fixedbugs/issue44432.go +++ b/test/fixedbugs/issue44432.go @@ -8,6 +8,6 @@ package p var m = map[string]int{ "a": 1, - 1: 1, // ERROR "cannot use 1.*as type string in map key" - 2: 2, // ERROR "cannot use 2.*as type string in map key" + 1: 1, // ERROR "cannot use 1.*as.*string.*in map" + 2: 2, // ERROR "cannot use 2.*as.*string.*in map" } diff --git a/test/fixedbugs/issue4909b.go b/test/fixedbugs/issue4909b.go index 0f594e3db67..7d7922701a2 100644 --- a/test/fixedbugs/issue4909b.go +++ b/test/fixedbugs/issue4909b.go @@ -73,7 +73,7 @@ func writeDot(ns ...int) { } fmt.Print(")") if isIndirect { - fmt.Print(` // ERROR "indirection"`) + fmt.Print(` // ERROR "indirection|embedded via a pointer"`) } fmt.Print("\n") } diff --git a/test/run.go b/test/run.go index fc4e89fc64c..d64affb772b 100644 --- a/test/run.go +++ b/test/run.go @@ -2051,16 +2051,13 @@ var excludedFiles = map[string]bool{ "fixedbugs/bug195.go": true, // types2 reports slightly different (but correct) bugs "fixedbugs/bug228.go": true, // types2 doesn't run when there are syntax errors "fixedbugs/bug231.go": true, // types2 bug? (same error reported twice) - "fixedbugs/bug248.go": true, // types2 reports different (but ok) error message "fixedbugs/bug255.go": true, // types2 reports extra errors - "fixedbugs/bug345.go": true, // types2 reports different (but ok) error message "fixedbugs/bug351.go": true, // types2 reports extra errors "fixedbugs/bug374.go": true, // types2 reports extra errors "fixedbugs/bug385_32.go": true, // types2 doesn't produce missing error "type .* too large" (32-bit specific) "fixedbugs/bug388.go": true, // types2 not run due to syntax errors "fixedbugs/bug412.go": true, // types2 produces a follow-on error "fixedbugs/bug420.go": true, // ICE in irgen - "fixedbugs/bug460.go": true, // types2 reports different (but probably ok) error message "fixedbugs/issue10700.go": true, // types2 reports ok hint, but does not match regexp "fixedbugs/issue11590.go": true, // types2 doesn't report a follow-on error (pref: types2) @@ -2095,10 +2092,8 @@ var excludedFiles = map[string]bool{ "fixedbugs/issue4232.go": true, // types2 reports (correct) extra errors "fixedbugs/issue43479.go": true, // ICE in iexport due to Syms from the wrong package "fixedbugs/issue43962.go": true, // types2 panics when importing package named "init" - "fixedbugs/issue44432.go": true, // types2 reports different (but ok) error message "fixedbugs/issue4452.go": true, // types2 reports (correct) extra errors "fixedbugs/issue4510.go": true, // types2 reports different (but ok) line numbers - "fixedbugs/issue4909b.go": true, // types2 reports different (but ok) error message "fixedbugs/issue5609.go": true, // types2 needs a better error message "fixedbugs/issue6889.go": true, // types2 can handle this without constant overflow "fixedbugs/issue7525b.go": true, // types2 reports init cycle error on different line - ok otherwise From fc9e64cc98edda355471f0390da4d1d1de4100a0 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 17 May 2021 10:50:41 -0700 Subject: [PATCH 079/940] [dev.typeparams] cmd/compile/internal/types2: fix types2 panic When reporting a "cannot import package as init" error, we can't rely on s.LocalPkgName being non-nil, as the original package's name may already be nil. Change-Id: Idec006780f12ee4398501d05a5b2ed13157f88ea Reviewed-on: https://go-review.googlesource.com/c/go/+/320490 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types2/resolver.go | 2 +- test/run.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/types2/resolver.go b/src/cmd/compile/internal/types2/resolver.go index fa30650bd44..ef49a8b48da 100644 --- a/src/cmd/compile/internal/types2/resolver.go +++ b/src/cmd/compile/internal/types2/resolver.go @@ -265,7 +265,7 @@ func (check *Checker) collectObjects() { } if name == "init" { - check.error(s.LocalPkgName, "cannot import package as init - init must be a func") + check.error(s, "cannot import package as init - init must be a func") continue } diff --git a/test/run.go b/test/run.go index d64affb772b..506380a7a5a 100644 --- a/test/run.go +++ b/test/run.go @@ -2091,7 +2091,6 @@ var excludedFiles = map[string]bool{ "fixedbugs/issue42058b.go": true, // types2 doesn't report "channel element type too large" "fixedbugs/issue4232.go": true, // types2 reports (correct) extra errors "fixedbugs/issue43479.go": true, // ICE in iexport due to Syms from the wrong package - "fixedbugs/issue43962.go": true, // types2 panics when importing package named "init" "fixedbugs/issue4452.go": true, // types2 reports (correct) extra errors "fixedbugs/issue4510.go": true, // types2 reports different (but ok) line numbers "fixedbugs/issue5609.go": true, // types2 needs a better error message From 90b6e7260553a742522830ddd38f5854657f2985 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 17 May 2021 14:25:49 -0700 Subject: [PATCH 080/940] [dev.typeparams] cmd/compile/internal/types2: tweak anonymous parameter position When declaring anonymous parameters, use the syntax.Field's Pos directly rather than its Type field's Pos. When the type expression is a qualified identifier (i.e., SelectorExpr), its Pos returns the position of the dot, whereas we typically declare the anonymous parameter at the starting position of the type. (We could equivalently use syntax.StartPos(field.Type), but we already have this as field.Pos().) Change-Id: If6ac9635b6e9c2b75a1989d5893a78e0b21cba88 Reviewed-on: https://go-review.googlesource.com/c/go/+/320611 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types2/typexpr.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index e64d804c30b..a1663d2aa0c 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -778,7 +778,7 @@ func (check *Checker) collectParams(scope *Scope, list []*syntax.Field, type0 sy named = true } else { // anonymous parameter - par := NewParam(ftype.Pos(), check.pkg, "", typ) + par := NewParam(field.Pos(), check.pkg, "", typ) check.recordImplicit(field, par) params = append(params, par) anonymous = true From c92ae885d98d331ec489f6e705f2c5371e5f0e42 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 17 May 2021 10:47:04 -0700 Subject: [PATCH 081/940] [dev.typeparams] cmd/compile/internal/types2: better recv Var for method expressions When synthesizing the Signature to represent a method expression, keep as much of the original parameter as possible, substituting only the receiver type. Fixes #46209. Change-Id: Ic4531820ae7d203bb0ba25a985f72d219b4aa25f Reviewed-on: https://go-review.googlesource.com/c/go/+/320489 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types2/call.go | 10 ++++++++-- .../compile/internal/types2/testdata/check/decls0.src | 8 ++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index 6d149340b28..f0f769ec705 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -576,17 +576,23 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) { check.recordSelection(e, MethodExpr, x.typ, m, index, indirect) + sig := m.typ.(*Signature) + if sig.recv == nil { + check.error(e, "illegal cycle in method declaration") + goto Error + } + // the receiver type becomes the type of the first function // argument of the method expression's function type var params []*Var - sig := m.typ.(*Signature) if sig.params != nil { params = sig.params.vars } + params = append([]*Var{NewVar(sig.recv.pos, sig.recv.pkg, sig.recv.name, x.typ)}, params...) x.mode = value x.typ = &Signature{ tparams: sig.tparams, - params: NewTuple(append([]*Var{NewVar(nopos, check.pkg, "_", x.typ)}, params...)...), + params: NewTuple(params...), results: sig.results, variadic: sig.variadic, } diff --git a/src/cmd/compile/internal/types2/testdata/check/decls0.src b/src/cmd/compile/internal/types2/testdata/check/decls0.src index e78d8867e09..80bf4ebb3db 100644 --- a/src/cmd/compile/internal/types2/testdata/check/decls0.src +++ b/src/cmd/compile/internal/types2/testdata/check/decls0.src @@ -185,10 +185,10 @@ func f2(x *f2 /* ERROR "not a type" */ ) {} func f3() (x f3 /* ERROR "not a type" */ ) { return } func f4() (x *f4 /* ERROR "not a type" */ ) { return } -func (S0) m1(x S0 /* ERROR value .* is not a type */ .m1) {} -func (S0) m2(x *S0 /* ERROR value .* is not a type */ .m2) {} -func (S0) m3() (x S0 /* ERROR value .* is not a type */ .m3) { return } -func (S0) m4() (x *S0 /* ERROR value .* is not a type */ .m4) { return } +func (S0) m1(x S0 /* ERROR illegal cycle in method declaration */ .m1) {} +func (S0) m2(x *S0 /* ERROR illegal cycle in method declaration */ .m2) {} +func (S0) m3() (x S0 /* ERROR illegal cycle in method declaration */ .m3) { return } +func (S0) m4() (x *S0 /* ERROR illegal cycle in method declaration */ .m4) { return } // interfaces may not have any blank methods type BlankI interface { From fb79f6955e8d13fd6c98f6bd036819d7cc6dfad6 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 17 May 2021 15:30:00 -0700 Subject: [PATCH 082/940] [dev.typeparams] cmd/compile/internal/importer: implement position reading This CL finishes importReader.pos's stub implementation to actually return syntax.Pos. New PosBase handling is analogous to typecheck/iimport.go, except for using syntax.PosBase instead of src.PosBase. Change-Id: I7629f9f5e69a38ffc2eec772504d6fb2169e1f12 Reviewed-on: https://go-review.googlesource.com/c/go/+/320614 Trust: Matthew Dempsky Trust: Dan Scales Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Dan Scales Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/importer/iimport.go | 52 ++++++++++++-------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/src/cmd/compile/internal/importer/iimport.go b/src/cmd/compile/internal/importer/iimport.go index 8ab0b7b9896..5c02f837ef4 100644 --- a/src/cmd/compile/internal/importer/iimport.go +++ b/src/cmd/compile/internal/importer/iimport.go @@ -99,9 +99,10 @@ func iImportData(imports map[string]*types2.Package, data []byte, path string) ( ipath: path, version: int(version), - stringData: stringData, - stringCache: make(map[uint64]string), - pkgCache: make(map[uint64]*types2.Package), + stringData: stringData, + stringCache: make(map[uint64]string), + pkgCache: make(map[uint64]*types2.Package), + posBaseCache: make(map[uint64]*syntax.PosBase), declData: declData, pkgIndex: make(map[*types2.Package]map[string]uint64), @@ -173,9 +174,10 @@ type iimporter struct { ipath string version int - stringData []byte - stringCache map[uint64]string - pkgCache map[uint64]*types2.Package + stringData []byte + stringCache map[uint64]string + pkgCache map[uint64]*types2.Package + posBaseCache map[uint64]*syntax.PosBase declData []byte pkgIndex map[*types2.Package]map[string]uint64 @@ -228,6 +230,16 @@ func (p *iimporter) pkgAt(off uint64) *types2.Package { return nil } +func (p *iimporter) posBaseAt(off uint64) *syntax.PosBase { + if posBase, ok := p.posBaseCache[off]; ok { + return posBase + } + filename := p.stringAt(off) + posBase := syntax.NewFileBase(filename) + p.posBaseCache[off] = posBase + return posBase +} + func (p *iimporter) typAt(off uint64, base *types2.Named) types2.Type { if t, ok := p.typCache[off]; ok && (base == nil || !isInterface(t)) { return t @@ -251,12 +263,12 @@ func (p *iimporter) typAt(off uint64, base *types2.Named) types2.Type { } type importReader struct { - p *iimporter - declReader bytes.Reader - currPkg *types2.Package - prevFile string - prevLine int64 - prevColumn int64 + p *iimporter + declReader bytes.Reader + currPkg *types2.Package + prevPosBase *syntax.PosBase + prevLine int64 + prevColumn int64 } func (r *importReader) obj(name string) { @@ -439,12 +451,11 @@ func (r *importReader) pos() syntax.Pos { r.posv0() } - if r.prevFile == "" && r.prevLine == 0 && r.prevColumn == 0 { + if (r.prevPosBase == nil || r.prevPosBase.Filename() == "") && r.prevLine == 0 && r.prevColumn == 0 { return syntax.Pos{} } - // TODO(gri) fix this - // return r.p.fake.pos(r.prevFile, int(r.prevLine), int(r.prevColumn)) - return syntax.Pos{} + + return syntax.MakePos(r.prevPosBase, uint(r.prevLine), uint(r.prevColumn)) } func (r *importReader) posv0() { @@ -454,7 +465,7 @@ func (r *importReader) posv0() { } else if l := r.int64(); l == -1 { r.prevLine += deltaNewFile } else { - r.prevFile = r.string() + r.prevPosBase = r.posBase() r.prevLine = l } } @@ -466,7 +477,7 @@ func (r *importReader) posv1() { delta = r.int64() r.prevLine += delta >> 1 if delta&1 != 0 { - r.prevFile = r.string() + r.prevPosBase = r.posBase() } } } @@ -480,8 +491,9 @@ func isInterface(t types2.Type) bool { return ok } -func (r *importReader) pkg() *types2.Package { return r.p.pkgAt(r.uint64()) } -func (r *importReader) string() string { return r.p.stringAt(r.uint64()) } +func (r *importReader) pkg() *types2.Package { return r.p.pkgAt(r.uint64()) } +func (r *importReader) string() string { return r.p.stringAt(r.uint64()) } +func (r *importReader) posBase() *syntax.PosBase { return r.p.posBaseAt(r.uint64()) } func (r *importReader) doType(base *types2.Named) types2.Type { switch k := r.kind(); k { From c2966ae272b7ddd44ee6f93beb32da925e8336df Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 18 May 2021 16:34:44 -0700 Subject: [PATCH 083/940] [dev.typeparams] cmd/compile/internal/ir: more position details in dump When dumping node positions, include column position and the full inlining tree. These details are helpful for diagnosing "toolstash -cmp" failures due to subtly changing positions. Change-Id: I953292d6c01899fd98e2f315bafaa123c4d98ffd Reviewed-on: https://go-review.googlesource.com/c/go/+/321089 Trust: Matthew Dempsky Trust: Dan Scales Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/ir/fmt.go | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/cmd/compile/internal/ir/fmt.go b/src/cmd/compile/internal/ir/fmt.go index f2ae0f7606e..4ac5f3fea29 100644 --- a/src/cmd/compile/internal/ir/fmt.go +++ b/src/cmd/compile/internal/ir/fmt.go @@ -1114,16 +1114,21 @@ func dumpNodeHeader(w io.Writer, n Node) { } if n.Pos().IsKnown() { - pfx := "" + fmt.Fprint(w, " # ") switch n.Pos().IsStmt() { case src.PosNotStmt: - pfx = "_" // "-" would be confusing + fmt.Fprint(w, "_") // "-" would be confusing case src.PosIsStmt: - pfx = "+" + fmt.Fprint(w, "+") + } + for i, pos := range base.Ctxt.AllPos(n.Pos(), nil) { + if i > 0 { + fmt.Fprint(w, ",") + } + // TODO(mdempsky): Print line pragma details too. + file := filepath.Base(pos.Filename()) + fmt.Fprintf(w, "%s:%d:%d", file, pos.Line(), pos.Col()) } - pos := base.Ctxt.PosTable.Pos(n.Pos()) - file := filepath.Base(pos.Filename()) - fmt.Fprintf(w, " # %s%s:%d", pfx, file, pos.Line()) } } From 658b5e66ecbc41a49e6fb5aa63c5d9c804cf305f Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Tue, 18 May 2021 12:23:56 -0400 Subject: [PATCH 084/940] net: return nil UDPAddr from ReadFromUDP In cases where the socket operation has no underlying address, golang.org/cl/291509 unintentionally changed ReadFromUDP from return a nil *UDPAddr to a non-nil (but zero value) *UDPAddr. This may break callers that assume "no address" is always addr == nil, so change it back to remain nil. Fixes #46238 Change-Id: I8531e8fa16b853ed7560088eabda0b9e3e53f5be Reviewed-on: https://go-review.googlesource.com/c/go/+/320909 Trust: Michael Pratt Trust: Josh Bleecher Snyder Reviewed-by: Filippo Valsorda Reviewed-by: Josh Bleecher Snyder --- src/net/udpsock_posix.go | 3 +++ src/net/udpsock_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/net/udpsock_posix.go b/src/net/udpsock_posix.go index fcfb9c004cd..96fb373ce77 100644 --- a/src/net/udpsock_posix.go +++ b/src/net/udpsock_posix.go @@ -50,6 +50,9 @@ func (c *UDPConn) readFrom(b []byte, addr *UDPAddr) (int, *UDPAddr, error) { *addr = UDPAddr{IP: sa.Addr[0:], Port: sa.Port} case *syscall.SockaddrInet6: *addr = UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneCache.name(int(sa.ZoneId))} + default: + // No sockaddr, so don't return UDPAddr. + addr = nil } return n, addr, err } diff --git a/src/net/udpsock_test.go b/src/net/udpsock_test.go index b4000b5664d..0e8c3511c36 100644 --- a/src/net/udpsock_test.go +++ b/src/net/udpsock_test.go @@ -8,7 +8,9 @@ package net import ( + "errors" "internal/testenv" + "os" "reflect" "runtime" "testing" @@ -446,6 +448,33 @@ func TestUDPReadSizeError(t *testing.T) { } } +// TestUDPReadTimeout verifies that ReadFromUDP with timeout returns an error +// without data or an address. +func TestUDPReadTimeout(t *testing.T) { + la, err := ResolveUDPAddr("udp4", "127.0.0.1:0") + if err != nil { + t.Fatal(err) + } + c, err := ListenUDP("udp4", la) + if err != nil { + t.Fatal(err) + } + defer c.Close() + + c.SetDeadline(time.Now()) + b := make([]byte, 1) + n, addr, err := c.ReadFromUDP(b) + if !errors.Is(err, os.ErrDeadlineExceeded) { + t.Errorf("ReadFromUDP got err %v want os.ErrDeadlineExceeded", err) + } + if n != 0 { + t.Errorf("ReadFromUDP got n %d want 0", n) + } + if addr != nil { + t.Errorf("ReadFromUDP got addr %+#v want nil", addr) + } +} + func BenchmarkWriteToReadFromUDP(b *testing.B) { conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)}) if err != nil { From 6c1c055d1ea417d050503efe92c1eead0da68cef Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Tue, 18 May 2021 23:29:14 -0400 Subject: [PATCH 085/940] cmd/internal/moddeps: use filepath.SkipDir only on directories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a filepath.WalkFunc returns filepath.SkipDir when invoked on a non-directory file, it skips the remaining files in the containing directory.¹ CL 276272 accidentally added a code path that triggers this behavior whenever filepath.Walk reaches a non-directory file that begins with a dot, such as .gitattributes or .DS_Store, causing findGorootModules to return early without finding any modules in GOROOT. Tests that use it ceased to provide test coverage that the tree is tidy. Add an explicit check for info.IsDir in the 5 places that intend to use filepath.SkipDir to skip traversing that directory. Even paths like GOROOT/bin and GOROOT/pkg which are unlikely to be anything but a directory are worth checking, since the goal of moddeps is to take a possibly problematic GOROOT tree as input and detect problems. While the goal of findGorootModules is to find all modules in GOROOT programmatically (in case new modules are added or modified), there are 4 modules now that are quite likely to exist, so check for their presence to avoid similar regressions. (It's not hard to update this test if a well-known GOROOT module is removed or otherwise modified; but if it becomes hard we can simplify it to check for a reasonable number of modules instead.) Also fix the minor skew that has crept in since the test got disabled. ¹ This wasn't necessarily an intentional design decision, but it was found only when Go 1.4 was already out. See CL 11690 for details. Fixes #46254. Change-Id: Id55ed926f8c0094b1af923070de72bacca05996f Reviewed-on: https://go-review.googlesource.com/c/go/+/320991 Trust: Dmitri Shuralyov Run-TryBot: Dmitri Shuralyov TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills Reviewed-by: Filippo Valsorda --- src/cmd/internal/moddeps/moddeps_test.go | 36 ++++-- src/go.mod | 2 +- src/go.sum | 4 +- src/net/http/h2_bundle.go | 133 ++++++++++++++++----- src/net/http/socks_bundle.go | 2 +- src/vendor/golang.org/x/sys/cpu/cpu.go | 5 +- src/vendor/golang.org/x/sys/cpu/cpu_aix.go | 1 + src/vendor/modules.txt | 2 +- 8 files changed, 137 insertions(+), 48 deletions(-) diff --git a/src/cmd/internal/moddeps/moddeps_test.go b/src/cmd/internal/moddeps/moddeps_test.go index ba574f40049..7723250468e 100644 --- a/src/cmd/internal/moddeps/moddeps_test.go +++ b/src/cmd/internal/moddeps/moddeps_test.go @@ -227,7 +227,7 @@ func makeGOROOTCopy(t *testing.T) string { if err != nil { return err } - if src == filepath.Join(runtime.GOROOT(), ".git") { + if info.IsDir() && src == filepath.Join(runtime.GOROOT(), ".git") { return filepath.SkipDir } @@ -237,9 +237,8 @@ func makeGOROOTCopy(t *testing.T) string { } dst := filepath.Join(gorootCopyDir, rel) - switch src { - case filepath.Join(runtime.GOROOT(), "bin"), - filepath.Join(runtime.GOROOT(), "pkg"): + if info.IsDir() && (src == filepath.Join(runtime.GOROOT(), "bin") || + src == filepath.Join(runtime.GOROOT(), "pkg")) { // If the OS supports symlinks, use them instead // of copying the bin and pkg directories. if err := os.Symlink(src, dst); err == nil { @@ -414,7 +413,7 @@ func findGorootModules(t *testing.T) []gorootModule { if info.IsDir() && (info.Name() == "vendor" || info.Name() == "testdata") { return filepath.SkipDir } - if path == filepath.Join(runtime.GOROOT(), "pkg") { + if info.IsDir() && path == filepath.Join(runtime.GOROOT(), "pkg") { // GOROOT/pkg contains generated artifacts, not source code. // // In https://golang.org/issue/37929 it was observed to somehow contain @@ -422,7 +421,7 @@ func findGorootModules(t *testing.T) []gorootModule { // running time of this test anyway.) return filepath.SkipDir } - if strings.HasPrefix(info.Name(), "_") || strings.HasPrefix(info.Name(), ".") { + if info.IsDir() && (strings.HasPrefix(info.Name(), "_") || strings.HasPrefix(info.Name(), ".")) { // _ and . prefixed directories can be used for internal modules // without a vendor directory that don't contribute to the build // but might be used for example as code generators. @@ -457,8 +456,31 @@ func findGorootModules(t *testing.T) []gorootModule { goroot.modules = append(goroot.modules, m) return nil }) - }) + if goroot.err != nil { + return + } + // knownGOROOTModules is a hard-coded list of modules that are known to exist in GOROOT. + // If findGorootModules doesn't find a module, it won't be covered by tests at all, + // so make sure at least these modules are found. See issue 46254. If this list + // becomes a nuisance to update, can be replaced with len(goroot.modules) check. + knownGOROOTModules := [...]string{ + "std", + "cmd", + "misc", + "test/bench/go1", + } + var seen = make(map[string]bool) // Key is module path. + for _, m := range goroot.modules { + seen[m.Path] = true + } + for _, m := range knownGOROOTModules { + if !seen[m] { + goroot.err = fmt.Errorf("findGorootModules didn't find the well-known module %q", m) + break + } + } + }) if goroot.err != nil { t.Fatal(goroot.err) } diff --git a/src/go.mod b/src/go.mod index 93ff2d8d3c1..379dcf504e5 100644 --- a/src/go.mod +++ b/src/go.mod @@ -5,6 +5,6 @@ go 1.17 require ( golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e golang.org/x/net v0.0.0-20210510120150-4163338589ed - golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 // indirect + golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 // indirect golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f // indirect ) diff --git a/src/go.sum b/src/go.sum index 1390ce6d458..b3de6c526c9 100644 --- a/src/go.sum +++ b/src/go.sum @@ -2,7 +2,7 @@ golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4 golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I= golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 h1:cdsMqa2nXzqlgs183pHxtvoVwU7CyzaCTAUOg94af4c= -golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 h1:yhBbb4IRs2HS9PPlAg6DMC6mUOKexJBNsLf4Z+6En1Q= +golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f h1:yQJrRE0hDxDFmZLlRaw+3vusO4fwNHgHIjUOMO7bHYI= golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index fd540ff255e..a948ff3eed4 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -53,6 +53,48 @@ import ( "golang.org/x/net/idna" ) +// asciiEqualFold is strings.EqualFold, ASCII only. It reports whether s and t +// are equal, ASCII-case-insensitively. +func http2asciiEqualFold(s, t string) bool { + if len(s) != len(t) { + return false + } + for i := 0; i < len(s); i++ { + if http2lower(s[i]) != http2lower(t[i]) { + return false + } + } + return true +} + +// lower returns the ASCII lowercase version of b. +func http2lower(b byte) byte { + if 'A' <= b && b <= 'Z' { + return b + ('a' - 'A') + } + return b +} + +// isASCIIPrint returns whether s is ASCII and printable according to +// https://tools.ietf.org/html/rfc20#section-4.2. +func http2isASCIIPrint(s string) bool { + for i := 0; i < len(s); i++ { + if s[i] < ' ' || s[i] > '~' { + return false + } + } + return true +} + +// asciiToLower returns the lowercase version of s if s is ASCII and printable, +// and whether or not it was. +func http2asciiToLower(s string) (lower string, ok bool) { + if !http2isASCIIPrint(s) { + return "", false + } + return strings.ToLower(s), true +} + // A list of the possible cipher suite ids. Taken from // https://www.iana.org/assignments/tls-parameters/tls-parameters.txt @@ -2907,6 +2949,20 @@ func http2traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textpr return nil } +// dialTLSWithContext uses tls.Dialer, added in Go 1.15, to open a TLS +// connection. +func (t *http2Transport) dialTLSWithContext(ctx context.Context, network, addr string, cfg *tls.Config) (*tls.Conn, error) { + dialer := &tls.Dialer{ + Config: cfg, + } + cn, err := dialer.DialContext(ctx, network, addr) + if err != nil { + return nil, err + } + tlsCn := cn.(*tls.Conn) // DialContext comment promises this will always succeed + return tlsCn, nil +} + var http2DebugGoroutines = os.Getenv("DEBUG_HTTP2_GOROUTINES") == "1" type http2goroutineLock uint64 @@ -3128,12 +3184,12 @@ func http2buildCommonHeaderMaps() { } } -func http2lowerHeader(v string) string { +func http2lowerHeader(v string) (lower string, ascii bool) { http2buildCommonHeaderMapsOnce() if s, ok := http2commonLowerHeader[v]; ok { - return s + return s, true } - return strings.ToLower(v) + return http2asciiToLower(v) } var ( @@ -3831,13 +3887,12 @@ func http2ConfigureServer(s *Server, conf *http2Server) error { if s.TLSConfig == nil { s.TLSConfig = new(tls.Config) - } else if s.TLSConfig.CipherSuites != nil { - // If they already provided a CipherSuite list, return - // an error if it has a bad order or is missing - // ECDHE_RSA_WITH_AES_128_GCM_SHA256 or ECDHE_ECDSA_WITH_AES_128_GCM_SHA256. + } else if s.TLSConfig.CipherSuites != nil && s.TLSConfig.MinVersion < tls.VersionTLS13 { + // If they already provided a TLS 1.0–1.2 CipherSuite list, return an + // error if it is missing ECDHE_RSA_WITH_AES_128_GCM_SHA256 or + // ECDHE_ECDSA_WITH_AES_128_GCM_SHA256. haveRequired := false - sawBad := false - for i, cs := range s.TLSConfig.CipherSuites { + for _, cs := range s.TLSConfig.CipherSuites { switch cs { case tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, // Alternative MTI cipher to not discourage ECDSA-only servers. @@ -3845,14 +3900,9 @@ func http2ConfigureServer(s *Server, conf *http2Server) error { tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: haveRequired = true } - if http2isBadCipher(cs) { - sawBad = true - } else if sawBad { - return fmt.Errorf("http2: TLSConfig.CipherSuites index %d contains an HTTP/2-approved cipher suite (%#04x), but it comes after unapproved cipher suites. With this configuration, clients that don't support previous, approved cipher suites may be given an unapproved one and reject the connection.", i, cs) - } } if !haveRequired { - return fmt.Errorf("http2: TLSConfig.CipherSuites is missing an HTTP/2-required AES_128_GCM_SHA256 cipher (need at least one of TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 or TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256).") + return fmt.Errorf("http2: TLSConfig.CipherSuites is missing an HTTP/2-required AES_128_GCM_SHA256 cipher (need at least one of TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 or TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)") } } @@ -6394,8 +6444,12 @@ func (w *http2responseWriter) Push(target string, opts *PushOptions) error { // but PUSH_PROMISE requests cannot have a body. // http://tools.ietf.org/html/rfc7540#section-8.2 // Also disallow Host, since the promised URL must be absolute. - switch strings.ToLower(k) { - case "content-length", "content-encoding", "trailer", "te", "expect", "host": + if http2asciiEqualFold(k, "content-length") || + http2asciiEqualFold(k, "content-encoding") || + http2asciiEqualFold(k, "trailer") || + http2asciiEqualFold(k, "te") || + http2asciiEqualFold(k, "expect") || + http2asciiEqualFold(k, "host") { return fmt.Errorf("promised request headers cannot include %q", k) } } @@ -7148,14 +7202,10 @@ func (t *http2Transport) dialTLS(ctx context.Context) func(string, string, *tls. return t.DialTLS } return func(network, addr string, cfg *tls.Config) (net.Conn, error) { - dialer := &tls.Dialer{ - Config: cfg, - } - cn, err := dialer.DialContext(ctx, network, addr) + tlsCn, err := t.dialTLSWithContext(ctx, network, addr, cfg) if err != nil { return nil, err } - tlsCn := cn.(*tls.Conn) // DialContext comment promises this will always succeed state := tlsCn.ConnectionState() if p := state.NegotiatedProtocol; p != http2NextProtoTLS { return nil, fmt.Errorf("http2: unexpected ALPN protocol %q; want %q", p, http2NextProtoTLS) @@ -7163,7 +7213,7 @@ func (t *http2Transport) dialTLS(ctx context.Context) func(string, string, *tls. if !state.NegotiatedProtocolIsMutual { return nil, errors.New("http2: could not negotiate protocol mutually") } - return cn, nil + return tlsCn, nil } } @@ -7552,7 +7602,7 @@ func http2checkConnHeaders(req *Request) error { if vv := req.Header["Transfer-Encoding"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && vv[0] != "chunked") { return fmt.Errorf("http2: invalid Transfer-Encoding request header: %q", vv) } - if vv := req.Header["Connection"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && !strings.EqualFold(vv[0], "close") && !strings.EqualFold(vv[0], "keep-alive")) { + if vv := req.Header["Connection"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && !http2asciiEqualFold(vv[0], "close") && !http2asciiEqualFold(vv[0], "keep-alive")) { return fmt.Errorf("http2: invalid Connection request header: %q", vv) } return nil @@ -8078,19 +8128,21 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail var didUA bool for k, vv := range req.Header { - if strings.EqualFold(k, "host") || strings.EqualFold(k, "content-length") { + if http2asciiEqualFold(k, "host") || http2asciiEqualFold(k, "content-length") { // Host is :authority, already sent. // Content-Length is automatic, set below. continue - } else if strings.EqualFold(k, "connection") || strings.EqualFold(k, "proxy-connection") || - strings.EqualFold(k, "transfer-encoding") || strings.EqualFold(k, "upgrade") || - strings.EqualFold(k, "keep-alive") { + } else if http2asciiEqualFold(k, "connection") || + http2asciiEqualFold(k, "proxy-connection") || + http2asciiEqualFold(k, "transfer-encoding") || + http2asciiEqualFold(k, "upgrade") || + http2asciiEqualFold(k, "keep-alive") { // Per 8.1.2.2 Connection-Specific Header // Fields, don't send connection-specific // fields. We have already checked if any // are error-worthy so just ignore the rest. continue - } else if strings.EqualFold(k, "user-agent") { + } else if http2asciiEqualFold(k, "user-agent") { // Match Go's http1 behavior: at most one // User-Agent. If set to nil or empty string, // then omit it. Otherwise if not mentioned, @@ -8103,7 +8155,7 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail if vv[0] == "" { continue } - } else if strings.EqualFold(k, "cookie") { + } else if http2asciiEqualFold(k, "cookie") { // Per 8.1.2.5 To allow for better compression efficiency, the // Cookie header field MAY be split into separate header fields, // each with one or more cookie-pairs. @@ -8162,7 +8214,12 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail // Header list size is ok. Write the headers. enumerateHeaders(func(name, value string) { - name = strings.ToLower(name) + name, ascii := http2asciiToLower(name) + if !ascii { + // Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header + // field names have to be ASCII characters (just as in HTTP/1.x). + return + } cc.writeHeader(name, value) if traceHeaders { http2traceWroteHeaderField(trace, name, value) @@ -8210,9 +8267,14 @@ func (cc *http2ClientConn) encodeTrailers(req *Request) ([]byte, error) { } for k, vv := range req.Trailer { + lowKey, ascii := http2asciiToLower(k) + if !ascii { + // Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header + // field names have to be ASCII characters (just as in HTTP/1.x). + continue + } // Transfer-Encoding, etc.. have already been filtered at the // start of RoundTrip - lowKey := strings.ToLower(k) for _, v := range vv { cc.writeHeader(lowKey, v) } @@ -9635,7 +9697,12 @@ func http2encodeHeaders(enc *hpack.Encoder, h Header, keys []string) { } for _, k := range keys { vv := h[k] - k = http2lowerHeader(k) + k, ascii := http2lowerHeader(k) + if !ascii { + // Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header + // field names have to be ASCII characters (just as in HTTP/1.x). + continue + } if !http2validWireHeaderFieldName(k) { // Skip it as backup paranoia. Per // golang.org/issue/14048, these should diff --git a/src/net/http/socks_bundle.go b/src/net/http/socks_bundle.go index e6db1c7640f..e4466695899 100644 --- a/src/net/http/socks_bundle.go +++ b/src/net/http/socks_bundle.go @@ -453,7 +453,7 @@ func (up *socksUsernamePassword) Authenticate(ctx context.Context, rw io.ReadWri b = append(b, up.Username...) b = append(b, byte(len(up.Password))) b = append(b, up.Password...) - // TODO(mikio): handle IO deadlines and cancellation if + // TODO(mikio): handle IO deadlines and cancelation if // necessary if _, err := rw.Write(b); err != nil { return err diff --git a/src/vendor/golang.org/x/sys/cpu/cpu.go b/src/vendor/golang.org/x/sys/cpu/cpu.go index f77701fe868..abbec2d44bf 100644 --- a/src/vendor/golang.org/x/sys/cpu/cpu.go +++ b/src/vendor/golang.org/x/sys/cpu/cpu.go @@ -154,14 +154,13 @@ var MIPS64X struct { // For ppc64/ppc64le, it is safe to check only for ISA level starting on ISA v3.00, // since there are no optional categories. There are some exceptions that also // require kernel support to work (DARN, SCV), so there are feature bits for -// those as well. The minimum processor requirement is POWER8 (ISA 2.07). -// The struct is padded to avoid false sharing. +// those as well. The struct is padded to avoid false sharing. var PPC64 struct { _ CacheLinePad HasDARN bool // Hardware random number generator (requires kernel enablement) HasSCV bool // Syscall vectored (requires kernel enablement) IsPOWER8 bool // ISA v2.07 (POWER8) - IsPOWER9 bool // ISA v3.00 (POWER9) + IsPOWER9 bool // ISA v3.00 (POWER9), implies IsPOWER8 _ CacheLinePad } diff --git a/src/vendor/golang.org/x/sys/cpu/cpu_aix.go b/src/vendor/golang.org/x/sys/cpu/cpu_aix.go index 28b521643b1..8aaeef545a7 100644 --- a/src/vendor/golang.org/x/sys/cpu/cpu_aix.go +++ b/src/vendor/golang.org/x/sys/cpu/cpu_aix.go @@ -20,6 +20,7 @@ func archInit() { PPC64.IsPOWER8 = true } if impl&_IMPL_POWER9 != 0 { + PPC64.IsPOWER8 = true PPC64.IsPOWER9 = true } diff --git a/src/vendor/modules.txt b/src/vendor/modules.txt index 1b850342a5a..ff01db5cdc7 100644 --- a/src/vendor/modules.txt +++ b/src/vendor/modules.txt @@ -18,7 +18,7 @@ golang.org/x/net/idna golang.org/x/net/lif golang.org/x/net/nettest golang.org/x/net/route -# golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 +# golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 ## explicit; go 1.17 golang.org/x/sys/cpu # golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f From 701bd6064655fb51d189c9f421f876a67f6619a3 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Wed, 19 May 2021 09:58:01 -0700 Subject: [PATCH 086/940] [dev.typeparams] cmd/compile: simplify targ's type Make the base type of targ a *types.Type instead of an ir.Node containing a type. Also move makeInstName to typecheck, so it can later be used by reflectdata for making wrappers. Change-Id: If148beaa972e5112ead2771d6e32d73f16ca30c1 Reviewed-on: https://go-review.googlesource.com/c/go/+/321209 Trust: Keith Randall Trust: Dan Scales Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/noder/stencil.go | 63 ++++------------------ src/cmd/compile/internal/noder/types.go | 4 +- src/cmd/compile/internal/typecheck/subr.go | 58 ++++++++++++++++++++ 3 files changed, 70 insertions(+), 55 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index adcea2c087d..87c61b2cf1c 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -166,12 +166,8 @@ func (g *irgen) instantiateMethods() { baseSym := typ.Sym().Pkg.Lookup(genericTypeName(typ.Sym())) baseType := baseSym.Def.(*ir.Name).Type() for j, m := range typ.Methods().Slice() { - targs := make([]ir.Node, len(typ.RParams())) - for k, targ := range typ.RParams() { - targs[k] = ir.TypeNode(targ) - } baseNname := baseType.Methods().Slice()[j].Nname.(*ir.Name) - f := g.getInstantiation(baseNname, targs, true) + f := g.getInstantiation(baseNname, typ.RParams(), true) m.Nname = f.Nname } } @@ -190,17 +186,17 @@ func genericTypeName(sym *types.Sym) string { // InstExpr node inst. func (g *irgen) getInstantiationForNode(inst *ir.InstExpr) *ir.Func { if meth, ok := inst.X.(*ir.SelectorExpr); ok { - return g.getInstantiation(meth.Selection.Nname.(*ir.Name), inst.Targs, true) + return g.getInstantiation(meth.Selection.Nname.(*ir.Name), typecheck.TypesOf(inst.Targs), true) } else { - return g.getInstantiation(inst.X.(*ir.Name), inst.Targs, false) + return g.getInstantiation(inst.X.(*ir.Name), typecheck.TypesOf(inst.Targs), false) } } // getInstantiation gets the instantiantion of the function or method nameNode // with the type arguments targs. If the instantiated function is not already // cached, then it calls genericSubst to create the new instantiation. -func (g *irgen) getInstantiation(nameNode *ir.Name, targs []ir.Node, isMeth bool) *ir.Func { - sym := makeInstName(nameNode.Sym(), targs, isMeth) +func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth bool) *ir.Func { + sym := typecheck.MakeInstName(nameNode.Sym(), targs, isMeth) st := g.target.Stencils[sym] if st == nil { // If instantiation doesn't exist yet, create it and add @@ -215,45 +211,6 @@ func (g *irgen) getInstantiation(nameNode *ir.Name, targs []ir.Node, isMeth bool return st } -// makeInstName makes the unique name for a stenciled generic function or method, -// based on the name of the function fy=nsym and the targs. It replaces any -// existing bracket type list in the name. makeInstName asserts that fnsym has -// brackets in its name if and only if hasBrackets is true. -// TODO(danscales): remove the assertions and the hasBrackets argument later. -// -// Names of declared generic functions have no brackets originally, so hasBrackets -// should be false. Names of generic methods already have brackets, since the new -// type parameter is specified in the generic type of the receiver (e.g. func -// (func (v *value[T]).set(...) { ... } has the original name (*value[T]).set. -// -// The standard naming is something like: 'genFn[int,bool]' for functions and -// '(*genType[int,bool]).methodName' for methods -func makeInstName(fnsym *types.Sym, targs []ir.Node, hasBrackets bool) *types.Sym { - b := bytes.NewBufferString("") - name := fnsym.Name - i := strings.Index(name, "[") - assert(hasBrackets == (i >= 0)) - if i >= 0 { - b.WriteString(name[0:i]) - } else { - b.WriteString(name) - } - b.WriteString("[") - for i, targ := range targs { - if i > 0 { - b.WriteString(",") - } - b.WriteString(targ.Type().String()) - } - b.WriteString("]") - if i >= 0 { - i2 := strings.Index(name[i:], "]") - assert(i2 >= 0) - b.WriteString(name[i+i2+1:]) - } - return typecheck.Lookup(b.String()) -} - // Struct containing info needed for doing the substitution as we create the // instantiation of a generic function with specified type arguments. type subster struct { @@ -261,7 +218,7 @@ type subster struct { isMethod bool // If a method is being instantiated newf *ir.Func // Func node for the new stenciled function tparams []*types.Field - targs []ir.Node + targs []*types.Type // The substitution map from name nodes in the generic function to the // name nodes in the new stenciled function. vars map[*ir.Name]*ir.Name @@ -273,7 +230,7 @@ type subster struct { // function type where the receiver becomes the first parameter. Otherwise the // instantiated method would still need to be transformed by later compiler // phases. -func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []ir.Node, isMethod bool) *ir.Func { +func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*types.Type, isMethod bool) *ir.Func { var tparams []*types.Field if isMethod { // Get the type params from the method receiver (after skipping @@ -545,7 +502,7 @@ func (subst *subster) node(n ir.Node) ir.Node { m.(*ir.ClosureExpr).Func = newfn // Closure name can already have brackets, if it derives // from a generic method - newsym := makeInstName(oldfn.Nname.Sym(), subst.targs, subst.isMethod) + newsym := typecheck.MakeInstName(oldfn.Nname.Sym(), subst.targs, subst.isMethod) newfn.Nname = ir.NewNameAt(oldfn.Nname.Pos(), newsym) newfn.Nname.Func = newfn newfn.Nname.Defn = newfn @@ -704,7 +661,7 @@ func (subst *subster) typ(t *types.Type) *types.Type { if t.Kind() == types.TTYPEPARAM { for i, tp := range subst.tparams { if tp.Type == t { - return subst.targs[i].Type() + return subst.targs[i] } } // If t is a simple typeparam T, then t has the name/symbol 'T' @@ -872,7 +829,7 @@ func (subst *subster) typ(t *types.Type) *types.Type { for i, f := range t.Methods().Slice() { t2 := subst.typ(f.Type) oldsym := f.Nname.Sym() - newsym := makeInstName(oldsym, subst.targs, true) + newsym := typecheck.MakeInstName(oldsym, subst.targs, true) var nname *ir.Name if newsym.Def != nil { nname = newsym.Def.(*ir.Name) diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go index 8a2c023a1a3..107488e6501 100644 --- a/src/cmd/compile/internal/noder/types.go +++ b/src/cmd/compile/internal/noder/types.go @@ -240,9 +240,9 @@ func (g *irgen) typ0(typ types2.Type) *types.Type { // and for actually generating the methods for instantiated types. func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) { if typ.NumMethods() != 0 { - targs := make([]ir.Node, len(typ.TArgs())) + targs := make([]*types.Type, len(typ.TArgs())) for i, targ := range typ.TArgs() { - targs[i] = ir.TypeNode(g.typ1(targ)) + targs[i] = g.typ1(targ) } methods := make([]*types.Field, typ.NumMethods()) diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index 9ee7a94b1f2..97fb1451327 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -5,6 +5,7 @@ package typecheck import ( + "bytes" "fmt" "sort" "strconv" @@ -874,3 +875,60 @@ var slist []symlink type symlink struct { field *types.Field } + +// TypesOf converts a list of nodes to a list +// of types of those nodes. +func TypesOf(x []ir.Node) []*types.Type { + r := make([]*types.Type, len(x)) + for i, n := range x { + r[i] = n.Type() + } + return r +} + +// MakeInstName makes the unique name for a stenciled generic function or method, +// based on the name of the function fy=nsym and the targs. It replaces any +// existing bracket type list in the name. makeInstName asserts that fnsym has +// brackets in its name if and only if hasBrackets is true. +// TODO(danscales): remove the assertions and the hasBrackets argument later. +// +// Names of declared generic functions have no brackets originally, so hasBrackets +// should be false. Names of generic methods already have brackets, since the new +// type parameter is specified in the generic type of the receiver (e.g. func +// (func (v *value[T]).set(...) { ... } has the original name (*value[T]).set. +// +// The standard naming is something like: 'genFn[int,bool]' for functions and +// '(*genType[int,bool]).methodName' for methods +func MakeInstName(fnsym *types.Sym, targs []*types.Type, hasBrackets bool) *types.Sym { + b := bytes.NewBufferString("") + name := fnsym.Name + i := strings.Index(name, "[") + assert(hasBrackets == (i >= 0)) + if i >= 0 { + b.WriteString(name[0:i]) + } else { + b.WriteString(name) + } + b.WriteString("[") + for i, targ := range targs { + if i > 0 { + b.WriteString(",") + } + b.WriteString(targ.String()) + } + b.WriteString("]") + if i >= 0 { + i2 := strings.Index(name[i:], "]") + assert(i2 >= 0) + b.WriteString(name[i+i2+1:]) + } + return Lookup(b.String()) +} + +// For catching problems as we add more features +// TODO(danscales): remove assertions or replace with base.FatalfAt() +func assert(p bool) { + if !p { + panic("assertion failed") + } +} From b69347d24acbf4ab0cff815097dc3ebea1c9b6b0 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Wed, 19 May 2021 10:04:44 -0700 Subject: [PATCH 087/940] [dev.typeparams] cmd/compile: simplify tparam's type We just need the type of the param, no need for a full Field. Change-Id: I851ff2628e1323d971e58d0cabbdfd93c63e1d3c Reviewed-on: https://go-review.googlesource.com/c/go/+/321229 Trust: Keith Randall Trust: Dan Scales Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/noder/stencil.go | 17 +++++++++-------- src/cmd/compile/internal/noder/types.go | 4 ++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 87c61b2cf1c..e6498e5ef84 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -217,7 +217,7 @@ type subster struct { g *irgen isMethod bool // If a method is being instantiated newf *ir.Func // Func node for the new stenciled function - tparams []*types.Field + tparams []*types.Type targs []*types.Type // The substitution map from name nodes in the generic function to the // name nodes in the new stenciled function. @@ -231,18 +231,19 @@ type subster struct { // instantiated method would still need to be transformed by later compiler // phases. func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*types.Type, isMethod bool) *ir.Func { - var tparams []*types.Field + var tparams []*types.Type if isMethod { // Get the type params from the method receiver (after skipping // over any pointer) recvType := nameNode.Type().Recv().Type recvType = deref(recvType) - tparams = make([]*types.Field, len(recvType.RParams())) - for i, rparam := range recvType.RParams() { - tparams[i] = types.NewField(src.NoXPos, nil, rparam) - } + tparams = recvType.RParams() } else { - tparams = nameNode.Type().TParams().Fields().Slice() + fields := nameNode.Type().TParams().Fields().Slice() + tparams = make([]*types.Type, len(fields)) + for i, f := range fields { + tparams[i] = f.Type + } } gf := nameNode.Func // Pos of the instantiated function is same as the generic function @@ -660,7 +661,7 @@ func (subst *subster) typ(t *types.Type) *types.Type { if t.Kind() == types.TTYPEPARAM { for i, tp := range subst.tparams { - if tp.Type == t { + if tp == t { return subst.targs[i] } } diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go index 107488e6501..35ba1cd2388 100644 --- a/src/cmd/compile/internal/noder/types.go +++ b/src/cmd/compile/internal/noder/types.go @@ -273,9 +273,9 @@ func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) { } else { meth2 = ir.NewNameAt(meth.Pos(), newsym) rparams := types2.AsSignature(m.Type()).RParams() - tparams := make([]*types.Field, len(rparams)) + tparams := make([]*types.Type, len(rparams)) for i, rparam := range rparams { - tparams[i] = types.NewField(src.NoXPos, nil, g.typ1(rparam.Type())) + tparams[i] = g.typ1(rparam.Type()) } assert(len(tparams) == len(targs)) subst := &subster{ From 3f6f12972b08d8559264971e8706efb3fbfd106a Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 18 May 2021 14:48:28 -0400 Subject: [PATCH 088/940] [dev.typeparams] runtime: use internal/abi.FuncPCABI0 for sigtramp PC on DragonflyBSD Same as CL 313230, for DragonflyBSD. sigtramp is the only one we need. Change-Id: Ic11d0aedc7422512b43b2e4505e8f95056f915bd Reviewed-on: https://go-review.googlesource.com/c/go/+/321312 Trust: Cherry Mui Run-TryBot: Cherry Mui Reviewed-by: Than McIntosh Reviewed-by: Michael Knyszek TryBot-Result: Go Bot --- src/runtime/os_dragonfly.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/runtime/os_dragonfly.go b/src/runtime/os_dragonfly.go index 5c688a31096..ab0ad4728fe 100644 --- a/src/runtime/os_dragonfly.go +++ b/src/runtime/os_dragonfly.go @@ -5,6 +5,7 @@ package runtime import ( + "internal/abi" "runtime/internal/sys" "unsafe" ) @@ -227,7 +228,7 @@ func setsig(i uint32, fn uintptr) { sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART sa.sa_mask = sigset_all if fn == funcPC(sighandler) { - fn = funcPC(sigtramp) + fn = abi.FuncPCABI0(sigtramp) } sa.sa_sigaction = fn sigaction(i, &sa, nil) From eff66248ea242c2611a9a0e2be47a762073e81b2 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 18 May 2021 19:03:00 -0700 Subject: [PATCH 089/940] [dev.typeparams] cmd/compile/internal/types2: implement package height This CL extends types2 with package height information, styled after the way it works already in cmd/compile: - A new NewPackageHeight entry point for constructing packages with explicit height information, and a corresponding Height accessor method. - The types2 importer is updated to provide package height for imported packages. - The types2 type checker sets height based on imported packages. - Adds an assertion to irgen to verify that types1 and types2 calculated the same height for the source package. - Func.less's ordering incorporates package height to match types.Sym.less and is generalized to object.less. - sortTypes (used for sorting embedded types) now sorts defined types using object.less as well. Change-Id: Id4dbbb627aef405cc7438d611cbdd5a5bd97fc96 Reviewed-on: https://go-review.googlesource.com/c/go/+/321231 Run-TryBot: Matthew Dempsky Trust: Matthew Dempsky Trust: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/importer/iimport.go | 13 ++-- src/cmd/compile/internal/noder/irgen.go | 1 + src/cmd/compile/internal/types2/object.go | 69 +++++++++++--------- src/cmd/compile/internal/types2/package.go | 14 +++- src/cmd/compile/internal/types2/resolver.go | 10 +++ src/cmd/compile/internal/types2/typexpr.go | 10 +-- 6 files changed, 76 insertions(+), 41 deletions(-) diff --git a/src/cmd/compile/internal/importer/iimport.go b/src/cmd/compile/internal/importer/iimport.go index 5c02f837ef4..b91b209d35e 100644 --- a/src/cmd/compile/internal/importer/iimport.go +++ b/src/cmd/compile/internal/importer/iimport.go @@ -118,17 +118,22 @@ func iImportData(imports map[string]*types2.Package, data []byte, path string) ( pkgPathOff := r.uint64() pkgPath := p.stringAt(pkgPathOff) pkgName := p.stringAt(r.uint64()) - _ = r.uint64() // package height; unused by go/types + pkgHeight := int(r.uint64()) if pkgPath == "" { pkgPath = path } pkg := imports[pkgPath] if pkg == nil { - pkg = types2.NewPackage(pkgPath, pkgName) + pkg = types2.NewPackageHeight(pkgPath, pkgName, pkgHeight) imports[pkgPath] = pkg - } else if pkg.Name() != pkgName { - errorf("conflicting names %s and %s for package %q", pkg.Name(), pkgName, path) + } else { + if pkg.Name() != pkgName { + errorf("conflicting names %s and %s for package %q", pkg.Name(), pkgName, path) + } + if pkg.Height() != pkgHeight { + errorf("conflicting heights %v and %v for package %q", pkg.Height(), pkgHeight, path) + } } p.pkgCache[pkgPathOff] = pkg diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go index 3e0d3285ab9..2a9f0e99d8a 100644 --- a/src/cmd/compile/internal/noder/irgen.go +++ b/src/cmd/compile/internal/noder/irgen.go @@ -132,6 +132,7 @@ Outer: } } } + assert(myheight == g.self.Height()) types.LocalPkg.Height = myheight // 2. Process all package-block type declarations. As with imports, diff --git a/src/cmd/compile/internal/types2/object.go b/src/cmd/compile/internal/types2/object.go index 844bc34b6a3..8ed55f1dbf9 100644 --- a/src/cmd/compile/internal/types2/object.go +++ b/src/cmd/compile/internal/types2/object.go @@ -186,6 +186,45 @@ func (obj *object) sameId(pkg *Package, name string) bool { return pkg.path == obj.pkg.path } +// less reports whether object a is ordered before object b. +// +// Objects are ordered nil before non-nil, exported before +// non-exported, then by name, and finally (for non-exported +// functions) by package height and path. +func (a *object) less(b *object) bool { + if a == b { + return false + } + + // Nil before non-nil. + if a == nil { + return true + } + if b == nil { + return false + } + + // Exported functions before non-exported. + ea := isExported(a.name) + eb := isExported(b.name) + if ea != eb { + return ea + } + + // Order by name and then (for non-exported names) by package. + if a.name != b.name { + return a.name < b.name + } + if !ea { + if a.pkg.height != b.pkg.height { + return a.pkg.height < b.pkg.height + } + return a.pkg.path < b.pkg.path + } + + return false +} + // A PkgName represents an imported Go package. // PkgNames don't have a type. type PkgName struct { @@ -329,36 +368,6 @@ func (obj *Func) FullName() string { // Scope returns the scope of the function's body block. func (obj *Func) Scope() *Scope { return obj.typ.(*Signature).scope } -// Less reports whether function a is ordered before function b. -// -// Functions are ordered exported before non-exported, then by name, -// and finally (for non-exported functions) by package path. -// -// TODO(gri) The compiler also sorts by package height before package -// path for non-exported names. -func (a *Func) less(b *Func) bool { - if a == b { - return false - } - - // Exported functions before non-exported. - ea := isExported(a.name) - eb := isExported(b.name) - if ea != eb { - return ea - } - - // Order by name and then (for non-exported names) by package. - if a.name != b.name { - return a.name < b.name - } - if !ea { - return a.pkg.path < b.pkg.path - } - - return false -} - func (*Func) isDependency() {} // a function may be a dependency of an initialization expression // A Label represents a declared label. diff --git a/src/cmd/compile/internal/types2/package.go b/src/cmd/compile/internal/types2/package.go index 31b1e717877..c5804a05adc 100644 --- a/src/cmd/compile/internal/types2/package.go +++ b/src/cmd/compile/internal/types2/package.go @@ -13,8 +13,9 @@ type Package struct { path string name string scope *Scope - complete bool imports []*Package + height int + complete bool fake bool // scope lookup errors are silently dropped if package is fake (internal use only) cgo bool // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go } @@ -22,8 +23,14 @@ type Package struct { // NewPackage returns a new Package for the given package path and name. // The package is not complete and contains no explicit imports. func NewPackage(path, name string) *Package { + return NewPackageHeight(path, name, 0) +} + +// NewPackageHeight is like NewPackage, but allows specifying the +// package's height. +func NewPackageHeight(path, name string, height int) *Package { scope := NewScope(Universe, nopos, nopos, fmt.Sprintf("package %q", path)) - return &Package{path: path, name: name, scope: scope} + return &Package{path: path, name: name, scope: scope, height: height} } // Path returns the package path. @@ -32,6 +39,9 @@ func (pkg *Package) Path() string { return pkg.path } // Name returns the package name. func (pkg *Package) Name() string { return pkg.name } +// Height returns the package height. +func (pkg *Package) Height() int { return pkg.height } + // SetName sets the package name. func (pkg *Package) SetName(name string) { pkg.name = name } diff --git a/src/cmd/compile/internal/types2/resolver.go b/src/cmd/compile/internal/types2/resolver.go index ef49a8b48da..9b1482b14e1 100644 --- a/src/cmd/compile/internal/types2/resolver.go +++ b/src/cmd/compile/internal/types2/resolver.go @@ -196,6 +196,7 @@ func (check *Checker) importPackage(pos syntax.Pos, path, dir string) *Package { // methods with receiver base type names. func (check *Checker) collectObjects() { pkg := check.pkg + pkg.height = 0 // pkgImports is the set of packages already imported by any package file seen // so far. Used to avoid duplicate entries in pkg.imports. Allocate and populate @@ -253,6 +254,15 @@ func (check *Checker) collectObjects() { continue } + if imp == Unsafe { + // typecheck ignores imports of package unsafe for + // calculating height. + // TODO(mdempsky): Revisit this. This seems fine, but I + // don't remember explicitly considering this case. + } else if h := imp.height + 1; h > pkg.height { + pkg.height = h + } + // local name overrides imported package name name := imp.name if s.LocalPkgName != nil { diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index a1663d2aa0c..7fb914cd7ec 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -1055,14 +1055,14 @@ func sortTypes(list []Type) { type byUniqueTypeName []Type func (a byUniqueTypeName) Len() int { return len(a) } -func (a byUniqueTypeName) Less(i, j int) bool { return sortName(a[i]) < sortName(a[j]) } +func (a byUniqueTypeName) Less(i, j int) bool { return sortObj(a[i]).less(sortObj(a[j])) } func (a byUniqueTypeName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func sortName(t Type) string { +func sortObj(t Type) *object { if named := asNamed(t); named != nil { - return named.obj.Id() + return &named.obj.object } - return "" + return nil } func sortMethods(list []*Func) { @@ -1082,7 +1082,7 @@ func assertSortedMethods(list []*Func) { type byUniqueMethodName []*Func func (a byUniqueMethodName) Len() int { return len(a) } -func (a byUniqueMethodName) Less(i, j int) bool { return a[i].less(a[j]) } +func (a byUniqueMethodName) Less(i, j int) bool { return a[i].less(&a[j].object) } func (a byUniqueMethodName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (check *Checker) tag(t *syntax.BasicLit) string { From 6bdfff112f098b371bca718efffa47225cc1b608 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 19 May 2021 16:25:31 -0700 Subject: [PATCH 090/940] [dev.typeparams] cmd/compile/internal/types2: use correct type parameter list in missingMethod For #46275 Change-Id: Iaed9d8ba034ad793e5c57f2be174f01a535fee95 Reviewed-on: https://go-review.googlesource.com/c/go/+/321232 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/lookup.go | 21 ++++++++++++++- .../types2/testdata/fixedbugs/issue46275.go2 | 26 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 src/cmd/compile/internal/types2/testdata/fixedbugs/issue46275.go2 diff --git a/src/cmd/compile/internal/types2/lookup.go b/src/cmd/compile/internal/types2/lookup.go index 78299502e9c..eb2b17dd4de 100644 --- a/src/cmd/compile/internal/types2/lookup.go +++ b/src/cmd/compile/internal/types2/lookup.go @@ -333,6 +333,9 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, if len(ftyp.tparams) != len(mtyp.tparams) { return m, f } + if !acceptMethodTypeParams && len(ftyp.tparams) > 0 { + panic("internal error: method with type parameters") + } // If the methods have type parameters we don't care whether they // are the same or not, as long as they match up. Use unification @@ -386,6 +389,9 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, if len(ftyp.tparams) != len(mtyp.tparams) { return m, f } + if !acceptMethodTypeParams && len(ftyp.tparams) > 0 { + panic("internal error: method with type parameters") + } // If V is a (instantiated) generic type, its methods are still // parameterized using the original (declaration) receiver type @@ -413,7 +419,20 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // TODO(gri) is this always correct? what about type bounds? // (Alternative is to rename/subst type parameters and compare.) u := newUnifier(check, true) - u.x.init(ftyp.tparams) + if len(ftyp.tparams) > 0 { + // We reach here only if we accept method type parameters. + // In this case, unification must consider any receiver + // and method type parameters as "free" type parameters. + assert(acceptMethodTypeParams) + // We don't have a test case for this at the moment since + // we can't parse method type parameters. Keeping the + // unimplemented call so that we test this code if we + // enable method type parameters. + unimplemented() + u.x.init(append(ftyp.rparams, ftyp.tparams...)) + } else { + u.x.init(ftyp.rparams) + } if !u.unify(ftyp, mtyp) { return m, f } diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue46275.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue46275.go2 new file mode 100644 index 00000000000..f41ae26e4bd --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue46275.go2 @@ -0,0 +1,26 @@ +// Copyright 2021 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 issue46275 + +type N[T any] struct { + *N[T] + t T +} + +func (n *N[T]) Elem() T { + return n.t +} + +type I interface { + Elem() string +} + +func _() { + var n1 *N[string] + var _ I = n1 + type NS N[string] + var n2 *NS + var _ I = n2 +} From a8d85918b63d481a414ec5ca3978d07b2b047363 Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Wed, 19 May 2021 22:51:11 +0000 Subject: [PATCH 091/940] misc/cgo/testplugin: skip TestIssue25756pie on darwin/arm64 builder This test is known to be broken on the darwin/arm64 builder. Skip it while it's being investigated so it doesn't mask other failures. For #46239. Updates #43228. Change-Id: I8fe57a0636bba84c3100337146dcb96cc264e524 Reviewed-on: https://go-review.googlesource.com/c/go/+/321349 Trust: Dmitri Shuralyov Run-TryBot: Dmitri Shuralyov TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- misc/cgo/testplugin/plugin_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/misc/cgo/testplugin/plugin_test.go b/misc/cgo/testplugin/plugin_test.go index a6accc1dfbb..9697dbf7a78 100644 --- a/misc/cgo/testplugin/plugin_test.go +++ b/misc/cgo/testplugin/plugin_test.go @@ -265,6 +265,10 @@ func TestIssue25756(t *testing.T) { // Test with main using -buildmode=pie with plugin for issue #43228 func TestIssue25756pie(t *testing.T) { + if os.Getenv("GO_BUILDER_NAME") == "darwin-arm64-11_0-toothrot" { + t.Skip("broken on darwin/arm64 builder in sharded mode; see issue 46239") + } + goCmd(t, "build", "-buildmode=plugin", "-o", "life.so", "./issue25756/plugin") goCmd(t, "build", "-buildmode=pie", "-o", "issue25756pie.exe", "./issue25756/main.go") run(t, "./issue25756pie.exe") From f07e4dae3c5cb608b4f0b9db57d1562d2125243b Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Wed, 19 May 2021 15:46:44 +0000 Subject: [PATCH 092/940] syscall: document NewCallback and NewCallbackCDecl limitations Currently NewCallback and NewCallbackCDecl may only be called a limited number of times in a single Go process, but this property of the API is not documented. This change fixes that, but does not document the precise limit to avoid making that limit part of the API, leaving us open to increasing or decreasing the limit in the future as needed. Although the API avoids documenting a limit, it does guarantee a minimum callback count so users can rely on at least some amount of callbacks working. Updates #46184. Change-Id: I5129bf5fe301efff73ac112ba1f207ab32058833 Reviewed-on: https://go-review.googlesource.com/c/go/+/321133 Trust: Michael Knyszek Reviewed-by: Ian Lance Taylor --- src/syscall/syscall_windows.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go index fa0b5d959af..fc734effbbe 100644 --- a/src/syscall/syscall_windows.go +++ b/src/syscall/syscall_windows.go @@ -174,6 +174,9 @@ func compileCallback(fn interface{}, cleanstack bool) uintptr // NewCallback converts a Go function to a function pointer conforming to the stdcall calling convention. // This is useful when interoperating with Windows code requiring callbacks. // The argument is expected to be a function with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr. +// Only a limited number of callbacks may be created in a single Go process, and any memory allocated +// for these callbacks is never released. +// Between NewCallback and NewCallbackCDecl, at least 1024 callbacks can always be created. func NewCallback(fn interface{}) uintptr { return compileCallback(fn, true) } @@ -181,6 +184,9 @@ func NewCallback(fn interface{}) uintptr { // NewCallbackCDecl converts a Go function to a function pointer conforming to the cdecl calling convention. // This is useful when interoperating with Windows code requiring callbacks. // The argument is expected to be a function with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr. +// Only a limited number of callbacks may be created in a single Go process, and any memory allocated +// for these callbacks is never released. +// Between NewCallback and NewCallbackCDecl, at least 1024 callbacks can always be created. func NewCallbackCDecl(fn interface{}) uintptr { return compileCallback(fn, false) } From a5cd89b8c36df906e9f0e2932b83d66a43b5e745 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 19 May 2021 17:20:45 -0400 Subject: [PATCH 093/940] [dev.typeparams] runtime: use internal/abi.FuncPCABI0 and cgo_unsafe_args for Solaris syscall wrappers Similar to CL 313230, for Solaris (and Illumos). Also mark functions that take address of one arg and pass to asmcgocall cgo_unsafe_args, as it effectively takes address of all args. Change-Id: I4281dd774719fb21ecba82e5ed94a609378a3df5 Reviewed-on: https://go-review.googlesource.com/c/go/+/321314 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/runtime/os3_solaris.go | 8 +++++--- src/runtime/os_solaris.go | 3 +++ src/runtime/syscall_solaris.go | 10 ++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/runtime/os3_solaris.go b/src/runtime/os3_solaris.go index 39ef831acfe..3b1a773ee24 100644 --- a/src/runtime/os3_solaris.go +++ b/src/runtime/os3_solaris.go @@ -5,6 +5,7 @@ package runtime import ( + "internal/abi" "runtime/internal/sys" "unsafe" ) @@ -172,7 +173,7 @@ func newosproc(mp *m) { // Disable signals during create, so that the new thread starts // with signals disabled. It will enable them in minit. sigprocmask(_SIG_SETMASK, &sigset_all, &oset) - ret = pthread_create(&tid, &attr, funcPC(tstart_sysvicall), unsafe.Pointer(mp)) + ret = pthread_create(&tid, &attr, abi.FuncPCABI0(tstart_sysvicall), unsafe.Pointer(mp)) sigprocmask(_SIG_SETMASK, &oset, nil) if ret != 0 { print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", ret, ")\n") @@ -215,7 +216,7 @@ func miniterrno() // Called to initialize a new m (including the bootstrap m). // Called on the new thread, cannot allocate memory. func minit() { - asmcgocall(unsafe.Pointer(funcPC(miniterrno)), unsafe.Pointer(&libc____errno)) + asmcgocall(unsafe.Pointer(abi.FuncPCABI0(miniterrno)), unsafe.Pointer(&libc____errno)) minitSignals() @@ -242,7 +243,7 @@ func setsig(i uint32, fn uintptr) { sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART sa.sa_mask = sigset_all if fn == funcPC(sighandler) { - fn = funcPC(sigtramp) + fn = abi.FuncPCABI0(sigtramp) } *((*uintptr)(unsafe.Pointer(&sa._funcptr))) = fn sigaction(i, &sa, nil) @@ -390,6 +391,7 @@ func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) (un } //go:nosplit +//go:cgo_unsafe_args func doMmap(addr, n, prot, flags, fd, off uintptr) (uintptr, uintptr) { var libcall libcall libcall.fn = uintptr(unsafe.Pointer(&libc_mmap)) diff --git a/src/runtime/os_solaris.go b/src/runtime/os_solaris.go index 89129e5f1ac..8ac1b08f690 100644 --- a/src/runtime/os_solaris.go +++ b/src/runtime/os_solaris.go @@ -179,6 +179,7 @@ func sysvicall3Err(fn *libcFunc, a1, a2, a3 uintptr) (r1, err uintptr) { } //go:nosplit +//go:cgo_unsafe_args func sysvicall4(fn *libcFunc, a1, a2, a3, a4 uintptr) uintptr { // Leave caller's PC/SP around for traceback. gp := getg() @@ -208,6 +209,7 @@ func sysvicall4(fn *libcFunc, a1, a2, a3, a4 uintptr) uintptr { } //go:nosplit +//go:cgo_unsafe_args func sysvicall5(fn *libcFunc, a1, a2, a3, a4, a5 uintptr) uintptr { // Leave caller's PC/SP around for traceback. gp := getg() @@ -237,6 +239,7 @@ func sysvicall5(fn *libcFunc, a1, a2, a3, a4, a5 uintptr) uintptr { } //go:nosplit +//go:cgo_unsafe_args func sysvicall6(fn *libcFunc, a1, a2, a3, a4, a5, a6 uintptr) uintptr { // Leave caller's PC/SP around for traceback. gp := getg() diff --git a/src/runtime/syscall_solaris.go b/src/runtime/syscall_solaris.go index 094516927f3..15be8e1c61a 100644 --- a/src/runtime/syscall_solaris.go +++ b/src/runtime/syscall_solaris.go @@ -35,6 +35,7 @@ func pipe1() // declared for vet; do NOT call //go:nosplit //go:linkname syscall_sysvicall6 +//go:cgo_unsafe_args func syscall_sysvicall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) { call := libcall{ fn: fn, @@ -49,6 +50,7 @@ func syscall_sysvicall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err //go:nosplit //go:linkname syscall_rawsysvicall6 +//go:cgo_unsafe_args func syscall_rawsysvicall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) { call := libcall{ fn: fn, @@ -104,6 +106,7 @@ func syscall_dup2(oldfd, newfd uintptr) (val, err uintptr) { //go:nosplit //go:linkname syscall_execve +//go:cgo_unsafe_args func syscall_execve(path, argv, envp uintptr) (err uintptr) { call := libcall{ fn: uintptr(unsafe.Pointer(&libc_execve)), @@ -123,6 +126,7 @@ func syscall_exit(code uintptr) { //go:nosplit //go:linkname syscall_fcntl +//go:cgo_unsafe_args func syscall_fcntl(fd, cmd, arg uintptr) (val, err uintptr) { call := libcall{ fn: uintptr(unsafe.Pointer(&libc_fcntl)), @@ -181,6 +185,7 @@ func syscall_getpid() (pid, err uintptr) { //go:nosplit //go:linkname syscall_ioctl +//go:cgo_unsafe_args func syscall_ioctl(fd, req, arg uintptr) (err uintptr) { call := libcall{ fn: uintptr(unsafe.Pointer(&libc_ioctl)), @@ -234,6 +239,7 @@ func syscall_setgid(gid uintptr) (err uintptr) { //go:nosplit //go:linkname syscall_setgroups +//go:cgo_unsafe_args func syscall_setgroups(ngid, gid uintptr) (err uintptr) { call := libcall{ fn: uintptr(unsafe.Pointer(&libc_setgroups)), @@ -270,6 +276,7 @@ func syscall_setuid(uid uintptr) (err uintptr) { //go:nosplit //go:linkname syscall_setpgid +//go:cgo_unsafe_args func syscall_setpgid(pid, pgid uintptr) (err uintptr) { call := libcall{ fn: uintptr(unsafe.Pointer(&libc_setpgid)), @@ -281,6 +288,7 @@ func syscall_setpgid(pid, pgid uintptr) (err uintptr) { } //go:linkname syscall_syscall +//go:cgo_unsafe_args func syscall_syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) { call := libcall{ fn: uintptr(unsafe.Pointer(&libc_syscall)), @@ -294,6 +302,7 @@ func syscall_syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) { } //go:linkname syscall_wait4 +//go:cgo_unsafe_args func syscall_wait4(pid uintptr, wstatus *uint32, options uintptr, rusage unsafe.Pointer) (wpid int, err uintptr) { call := libcall{ fn: uintptr(unsafe.Pointer(&libc_wait4)), @@ -308,6 +317,7 @@ func syscall_wait4(pid uintptr, wstatus *uint32, options uintptr, rusage unsafe. //go:nosplit //go:linkname syscall_write +//go:cgo_unsafe_args func syscall_write(fd, buf, nbyte uintptr) (n, err uintptr) { call := libcall{ fn: uintptr(unsafe.Pointer(&libc_write)), From bb7495a46d6024da9d77722f04b438e573bcb26f Mon Sep 17 00:00:00 2001 From: Vishal Dalwadi Date: Fri, 7 May 2021 10:25:27 +0530 Subject: [PATCH 094/940] doc/go1.17: document new math constants Documents the newly introduced: * MaxInt * MinInt * MaxUint Updates #28538. For #44513. Fixes #46012. Change-Id: Iab6bbcf8f76ebe105b973d5fd39b86b8cd078348 Reviewed-on: https://go-review.googlesource.com/c/go/+/317911 Trust: Heschi Kreinick Reviewed-by: Emmanuel Odeke --- doc/go1.17.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 4b2f4bce796..4c7348a36d5 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -334,7 +334,9 @@ Do not send CLs removing the interior tags from such phrases.

math

- TODO: https://golang.org/cl/247058: add MaxUint, MinInt, MaxInt + The math package now defines three more constants: MaxUint, MaxInt and MinInt. + For 32-bit systems their values are 2^32 - 1, 2^31 - 1 and -2^31, respectively. + For 64-bit systems their values are 2^64 - 1, 2^63 - 1 and -2^63, respectively.

From ef1f52cc38cc8773a4ae2e4e71219140a08ce98f Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 19 May 2021 16:07:52 -0400 Subject: [PATCH 095/940] doc/go1.17: add release note for windows/arm64 port Updates #44513, #42604. Change-Id: I8200e8087c219a0042ab2a6770a7275c3b17942a Reviewed-on: https://go-review.googlesource.com/c/go/+/321309 Trust: Cherry Mui Reviewed-by: Dmitri Shuralyov --- doc/go1.17.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/go1.17.html b/doc/go1.17.html index 4c7348a36d5..ea8bc3ccd66 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -43,6 +43,13 @@ Do not send CLs removing the interior tags from such phrases. for previous versions has been discontinued.

+

Windows

+ +

+ Go 1.17 adds support of 64-bit ARM architecture on Windows (the + windows/arm64 port). This port supports cgo. +

+

TODO: complete the Ports section

From def53605418c8134880ffa3700c6a4ba6c689234 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 19 May 2021 16:22:34 -0400 Subject: [PATCH 096/940] doc/go1.17: add release notes for OpenBSD ports Updates #44513. Change-Id: I8758768f6231fd7fcbaa7109eb49ee56cd60d93d Reviewed-on: https://go-review.googlesource.com/c/go/+/321310 Trust: Cherry Mui Reviewed-by: Dmitri Shuralyov --- doc/go1.17.html | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/doc/go1.17.html b/doc/go1.17.html index ea8bc3ccd66..97307bc508d 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -50,6 +50,24 @@ Do not send CLs removing the interior tags from such phrases. windows/arm64 port). This port supports cgo.

+

OpenBSD

+ +

+ The 64-bit MIPS architecture on OpenBSD (the openbsd/mips64 + port) now supports cgo. +

+ +

+ In Go 1.16, on the 64-bit x86 and 64-bit ARM architectures on + OpenBSD (the openbsd/amd64 and openbsd/arm64 + ports) system calls are made through libc, instead + of directly using the machine instructions. In Go 1.17, this is + also done on the 32-bit x86 and 32-bit ARM architectures on OpenBSD + (the openbsd/386 and openbsd/arm ports). + This ensures forward-compatibility with future versions of + OpenBSD. +

+

TODO: complete the Ports section

From f8be906d7437f2528abc7cd1a57fe46aa9348b97 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Thu, 20 May 2021 02:23:04 +1000 Subject: [PATCH 097/940] test: re-enable test on riscv64 now that it supports external linking Update #36739 Change-Id: I14ab2cd0e29966b9a2f992e8c3bcb415203e63e6 Reviewed-on: https://go-review.googlesource.com/c/go/+/321449 Trust: Joel Sing Reviewed-by: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot --- test/fixedbugs/issue10607.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/fixedbugs/issue10607.go b/test/fixedbugs/issue10607.go index 448a37dcac2..8a04bc9def7 100644 --- a/test/fixedbugs/issue10607.go +++ b/test/fixedbugs/issue10607.go @@ -1,4 +1,4 @@ -// +build linux,!ppc64,!riscv64,gc +// +build linux,!ppc64,gc // run // Copyright 2015 The Go Authors. All rights reserved. @@ -8,9 +8,6 @@ // Test that a -B option is passed through when using both internal // and external linking mode. -// TODO(jsing): Re-enable on riscv64 when it has support for external -// linking - see golang.org/issue/36739 - package main import ( From ce9a3b79d5bb783f5f31c9d41665a488fe63f546 Mon Sep 17 00:00:00 2001 From: Lapo Luchini Date: Thu, 20 May 2021 15:41:02 +0000 Subject: [PATCH 098/940] crypto/x509: add new FreeBSD 12.2+ trusted certificate folder Up to FreeBSD 12.1 the package ca_root_nss was needed in order to have certificates under /usr/local/share/certs as the base system didn't have a system trusted certificate store. This has been fixed in FreeBSD 12.2 using /etc/ssl/certs: https://svnweb.freebsd.org/base?view=revision&revision=357082 Fixes #46284 Change-Id: I912b1bacc30cdf20d19e3ef9d09b69bb8055ff49 GitHub-Last-Rev: 0fa5542ea3c70ecb03e621381d7c34fbadf7ea47 GitHub-Pull-Request: golang/go#46276 Reviewed-on: https://go-review.googlesource.com/c/go/+/321190 Reviewed-by: Filippo Valsorda Run-TryBot: Filippo Valsorda TryBot-Result: Go Bot Trust: Tobias Klauser --- src/crypto/x509/root_bsd.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/crypto/x509/root_bsd.go b/src/crypto/x509/root_bsd.go index 822e8573ff1..6712ea32a68 100644 --- a/src/crypto/x509/root_bsd.go +++ b/src/crypto/x509/root_bsd.go @@ -18,6 +18,7 @@ var certFiles = []string{ // Possible directories with certificate files; stop after successfully // reading at least one file from a directory. var certDirectories = []string{ + "/etc/ssl/certs", // FreeBSD 12.2+ "/usr/local/share/certs", // FreeBSD "/etc/openssl/certs", // NetBSD } From 7c692cc7ea69ba4d8603fbada112289443a6f526 Mon Sep 17 00:00:00 2001 From: Vishal Dalwadi Date: Fri, 7 May 2021 10:05:36 +0530 Subject: [PATCH 099/940] doc/go1.17: document changes to os package Documents the changes to File.WriteString method. For #44513. Fixes #46018. Change-Id: I3a8ef9df9f84662614d54802710bd705d626b995 Reviewed-on: https://go-review.googlesource.com/c/go/+/317910 Reviewed-by: Dmitri Shuralyov Trust: Cherry Mui --- doc/go1.17.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 97307bc508d..48b5563602a 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -428,7 +428,8 @@ Do not send CLs removing the interior tags from such phrases.
os

- TODO: https://golang.org/cl/268020: avoid allocation in File.WriteString + The File.WriteString method + has been optimized to no longer make a copy of the input string.

From 02117775d1550653bd4f58fdaa12b1e906409052 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 19 May 2021 18:13:45 -0400 Subject: [PATCH 100/940] [dev.typeparams] cmd/compile, runtime: do not zero X15 on Plan 9 On Plan 9, we cannot use SSE registers in note handlers, so we don't use X15 for zeroing (MOVOstorezero and DUFFZERO). Do not zero X15 on Plan 9. Change-Id: I2b083b01b27965611cb83d19afd66b383dc77846 Reviewed-on: https://go-review.googlesource.com/c/go/+/321329 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- src/cmd/compile/internal/amd64/ssa.go | 12 +++++++++--- src/runtime/asm_amd64.s | 2 ++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go index ca5f36e7759..7e2dc41928f 100644 --- a/src/cmd/compile/internal/amd64/ssa.go +++ b/src/cmd/compile/internal/amd64/ssa.go @@ -1005,14 +1005,18 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { case ssa.OpAMD64CALLstatic: if buildcfg.Experiment.RegabiG && s.ABI == obj.ABI0 && v.Aux.(*ssa.AuxCall).Fn.ABI() == obj.ABIInternal { // zeroing X15 when entering ABIInternal from ABI0 - opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15) + if buildcfg.GOOS != "plan9" { // do not use SSE on Plan 9 + opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15) + } // set G register from TLS getgFromTLS(s, x86.REG_R14) } s.Call(v) if buildcfg.Experiment.RegabiG && s.ABI == obj.ABIInternal && v.Aux.(*ssa.AuxCall).Fn.ABI() == obj.ABI0 { // zeroing X15 when entering ABIInternal from ABI0 - opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15) + if buildcfg.GOOS != "plan9" { // do not use SSE on Plan 9 + opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15) + } // set G register from TLS getgFromTLS(s, x86.REG_R14) } @@ -1306,7 +1310,9 @@ func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) { case ssa.BlockRetJmp: if buildcfg.Experiment.RegabiG && s.ABI == obj.ABI0 && b.Aux.(*obj.LSym).ABI() == obj.ABIInternal { // zeroing X15 when entering ABIInternal from ABI0 - opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15) + if buildcfg.GOOS != "plan9" { // do not use SSE on Plan 9 + opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15) + } // set G register from TLS getgFromTLS(s, x86.REG_R14) } diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index 14f29e19647..5990ce54c8d 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -1600,7 +1600,9 @@ TEXT ·sigpanic0(SB),NOSPLIT,$0-0 #ifdef GOEXPERIMENT_regabig get_tls(R14) MOVQ g(R14), R14 +#ifndef GOOS_plan9 XORPS X15, X15 +#endif #endif JMP ·sigpanic(SB) From ed2001232acd78319bd028a2e8775072c9339e1b Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 19 May 2021 17:33:32 -0400 Subject: [PATCH 101/940] [dev.typeparams] runtime: use internal/abi.FuncPCABI0 for sigtramp PC on Plan 9 Same as CL 313230, for Plan 9. Change-Id: I0e99c095856c4b21b89abdffa4c0699b24ea9428 Reviewed-on: https://go-review.googlesource.com/c/go/+/321330 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek Reviewed-by: Than McIntosh --- src/runtime/os_plan9.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/runtime/os_plan9.go b/src/runtime/os_plan9.go index 4d428346f0e..975d460a7da 100644 --- a/src/runtime/os_plan9.go +++ b/src/runtime/os_plan9.go @@ -5,6 +5,7 @@ package runtime import ( + "internal/abi" "runtime/internal/atomic" "unsafe" ) @@ -346,7 +347,7 @@ func getRandomData(r []byte) { func initsig(preinit bool) { if !preinit { - notify(unsafe.Pointer(funcPC(sigtramp))) + notify(unsafe.Pointer(abi.FuncPCABI0(sigtramp))) } } From 240d6d00ca561b7d293976e758642addb467d6b9 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 19 May 2021 17:34:19 -0400 Subject: [PATCH 102/940] [dev.typeparams] cmd/link: mangle symbol ABI name on Plan 9 It is probably not strictly necessary (as we don't support external linking on Plan 9). Do it for consistency (and less confusion). Change-Id: I0b48562061273ccbd4be83db4a981b8e465b1c95 Reviewed-on: https://go-review.googlesource.com/c/go/+/321331 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- src/cmd/link/internal/ld/symtab.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go index 00f557875a9..1f5e333cfd5 100644 --- a/src/cmd/link/internal/ld/symtab.go +++ b/src/cmd/link/internal/ld/symtab.go @@ -300,6 +300,7 @@ func putplan9sym(ctxt *Link, ldr *loader.Loader, s loader.Sym, char SymbolType) ctxt.Out.Write8(uint8(t + 0x80)) /* 0x80 is variable length */ name := ldr.SymName(s) + name = mangleABIName(ctxt, ldr, s, name) ctxt.Out.WriteString(name) ctxt.Out.Write8(0) From 382c5dd5f754392444fbe2c3489d09b2f36f3939 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Fri, 14 May 2021 15:04:51 -0400 Subject: [PATCH 103/940] [dev.typeparams] internal/buildcfg: turn on register ABI on all AMD64 platforms Register ABI is already enabled by default on AMD64 on Linux (including Android), macOS, and Windows. This CL enables it on the rest, specifically, on FreeBSD, OpenBSD, NetBSD, DragonflyBSD, Solaris (including Illumos), iOS (simulator), and Plan 9. Change-Id: I80fa20c8bbc8d67b16a19f71b65422e890210ab5 Reviewed-on: https://go-review.googlesource.com/c/go/+/321332 Trust: Cherry Mui Run-TryBot: Cherry Mui Reviewed-by: Than McIntosh Reviewed-by: David Chase Reviewed-by: Michael Knyszek --- src/internal/buildcfg/exp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/buildcfg/exp.go b/src/internal/buildcfg/exp.go index 2435a79dcec..417d87cf4af 100644 --- a/src/internal/buildcfg/exp.go +++ b/src/internal/buildcfg/exp.go @@ -20,7 +20,7 @@ import ( // was built with.) var Experiment goexperiment.Flags = parseExperiments() -var regabiSupported = GOARCH == "amd64" && (GOOS == "android" || GOOS == "linux" || GOOS == "darwin" || GOOS == "windows") +var regabiSupported = GOARCH == "amd64" // experimentBaseline specifies the experiment flags that are enabled by // default in the current toolchain. This is, in effect, the "control" From baa934d26dd6e201dcda0962dd51b0e5f6f69c1b Mon Sep 17 00:00:00 2001 From: Tim King Date: Wed, 19 May 2021 18:45:53 -0700 Subject: [PATCH 104/940] cmd: go get golang.org/x/tools/analysis@49064d23 && go mod vendor This brings in CLs 312829, 317431, 319211. Fixes #40356. Fixes #46129. Change-Id: I2ee1f858b2a41ffa60d88b0c17511ccad57f1816 Reviewed-on: https://go-review.googlesource.com/c/go/+/321389 Reviewed-by: Dmitri Shuralyov Trust: Tim King Run-TryBot: Tim King TryBot-Result: Go Bot --- src/cmd/go.mod | 2 +- src/cmd/go.sum | 4 ++-- .../x/tools/go/analysis/passes/printf/printf.go | 2 +- .../analysis/passes/sigchanyzer/sigchanyzer.go | 11 +++++++++-- .../go/analysis/passes/stdmethods/stdmethods.go | 17 +++++++++++++++++ src/cmd/vendor/modules.txt | 2 +- 6 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/cmd/go.mod b/src/cmd/go.mod index 88f5f2883a6..1aa0320d078 100644 --- a/src/cmd/go.mod +++ b/src/cmd/go.mod @@ -10,6 +10,6 @@ require ( golang.org/x/mod v0.4.3-0.20210512182355-6088ed88cecd golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 // indirect golang.org/x/term v0.0.0-20210503060354-a79de5458b56 - golang.org/x/tools v0.1.1-0.20210505014545-7cab0ef2e9a5 + golang.org/x/tools v0.1.2-0.20210519160823-49064d2332f9 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect ) diff --git a/src/cmd/go.sum b/src/cmd/go.sum index 73750802bc1..9af4978d669 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -16,7 +16,7 @@ golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 h1:yhBbb4IRs2HS9PPlAg6DMC6mU golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= -golang.org/x/tools v0.1.1-0.20210505014545-7cab0ef2e9a5 h1:ImcI7RFHWLu2QWpFDXaReu0j+sQAHIy65vUFZImXiqY= -golang.org/x/tools v0.1.1-0.20210505014545-7cab0ef2e9a5/go.mod h1:sH/Eidr0EddymY8HZSakBo32zU3fG5ovDq874hJLjVg= +golang.org/x/tools v0.1.2-0.20210519160823-49064d2332f9 h1:2XlR/j4I4xz5GQZI7zBjqTfezYyRIE2jD5IMousB2rg= +golang.org/x/tools v0.1.2-0.20210519160823-49064d2332f9/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go index ddad4c796cb..822820f06e9 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go @@ -590,7 +590,7 @@ func checkPrintf(pass *analysis.Pass, kind Kind, call *ast.CallExpr, fn *types.F } if state.verb == 'w' { if kind != KindErrorf { - pass.Reportf(call.Pos(), "%s call has error-wrapping directive %%w", state.name) + pass.Reportf(call.Pos(), "%s call has error-wrapping directive %%w, which is only supported by Errorf", state.name) return } if anyW { diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go index b00aa7e1440..0d6c8ebf165 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go @@ -59,12 +59,19 @@ func run(pass *analysis.Pass) (interface{}, error) { if chanDecl == nil || len(chanDecl.Args) != 1 { return } - chanDecl.Args = append(chanDecl.Args, &ast.BasicLit{ + + // Make a copy of the channel's declaration to avoid + // mutating the AST. See https://golang.org/issue/46129. + chanDeclCopy := &ast.CallExpr{} + *chanDeclCopy = *chanDecl + chanDeclCopy.Args = append([]ast.Expr(nil), chanDecl.Args...) + chanDeclCopy.Args = append(chanDeclCopy.Args, &ast.BasicLit{ Kind: token.INT, Value: "1", }) + var buf bytes.Buffer - if err := format.Node(&buf, token.NewFileSet(), chanDecl); err != nil { + if err := format.Node(&buf, token.NewFileSet(), chanDeclCopy); err != nil { return } pass.Report(analysis.Diagnostic{ diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go index 856c6ae0d81..64a28ac0b97 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go @@ -61,10 +61,12 @@ var Analyzer = &analysis.Analyzer{ // we let it go. But if it does have a fmt.ScanState, then the // rest has to match. var canonicalMethods = map[string]struct{ args, results []string }{ + "As": {[]string{"interface{}"}, []string{"bool"}}, // errors.As // "Flush": {{}, {"error"}}, // http.Flusher and jpeg.writer conflict "Format": {[]string{"=fmt.State", "rune"}, []string{}}, // fmt.Formatter "GobDecode": {[]string{"[]byte"}, []string{"error"}}, // gob.GobDecoder "GobEncode": {[]string{}, []string{"[]byte", "error"}}, // gob.GobEncoder + "Is": {[]string{"error"}, []string{"bool"}}, // errors.Is "MarshalJSON": {[]string{}, []string{"[]byte", "error"}}, // json.Marshaler "MarshalXML": {[]string{"*xml.Encoder", "xml.StartElement"}, []string{"error"}}, // xml.Marshaler "ReadByte": {[]string{}, []string{"byte", "error"}}, // io.ByteReader @@ -76,6 +78,7 @@ var canonicalMethods = map[string]struct{ args, results []string }{ "UnmarshalXML": {[]string{"*xml.Decoder", "xml.StartElement"}, []string{"error"}}, // xml.Unmarshaler "UnreadByte": {[]string{}, []string{"error"}}, "UnreadRune": {[]string{}, []string{"error"}}, + "Unwrap": {[]string{}, []string{"error"}}, // errors.Unwrap "WriteByte": {[]string{"byte"}, []string{"error"}}, // jpeg.writer (matching bufio.Writer) "WriteTo": {[]string{"=io.Writer"}, []string{"int64", "error"}}, // io.WriterTo } @@ -123,6 +126,14 @@ func canonicalMethod(pass *analysis.Pass, id *ast.Ident) { return } + // Special case: Is, As and Unwrap only apply when type + // implements error. + if id.Name == "Is" || id.Name == "As" || id.Name == "Unwrap" { + if recv := sign.Recv(); recv == nil || !implementsError(recv.Type()) { + return + } + } + // Do the =s (if any) all match? if !matchParams(pass, expect.args, args, "=") || !matchParams(pass, expect.results, results, "=") { return @@ -185,3 +196,9 @@ func matchParamType(expect string, actual types.Type) bool { // Overkill but easy. return typeString(actual) == expect } + +var errorType = types.Universe.Lookup("error").Type().Underlying().(*types.Interface) + +func implementsError(actual types.Type) bool { + return types.Implements(actual, errorType) +} diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt index 016ec011a97..9a1723d32c7 100644 --- a/src/cmd/vendor/modules.txt +++ b/src/cmd/vendor/modules.txt @@ -48,7 +48,7 @@ golang.org/x/sys/windows # golang.org/x/term v0.0.0-20210503060354-a79de5458b56 ## explicit; go 1.17 golang.org/x/term -# golang.org/x/tools v0.1.1-0.20210505014545-7cab0ef2e9a5 +# golang.org/x/tools v0.1.2-0.20210519160823-49064d2332f9 ## explicit; go 1.17 golang.org/x/tools/cover golang.org/x/tools/go/analysis From 468efd5e2fb05860430c0bdede4e1cd0f8c07f65 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Thu, 20 May 2021 15:35:55 -0700 Subject: [PATCH 105/940] [dev.typeparams] cmd/compile: change method instantiations back to being functions Change all instantiated methods to being functions again. We found that this is easier for adding the dictionary argument consistently. A method wrapper will usually be added around the instantiation call, so that eliminate the inconsistency in the type of the top-level method and the the associated function node type. Change-Id: I9034a0c5cc901e7a89e60756bff574c1346adbc7 Reviewed-on: https://go-review.googlesource.com/c/go/+/321609 Run-TryBot: Dan Scales Reviewed-by: Keith Randall TryBot-Result: Go Bot Trust: Dan Scales --- src/cmd/compile/internal/noder/stencil.go | 52 ++++++++++------------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index e6498e5ef84..f9cf6d8a1a9 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -86,21 +86,20 @@ func (g *irgen) stencil() { // instantiation. call := n.(*ir.CallExpr) inst := call.X.(*ir.InstExpr) + // Replace the OFUNCINST with a direct reference to the + // new stenciled function st := g.getInstantiationForNode(inst) + call.X = st.Nname if inst.X.Op() == ir.OCALLPART { - // Replace the OFUNCINST with the selector - // expression, and update the selector expression - // to refer to the new stenciled function. - call.X = inst.X - se := call.X.(*ir.SelectorExpr) - se.Selection = types.NewField(se.Pos(), se.Sel, st.Type()) - se.Selection.Nname = st.Nname - se.SetOp(ir.ODOTMETH) - se.SetType(st.Type()) - } else { - // Replace the OFUNCINST with a direct reference to the - // new stenciled function - call.X = st.Nname + // When we create an instantiation of a method + // call, we make it a function. So, move the + // receiver to be the first arg of the function + // call. + withRecv := make([]ir.Node, len(call.Args)+1) + dot := inst.X.(*ir.SelectorExpr) + withRecv[0] = dot.X + copy(withRecv[1:], call.Args) + call.Args = withRecv } // Transform the Call now, which changes OCALL // to OCALLFUNC and does typecheckaste/assignconvfn. @@ -166,9 +165,13 @@ func (g *irgen) instantiateMethods() { baseSym := typ.Sym().Pkg.Lookup(genericTypeName(typ.Sym())) baseType := baseSym.Def.(*ir.Name).Type() for j, m := range typ.Methods().Slice() { + name := m.Nname.(*ir.Name) baseNname := baseType.Methods().Slice()[j].Nname.(*ir.Name) - f := g.getInstantiation(baseNname, typ.RParams(), true) - m.Nname = f.Nname + // Note: we are breaking an invariant here: + // m.Nname is now not equal m.Nname.Func.Nname. + // m.Nname has the type of a method, whereas m.Nname.Func.Nname has + // the type of a function, since it is an function instantiation. + name.Func = g.getInstantiation(baseNname, typ.RParams(), true) } } g.instTypeList = nil @@ -279,20 +282,11 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*type // the function type. The current function type has no Nname fields set, // because it came via conversion from the types2 type. oldt := nameNode.Type() - dcl := newf.Dcl - var newrecv *types.Field - if oldt.Recv() != nil { - newrecv = subst.fields(ir.PPARAM, oldt.Recvs().FieldSlice(), dcl)[0] - if newrecv.Nname != nil { - // If we found the receiver in the dcl list, then skip it - // when we scan for the remaining params below. - assert(newrecv.Nname == dcl[0]) - dcl = dcl[1:] - } - } - newt := types.NewSignature(oldt.Pkg(), newrecv, nil, - subst.fields(ir.PPARAM, oldt.Params().FieldSlice(), dcl), - subst.fields(ir.PPARAMOUT, oldt.Results().FieldSlice(), dcl)) + // We also transform a generic method type to the corresponding + // instantiated function type where the receiver is the first parameter. + newt := types.NewSignature(oldt.Pkg(), nil, nil, + subst.fields(ir.PPARAM, append(oldt.Recvs().FieldSlice(), oldt.Params().FieldSlice()...), newf.Dcl), + subst.fields(ir.PPARAMOUT, oldt.Results().FieldSlice(), newf.Dcl)) newf.Nname.SetType(newt) ir.MarkFunc(newf.Nname) From 831573cd21e65c37b4e1bf5d44dc23b125084b7a Mon Sep 17 00:00:00 2001 From: Adam Mitha Date: Thu, 13 May 2021 20:52:41 -0700 Subject: [PATCH 106/940] io/fs: added an example for io/fs.WalkDir The documentation currently does not show how to get an `FS` instance for the operating system's filesystem. This example demonstrates how to accomplish this using the `os` package. Fixes #46083 Change-Id: I053111c12ab09ef13f0d04fcdff8a6ea0dccf379 Reviewed-on: https://go-review.googlesource.com/c/go/+/319989 Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor Trust: Emmanuel Odeke --- src/io/fs/example_test.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/io/fs/example_test.go diff --git a/src/io/fs/example_test.go b/src/io/fs/example_test.go new file mode 100644 index 00000000000..c9027034c4a --- /dev/null +++ b/src/io/fs/example_test.go @@ -0,0 +1,25 @@ +// Copyright 2021 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 fs_test + +import ( + "fmt" + "io/fs" + "log" + "os" +) + +func ExampleWalkDir() { + root := "/usr/local/go/bin" + fileSystem := os.DirFS(root) + + fs.WalkDir(fileSystem, ".", func(path string, d fs.DirEntry, err error) error { + if err != nil { + log.Fatal(err) + } + fmt.Println(path) + return nil + }) +} From 15ad61aff5e6b7774101483a933b3d975ae9bae8 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Tue, 13 Apr 2021 15:37:36 -0700 Subject: [PATCH 107/940] [dev.typeparams] cmd/compile: get export/import of generic types & functions working The general idea is that we now export/import typeparams, typeparam lists for generic types and functions, and instantiated types (instantiations of generic types with either new typeparams or concrete types). This changes the export format -- the next CL in the stack adds the export versions and checks for it in the appropriate places. We always export/import generic function bodies, using the same code that we use for exporting/importing the bodies of inlineable functions. To avoid complicated scoping, we consider all type params as unique and give them unique names for types1. We therefore include the types2 ids (subscripts) in the export format and re-create on import. We always access the same unique types1 typeParam type for the same typeparam name. We create fully-instantiated generic types and functions in the original source package. We do an extra NeedRuntimeType() call to make sure that the correct DWARF information is written out. We call SetDupOK(true) for the functions/methods to have the linker automatically drop duplicate instantiations. Other miscellaneous details: - Export/import of typeparam bounds works for methods (but not typelists) for now, but will change with the typeset changes. - Added a new types.Instantiate function roughly analogous to the types2.Instantiate function recently added. - Always access methods info from the original/base generic type, since the methods of an instantiated type are not filled in (in types2 or types1). - New field OrigSym in types.Type to keep track of base generic type that instantiated type was based on. We use the generic type's symbol (OrigSym) as the link, rather than a Type pointer, since we haven't always created the base type yet when we want to set the link (during types2 to types1 conversion). - Added types2.AsTypeParam(), (*types2.TypeParam).SetId() - New test minimp.dir, which tests use of generic function Min across packages. Another test stringimp.dir, which also exports a generic function Stringify across packages, where the type param has a bound (Stringer) as well. New test pairimp.dir, which tests use of generic type Pair (with no methods) across packages. - New test valimp.dir, which tests use of generic type (with methods and related functions) across packages. - Modified several other tests (adder.go, settable.go, smallest.go, stringable.go, struct.go, sum.go) to export their generic functions/types to show that generic functions/types can be exported successfully (but this doesn't test import). Change-Id: Ie61ce9d54a46d368ddc7a76c41399378963bb57f Reviewed-on: https://go-review.googlesource.com/c/go/+/319930 Trust: Dan Scales Trust: Robert Griesemer Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/gc/export.go | 12 +- src/cmd/compile/internal/importer/iimport.go | 85 ++++++++ src/cmd/compile/internal/noder/decl.go | 14 +- src/cmd/compile/internal/noder/expr.go | 8 +- src/cmd/compile/internal/noder/irgen.go | 6 +- src/cmd/compile/internal/noder/object.go | 10 +- src/cmd/compile/internal/noder/stencil.go | 69 +++---- src/cmd/compile/internal/noder/types.go | 35 +++- .../compile/internal/reflectdata/reflect.go | 8 +- src/cmd/compile/internal/typecheck/iexport.go | 97 ++++++++- src/cmd/compile/internal/typecheck/iimport.go | 188 +++++++++++++++--- src/cmd/compile/internal/typecheck/subr.go | 10 +- src/cmd/compile/internal/types/sizeof_test.go | 2 +- src/cmd/compile/internal/types/type.go | 21 +- src/cmd/compile/internal/types2/api_test.go | 14 +- src/cmd/compile/internal/types2/type.go | 10 + src/cmd/compile/internal/types2/typestring.go | 7 + src/go/internal/gcimporter/gcimporter_test.go | 3 +- src/go/internal/gcimporter/iimport.go | 20 ++ test/typeparam/adder.go | 8 +- test/typeparam/min.go | 11 +- test/typeparam/minimp.dir/a.go | 16 ++ test/typeparam/minimp.dir/main.go | 38 ++++ test/typeparam/minimp.go | 7 + test/typeparam/pair.go | 1 + test/typeparam/pairimp.dir/a.go | 10 + test/typeparam/pairimp.dir/main.go | 27 +++ test/typeparam/pairimp.go | 7 + test/typeparam/settable.go | 10 +- test/typeparam/smallest.go | 6 +- test/typeparam/stringable.go | 8 +- test/typeparam/stringerimp.dir/a.go | 16 ++ test/typeparam/stringerimp.dir/main.go | 38 ++++ test/typeparam/stringerimp.go | 7 + test/typeparam/struct.go | 34 ++-- test/typeparam/sum.go | 16 +- test/typeparam/valimp.dir/a.go | 32 +++ test/typeparam/valimp.dir/main.go | 56 ++++++ test/typeparam/valimp.go | 7 + 39 files changed, 816 insertions(+), 158 deletions(-) create mode 100644 test/typeparam/minimp.dir/a.go create mode 100644 test/typeparam/minimp.dir/main.go create mode 100644 test/typeparam/minimp.go create mode 100644 test/typeparam/pairimp.dir/a.go create mode 100644 test/typeparam/pairimp.dir/main.go create mode 100644 test/typeparam/pairimp.go create mode 100644 test/typeparam/stringerimp.dir/a.go create mode 100644 test/typeparam/stringerimp.dir/main.go create mode 100644 test/typeparam/stringerimp.go create mode 100644 test/typeparam/valimp.dir/a.go create mode 100644 test/typeparam/valimp.dir/main.go create mode 100644 test/typeparam/valimp.go diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go index 2137f1d1961..e19d52fa952 100644 --- a/src/cmd/compile/internal/gc/export.go +++ b/src/cmd/compile/internal/gc/export.go @@ -25,11 +25,6 @@ func exportf(bout *bio.Writer, format string, args ...interface{}) { func dumpexport(bout *bio.Writer) { p := &exporter{marked: make(map[*types.Type]bool)} for _, n := range typecheck.Target.Exports { - // Must catch it here rather than Export(), because the type can be - // not fully set (still TFORW) when Export() is called. - if n.Type() != nil && n.Type().HasTParam() { - base.Fatalf("Cannot (yet) export a generic type: %v", n) - } p.markObject(n) } @@ -103,6 +98,11 @@ func (p *exporter) markType(t *types.Type) { return } p.marked[t] = true + if t.HasTParam() { + // Don't deal with any generic types or their methods, since we + // will only be inlining actual instantiations, not generic methods. + return + } // If this is a named type, mark all of its associated // methods. Skip interface types because t.Methods contains @@ -152,6 +152,8 @@ func (p *exporter) markType(t *types.Type) { } case types.TINTER: + // TODO(danscales) - will have to deal with the types in interface + // elements here when implemented in types2 and represented in types1. for _, f := range t.AllMethods().Slice() { if types.IsExported(f.Sym.Name) { p.markType(f.Type) diff --git a/src/cmd/compile/internal/importer/iimport.go b/src/cmd/compile/internal/importer/iimport.go index b91b209d35e..a4637ec34f9 100644 --- a/src/cmd/compile/internal/importer/iimport.go +++ b/src/cmd/compile/internal/importer/iimport.go @@ -57,6 +57,8 @@ const ( signatureType structType interfaceType + typeParamType + instType ) const io_SeekCurrent = 1 // io.SeekCurrent (not defined in Go 1.4) @@ -292,15 +294,20 @@ func (r *importReader) obj(name string) { r.declare(types2.NewConst(pos, r.currPkg, name, typ, val)) case 'F': + tparams := r.tparamList() sig := r.signature(nil) + sig.SetTParams(tparams) r.declare(types2.NewFunc(pos, r.currPkg, name, sig)) case 'T': + tparams := r.tparamList() + // Types can be recursive. We need to setup a stub // declaration before recursing. obj := types2.NewTypeName(pos, r.currPkg, name, nil) named := types2.NewNamed(obj, nil, nil) + named.SetTParams(tparams) r.declare(obj) underlying := r.p.typAt(r.uint64(), named).Underlying() @@ -313,6 +320,18 @@ func (r *importReader) obj(name string) { recv := r.param() msig := r.signature(recv) + // If the receiver has any targs, set those as the + // rparams of the method (since those are the + // typeparams being used in the method sig/body). + targs := baseType(msig.Recv().Type()).TArgs() + if len(targs) > 0 { + rparams := make([]*types2.TypeName, len(targs)) + for i, targ := range targs { + rparams[i] = types2.AsTypeParam(targ).Obj() + } + msig.SetRParams(rparams) + } + named.AddMethod(types2.NewFunc(mpos, r.currPkg, mname, msig)) } } @@ -571,6 +590,49 @@ func (r *importReader) doType(base *types2.Named) types2.Type { typ := types2.NewInterfaceType(methods, embeddeds) r.p.interfaceList = append(r.p.interfaceList, typ) return typ + + case typeParamType: + r.currPkg = r.pkg() + pos := r.pos() + name := r.string() + + // Extract the subscript value from the type param name. We export + // and import the subscript value, so that all type params have + // unique names. + sub := uint64(0) + startsub := -1 + for i, r := range name { + if '₀' <= r && r < '₀'+10 { + if startsub == -1 { + startsub = i + } + sub = sub*10 + uint64(r-'₀') + } + } + if startsub >= 0 { + name = name[:startsub] + } + index := int(r.int64()) + bound := r.typ() + tn := types2.NewTypeName(pos, r.currPkg, name, nil) + t := (*types2.Checker)(nil).NewTypeParam(tn, index, bound) + if sub >= 0 { + t.SetId(sub) + } + return t + + case instType: + pos := r.pos() + len := r.uint64() + targs := make([]types2.Type, len) + for i := range targs { + targs[i] = r.typ() + } + baseType := r.typ() + // The imported instantiated type doesn't include any methods, so + // we must always use the methods of the base (orig) type. + t := types2.Instantiate(pos, baseType, targs) + return t } } @@ -585,6 +647,19 @@ func (r *importReader) signature(recv *types2.Var) *types2.Signature { return types2.NewSignature(recv, params, results, variadic) } +func (r *importReader) tparamList() []*types2.TypeName { + n := r.uint64() + if n == 0 { + return nil + } + xs := make([]*types2.TypeName, n) + for i := range xs { + typ := r.typ() + xs[i] = types2.AsTypeParam(typ).Obj() + } + return xs +} + func (r *importReader) paramList() *types2.Tuple { xs := make([]*types2.Var, r.uint64()) for i := range xs { @@ -627,3 +702,13 @@ func (r *importReader) byte() byte { } return x } + +func baseType(typ types2.Type) *types2.Named { + // pointer receivers are never types2.Named types + if p, _ := typ.(*types2.Pointer); p != nil { + typ = p.Elem() + } + // receiver base types are always (possibly generic) types2.Named types + n, _ := typ.(*types2.Named) + return n +} diff --git a/src/cmd/compile/internal/noder/decl.go b/src/cmd/compile/internal/noder/decl.go index 3e55437afab..40cbe50affd 100644 --- a/src/cmd/compile/internal/noder/decl.go +++ b/src/cmd/compile/internal/noder/decl.go @@ -148,11 +148,15 @@ func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) { // [mdempsky: Subtleties like these are why I always vehemently // object to new type pragmas.] ntyp.SetUnderlying(g.typeExpr(decl.Type)) - if len(decl.TParamList) > 0 { - // Set HasTParam if there are any tparams, even if no tparams are - // used in the type itself (e.g., if it is an empty struct, or no - // fields in the struct use the tparam). - ntyp.SetHasTParam(true) + + tparams := otyp.(*types2.Named).TParams() + if len(tparams) > 0 { + rparams := make([]*types.Type, len(tparams)) + for i := range rparams { + rparams[i] = g.typ(tparams[i].Type()) + } + // This will set hasTParam flag if any rparams are not concrete types. + ntyp.SetRParams(rparams) } types.ResumeCheckSize() diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go index b7f7a34953a..f96144f8d70 100644 --- a/src/cmd/compile/internal/noder/expr.go +++ b/src/cmd/compile/internal/noder/expr.go @@ -264,8 +264,12 @@ func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.Selecto // instantiated for this method call. // selinfo.Recv() is the instantiated type recvType2 = recvType2Base - // method is the generic method associated with the gen type - method := g.obj(types2.AsNamed(recvType2).Method(last)) + recvTypeSym := g.pkg(method2.Pkg()).Lookup(recvType2.(*types2.Named).Obj().Name()) + recvType := recvTypeSym.Def.(*ir.Name).Type() + // method is the generic method associated with + // the base generic type. The instantiated type may not + // have method bodies filled in, if it was imported. + method := recvType.Methods().Index(last).Nname.(*ir.Name) n = ir.NewSelectorExpr(pos, ir.OCALLPART, x, typecheck.Lookup(expr.Sel.Value)) n.(*ir.SelectorExpr).Selection = types.NewField(pos, method.Sym(), method.Type()) n.(*ir.SelectorExpr).Selection.Nname = method diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go index 2a9f0e99d8a..f02246111fc 100644 --- a/src/cmd/compile/internal/noder/irgen.go +++ b/src/cmd/compile/internal/noder/irgen.go @@ -185,9 +185,9 @@ Outer: // Create any needed stencils of generic functions g.stencil() - // For now, remove all generic functions from g.target.Decl, since they - // have been used for stenciling, but don't compile. TODO: We will - // eventually export any exportable generic functions. + // Remove all generic functions from g.target.Decl, since they have been + // used for stenciling, but don't compile. Generic functions will already + // have been marked for export as appropriate. j := 0 for i, decl := range g.target.Decls { if decl.Op() != ir.ODCLFUNC || !decl.Type().HasTParam() { diff --git a/src/cmd/compile/internal/noder/object.go b/src/cmd/compile/internal/noder/object.go index 7af2fe6715e..a1a10e4eaaf 100644 --- a/src/cmd/compile/internal/noder/object.go +++ b/src/cmd/compile/internal/noder/object.go @@ -49,6 +49,11 @@ func (g *irgen) obj(obj types2.Object) *ir.Name { // For imported objects, we use iimport directly instead of mapping // the types2 representation. if obj.Pkg() != g.self { + if sig, ok := obj.Type().(*types2.Signature); ok && sig.Recv() != nil { + // We can't import a method by name - must import the type + // and access the method from it. + base.FatalfAt(g.pos(obj), "tried to import a method directly") + } sym := g.sym(obj) if sym.Def != nil { return sym.Def.(*ir.Name) @@ -165,9 +170,8 @@ func (g *irgen) objFinish(name *ir.Name, class ir.Class, typ *types.Type) { break // methods are exported with their receiver type } if types.IsExported(sym.Name) { - if name.Class == ir.PFUNC && name.Type().NumTParams() > 0 { - base.FatalfAt(name.Pos(), "Cannot export a generic function (yet): %v", name) - } + // Generic functions can be marked for export here, even + // though they will not be compiled until instantiated. typecheck.Export(name) } if base.Flag.AsmHdr != "" && !name.Sym().Asm() { diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index f9cf6d8a1a9..7a7c05280d7 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -8,12 +8,10 @@ package noder import ( - "bytes" "cmd/compile/internal/base" "cmd/compile/internal/ir" "cmd/compile/internal/typecheck" "cmd/compile/internal/types" - "cmd/internal/src" "fmt" "strings" ) @@ -160,9 +158,14 @@ func (g *irgen) stencil() { func (g *irgen) instantiateMethods() { for i := 0; i < len(g.instTypeList); i++ { typ := g.instTypeList[i] - // Get the base generic type by looking up the symbol of the - // generic (uninstantiated) name. - baseSym := typ.Sym().Pkg.Lookup(genericTypeName(typ.Sym())) + // Mark runtime type as needed, since this ensures that the + // compiler puts out the needed DWARF symbols, when this + // instantiated type has a different package from the local + // package. + typecheck.NeedRuntimeType(typ) + // Lookup the method on the base generic type, since methods may + // not be set on imported instantiated types. + baseSym := typ.OrigSym baseType := baseSym.Def.(*ir.Name).Type() for j, m := range typ.Methods().Slice() { name := m.Nname.(*ir.Name) @@ -199,12 +202,24 @@ func (g *irgen) getInstantiationForNode(inst *ir.InstExpr) *ir.Func { // with the type arguments targs. If the instantiated function is not already // cached, then it calls genericSubst to create the new instantiation. func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth bool) *ir.Func { + if nameNode.Func.Body == nil && nameNode.Func.Inl != nil { + // If there is no body yet but Func.Inl exists, then we can can + // import the whole generic body. + assert(nameNode.Func.Inl.Cost == 1 && nameNode.Sym().Pkg != types.LocalPkg) + typecheck.ImportBody(nameNode.Func) + assert(nameNode.Func.Inl.Body != nil) + nameNode.Func.Body = nameNode.Func.Inl.Body + nameNode.Func.Dcl = nameNode.Func.Inl.Dcl + } sym := typecheck.MakeInstName(nameNode.Sym(), targs, isMeth) st := g.target.Stencils[sym] if st == nil { // If instantiation doesn't exist yet, create it and add // to the list of decls. st = g.genericSubst(sym, nameNode, targs, isMeth) + // This ensures that the linker drops duplicates of this instantiation. + // All just works! + st.SetDupok(true) g.target.Stencils[sym] = st g.target.Decls = append(g.target.Decls, st) if base.Flag.W > 1 { @@ -626,21 +641,6 @@ func (subst *subster) tinter(t *types.Type) *types.Type { return t } -// instTypeName creates a name for an instantiated type, based on the name of the -// generic type and the type args -func instTypeName(name string, targs []*types.Type) string { - b := bytes.NewBufferString(name) - b.WriteByte('[') - for i, targ := range targs { - if i > 0 { - b.WriteByte(',') - } - b.WriteString(targ.String()) - } - b.WriteByte(']') - return b.String() -} - // typ computes the type obtained by substituting any type parameter in t with the // corresponding type argument in subst. If t contains no type parameters, the // result is t; otherwise the result is a new type. It deals with recursive types @@ -696,7 +696,7 @@ func (subst *subster) typ(t *types.Type) *types.Type { // already seen this type during this substitution or other // definitions/substitutions. genName := genericTypeName(t.Sym()) - newsym = t.Sym().Pkg.Lookup(instTypeName(genName, neededTargs)) + newsym = t.Sym().Pkg.Lookup(typecheck.InstTypeName(genName, neededTargs)) if newsym.Def != nil { // We've already created this instantiated defined type. return newsym.Def.Type() @@ -705,9 +705,13 @@ func (subst *subster) typ(t *types.Type) *types.Type { // In order to deal with recursive generic types, create a TFORW // type initially and set the Def field of its sym, so it can be // found if this type appears recursively within the type. - forw = newIncompleteNamedType(t.Pos(), newsym) + forw = typecheck.NewIncompleteNamedType(t.Pos(), newsym) //println("Creating new type by sub", newsym.Name, forw.HasTParam()) forw.SetRParams(neededTargs) + // Copy the OrigSym from the re-instantiated type (which is the sym of + // the base generic type). + assert(t.OrigSym != nil) + forw.OrigSym = t.OrigSym } var newt *types.Type @@ -865,11 +869,14 @@ func (subst *subster) fields(class ir.Class, oldfields []*types.Field, dcl []*ir for j := range oldfields { newfields[j] = oldfields[j].Copy() newfields[j].Type = subst.typ(oldfields[j].Type) - // A param field will be missing from dcl if its name is + // A PPARAM field will be missing from dcl if its name is // unspecified or specified as "_". So, we compare the dcl sym - // with the field sym. If they don't match, this dcl (if there is - // one left) must apply to a later field. - if i < len(dcl) && dcl[i].Sym() == oldfields[j].Sym { + // with the field sym (or sym of the field's Nname node). (Unnamed + // results still have a name like ~r2 in their Nname node.) If + // they don't match, this dcl (if there is one left) must apply to + // a later field. + if i < len(dcl) && (dcl[i].Sym() == oldfields[j].Sym || + (oldfields[j].Nname != nil && dcl[i].Sym() == oldfields[j].Nname.Sym())) { newfields[j].Nname = dcl[i] i++ } @@ -884,13 +891,3 @@ func deref(t *types.Type) *types.Type { } return t } - -// newIncompleteNamedType returns a TFORW type t with name specified by sym, such -// that t.nod and sym.Def are set correctly. -func newIncompleteNamedType(pos src.XPos, sym *types.Sym) *types.Type { - name := ir.NewDeclNameAt(pos, ir.OTYPE, sym) - forw := types.NewNamed(name) - name.SetType(forw) - sym.Def = name - return forw -} diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go index 35ba1cd2388..7fdad29e163 100644 --- a/src/cmd/compile/internal/noder/types.go +++ b/src/cmd/compile/internal/noder/types.go @@ -68,8 +68,10 @@ func instTypeName2(name string, targs []types2.Type) string { if i > 0 { b.WriteByte(',') } + // Include package names for all types, including typeparams, to + // make sure type arguments are uniquely specified. tname := types2.TypeString(targ, - func(*types2.Package) string { return "" }) + func(pkg *types2.Package) string { return pkg.Name() }) if strings.Index(tname, ", ") >= 0 { // types2.TypeString puts spaces after a comma in a type // list, but we don't want spaces in our actual type names @@ -120,7 +122,7 @@ func (g *irgen) typ0(typ types2.Type) *types.Type { // which may set HasTParam) before translating the // underlying type itself, so we handle recursion // correctly, including via method signatures. - ntyp := newIncompleteNamedType(g.pos(typ.Obj().Pos()), s) + ntyp := typecheck.NewIncompleteNamedType(g.pos(typ.Obj().Pos()), s) g.typs[typ] = ntyp // If ntyp still has type params, then we must be @@ -143,6 +145,8 @@ func (g *irgen) typ0(typ types2.Type) *types.Type { ntyp.SetUnderlying(g.typ1(typ.Underlying())) g.fillinMethods(typ, ntyp) + // Save the symbol for the base generic type. + ntyp.OrigSym = g.pkg(typ.Obj().Pkg()).Lookup(typ.Obj().Name()) return ntyp } obj := g.obj(typ.Obj()) @@ -206,8 +210,19 @@ func (g *irgen) typ0(typ types2.Type) *types.Type { case *types2.TypeParam: // Save the name of the type parameter in the sym of the type. // Include the types2 subscript in the sym name - sym := g.pkg(typ.Obj().Pkg()).Lookup(types2.TypeString(typ, func(*types2.Package) string { return "" })) + pkg := g.tpkg(typ) + sym := pkg.Lookup(types2.TypeString(typ, func(*types2.Package) string { return "" })) + if sym.Def != nil { + // Make sure we use the same type param type for the same + // name, whether it is created during types1-import or + // this types2-to-types1 translation. + return sym.Def.Type() + } tp := types.NewTypeParam(sym, typ.Index()) + nname := ir.NewDeclNameAt(g.pos(typ.Obj().Pos()), ir.OTYPE, sym) + sym.Def = nname + nname.SetType(tp) + tp.SetNod(nname) // Set g.typs[typ] in case the bound methods reference typ. g.typs[typ] = tp @@ -248,12 +263,20 @@ func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) { methods := make([]*types.Field, typ.NumMethods()) for i := range methods { m := typ.Method(i) - meth := g.obj(m) recvType := types2.AsSignature(m.Type()).Recv().Type() ptr := types2.AsPointer(recvType) if ptr != nil { recvType = ptr.Elem() } + var meth *ir.Name + if m.Pkg() != g.self { + // Imported methods cannot be loaded by name (what + // g.obj() does) - they must be loaded via their + // type. + meth = g.obj(recvType.(*types2.Named).Obj()).Type().Methods().Index(i).Nname.(*ir.Name) + } else { + meth = g.obj(m) + } if recvType != types2.Type(typ) { // Unfortunately, meth is the type of the method of the // generic type, so we have to do a substitution to get @@ -343,7 +366,7 @@ func (g *irgen) selector(obj types2.Object) *types.Sym { return pkg.Lookup(name) } -// tpkg returns the package that a function, interface, or struct type +// tpkg returns the package that a function, interface, struct, or typeparam type // expression appeared in. // // Caveat: For the degenerate types "func()", "interface{}", and @@ -373,6 +396,8 @@ func (g *irgen) tpkg(typ types2.Type) *types.Pkg { if typ.NumExplicitMethods() > 0 { return typ.ExplicitMethod(0) } + case *types2.TypeParam: + return typ.Obj() } return nil } diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index 8c0e33f6df1..f65841b33c5 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -951,8 +951,12 @@ func writeType(t *types.Type) *obj.LSym { } if base.Ctxt.Pkgpath != "runtime" || (tbase != types.Types[tbase.Kind()] && tbase != types.ByteType && tbase != types.RuneType && tbase != types.ErrorType) { // int, float, etc - // named types from other files are defined only by those files - if tbase.Sym() != nil && tbase.Sym().Pkg != types.LocalPkg { + // Named types from other files are defined only by those files. + // However, as an exception, we can write out instantiated types + // in the local package, even if they may be marked as part of + // another package (the package of their base generic type). + if tbase.Sym() != nil && tbase.Sym().Pkg != types.LocalPkg && + len(tbase.RParams()) == 0 { if i := typecheck.BaseTypeIndex(t); i >= 0 { lsym.Pkg = tbase.Sym().Pkg.Prefix lsym.SymIdx = int32(i) diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index 3538c4d5a66..11b9755148e 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -173,6 +173,8 @@ // } // // +// TODO(danscales): fill in doc for 'type TypeParamType' and 'type InstType' +// // type Signature struct { // Params []Param // Results []Param @@ -244,6 +246,8 @@ const ( signatureType structType interfaceType + typeParamType + instType ) const ( @@ -459,6 +463,13 @@ func (p *iexporter) doDecl(n *ir.Name) { // Function. w.tag('F') w.pos(n.Pos()) + // The tparam list of the function type is the + // declaration of the type params. So, write out the type + // params right now. Then those type params will be + // referenced via their type offset (via typOff) in all + // other places in the signature and function that they + // are used. + w.tparamList(n.Type().TParams().FieldSlice()) w.signature(n.Type()) w.funcExt(n) @@ -491,6 +502,8 @@ func (p *iexporter) doDecl(n *ir.Name) { w.tag('T') w.pos(n.Pos()) + // Export any new typeparams needed for this type + w.typeList(n.Type().RParams()) underlying := n.Type().Underlying() if underlying == types.ErrorType.Underlying() { // For "type T error", use error as the @@ -803,8 +816,49 @@ func (w *exportWriter) startType(k itag) { } func (w *exportWriter) doTyp(t *types.Type) { - if t.Sym() != nil { - if t.Sym().Pkg == types.BuiltinPkg || t.Sym().Pkg == ir.Pkgs.Unsafe { + if t.Kind() == types.TTYPEPARAM { + // A typeparam has a name, but doesn't have an underlying type. + // Just write out the details of the type param here. All other + // uses of this typeparam type will be written out as its unique + // type offset. + w.startType(typeParamType) + s := t.Sym() + w.setPkg(s.Pkg, true) + w.pos(t.Pos()) + + // We are writing out the name with the subscript, so that the + // typeparam name is unique. + w.string(s.Name) + w.int64(int64(t.Index())) + + w.typ(t.Bound()) + return + } + + s := t.Sym() + if s != nil && t.OrigSym != nil { + // This is an instantiated type - could be a re-instantiation like + // Value[T2] or a full instantiation like Value[int]. + if strings.Index(s.Name, "[") < 0 { + base.Fatalf("incorrect name for instantiated type") + } + w.startType(instType) + w.pos(t.Pos()) + // Export the type arguments for the instantiated type. The + // instantiated type could be in a method header (e.g. "func (v + // *Value[T2]) set (...) { ... }"), so the type args are "new" + // typeparams. Or the instantiated type could be in a + // function/method body, so the type args are either concrete + // types or existing typeparams from the function/method header. + w.typeList(t.RParams()) + // Export a reference to the base type. + baseType := t.OrigSym.Def.(*ir.Name).Type() + w.typ(baseType) + return + } + + if s != nil { + if s.Pkg == types.BuiltinPkg || s.Pkg == ir.Pkgs.Unsafe { base.Fatalf("builtin type missing from typIndex: %v", t) } @@ -906,6 +960,23 @@ func (w *exportWriter) signature(t *types.Type) { } } +func (w *exportWriter) typeList(ts []*types.Type) { + w.uint64(uint64(len(ts))) + for _, rparam := range ts { + w.typ(rparam) + } +} + +func (w *exportWriter) tparamList(fs []*types.Field) { + w.uint64(uint64(len(fs))) + for _, f := range fs { + if f.Type.Kind() != types.TTYPEPARAM { + base.Fatalf("unexpected non-typeparam") + } + w.typ(f.Type) + } +} + func (w *exportWriter) paramList(fs []*types.Field) { w.uint64(uint64(len(fs))) for _, f := range fs { @@ -1186,9 +1257,21 @@ func (w *exportWriter) funcExt(n *ir.Name) { } // Inline body. + if n.Type().HasTParam() { + if n.Func.Inl != nil { + base.FatalfAt(n.Pos(), "generic function is marked inlineable") + } + // Populate n.Func.Inl, so body of exported generic function will + // be written out. + n.Func.Inl = &ir.Inline{ + Cost: 1, + Dcl: n.Func.Dcl, + Body: n.Func.Body, + } + } if n.Func.Inl != nil { w.uint64(1 + uint64(n.Func.Inl.Cost)) - if n.Func.ExportInline() { + if n.Func.ExportInline() || n.Type().HasTParam() { w.p.doInline(n) } @@ -1588,9 +1671,8 @@ func (w *exportWriter) expr(n ir.Node) { case ir.OXDOT, ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH, ir.OCALLPART, ir.OMETHEXPR: n := n.(*ir.SelectorExpr) if go117ExportTypes { - if n.Op() == ir.OXDOT { - base.Fatalf("shouldn't encounter XDOT in new exporter") - } + // For go117ExportTypes, we usually see all ops except + // OXDOT, but we can see OXDOT for generic functions. w.op(n.Op()) } else { w.op(ir.OXDOT) @@ -1604,7 +1686,8 @@ func (w *exportWriter) expr(n ir.Node) { w.exoticField(n.Selection) } // n.Selection is not required for OMETHEXPR, ODOTMETH, and OCALLPART. It will - // be reconstructed during import. + // be reconstructed during import. n.Selection is computed during + // transformDot() for OXDOT. } case ir.ODOTTYPE, ir.ODOTTYPE2: diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index a5ddbb5a74c..b6f227bb00e 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -8,6 +8,7 @@ package typecheck import ( + "bytes" "encoding/binary" "fmt" "go/constant" @@ -313,13 +314,16 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name { return n case 'F': - typ := r.signature(nil) + tparams := r.tparamList() + typ := r.signature(nil, tparams) n := importfunc(r.p.ipkg, pos, sym, typ) r.funcExt(n) return n case 'T': + rparams := r.typeList() + // Types can be recursive. We need to setup a stub // declaration before recursing. n := importtype(r.p.ipkg, pos, sym) @@ -332,6 +336,10 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name { t.SetUnderlying(underlying) types.ResumeCheckSize() + if rparams != nil { + t.SetRParams(rparams) + } + if underlying.IsInterface() { r.typeExt(t) return n @@ -342,7 +350,7 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name { mpos := r.pos() msym := r.selector() recv := r.param() - mtyp := r.signature(recv) + mtyp := r.signature(recv, nil) // MethodSym already marked m.Sym as a function. m := ir.NewNameAt(mpos, ir.MethodSym(recv.Type, msym)) @@ -680,7 +688,7 @@ func (r *importReader) typ1() *types.Type { case signatureType: r.setPkg() - return r.signature(nil) + return r.signature(nil, nil) case structType: r.setPkg() @@ -718,7 +726,7 @@ func (r *importReader) typ1() *types.Type { for i := range methods { pos := r.pos() sym := r.selector() - typ := r.signature(fakeRecvField()) + typ := r.signature(fakeRecvField(), nil) methods[i] = types.NewField(pos, sym, typ) } @@ -728,6 +736,40 @@ func (r *importReader) typ1() *types.Type { // Ensure we expand the interface in the frontend (#25055). types.CheckSize(t) return t + + case typeParamType: + r.setPkg() + pos := r.pos() + name := r.string() + sym := r.currPkg.Lookup(name) + index := int(r.int64()) + bound := r.typ() + if sym.Def != nil { + // Make sure we use the same type param type for the same + // name, whether it is created during types1-import or + // this types2-to-types1 translation. + return sym.Def.Type() + } + t := types.NewTypeParam(sym, index) + // Nname needed to save the pos. + nname := ir.NewDeclNameAt(pos, ir.OTYPE, sym) + sym.Def = nname + nname.SetType(t) + t.SetNod(nname) + + t.SetBound(bound) + return t + + case instType: + pos := r.pos() + len := r.uint64() + targs := make([]*types.Type, len) + for i := range targs { + targs[i] = r.typ() + } + baseType := r.typ() + t := Instantiate(pos, baseType, targs) + return t } } @@ -735,13 +777,38 @@ func (r *importReader) kind() itag { return itag(r.uint64()) } -func (r *importReader) signature(recv *types.Field) *types.Type { +func (r *importReader) signature(recv *types.Field, tparams []*types.Field) *types.Type { params := r.paramList() results := r.paramList() if n := len(params); n > 0 { params[n-1].SetIsDDD(r.bool()) } - return types.NewSignature(r.currPkg, recv, nil, params, results) + return types.NewSignature(r.currPkg, recv, tparams, params, results) +} + +func (r *importReader) typeList() []*types.Type { + n := r.uint64() + if n == 0 { + return nil + } + ts := make([]*types.Type, n) + for i := range ts { + ts[i] = r.typ() + } + return ts +} + +func (r *importReader) tparamList() []*types.Field { + n := r.uint64() + if n == 0 { + return nil + } + fs := make([]*types.Field, n) + for i := range fs { + typ := r.typ() + fs[i] = types.NewField(typ.Pos(), typ.Sym(), typ) + } + return fs } func (r *importReader) paramList() []*types.Field { @@ -809,7 +876,9 @@ func (r *importReader) funcExt(n *ir.Name) { n.Func.ABI = obj.ABI(r.uint64()) - n.SetPragma(ir.PragmaFlag(r.uint64())) + // Make sure //go:noinline pragma is imported (so stenciled functions have + // same noinline status as the corresponding generic function.) + n.Func.Pragma = ir.PragmaFlag(r.uint64()) // Escape analysis. for _, fs := range &types.RecvsParams { @@ -1117,7 +1186,7 @@ func (r *importReader) node() ir.Node { case ir.OCLOSURE: //println("Importing CLOSURE") pos := r.pos() - typ := r.signature(nil) + typ := r.signature(nil, nil) // All the remaining code below is similar to (*noder).funcLit(), but // with Dcls and ClosureVars lists already set up @@ -1202,35 +1271,32 @@ func (r *importReader) node() ir.Node { // case OSTRUCTKEY: // unreachable - handled in case OSTRUCTLIT by elemList - case ir.OXDOT: - // see parser.new_dotname - if go117ExportTypes { - base.Fatalf("shouldn't encounter XDOT in new importer") - } - return ir.NewSelectorExpr(r.pos(), ir.OXDOT, r.expr(), r.exoticSelector()) - - case ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH, ir.OCALLPART, ir.OMETHEXPR: - if !go117ExportTypes { - // unreachable - mapped to case OXDOT by exporter + case ir.OXDOT, ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH, ir.OCALLPART, ir.OMETHEXPR: + // For !go117ExportTypes, we should only see OXDOT. + // For go117ExportTypes, we usually see all the other ops, but can see + // OXDOT for generic functions. + if op != ir.OXDOT && !go117ExportTypes { goto error } pos := r.pos() expr := r.expr() sel := r.exoticSelector() n := ir.NewSelectorExpr(pos, op, expr, sel) - n.SetType(r.exoticType()) - switch op { - case ir.ODOT, ir.ODOTPTR, ir.ODOTINTER: - n.Selection = r.exoticField() - case ir.ODOTMETH, ir.OCALLPART, ir.OMETHEXPR: - // These require a Lookup to link to the correct declaration. - rcvrType := expr.Type() - typ := n.Type() - n.Selection = Lookdot(n, rcvrType, 1) - if op == ir.OCALLPART || op == ir.OMETHEXPR { - // Lookdot clobbers the opcode and type, undo that. - n.SetOp(op) - n.SetType(typ) + if go117ExportTypes { + n.SetType(r.exoticType()) + switch op { + case ir.ODOT, ir.ODOTPTR, ir.ODOTINTER: + n.Selection = r.exoticField() + case ir.ODOTMETH, ir.OCALLPART, ir.OMETHEXPR: + // These require a Lookup to link to the correct declaration. + rcvrType := expr.Type() + typ := n.Type() + n.Selection = Lookdot(n, rcvrType, 1) + if op == ir.OCALLPART || op == ir.OMETHEXPR { + // Lookdot clobbers the opcode and type, undo that. + n.SetOp(op) + n.SetType(typ) + } } } return n @@ -1544,3 +1610,63 @@ func builtinCall(pos src.XPos, op ir.Op) *ir.CallExpr { } return ir.NewCallExpr(pos, ir.OCALL, ir.NewIdent(base.Pos, types.BuiltinPkg.Lookup(ir.OpNames[op])), nil) } + +// InstTypeName creates a name for an instantiated type, based on the name of the +// generic type and the type args. +func InstTypeName(name string, targs []*types.Type) string { + b := bytes.NewBufferString(name) + b.WriteByte('[') + for i, targ := range targs { + if i > 0 { + b.WriteByte(',') + } + // WriteString() does not include the package name for the local + // package, but we want it to make sure type arguments (including + // type params) are uniquely specified. + if targ.Sym() != nil && targ.Sym().Pkg == types.LocalPkg { + b.WriteString(targ.Sym().Pkg.Name) + b.WriteByte('.') + } + b.WriteString(targ.String()) + } + b.WriteByte(']') + return b.String() +} + +// NewIncompleteNamedType returns a TFORW type t with name specified by sym, such +// that t.nod and sym.Def are set correctly. +func NewIncompleteNamedType(pos src.XPos, sym *types.Sym) *types.Type { + name := ir.NewDeclNameAt(pos, ir.OTYPE, sym) + forw := types.NewNamed(name) + name.SetType(forw) + sym.Def = name + return forw +} + +// Instantiate creates a new named type which is the instantiation of the base +// named generic type, with the specified type args. +func Instantiate(pos src.XPos, baseType *types.Type, targs []*types.Type) *types.Type { + baseSym := baseType.Sym() + if strings.Index(baseSym.Name, "[") >= 0 { + base.Fatalf("arg to Instantiate is not a base generic type") + } + name := InstTypeName(baseSym.Name, targs) + instSym := baseSym.Pkg.Lookup(name) + if instSym.Def != nil { + return instSym.Def.Type() + } + + t := NewIncompleteNamedType(baseType.Pos(), instSym) + t.SetRParams(targs) + // baseType may not yet be complete (since we are in the middle of + // importing it), but its underlying type will be updated when baseType's + // underlying type is finished. + t.SetUnderlying(baseType.Underlying()) + + // As with types2, the methods are the generic method signatures (without + // substitution). + t.Methods().Set(baseType.Methods().Slice()) + t.OrigSym = baseSym + + return t +} diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index 97fb1451327..9eac802dab8 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -887,7 +887,7 @@ func TypesOf(x []ir.Node) []*types.Type { } // MakeInstName makes the unique name for a stenciled generic function or method, -// based on the name of the function fy=nsym and the targs. It replaces any +// based on the name of the function fnsym and the targs. It replaces any // existing bracket type list in the name. makeInstName asserts that fnsym has // brackets in its name if and only if hasBrackets is true. // TODO(danscales): remove the assertions and the hasBrackets argument later. @@ -914,6 +914,12 @@ func MakeInstName(fnsym *types.Sym, targs []*types.Type, hasBrackets bool) *type if i > 0 { b.WriteString(",") } + // WriteString() does not include the package name for the local + // package, but we want it for uniqueness. + if targ.Sym() != nil && targ.Sym().Pkg == types.LocalPkg { + b.WriteString(targ.Sym().Pkg.Name) + b.WriteByte('.') + } b.WriteString(targ.String()) } b.WriteString("]") @@ -922,7 +928,7 @@ func MakeInstName(fnsym *types.Sym, targs []*types.Type, hasBrackets bool) *type assert(i2 >= 0) b.WriteString(name[i+i2+1:]) } - return Lookup(b.String()) + return fnsym.Pkg.Lookup(b.String()) } // For catching problems as we add more features diff --git a/src/cmd/compile/internal/types/sizeof_test.go b/src/cmd/compile/internal/types/sizeof_test.go index 70289387421..7349e52a73e 100644 --- a/src/cmd/compile/internal/types/sizeof_test.go +++ b/src/cmd/compile/internal/types/sizeof_test.go @@ -21,7 +21,7 @@ func TestSizeof(t *testing.T) { _64bit uintptr // size on 64bit platforms }{ {Sym{}, 44, 72}, - {Type{}, 60, 104}, + {Type{}, 64, 112}, {Map{}, 20, 40}, {Forward{}, 20, 32}, {Func{}, 28, 48}, diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index d3c02fc56d3..3b0a9706f65 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -182,12 +182,19 @@ type Type struct { flags bitset8 // For defined (named) generic types, a pointer to the list of type params - // (in order) of this type that need to be instantiated. For - // fully-instantiated generic types, this is the targs used to instantiate - // them (which are used when generating the corresponding instantiated - // methods). rparams is only set for named types that are generic or are - // fully-instantiated from a generic type, and is otherwise set to nil. + // (in order) of this type that need to be instantiated. For instantiated + // generic types, this is the targs used to instantiate them. These targs + // may be typeparams (for re-instantiated types such as Value[T2]) or + // concrete types (for fully instantiated types such as Value[int]). + // rparams is only set for named types that are generic or are fully + // instantiated from a generic type, and is otherwise set to nil. + // TODO(danscales): choose a better name. rparams *[]*Type + + // For an instantiated generic type, the symbol for the base generic type. + // This backpointer is useful, because the base type is the type that has + // the method bodies. + OrigSym *Sym } func (*Type) CanBeAnSSAAux() {} @@ -213,7 +220,9 @@ func (t *Type) SetBroke(b bool) { t.flags.set(typeBroke, b) } func (t *Type) SetNoalg(b bool) { t.flags.set(typeNoalg, b) } func (t *Type) SetDeferwidth(b bool) { t.flags.set(typeDeferwidth, b) } func (t *Type) SetRecur(b bool) { t.flags.set(typeRecur, b) } -func (t *Type) SetHasTParam(b bool) { t.flags.set(typeHasTParam, b) } + +// Generic types should never have alg functions. +func (t *Type) SetHasTParam(b bool) { t.flags.set(typeHasTParam, b); t.flags.set(typeNoalg, b) } // Kind returns the kind of type t. func (t *Type) Kind() Kind { return t.kind } diff --git a/src/cmd/compile/internal/types2/api_test.go b/src/cmd/compile/internal/types2/api_test.go index e1020a12194..d82d29cad87 100644 --- a/src/cmd/compile/internal/types2/api_test.go +++ b/src/cmd/compile/internal/types2/api_test.go @@ -329,23 +329,23 @@ func TestTypesInfo(t *testing.T) { {brokenPkg + `x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string]invalid type`}, // parameterized functions - {genericPkg + `p0; func f[T any](T); var _ = f[int]`, `f`, `func[T₁ interface{}](T₁)`}, + {genericPkg + `p0; func f[T any](T); var _ = f[int]`, `f`, `func[generic_p0.T₁ interface{}](generic_p0.T₁)`}, {genericPkg + `p1; func f[T any](T); var _ = f[int]`, `f[int]`, `func(int)`}, - {genericPkg + `p2; func f[T any](T); func _() { f(42) }`, `f`, `func[T₁ interface{}](T₁)`}, + {genericPkg + `p2; func f[T any](T); func _() { f(42) }`, `f`, `func[generic_p2.T₁ interface{}](generic_p2.T₁)`}, {genericPkg + `p3; func f[T any](T); func _() { f(42) }`, `f(42)`, `()`}, // type parameters {genericPkg + `t0; type t[] int; var _ t`, `t`, `generic_t0.t`}, // t[] is a syntax error that is ignored in this test in favor of t - {genericPkg + `t1; type t[P any] int; var _ t[int]`, `t`, `generic_t1.t[P₁ interface{}]`}, - {genericPkg + `t2; type t[P interface{}] int; var _ t[int]`, `t`, `generic_t2.t[P₁ interface{}]`}, - {genericPkg + `t3; type t[P, Q interface{}] int; var _ t[int, int]`, `t`, `generic_t3.t[P₁, Q₂ interface{}]`}, - {brokenPkg + `t4; type t[P, Q interface{ m() }] int; var _ t[int, int]`, `t`, `broken_t4.t[P₁, Q₂ interface{m()}]`}, + {genericPkg + `t1; type t[P any] int; var _ t[int]`, `t`, `generic_t1.t[generic_t1.P₁ interface{}]`}, + {genericPkg + `t2; type t[P interface{}] int; var _ t[int]`, `t`, `generic_t2.t[generic_t2.P₁ interface{}]`}, + {genericPkg + `t3; type t[P, Q interface{}] int; var _ t[int, int]`, `t`, `generic_t3.t[generic_t3.P₁, generic_t3.Q₂ interface{}]`}, + {brokenPkg + `t4; type t[P, Q interface{ m() }] int; var _ t[int, int]`, `t`, `broken_t4.t[broken_t4.P₁, broken_t4.Q₂ interface{m()}]`}, // instantiated types must be sanitized {genericPkg + `g0; type t[P any] int; var x struct{ f t[int] }; var _ = x.f`, `x.f`, `generic_g0.t[int]`}, // issue 45096 - {genericPkg + `issue45096; func _[T interface{ type int8, int16, int32 }](x T) { _ = x < 0 }`, `0`, `T₁`}, + {genericPkg + `issue45096; func _[T interface{ type int8, int16, int32 }](x T) { _ = x < 0 }`, `0`, `generic_issue45096.T₁`}, } for _, test := range tests { diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index cf119a1b23b..55c2f336ce8 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -250,6 +250,9 @@ func (s *Signature) RParams() []*TypeName { return s.rparams } // SetTParams sets the type parameters of signature s. func (s *Signature) SetTParams(tparams []*TypeName) { s.tparams = tparams } +// SetRParams sets the receiver type params of signature s. +func (s *Signature) SetRParams(rparams []*TypeName) { s.rparams = rparams } + // Params returns the parameters of signature s, or nil. func (s *Signature) Params() *Tuple { return s.params } @@ -771,6 +774,12 @@ func (t *TypeParam) Index() int { return t.index } +// SetId sets the unique id of a type param. Should only be used for type params +// in imported generic types. +func (t *TypeParam) SetId(id uint64) { + t.id = id +} + func (t *TypeParam) Bound() *Interface { iface := asInterface(t.bound) // use the type bound position if we have one @@ -1002,3 +1011,4 @@ func AsPointer(t Type) *Pointer { return asPointer(t) } func AsNamed(t Type) *Named { return asNamed(t) } func AsSignature(t Type) *Signature { return asSignature(t) } func AsInterface(t Type) *Interface { return asInterface(t) } +func AsTypeParam(t Type) *TypeParam { return asTypeParam(t) } diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go index e85cc8ed358..c534b041308 100644 --- a/src/cmd/compile/internal/types2/typestring.go +++ b/src/cmd/compile/internal/types2/typestring.go @@ -281,6 +281,13 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { case *TypeParam: s := "?" if t.obj != nil { + // Optionally write out package for typeparams (like Named). + // TODO(danscales): this is required for import/export, so + // we maybe need a separate function that won't be changed + // for debugging purposes. + if t.obj.pkg != nil { + writePackage(buf, t.obj.pkg, qf) + } s = t.obj.name } buf.WriteString(s + subscript(t.id)) diff --git a/src/go/internal/gcimporter/gcimporter_test.go b/src/go/internal/gcimporter/gcimporter_test.go index 3c76aafde39..c010dc506e7 100644 --- a/src/go/internal/gcimporter/gcimporter_test.go +++ b/src/go/internal/gcimporter/gcimporter_test.go @@ -138,7 +138,8 @@ func TestVersionHandling(t *testing.T) { skipSpecialPlatforms(t) // This package only handles gc export data. - if runtime.Compiler != "gc" { + // Disable test until we put in the new export version. + if true || runtime.Compiler != "gc" { t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler) } diff --git a/src/go/internal/gcimporter/iimport.go b/src/go/internal/gcimporter/iimport.go index a3184e7641a..4416f5b2b92 100644 --- a/src/go/internal/gcimporter/iimport.go +++ b/src/go/internal/gcimporter/iimport.go @@ -55,6 +55,8 @@ const ( signatureType structType interfaceType + typeParamType + instType ) // iImportData imports a package from the serialized package data @@ -271,11 +273,21 @@ func (r *importReader) obj(name string) { r.declare(types.NewConst(pos, r.currPkg, name, typ, val)) case 'F': + numTparams := r.uint64() + if numTparams > 0 { + errorf("unexpected tparam") + return + } sig := r.signature(nil) r.declare(types.NewFunc(pos, r.currPkg, name, sig)) case 'T': + numTparams := r.uint64() + if numTparams > 0 { + errorf("unexpected tparam") + } + // Types can be recursive. We need to setup a stub // declaration before recursing. obj := types.NewTypeName(pos, r.currPkg, name, nil) @@ -548,6 +560,14 @@ func (r *importReader) doType(base *types.Named) types.Type { typ := types.NewInterfaceType(methods, embeddeds) r.p.interfaceList = append(r.p.interfaceList, typ) return typ + + case typeParamType: + errorf("do not handle tparams yet") + return nil + + case instType: + errorf("do not handle instantiated types yet") + return nil } } diff --git a/test/typeparam/adder.go b/test/typeparam/adder.go index 0c25ad4ef2d..eb564b5bd54 100644 --- a/test/typeparam/adder.go +++ b/test/typeparam/adder.go @@ -14,16 +14,16 @@ type AddType interface { type int, int64, string } -// _Add can add numbers or strings -func _Add[T AddType](a, b T) T { +// Add can add numbers or strings +func Add[T AddType](a, b T) T { return a + b } func main() { - if got, want := _Add(5, 3), 8; got != want { + if got, want := Add(5, 3), 8; got != want { panic(fmt.Sprintf("got %d, want %d", got, want)) } - if got, want := _Add("ab", "cd"), "abcd"; got != want { + if got, want := Add("ab", "cd"), "abcd"; got != want { panic(fmt.Sprintf("got %d, want %d", got, want)) } } diff --git a/test/typeparam/min.go b/test/typeparam/min.go index a3e4464a303..6e28c062a8a 100644 --- a/test/typeparam/min.go +++ b/test/typeparam/min.go @@ -11,7 +11,7 @@ import ( ) type Ordered interface { - type int, int64, float64 + type int, int64, float64, string } func min[T Ordered](x, y T) T { @@ -38,4 +38,13 @@ func main() { if got := min(3.5, 2.0); got != want { panic(fmt.Sprintf("got %d, want %d", got, want)) } + + const want2 = "ay" + if got := min[string]("bb", "ay"); got != want2 { + panic(fmt.Sprintf("got %d, want %d", got, want2)) + } + + if got := min("bb", "ay"); got != want2 { + panic(fmt.Sprintf("got %d, want %d", got, want2)) + } } diff --git a/test/typeparam/minimp.dir/a.go b/test/typeparam/minimp.dir/a.go new file mode 100644 index 00000000000..16c1b035f48 --- /dev/null +++ b/test/typeparam/minimp.dir/a.go @@ -0,0 +1,16 @@ +// Copyright 2021 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 a + +type Ordered interface { + type int, int64, float64, string +} + +func Min[T Ordered](x, y T) T { + if x < y { + return x + } + return y +} diff --git a/test/typeparam/minimp.dir/main.go b/test/typeparam/minimp.dir/main.go new file mode 100644 index 00000000000..509f5aaed2b --- /dev/null +++ b/test/typeparam/minimp.dir/main.go @@ -0,0 +1,38 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "a" + "fmt" +) + +func main() { + const want = 2 + if got := a.Min[int](2, 3); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + if got := a.Min(2, 3); got != want { + panic(fmt.Sprintf("want %d, got %d", want, got)) + } + + if got := a.Min[float64](3.5, 2.0); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + if got := a.Min(3.5, 2.0); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + const want2 = "ay" + if got := a.Min[string]("bb", "ay"); got != want2 { + panic(fmt.Sprintf("got %d, want %d", got, want2)) + } + + if got := a.Min("bb", "ay"); got != want2 { + panic(fmt.Sprintf("got %d, want %d", got, want2)) + } +} diff --git a/test/typeparam/minimp.go b/test/typeparam/minimp.go new file mode 100644 index 00000000000..76930e5e4f6 --- /dev/null +++ b/test/typeparam/minimp.go @@ -0,0 +1,7 @@ +// rundir -G=3 + +// Copyright 2021 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 ignored diff --git a/test/typeparam/pair.go b/test/typeparam/pair.go index 7faf083c89d..57742022b10 100644 --- a/test/typeparam/pair.go +++ b/test/typeparam/pair.go @@ -24,6 +24,7 @@ func main() { if got, want := unsafe.Sizeof(p.f2), uintptr(8); got != want { panic(fmt.Sprintf("unexpected f2 size == %d, want %d", got, want)) } + type mypair struct { f1 int32; f2 int64 } mp := mypair(p) if mp.f1 != 1 || mp.f2 != 2 { diff --git a/test/typeparam/pairimp.dir/a.go b/test/typeparam/pairimp.dir/a.go new file mode 100644 index 00000000000..27b2412961b --- /dev/null +++ b/test/typeparam/pairimp.dir/a.go @@ -0,0 +1,10 @@ +// Copyright 2021 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 a + +type Pair[F1, F2 any] struct { + Field1 F1 + Field2 F2 +} diff --git a/test/typeparam/pairimp.dir/main.go b/test/typeparam/pairimp.dir/main.go new file mode 100644 index 00000000000..fc2face81df --- /dev/null +++ b/test/typeparam/pairimp.dir/main.go @@ -0,0 +1,27 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "a" + "fmt" + "unsafe" +) + +func main() { + p := a.Pair[int32, int64]{1, 2} + if got, want := unsafe.Sizeof(p.Field1), uintptr(4); got != want { + panic(fmt.Sprintf("unexpected f1 size == %d, want %d", got, want)) + } + if got, want := unsafe.Sizeof(p.Field2), uintptr(8); got != want { + panic(fmt.Sprintf("unexpected f2 size == %d, want %d", got, want)) + } + + type mypair struct { Field1 int32; Field2 int64 } + mp := mypair(p) + if mp.Field1 != 1 || mp.Field2 != 2 { + panic(fmt.Sprintf("mp == %#v, want %#v", mp, mypair{1, 2})) + } +} diff --git a/test/typeparam/pairimp.go b/test/typeparam/pairimp.go new file mode 100644 index 00000000000..76930e5e4f6 --- /dev/null +++ b/test/typeparam/pairimp.go @@ -0,0 +1,7 @@ +// rundir -G=3 + +// Copyright 2021 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 ignored diff --git a/test/typeparam/settable.go b/test/typeparam/settable.go index 588166da858..d0b831b5333 100644 --- a/test/typeparam/settable.go +++ b/test/typeparam/settable.go @@ -13,13 +13,13 @@ import ( // Various implementations of fromStrings(). -type _Setter[B any] interface { +type Setter[B any] interface { Set(string) type *B } // Takes two type parameters where PT = *T -func fromStrings1[T any, PT _Setter[T]](s []string) []T { +func fromStrings1[T any, PT Setter[T]](s []string) []T { result := make([]T, len(s)) for i, v := range s { // The type of &result[i] is *T which is in the type list @@ -31,7 +31,7 @@ func fromStrings1[T any, PT _Setter[T]](s []string) []T { return result } -func fromStrings1a[T any, PT _Setter[T]](s []string) []PT { +func fromStrings1a[T any, PT Setter[T]](s []string) []PT { result := make([]PT, len(s)) for i, v := range s { // The type new(T) is *T which is in the type list @@ -54,12 +54,12 @@ func fromStrings2[T any](s []string, set func(*T, string)) []T { return results } -type _Setter2 interface { +type Setter2 interface { Set(string) } // Takes only one type parameter, but causes a panic (see below) -func fromStrings3[T _Setter2](s []string) []T { +func fromStrings3[T Setter2](s []string) []T { results := make([]T, len(s)) for i, v := range s { // Panics if T is a pointer type because receiver is T(nil). diff --git a/test/typeparam/smallest.go b/test/typeparam/smallest.go index 63dd9ddb700..d8515360497 100644 --- a/test/typeparam/smallest.go +++ b/test/typeparam/smallest.go @@ -17,7 +17,7 @@ type Ordered interface { string } -func smallest[T Ordered](s []T) T { +func Smallest[T Ordered](s []T) T { r := s[0] // panics if slice is empty for _, v := range s[1:] { if v < r { @@ -32,11 +32,11 @@ func main() { vec2 := []string{"abc", "def", "aaa"} want1 := 1.2 - if got := smallest(vec1); got != want1 { + if got := Smallest(vec1); got != want1 { panic(fmt.Sprintf("got %d, want %d", got, want1)) } want2 := "aaa" - if got := smallest(vec2); got != want2 { + if got := Smallest(vec2); got != want2 { panic(fmt.Sprintf("got %d, want %d", got, want2)) } } diff --git a/test/typeparam/stringable.go b/test/typeparam/stringable.go index 9340a3b10a9..20da012cb87 100644 --- a/test/typeparam/stringable.go +++ b/test/typeparam/stringable.go @@ -16,11 +16,11 @@ type Stringer interface { String() string } -// stringableList is a slice of some type, where the type +// StringableList is a slice of some type, where the type // must have a String method. -type stringableList[T Stringer] []T +type StringableList[T Stringer] []T -func (s stringableList[T]) String() string { +func (s StringableList[T]) String() string { var sb strings.Builder for i, v := range s { if i > 0 { @@ -38,7 +38,7 @@ func (a myint) String() string { } func main() { - v := stringableList[myint]{ myint(1), myint(2) } + v := StringableList[myint]{ myint(1), myint(2) } if got, want := v.String(), "1, 2"; got != want { panic(fmt.Sprintf("got %s, want %s", got, want)) diff --git a/test/typeparam/stringerimp.dir/a.go b/test/typeparam/stringerimp.dir/a.go new file mode 100644 index 00000000000..3f70937ff55 --- /dev/null +++ b/test/typeparam/stringerimp.dir/a.go @@ -0,0 +1,16 @@ +// Copyright 2021 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 a + +type Stringer interface { + String() string +} + +func Stringify[T Stringer](s []T) (ret []string) { + for _, v := range s { + ret = append(ret, v.String()) + } + return ret +} diff --git a/test/typeparam/stringerimp.dir/main.go b/test/typeparam/stringerimp.dir/main.go new file mode 100644 index 00000000000..e30bdf1abeb --- /dev/null +++ b/test/typeparam/stringerimp.dir/main.go @@ -0,0 +1,38 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "a" + "fmt" + "reflect" + "strconv" +) + +type myint int + +func (i myint) String() string { + return strconv.Itoa(int(i)) +} + +func main() { + x := []myint{myint(1), myint(2), myint(3)} + + got := a.Stringify(x) + want := []string{"1", "2", "3"} + if !reflect.DeepEqual(got, want) { + panic(fmt.Sprintf("got %s, want %s", got, want)) + } + + m1 := myint(1) + m2 := myint(2) + m3 := myint(3) + y := []*myint{&m1, &m2, &m3} + got2 := a.Stringify(y) + want2 := []string{"1", "2", "3"} + if !reflect.DeepEqual(got2, want2) { + panic(fmt.Sprintf("got %s, want %s", got2, want2)) + } +} diff --git a/test/typeparam/stringerimp.go b/test/typeparam/stringerimp.go new file mode 100644 index 00000000000..76930e5e4f6 --- /dev/null +++ b/test/typeparam/stringerimp.go @@ -0,0 +1,7 @@ +// rundir -G=3 + +// Copyright 2021 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 ignored diff --git a/test/typeparam/struct.go b/test/typeparam/struct.go index 98f0fcd8888..093f6935e69 100644 --- a/test/typeparam/struct.go +++ b/test/typeparam/struct.go @@ -10,40 +10,40 @@ import ( "fmt" ) -type _E[T any] struct { +type E[T any] struct { v T } -type _S1 struct { - _E[int] +type S1 struct { + E[int] v string } -type _Eint = _E[int] -type _Ebool = _E[bool] +type Eint = E[int] +type Ebool = E[bool] -type _S2 struct { - _Eint - _Ebool +type S2 struct { + Eint + Ebool v string } -type _S3 struct { - *_E[int] +type S3 struct { + *E[int] } func main() { - s1 := _S1{_Eint{2}, "foo"} - if got, want := s1._E.v, 2; got != want { + s1 := S1{Eint{2}, "foo"} + if got, want := s1.E.v, 2; got != want { panic(fmt.Sprintf("got %d, want %d", got, want)) } - s2 := _S2{_Eint{3}, _Ebool{true}, "foo"} - if got, want := s2._Eint.v, 3; got != want { + s2 := S2{Eint{3}, Ebool{true}, "foo"} + if got, want := s2.Eint.v, 3; got != want { panic(fmt.Sprintf("got %d, want %d", got, want)) } - var s3 _S3 - s3._E = &_Eint{4} - if got, want := s3._E.v, 4; got != want { + var s3 S3 + s3.E = &Eint{4} + if got, want := s3.E.v, 4; got != want { panic(fmt.Sprintf("got %d, want %d", got, want)) } } diff --git a/test/typeparam/sum.go b/test/typeparam/sum.go index f0f5e6aa075..c82d8e4c612 100644 --- a/test/typeparam/sum.go +++ b/test/typeparam/sum.go @@ -10,7 +10,7 @@ import ( "fmt" ) -func sum[T interface{ type int, float64 }](vec []T) T { +func Sum[T interface{ type int, float64 }](vec []T) T { var sum T for _, elt := range vec { sum = sum + elt @@ -18,7 +18,7 @@ func sum[T interface{ type int, float64 }](vec []T) T { return sum } -func abs(f float64) float64 { +func Abs(f float64) float64 { if f < 0.0 { return -f } @@ -28,23 +28,23 @@ func abs(f float64) float64 { func main() { vec1 := []int{3, 4} vec2 := []float64{5.8, 9.6} - got := sum[int](vec1) + got := Sum[int](vec1) want := vec1[0] + vec1[1] if got != want { panic(fmt.Sprintf("got %d, want %d", got, want)) } - got = sum(vec1) + got = Sum(vec1) if want != got { panic(fmt.Sprintf("got %d, want %d", got, want)) } fwant := vec2[0] + vec2[1] - fgot := sum[float64](vec2) - if abs(fgot - fwant) > 1e-10 { + fgot := Sum[float64](vec2) + if Abs(fgot - fwant) > 1e-10 { panic(fmt.Sprintf("got %f, want %f", fgot, fwant)) } - fgot = sum(vec2) - if abs(fgot - fwant) > 1e-10 { + fgot = Sum(vec2) + if Abs(fgot - fwant) > 1e-10 { panic(fmt.Sprintf("got %f, want %f", fgot, fwant)) } } diff --git a/test/typeparam/valimp.dir/a.go b/test/typeparam/valimp.dir/a.go new file mode 100644 index 00000000000..5aa5ebfa976 --- /dev/null +++ b/test/typeparam/valimp.dir/a.go @@ -0,0 +1,32 @@ +// Copyright 2021 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 a + +type Value[T any] struct { + val T +} + +// The noinline directive should survive across import, and prevent instantiations +// of these functions from being inlined. + +//go:noinline +func Get[T any](v *Value[T]) T { + return v.val +} + +//go:noinline +func Set[T any](v *Value[T], val T) { + v.val = val +} + +//go:noinline +func (v *Value[T]) Set(val T) { + v.val = val +} + +//go:noinline +func (v *Value[T]) Get() T { + return v.val +} diff --git a/test/typeparam/valimp.dir/main.go b/test/typeparam/valimp.dir/main.go new file mode 100644 index 00000000000..925fb1e6994 --- /dev/null +++ b/test/typeparam/valimp.dir/main.go @@ -0,0 +1,56 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "a" + "fmt" +) + +func main() { + var v1 a.Value[int] + + a.Set(&v1, 1) + if got, want := a.Get(&v1), 1; got != want { + panic(fmt.Sprintf("Get() == %d, want %d", got, want)) + } + v1.Set(2) + if got, want := v1.Get(), 2; got != want { + panic(fmt.Sprintf("Get() == %d, want %d", got, want)) + } + v1p := new(a.Value[int]) + a.Set(v1p, 3) + if got, want := a.Get(v1p), 3; got != want { + panic(fmt.Sprintf("Get() == %d, want %d", got, want)) + } + + v1p.Set(4) + if got, want := v1p.Get(), 4; got != want { + panic(fmt.Sprintf("Get() == %d, want %d", got, want)) + } + + var v2 a.Value[string] + a.Set(&v2, "a") + if got, want := a.Get(&v2), "a"; got != want { + panic(fmt.Sprintf("Get() == %q, want %q", got, want)) + } + + v2.Set("b") + if got, want := a.Get(&v2), "b"; got != want { + panic(fmt.Sprintf("Get() == %q, want %q", got, want)) + } + + v2p := new(a.Value[string]) + a.Set(v2p, "c") + if got, want := a.Get(v2p), "c"; got != want { + panic(fmt.Sprintf("Get() == %d, want %d", got, want)) + } + + v2p.Set("d") + if got, want := v2p.Get(), "d"; got != want { + panic(fmt.Sprintf("Get() == %d, want %d", got, want)) + } +} + diff --git a/test/typeparam/valimp.go b/test/typeparam/valimp.go new file mode 100644 index 00000000000..76930e5e4f6 --- /dev/null +++ b/test/typeparam/valimp.go @@ -0,0 +1,7 @@ +// rundir -G=3 + +// Copyright 2021 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 ignored From 7b3ee6102d4690c768a7a4b303a89f3f8c811124 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Wed, 14 Apr 2021 09:34:17 -0700 Subject: [PATCH 108/940] [dev.typeparams] cmd/compile: move to new export version, keep reading previous version I added constants for the previous export versions, and for the final generics export version. I also added a const for the current export version. We can increment the current export version for unstable changes in dev.typeparams, and eventally set it back to the generics version (2) before release. Added the same constants in typecheck/iexport.go, importer/iimport.go, and gcimporter/iimport.go, must be kept in sync. Put in the needed conditionals to be able to read old versions. Added new export/import test listimp.dir. Change-Id: I166d17d943e07951aa752562e952b067704aeeca Reviewed-on: https://go-review.googlesource.com/c/go/+/319931 Trust: Dan Scales Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/importer/iimport.go | 47 +++++++++++++---- src/cmd/compile/internal/typecheck/iexport.go | 14 ++++-- src/cmd/compile/internal/typecheck/iimport.go | 32 +++++++++--- src/go/internal/gcimporter/gcimporter_test.go | 2 +- src/go/internal/gcimporter/iimport.go | 49 ++++++++++++------ test/typeparam/listimp.dir/a.go | 50 +++++++++++++++++++ test/typeparam/listimp.dir/main.go | 48 ++++++++++++++++++ test/typeparam/listimp.go | 7 +++ 8 files changed, 214 insertions(+), 35 deletions(-) create mode 100644 test/typeparam/listimp.dir/a.go create mode 100644 test/typeparam/listimp.dir/main.go create mode 100644 test/typeparam/listimp.go diff --git a/src/cmd/compile/internal/importer/iimport.go b/src/cmd/compile/internal/importer/iimport.go index a4637ec34f9..37e5113435c 100644 --- a/src/cmd/compile/internal/importer/iimport.go +++ b/src/cmd/compile/internal/importer/iimport.go @@ -1,4 +1,3 @@ -// UNREVIEWED // Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -42,6 +41,16 @@ func (r *intReader) uint64() uint64 { return i } +// Keep this in sync with constants in iexport.go. +const ( + iexportVersionGo1_11 = 0 + iexportVersionPosCol = 1 + iexportVersionGenerics = 2 + + // Start of the unstable series of versions, remove "+ n" before release. + iexportVersionCurrent = iexportVersionGenerics + 1 +) + const predeclReserved = 32 type itag uint64 @@ -68,7 +77,7 @@ const io_SeekCurrent = 1 // io.SeekCurrent (not defined in Go 1.4) // If the export data version is not recognized or the format is otherwise // compromised, an error is returned. func iImportData(imports map[string]*types2.Package, data []byte, path string) (_ int, pkg *types2.Package, err error) { - const currentVersion = 1 + const currentVersion = iexportVersionCurrent version := int64(-1) defer func() { if e := recover(); e != nil { @@ -84,9 +93,13 @@ func iImportData(imports map[string]*types2.Package, data []byte, path string) ( version = int64(r.uint64()) switch version { - case currentVersion, 0: + case currentVersion, iexportVersionPosCol, iexportVersionGo1_11: default: - errorf("unknown iexport format version %d", version) + if version > iexportVersionGenerics { + errorf("unstable iexport format version %d, just rebuild compiler and std library", version) + } else { + errorf("unknown iexport format version %d", version) + } } sLen := int64(r.uint64()) @@ -98,8 +111,9 @@ func iImportData(imports map[string]*types2.Package, data []byte, path string) ( r.Seek(sLen+dLen, io_SeekCurrent) p := iimporter{ - ipath: path, - version: int(version), + exportVersion: version, + ipath: path, + version: int(version), stringData: stringData, stringCache: make(map[uint64]string), @@ -178,8 +192,9 @@ func iImportData(imports map[string]*types2.Package, data []byte, path string) ( } type iimporter struct { - ipath string - version int + exportVersion int64 + ipath string + version int stringData []byte stringCache map[uint64]string @@ -294,14 +309,20 @@ func (r *importReader) obj(name string) { r.declare(types2.NewConst(pos, r.currPkg, name, typ, val)) case 'F': - tparams := r.tparamList() + var tparams []*types2.TypeName + if r.p.exportVersion >= iexportVersionGenerics { + tparams = r.tparamList() + } sig := r.signature(nil) sig.SetTParams(tparams) r.declare(types2.NewFunc(pos, r.currPkg, name, sig)) case 'T': - tparams := r.tparamList() + var tparams []*types2.TypeName + if r.p.exportVersion >= iexportVersionGenerics { + tparams = r.tparamList() + } // Types can be recursive. We need to setup a stub // declaration before recursing. @@ -592,6 +613,9 @@ func (r *importReader) doType(base *types2.Named) types2.Type { return typ case typeParamType: + if r.p.exportVersion < iexportVersionGenerics { + errorf("unexpected type param type") + } r.currPkg = r.pkg() pos := r.pos() name := r.string() @@ -622,6 +646,9 @@ func (r *importReader) doType(base *types2.Named) types2.Type { return t case instType: + if r.p.exportVersion < iexportVersionGenerics { + errorf("unexpected instantiation type") + } pos := r.pos() len := r.uint64() targs := make([]types2.Type, len) diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index 11b9755148e..e6813adbf90 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -223,9 +223,17 @@ import ( ) // Current indexed export format version. Increase with each format change. -// 1: added column details to Pos // 0: Go1.11 encoding -const iexportVersion = 1 +// 1: added column details to Pos +// 2: added information for generic function/types (currently unstable) +const ( + iexportVersionGo1_11 = 0 + iexportVersionPosCol = 1 + iexportVersionGenerics = 2 + + // Start of the unstable series of versions, remove "+ n" before release. + iexportVersionCurrent = iexportVersionGenerics + 1 +) // predeclReserved is the number of type offsets reserved for types // implicitly declared in the universe block. @@ -297,7 +305,7 @@ func WriteExports(out *bufio.Writer) { // Assemble header. var hdr intWriter hdr.WriteByte('i') - hdr.uint64(iexportVersion) + hdr.uint64(iexportVersionCurrent) hdr.uint64(uint64(p.strings.Len())) hdr.uint64(dataLen) diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index b6f227bb00e..778ce4be12a 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -121,8 +121,14 @@ func ReadImports(pkg *types.Pkg, in *bio.Reader) (fingerprint goobj.FingerprintT ird := &intReader{in, pkg} version := ird.uint64() - if version != iexportVersion { - base.Errorf("import %q: unknown export format version %d", pkg.Path, version) + switch version { + case iexportVersionCurrent, iexportVersionPosCol, iexportVersionGo1_11: + default: + if version > iexportVersionGenerics { + base.Errorf("import %q: unstable export format version %d, just recompile", pkg.Path, version) + } else { + base.Errorf("import %q: unknown export format version %d", pkg.Path, version) + } base.ErrorExit() } @@ -143,7 +149,8 @@ func ReadImports(pkg *types.Pkg, in *bio.Reader) (fingerprint goobj.FingerprintT in.MustSeek(int64(sLen+dLen), os.SEEK_CUR) p := &iimporter{ - ipkg: pkg, + exportVersion: version, + ipkg: pkg, pkgCache: map[uint64]*types.Pkg{}, posBaseCache: map[uint64]*src.PosBase{}, @@ -212,7 +219,8 @@ func ReadImports(pkg *types.Pkg, in *bio.Reader) (fingerprint goobj.FingerprintT } type iimporter struct { - ipkg *types.Pkg + exportVersion uint64 + ipkg *types.Pkg pkgCache map[uint64]*types.Pkg posBaseCache map[uint64]*src.PosBase @@ -314,7 +322,10 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name { return n case 'F': - tparams := r.tparamList() + var tparams []*types.Field + if r.p.exportVersion >= iexportVersionGenerics { + tparams = r.tparamList() + } typ := r.signature(nil, tparams) n := importfunc(r.p.ipkg, pos, sym, typ) @@ -322,7 +333,10 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name { return n case 'T': - rparams := r.typeList() + var rparams []*types.Type + if r.p.exportVersion >= iexportVersionGenerics { + rparams = r.typeList() + } // Types can be recursive. We need to setup a stub // declaration before recursing. @@ -738,6 +752,9 @@ func (r *importReader) typ1() *types.Type { return t case typeParamType: + if r.p.exportVersion < iexportVersionGenerics { + base.Fatalf("unexpected type param type") + } r.setPkg() pos := r.pos() name := r.string() @@ -761,6 +778,9 @@ func (r *importReader) typ1() *types.Type { return t case instType: + if r.p.exportVersion < iexportVersionGenerics { + base.Fatalf("unexpected instantiation type") + } pos := r.pos() len := r.uint64() targs := make([]*types.Type, len) diff --git a/src/go/internal/gcimporter/gcimporter_test.go b/src/go/internal/gcimporter/gcimporter_test.go index c010dc506e7..286b8a63471 100644 --- a/src/go/internal/gcimporter/gcimporter_test.go +++ b/src/go/internal/gcimporter/gcimporter_test.go @@ -139,7 +139,7 @@ func TestVersionHandling(t *testing.T) { // This package only handles gc export data. // Disable test until we put in the new export version. - if true || runtime.Compiler != "gc" { + if runtime.Compiler != "gc" { t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler) } diff --git a/src/go/internal/gcimporter/iimport.go b/src/go/internal/gcimporter/iimport.go index 4416f5b2b92..e003dc9767a 100644 --- a/src/go/internal/gcimporter/iimport.go +++ b/src/go/internal/gcimporter/iimport.go @@ -40,6 +40,16 @@ func (r *intReader) uint64() uint64 { return i } +// Keep this in sync with constants in iexport.go. +const ( + iexportVersionGo1_11 = 0 + iexportVersionPosCol = 1 + iexportVersionGenerics = 2 + + // Start of the unstable series of versions, remove "+ n" before release. + iexportVersionCurrent = iexportVersionGenerics + 1 +) + const predeclReserved = 32 type itag uint64 @@ -64,7 +74,7 @@ const ( // If the export data version is not recognized or the format is otherwise // compromised, an error is returned. func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) { - const currentVersion = 1 + const currentVersion = iexportVersionCurrent version := int64(-1) defer func() { if e := recover(); e != nil { @@ -80,9 +90,13 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data [] version = int64(r.uint64()) switch version { - case currentVersion, 0: + case currentVersion, iexportVersionPosCol, iexportVersionGo1_11: default: - errorf("unknown iexport format version %d", version) + if version > iexportVersionGenerics { + errorf("unstable iexport format version %d, just rebuild compiler and std library", version) + } else { + errorf("unknown iexport format version %d", version) + } } sLen := int64(r.uint64()) @@ -94,8 +108,9 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data [] r.Seek(sLen+dLen, io.SeekCurrent) p := iimporter{ - ipath: path, - version: int(version), + exportVersion: version, + ipath: path, + version: int(version), stringData: stringData, stringCache: make(map[uint64]string), @@ -173,8 +188,9 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data [] } type iimporter struct { - ipath string - version int + exportVersion int64 + ipath string + version int stringData []byte stringCache map[uint64]string @@ -273,19 +289,22 @@ func (r *importReader) obj(name string) { r.declare(types.NewConst(pos, r.currPkg, name, typ, val)) case 'F': - numTparams := r.uint64() - if numTparams > 0 { - errorf("unexpected tparam") - return + if r.p.exportVersion >= iexportVersionGenerics { + numTparams := r.uint64() + if numTparams > 0 { + errorf("unexpected tparam") + } } sig := r.signature(nil) r.declare(types.NewFunc(pos, r.currPkg, name, sig)) case 'T': - numTparams := r.uint64() - if numTparams > 0 { - errorf("unexpected tparam") + if r.p.exportVersion >= iexportVersionGenerics { + numTparams := r.uint64() + if numTparams > 0 { + errorf("unexpected tparam") + } } // Types can be recursive. We need to setup a stub @@ -562,7 +581,7 @@ func (r *importReader) doType(base *types.Named) types.Type { return typ case typeParamType: - errorf("do not handle tparams yet") + errorf("do not handle type param types yet") return nil case instType: diff --git a/test/typeparam/listimp.dir/a.go b/test/typeparam/listimp.dir/a.go new file mode 100644 index 00000000000..ea569751a67 --- /dev/null +++ b/test/typeparam/listimp.dir/a.go @@ -0,0 +1,50 @@ +package a + +type Ordered interface { + type int, int8, int16, int32, int64, + uint, uint8, uint16, uint32, uint64, uintptr, + float32, float64, + string +} + +// List is a linked list of ordered values of type T. +type List[T Ordered] struct { + Next *List[T] + Val T +} + +func (l *List[T]) Largest() T { + var max T + for p := l; p != nil; p = p.Next { + if p.Val > max { + max = p.Val + } + } + return max +} + +type OrderedNum interface { + type int, int8, int16, int32, int64, + uint, uint8, uint16, uint32, uint64, uintptr, + float32, float64 +} + +// ListNum is a linked _List of ordered numeric values of type T. +type ListNum[T OrderedNum] struct { + Next *ListNum[T] + Val T +} + +const Clip = 5 + +// clippedLargest returns the largest in the list of OrderNums, but a max of 5. +// TODO(danscales): fix export/import of an untype constant with typeparam type +func (l *ListNum[T]) ClippedLargest() T { + var max T + for p := l; p != nil; p = p.Next { + if p.Val > max && p.Val < T(Clip) { + max = p.Val + } + } + return max +} diff --git a/test/typeparam/listimp.dir/main.go b/test/typeparam/listimp.dir/main.go new file mode 100644 index 00000000000..4c1aa3e4934 --- /dev/null +++ b/test/typeparam/listimp.dir/main.go @@ -0,0 +1,48 @@ +package main + +import ( + "a" + "fmt" +) + +func main() { + i3 := &a.List[int]{nil, 1} + i2 := &a.List[int]{i3, 3} + i1 := &a.List[int]{i2, 2} + if got, want := i1.Largest(), 3; got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + b3 := &a.List[byte]{nil, byte(1)} + b2 := &a.List[byte]{b3, byte(3)} + b1 := &a.List[byte]{b2, byte(2)} + if got, want := b1.Largest(), byte(3); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + f3 := &a.List[float64]{nil, 13.5} + f2 := &a.List[float64]{f3, 1.2} + f1 := &a.List[float64]{f2, 4.5} + if got, want := f1.Largest(), 13.5; got != want { + panic(fmt.Sprintf("got %f, want %f", got, want)) + } + + s3 := &a.List[string]{nil, "dd"} + s2 := &a.List[string]{s3, "aa"} + s1 := &a.List[string]{s2, "bb"} + if got, want := s1.Largest(), "dd"; got != want { + panic(fmt.Sprintf("got %s, want %s", got, want)) + } + j3 := &a.ListNum[int]{nil, 1} + j2 := &a.ListNum[int]{j3, 32} + j1 := &a.ListNum[int]{j2, 2} + if got, want := j1.ClippedLargest(), 2; got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + g3 := &a.ListNum[float64]{nil, 13.5} + g2 := &a.ListNum[float64]{g3, 1.2} + g1 := &a.ListNum[float64]{g2, 4.5} + if got, want := g1.ClippedLargest(), 4.5; got != want { + panic(fmt.Sprintf("got %f, want %f", got, want)) + } +} diff --git a/test/typeparam/listimp.go b/test/typeparam/listimp.go new file mode 100644 index 00000000000..76930e5e4f6 --- /dev/null +++ b/test/typeparam/listimp.go @@ -0,0 +1,7 @@ +// rundir -G=3 + +// Copyright 2021 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 ignored From 7e63c8b765c30823131bd136d190afbe4c21abc9 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Fri, 21 May 2021 12:01:39 +0200 Subject: [PATCH 109/940] runtime: wait for Go runtime to initialize in Windows signal test The test harness waits for "ready" as a sign that the Go runtime has installed its signal handler and is ready to be tested. But actually, while LoadLibrary starts the loading of the Go runtime, it does so asynchronously, so the "ready" sign is potentially premature and certainly racy. However, all exported cgo entry points make a call to _cgo_wait_runtime_init_done which waits for that asynchronous initialization to complete. Therefore, this commit fixes the test to call into the exported "Dummy" cgo function before emitting the "ready" sign, so that we're sure the Go runtime is actually loaded. Updates #45638. Change-Id: I9b12b172d45bdcc09d54dd301de3a3e499544834 Reviewed-on: https://go-review.googlesource.com/c/go/+/321769 Trust: Jason A. Donenfeld Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/runtime/testdata/testwinlibsignal/main.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/runtime/testdata/testwinlibsignal/main.c b/src/runtime/testdata/testwinlibsignal/main.c index 1787fef3b94..37f24823e66 100644 --- a/src/runtime/testdata/testwinlibsignal/main.c +++ b/src/runtime/testdata/testwinlibsignal/main.c @@ -19,13 +19,13 @@ int main(void) { waitForCtrlBreakEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (!waitForCtrlBreakEvent) { - fprintf(stderr, "ERROR: Could not create event"); + fprintf(stderr, "ERROR: Could not create event\n"); return 1; } if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) { - fprintf(stderr, "ERROR: Could not set control handler"); + fprintf(stderr, "ERROR: Could not set control handler\n"); return 1; } @@ -34,7 +34,14 @@ int main(void) // This way the library handler gets called first. HMODULE dummyDll = LoadLibrary("dummy.dll"); if (!dummyDll) { - fprintf(stderr, "ERROR: Could not load dummy.dll"); + fprintf(stderr, "ERROR: Could not load dummy.dll\n"); + return 1; + } + + // Call the Dummy function so that Go initialization completes, since + // all cgo entry points call out to _cgo_wait_runtime_init_done. + if (((int(*)(void))GetProcAddress(dummyDll, "Dummy"))() != 42) { + fprintf(stderr, "ERROR: Dummy function did not return 42\n"); return 1; } @@ -42,7 +49,7 @@ int main(void) fflush(stdout); if (WaitForSingleObject(waitForCtrlBreakEvent, 5000) != WAIT_OBJECT_0) { - fprintf(stderr, "FAILURE: No signal received"); + fprintf(stderr, "FAILURE: No signal received\n"); return 1; } From 211244e1720942af2f2b77b8c96ff7f3a019df31 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 20 May 2021 14:40:11 -0700 Subject: [PATCH 110/940] [dev.typeparams] cmd/compile/internal/types2: move interface checking into separate file This only moves functionality from one file into another. Except for import adjustments there are no changes to the code. Change-Id: Ia7d611d3a01c1ed3331dcc7cfe94a96f87b338e7 Reviewed-on: https://go-review.googlesource.com/c/go/+/321549 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/interface.go | 320 +++++++++++++++++++ src/cmd/compile/internal/types2/typexpr.go | 311 ------------------ 2 files changed, 320 insertions(+), 311 deletions(-) create mode 100644 src/cmd/compile/internal/types2/interface.go diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go new file mode 100644 index 00000000000..bbd25cbd094 --- /dev/null +++ b/src/cmd/compile/internal/types2/interface.go @@ -0,0 +1,320 @@ +// Copyright 2021 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 types2 + +import ( + "cmd/compile/internal/syntax" + "sort" +) + +func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType, def *Named) { + var tname *syntax.Name // most recent "type" name + var types []syntax.Expr + for _, f := range iface.MethodList { + if f.Name != nil { + // We have a method with name f.Name, or a type + // of a type list (f.Name.Value == "type"). + name := f.Name.Value + if name == "_" { + if check.conf.CompilerErrorMessages { + check.error(f.Name, "methods must have a unique non-blank name") + } else { + check.error(f.Name, "invalid method name _") + } + continue // ignore + } + + if name == "type" { + // Always collect all type list entries, even from + // different type lists, under the assumption that + // the author intended to include all types. + types = append(types, f.Type) + if tname != nil && tname != f.Name { + check.error(f.Name, "cannot have multiple type lists in an interface") + } + tname = f.Name + continue + } + + typ := check.typ(f.Type) + sig, _ := typ.(*Signature) + if sig == nil { + if typ != Typ[Invalid] { + check.errorf(f.Type, invalidAST+"%s is not a method signature", typ) + } + continue // ignore + } + + // Always type-check method type parameters but complain if they are not enabled. + // (This extra check is needed here because interface method signatures don't have + // a receiver specification.) + if sig.tparams != nil && !acceptMethodTypeParams { + check.error(f.Type, "methods cannot have type parameters") + } + + // use named receiver type if available (for better error messages) + var recvTyp Type = ityp + if def != nil { + recvTyp = def + } + sig.recv = NewVar(f.Name.Pos(), check.pkg, "", recvTyp) + + m := NewFunc(f.Name.Pos(), check.pkg, name, sig) + check.recordDef(f.Name, m) + ityp.methods = append(ityp.methods, m) + } else { + // We have an embedded type. completeInterface will + // eventually verify that we have an interface. + ityp.embeddeds = append(ityp.embeddeds, check.typ(f.Type)) + check.posMap[ityp] = append(check.posMap[ityp], f.Type.Pos()) + } + } + + // type constraints + ityp.types = NewSum(check.collectTypeConstraints(iface.Pos(), types)) + + if len(ityp.methods) == 0 && ityp.types == nil && len(ityp.embeddeds) == 0 { + // empty interface + ityp.allMethods = markComplete + return + } + + // sort for API stability + sortMethods(ityp.methods) + sortTypes(ityp.embeddeds) + + check.later(func() { check.completeInterface(iface.Pos(), ityp) }) +} + +func (check *Checker) collectTypeConstraints(pos syntax.Pos, types []syntax.Expr) []Type { + list := make([]Type, 0, len(types)) // assume all types are correct + for _, texpr := range types { + if texpr == nil { + check.error(pos, invalidAST+"missing type constraint") + continue + } + list = append(list, check.varType(texpr)) + } + + // Ensure that each type is only present once in the type list. Types may be + // interfaces, which may not be complete yet. It's ok to do this check at the + // end because it's not a requirement for correctness of the code. + // Note: This is a quadratic algorithm, but type lists tend to be short. + check.later(func() { + for i, t := range list { + if t := asInterface(t); t != nil { + check.completeInterface(types[i].Pos(), t) + } + if includes(list[:i], t) { + check.softErrorf(types[i], "duplicate type %s in type list", t) + } + } + }) + + return list +} + +// includes reports whether typ is in list +func includes(list []Type, typ Type) bool { + for _, e := range list { + if Identical(typ, e) { + return true + } + } + return false +} + +func (check *Checker) completeInterface(pos syntax.Pos, ityp *Interface) { + if ityp.allMethods != nil { + return + } + + // completeInterface may be called via the LookupFieldOrMethod, + // MissingMethod, Identical, or IdenticalIgnoreTags external API + // in which case check will be nil. In this case, type-checking + // must be finished and all interfaces should have been completed. + if check == nil { + panic("internal error: incomplete interface") + } + + if check.conf.Trace { + // Types don't generally have position information. + // If we don't have a valid pos provided, try to use + // one close enough. + if !pos.IsKnown() && len(ityp.methods) > 0 { + pos = ityp.methods[0].pos + } + + check.trace(pos, "complete %s", ityp) + check.indent++ + defer func() { + check.indent-- + check.trace(pos, "=> %s (methods = %v, types = %v)", ityp, ityp.allMethods, ityp.allTypes) + }() + } + + // An infinitely expanding interface (due to a cycle) is detected + // elsewhere (Checker.validType), so here we simply assume we only + // have valid interfaces. Mark the interface as complete to avoid + // infinite recursion if the validType check occurs later for some + // reason. + ityp.allMethods = markComplete + + // Methods of embedded interfaces are collected unchanged; i.e., the identity + // of a method I.m's Func Object of an interface I is the same as that of + // the method m in an interface that embeds interface I. On the other hand, + // if a method is embedded via multiple overlapping embedded interfaces, we + // don't provide a guarantee which "original m" got chosen for the embedding + // interface. See also issue #34421. + // + // If we don't care to provide this identity guarantee anymore, instead of + // reusing the original method in embeddings, we can clone the method's Func + // Object and give it the position of a corresponding embedded interface. Then + // we can get rid of the mpos map below and simply use the cloned method's + // position. + + var seen objset + var methods []*Func + mpos := make(map[*Func]syntax.Pos) // method specification or method embedding position, for good error messages + addMethod := func(pos syntax.Pos, m *Func, explicit bool) { + switch other := seen.insert(m); { + case other == nil: + methods = append(methods, m) + mpos[m] = pos + case explicit: + var err error_ + err.errorf(pos, "duplicate method %s", m.name) + err.errorf(mpos[other.(*Func)], "other declaration of %s", m.name) + check.report(&err) + default: + // We have a duplicate method name in an embedded (not explicitly declared) method. + // Check method signatures after all types are computed (issue #33656). + // If we're pre-go1.14 (overlapping embeddings are not permitted), report that + // error here as well (even though we could do it eagerly) because it's the same + // error message. + check.later(func() { + if !check.allowVersion(m.pkg, 1, 14) || !check.identical(m.typ, other.Type()) { + var err error_ + err.errorf(pos, "duplicate method %s", m.name) + err.errorf(mpos[other.(*Func)], "other declaration of %s", m.name) + check.report(&err) + } + }) + } + } + + for _, m := range ityp.methods { + addMethod(m.pos, m, true) + } + + // collect types + allTypes := ityp.types + + posList := check.posMap[ityp] + for i, typ := range ityp.embeddeds { + pos := posList[i] // embedding position + utyp := under(typ) + etyp := asInterface(utyp) + if etyp == nil { + if utyp != Typ[Invalid] { + var format string + if _, ok := utyp.(*TypeParam); ok { + format = "%s is a type parameter, not an interface" + } else { + format = "%s is not an interface" + } + check.errorf(pos, format, typ) + } + continue + } + check.completeInterface(pos, etyp) + for _, m := range etyp.allMethods { + addMethod(pos, m, false) // use embedding position pos rather than m.pos + } + allTypes = intersect(allTypes, etyp.allTypes) + } + + if methods != nil { + sortMethods(methods) + ityp.allMethods = methods + } + ityp.allTypes = allTypes +} + +// intersect computes the intersection of the types x and y. +// Note: A incomming nil type stands for the top type. A top +// type result is returned as nil. +func intersect(x, y Type) (r Type) { + defer func() { + if r == theTop { + r = nil + } + }() + + switch { + case x == theBottom || y == theBottom: + return theBottom + case x == nil || x == theTop: + return y + case y == nil || x == theTop: + return x + } + + xtypes := unpack(x) + ytypes := unpack(y) + // Compute the list rtypes which includes only + // types that are in both xtypes and ytypes. + // Quadratic algorithm, but good enough for now. + // TODO(gri) fix this + var rtypes []Type + for _, x := range xtypes { + if includes(ytypes, x) { + rtypes = append(rtypes, x) + } + } + + if rtypes == nil { + return theBottom + } + return NewSum(rtypes) +} + +func sortTypes(list []Type) { + sort.Stable(byUniqueTypeName(list)) +} + +// byUniqueTypeName named type lists can be sorted by their unique type names. +type byUniqueTypeName []Type + +func (a byUniqueTypeName) Len() int { return len(a) } +func (a byUniqueTypeName) Less(i, j int) bool { return sortObj(a[i]).less(sortObj(a[j])) } +func (a byUniqueTypeName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } + +func sortObj(t Type) *object { + if named := asNamed(t); named != nil { + return &named.obj.object + } + return nil +} + +func sortMethods(list []*Func) { + sort.Sort(byUniqueMethodName(list)) +} + +func assertSortedMethods(list []*Func) { + if !debug { + panic("internal error: assertSortedMethods called outside debug mode") + } + if !sort.IsSorted(byUniqueMethodName(list)) { + panic("internal error: methods not sorted") + } +} + +// byUniqueMethodName method lists can be sorted by their unique method names. +type byUniqueMethodName []*Func + +func (a byUniqueMethodName) Len() int { return len(a) } +func (a byUniqueMethodName) Less(i, j int) bool { return a[i].less(&a[j].object) } +func (a byUniqueMethodName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index 7fb914cd7ec..bae4d3e4b53 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -10,7 +10,6 @@ import ( "cmd/compile/internal/syntax" "fmt" "go/constant" - "sort" "strconv" "strings" ) @@ -813,278 +812,6 @@ func (check *Checker) declareInSet(oset *objset, pos syntax.Pos, obj Object) boo return true } -func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType, def *Named) { - var tname *syntax.Name // most recent "type" name - var types []syntax.Expr - for _, f := range iface.MethodList { - if f.Name != nil { - // We have a method with name f.Name, or a type - // of a type list (f.Name.Value == "type"). - name := f.Name.Value - if name == "_" { - if check.conf.CompilerErrorMessages { - check.error(f.Name, "methods must have a unique non-blank name") - } else { - check.error(f.Name, "invalid method name _") - } - continue // ignore - } - - if name == "type" { - // Always collect all type list entries, even from - // different type lists, under the assumption that - // the author intended to include all types. - types = append(types, f.Type) - if tname != nil && tname != f.Name { - check.error(f.Name, "cannot have multiple type lists in an interface") - } - tname = f.Name - continue - } - - typ := check.typ(f.Type) - sig, _ := typ.(*Signature) - if sig == nil { - if typ != Typ[Invalid] { - check.errorf(f.Type, invalidAST+"%s is not a method signature", typ) - } - continue // ignore - } - - // Always type-check method type parameters but complain if they are not enabled. - // (This extra check is needed here because interface method signatures don't have - // a receiver specification.) - if sig.tparams != nil && !acceptMethodTypeParams { - check.error(f.Type, "methods cannot have type parameters") - } - - // use named receiver type if available (for better error messages) - var recvTyp Type = ityp - if def != nil { - recvTyp = def - } - sig.recv = NewVar(f.Name.Pos(), check.pkg, "", recvTyp) - - m := NewFunc(f.Name.Pos(), check.pkg, name, sig) - check.recordDef(f.Name, m) - ityp.methods = append(ityp.methods, m) - } else { - // We have an embedded type. completeInterface will - // eventually verify that we have an interface. - ityp.embeddeds = append(ityp.embeddeds, check.typ(f.Type)) - check.posMap[ityp] = append(check.posMap[ityp], f.Type.Pos()) - } - } - - // type constraints - ityp.types = NewSum(check.collectTypeConstraints(iface.Pos(), types)) - - if len(ityp.methods) == 0 && ityp.types == nil && len(ityp.embeddeds) == 0 { - // empty interface - ityp.allMethods = markComplete - return - } - - // sort for API stability - sortMethods(ityp.methods) - sortTypes(ityp.embeddeds) - - check.later(func() { check.completeInterface(iface.Pos(), ityp) }) -} - -func (check *Checker) completeInterface(pos syntax.Pos, ityp *Interface) { - if ityp.allMethods != nil { - return - } - - // completeInterface may be called via the LookupFieldOrMethod, - // MissingMethod, Identical, or IdenticalIgnoreTags external API - // in which case check will be nil. In this case, type-checking - // must be finished and all interfaces should have been completed. - if check == nil { - panic("internal error: incomplete interface") - } - - if check.conf.Trace { - // Types don't generally have position information. - // If we don't have a valid pos provided, try to use - // one close enough. - if !pos.IsKnown() && len(ityp.methods) > 0 { - pos = ityp.methods[0].pos - } - - check.trace(pos, "complete %s", ityp) - check.indent++ - defer func() { - check.indent-- - check.trace(pos, "=> %s (methods = %v, types = %v)", ityp, ityp.allMethods, ityp.allTypes) - }() - } - - // An infinitely expanding interface (due to a cycle) is detected - // elsewhere (Checker.validType), so here we simply assume we only - // have valid interfaces. Mark the interface as complete to avoid - // infinite recursion if the validType check occurs later for some - // reason. - ityp.allMethods = markComplete - - // Methods of embedded interfaces are collected unchanged; i.e., the identity - // of a method I.m's Func Object of an interface I is the same as that of - // the method m in an interface that embeds interface I. On the other hand, - // if a method is embedded via multiple overlapping embedded interfaces, we - // don't provide a guarantee which "original m" got chosen for the embedding - // interface. See also issue #34421. - // - // If we don't care to provide this identity guarantee anymore, instead of - // reusing the original method in embeddings, we can clone the method's Func - // Object and give it the position of a corresponding embedded interface. Then - // we can get rid of the mpos map below and simply use the cloned method's - // position. - - var seen objset - var methods []*Func - mpos := make(map[*Func]syntax.Pos) // method specification or method embedding position, for good error messages - addMethod := func(pos syntax.Pos, m *Func, explicit bool) { - switch other := seen.insert(m); { - case other == nil: - methods = append(methods, m) - mpos[m] = pos - case explicit: - var err error_ - err.errorf(pos, "duplicate method %s", m.name) - err.errorf(mpos[other.(*Func)], "other declaration of %s", m.name) - check.report(&err) - default: - // We have a duplicate method name in an embedded (not explicitly declared) method. - // Check method signatures after all types are computed (issue #33656). - // If we're pre-go1.14 (overlapping embeddings are not permitted), report that - // error here as well (even though we could do it eagerly) because it's the same - // error message. - check.later(func() { - if !check.allowVersion(m.pkg, 1, 14) || !check.identical(m.typ, other.Type()) { - var err error_ - err.errorf(pos, "duplicate method %s", m.name) - err.errorf(mpos[other.(*Func)], "other declaration of %s", m.name) - check.report(&err) - } - }) - } - } - - for _, m := range ityp.methods { - addMethod(m.pos, m, true) - } - - // collect types - allTypes := ityp.types - - posList := check.posMap[ityp] - for i, typ := range ityp.embeddeds { - pos := posList[i] // embedding position - utyp := under(typ) - etyp := asInterface(utyp) - if etyp == nil { - if utyp != Typ[Invalid] { - var format string - if _, ok := utyp.(*TypeParam); ok { - format = "%s is a type parameter, not an interface" - } else { - format = "%s is not an interface" - } - check.errorf(pos, format, typ) - } - continue - } - check.completeInterface(pos, etyp) - for _, m := range etyp.allMethods { - addMethod(pos, m, false) // use embedding position pos rather than m.pos - } - allTypes = intersect(allTypes, etyp.allTypes) - } - - if methods != nil { - sortMethods(methods) - ityp.allMethods = methods - } - ityp.allTypes = allTypes -} - -// intersect computes the intersection of the types x and y. -// Note: A incomming nil type stands for the top type. A top -// type result is returned as nil. -func intersect(x, y Type) (r Type) { - defer func() { - if r == theTop { - r = nil - } - }() - - switch { - case x == theBottom || y == theBottom: - return theBottom - case x == nil || x == theTop: - return y - case y == nil || x == theTop: - return x - } - - xtypes := unpack(x) - ytypes := unpack(y) - // Compute the list rtypes which includes only - // types that are in both xtypes and ytypes. - // Quadratic algorithm, but good enough for now. - // TODO(gri) fix this - var rtypes []Type - for _, x := range xtypes { - if includes(ytypes, x) { - rtypes = append(rtypes, x) - } - } - - if rtypes == nil { - return theBottom - } - return NewSum(rtypes) -} - -func sortTypes(list []Type) { - sort.Stable(byUniqueTypeName(list)) -} - -// byUniqueTypeName named type lists can be sorted by their unique type names. -type byUniqueTypeName []Type - -func (a byUniqueTypeName) Len() int { return len(a) } -func (a byUniqueTypeName) Less(i, j int) bool { return sortObj(a[i]).less(sortObj(a[j])) } -func (a byUniqueTypeName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } - -func sortObj(t Type) *object { - if named := asNamed(t); named != nil { - return &named.obj.object - } - return nil -} - -func sortMethods(list []*Func) { - sort.Sort(byUniqueMethodName(list)) -} - -func assertSortedMethods(list []*Func) { - if !debug { - panic("internal error: assertSortedMethods called outside debug mode") - } - if !sort.IsSorted(byUniqueMethodName(list)) { - panic("internal error: methods not sorted") - } -} - -// byUniqueMethodName method lists can be sorted by their unique method names. -type byUniqueMethodName []*Func - -func (a byUniqueMethodName) Len() int { return len(a) } -func (a byUniqueMethodName) Less(i, j int) bool { return a[i].less(&a[j].object) } -func (a byUniqueMethodName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } - func (check *Checker) tag(t *syntax.BasicLit) string { // If t.Bad, an error was reported during parsing. if t != nil && !t.Bad { @@ -1222,44 +949,6 @@ func embeddedFieldIdent(e syntax.Expr) *syntax.Name { return nil // invalid embedded field } -func (check *Checker) collectTypeConstraints(pos syntax.Pos, types []syntax.Expr) []Type { - list := make([]Type, 0, len(types)) // assume all types are correct - for _, texpr := range types { - if texpr == nil { - check.error(pos, invalidAST+"missing type constraint") - continue - } - list = append(list, check.varType(texpr)) - } - - // Ensure that each type is only present once in the type list. Types may be - // interfaces, which may not be complete yet. It's ok to do this check at the - // end because it's not a requirement for correctness of the code. - // Note: This is a quadratic algorithm, but type lists tend to be short. - check.later(func() { - for i, t := range list { - if t := asInterface(t); t != nil { - check.completeInterface(types[i].Pos(), t) - } - if includes(list[:i], t) { - check.softErrorf(types[i], "duplicate type %s in type list", t) - } - } - }) - - return list -} - -// includes reports whether typ is in list -func includes(list []Type, typ Type) bool { - for _, e := range list { - if Identical(typ, e) { - return true - } - } - return false -} - func ptrBase(x *syntax.Operation) syntax.Expr { if x.Op == syntax.Mul && x.Y == nil { return x.X From cfe0250497aa2eaa7d3a9a56d815bfa1f4b9b8b5 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 20 May 2021 14:47:40 -0700 Subject: [PATCH 111/940] [dev.typeparams] cmd/compile/internal/types2: move struct checking into separate file This only moves functionality from one file into another. Except for import adjustments there are no changes to the code. Change-Id: I8dff41fe82693c96b09a152975c3fd1e3b439e8d Reviewed-on: https://go-review.googlesource.com/c/go/+/321589 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/struct.go | 165 +++++++++++++++++++++ src/cmd/compile/internal/types2/typexpr.go | 156 ------------------- 2 files changed, 165 insertions(+), 156 deletions(-) create mode 100644 src/cmd/compile/internal/types2/struct.go diff --git a/src/cmd/compile/internal/types2/struct.go b/src/cmd/compile/internal/types2/struct.go new file mode 100644 index 00000000000..302b9886f40 --- /dev/null +++ b/src/cmd/compile/internal/types2/struct.go @@ -0,0 +1,165 @@ +// Copyright 2021 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 types2 + +import ( + "cmd/compile/internal/syntax" + "strconv" +) + +func (check *Checker) structType(styp *Struct, e *syntax.StructType) { + if e.FieldList == nil { + return + } + + // struct fields and tags + var fields []*Var + var tags []string + + // for double-declaration checks + var fset objset + + // current field typ and tag + var typ Type + var tag string + add := func(ident *syntax.Name, embedded bool, pos syntax.Pos) { + if tag != "" && tags == nil { + tags = make([]string, len(fields)) + } + if tags != nil { + tags = append(tags, tag) + } + + name := ident.Value + fld := NewField(pos, check.pkg, name, typ, embedded) + // spec: "Within a struct, non-blank field names must be unique." + if name == "_" || check.declareInSet(&fset, pos, fld) { + fields = append(fields, fld) + check.recordDef(ident, fld) + } + } + + // addInvalid adds an embedded field of invalid type to the struct for + // fields with errors; this keeps the number of struct fields in sync + // with the source as long as the fields are _ or have different names + // (issue #25627). + addInvalid := func(ident *syntax.Name, pos syntax.Pos) { + typ = Typ[Invalid] + tag = "" + add(ident, true, pos) + } + + var prev syntax.Expr + for i, f := range e.FieldList { + // Fields declared syntactically with the same type (e.g.: a, b, c T) + // share the same type expression. Only check type if it's a new type. + if i == 0 || f.Type != prev { + typ = check.varType(f.Type) + prev = f.Type + } + tag = "" + if i < len(e.TagList) { + tag = check.tag(e.TagList[i]) + } + if f.Name != nil { + // named field + add(f.Name, false, f.Name.Pos()) + } else { + // embedded field + // spec: "An embedded type must be specified as a type name T or as a + // pointer to a non-interface type name *T, and T itself may not be a + // pointer type." + pos := syntax.StartPos(f.Type) + name := embeddedFieldIdent(f.Type) + if name == nil { + check.errorf(pos, "invalid embedded field type %s", f.Type) + name = &syntax.Name{Value: "_"} // TODO(gri) need to set position to pos + addInvalid(name, pos) + continue + } + add(name, true, pos) + + // Because we have a name, typ must be of the form T or *T, where T is the name + // of a (named or alias) type, and t (= deref(typ)) must be the type of T. + // We must delay this check to the end because we don't want to instantiate + // (via under(t)) a possibly incomplete type. + embeddedTyp := typ // for closure below + embeddedPos := pos + check.later(func() { + t, isPtr := deref(embeddedTyp) + switch t := optype(t).(type) { + case *Basic: + if t == Typ[Invalid] { + // error was reported before + return + } + // unsafe.Pointer is treated like a regular pointer + if t.kind == UnsafePointer { + check.error(embeddedPos, "embedded field type cannot be unsafe.Pointer") + } + case *Pointer: + check.error(embeddedPos, "embedded field type cannot be a pointer") + case *Interface: + if isPtr { + check.error(embeddedPos, "embedded field type cannot be a pointer to an interface") + } + } + }) + } + } + + styp.fields = fields + styp.tags = tags +} + +func embeddedFieldIdent(e syntax.Expr) *syntax.Name { + switch e := e.(type) { + case *syntax.Name: + return e + case *syntax.Operation: + if base := ptrBase(e); base != nil { + // *T is valid, but **T is not + if op, _ := base.(*syntax.Operation); op == nil || ptrBase(op) == nil { + return embeddedFieldIdent(e.X) + } + } + case *syntax.SelectorExpr: + return e.Sel + case *syntax.IndexExpr: + return embeddedFieldIdent(e.X) + } + return nil // invalid embedded field +} + +func (check *Checker) declareInSet(oset *objset, pos syntax.Pos, obj Object) bool { + if alt := oset.insert(obj); alt != nil { + var err error_ + err.errorf(pos, "%s redeclared", obj.Name()) + err.recordAltDecl(alt) + check.report(&err) + return false + } + return true +} + +func (check *Checker) tag(t *syntax.BasicLit) string { + // If t.Bad, an error was reported during parsing. + if t != nil && !t.Bad { + if t.Kind == syntax.StringLit { + if val, err := strconv.Unquote(t.Value); err == nil { + return val + } + } + check.errorf(t, invalidAST+"incorrect tag syntax: %q", t.Value) + } + return "" +} + +func ptrBase(x *syntax.Operation) syntax.Expr { + if x.Op == syntax.Mul && x.Y == nil { + return x.X + } + return nil +} diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index bae4d3e4b53..2352030b9b1 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -10,7 +10,6 @@ import ( "cmd/compile/internal/syntax" "fmt" "go/constant" - "strconv" "strings" ) @@ -800,158 +799,3 @@ func (check *Checker) collectParams(scope *Scope, list []*syntax.Field, type0 sy return } - -func (check *Checker) declareInSet(oset *objset, pos syntax.Pos, obj Object) bool { - if alt := oset.insert(obj); alt != nil { - var err error_ - err.errorf(pos, "%s redeclared", obj.Name()) - err.recordAltDecl(alt) - check.report(&err) - return false - } - return true -} - -func (check *Checker) tag(t *syntax.BasicLit) string { - // If t.Bad, an error was reported during parsing. - if t != nil && !t.Bad { - if t.Kind == syntax.StringLit { - if val, err := strconv.Unquote(t.Value); err == nil { - return val - } - } - check.errorf(t, invalidAST+"incorrect tag syntax: %q", t.Value) - } - return "" -} - -func (check *Checker) structType(styp *Struct, e *syntax.StructType) { - if e.FieldList == nil { - return - } - - // struct fields and tags - var fields []*Var - var tags []string - - // for double-declaration checks - var fset objset - - // current field typ and tag - var typ Type - var tag string - add := func(ident *syntax.Name, embedded bool, pos syntax.Pos) { - if tag != "" && tags == nil { - tags = make([]string, len(fields)) - } - if tags != nil { - tags = append(tags, tag) - } - - name := ident.Value - fld := NewField(pos, check.pkg, name, typ, embedded) - // spec: "Within a struct, non-blank field names must be unique." - if name == "_" || check.declareInSet(&fset, pos, fld) { - fields = append(fields, fld) - check.recordDef(ident, fld) - } - } - - // addInvalid adds an embedded field of invalid type to the struct for - // fields with errors; this keeps the number of struct fields in sync - // with the source as long as the fields are _ or have different names - // (issue #25627). - addInvalid := func(ident *syntax.Name, pos syntax.Pos) { - typ = Typ[Invalid] - tag = "" - add(ident, true, pos) - } - - var prev syntax.Expr - for i, f := range e.FieldList { - // Fields declared syntactically with the same type (e.g.: a, b, c T) - // share the same type expression. Only check type if it's a new type. - if i == 0 || f.Type != prev { - typ = check.varType(f.Type) - prev = f.Type - } - tag = "" - if i < len(e.TagList) { - tag = check.tag(e.TagList[i]) - } - if f.Name != nil { - // named field - add(f.Name, false, f.Name.Pos()) - } else { - // embedded field - // spec: "An embedded type must be specified as a type name T or as a - // pointer to a non-interface type name *T, and T itself may not be a - // pointer type." - pos := syntax.StartPos(f.Type) - name := embeddedFieldIdent(f.Type) - if name == nil { - check.errorf(pos, "invalid embedded field type %s", f.Type) - name = &syntax.Name{Value: "_"} // TODO(gri) need to set position to pos - addInvalid(name, pos) - continue - } - add(name, true, pos) - - // Because we have a name, typ must be of the form T or *T, where T is the name - // of a (named or alias) type, and t (= deref(typ)) must be the type of T. - // We must delay this check to the end because we don't want to instantiate - // (via under(t)) a possibly incomplete type. - embeddedTyp := typ // for closure below - embeddedPos := pos - check.later(func() { - t, isPtr := deref(embeddedTyp) - switch t := optype(t).(type) { - case *Basic: - if t == Typ[Invalid] { - // error was reported before - return - } - // unsafe.Pointer is treated like a regular pointer - if t.kind == UnsafePointer { - check.error(embeddedPos, "embedded field type cannot be unsafe.Pointer") - } - case *Pointer: - check.error(embeddedPos, "embedded field type cannot be a pointer") - case *Interface: - if isPtr { - check.error(embeddedPos, "embedded field type cannot be a pointer to an interface") - } - } - }) - } - } - - styp.fields = fields - styp.tags = tags -} - -func embeddedFieldIdent(e syntax.Expr) *syntax.Name { - switch e := e.(type) { - case *syntax.Name: - return e - case *syntax.Operation: - if base := ptrBase(e); base != nil { - // *T is valid, but **T is not - if op, _ := base.(*syntax.Operation); op == nil || ptrBase(op) == nil { - return embeddedFieldIdent(e.X) - } - } - case *syntax.SelectorExpr: - return e.Sel - case *syntax.IndexExpr: - return embeddedFieldIdent(e.X) - } - return nil // invalid embedded field -} - -func ptrBase(x *syntax.Operation) syntax.Expr { - if x.Op == syntax.Mul && x.Y == nil { - return x.X - } - return nil -} From 243076da64d251853ed7a69ce770e9fa71b5bf0d Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 20 May 2021 14:53:21 -0700 Subject: [PATCH 112/940] [dev.typeparams] cmd/compile/internal/types2: move signature checking into separate file This only moves functionality from one file into another. Except for import adjustments there are no changes to the code. Change-Id: Id0d20a7537f20abe3a257ad3f550b0cb4499598c Reviewed-on: https://go-review.googlesource.com/c/go/+/321590 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/signature.go | 314 +++++++++++++++++++ src/cmd/compile/internal/types2/typexpr.go | 304 ------------------ 2 files changed, 314 insertions(+), 304 deletions(-) create mode 100644 src/cmd/compile/internal/types2/signature.go diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go new file mode 100644 index 00000000000..c8c4cca0a78 --- /dev/null +++ b/src/cmd/compile/internal/types2/signature.go @@ -0,0 +1,314 @@ +// Copyright 2021 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 types2 + +import ( + "cmd/compile/internal/syntax" + "fmt" +) + +// Disabled by default, but enabled when running tests (via types_test.go). +var acceptMethodTypeParams bool + +// funcType type-checks a function or method type. +func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []*syntax.Field, ftyp *syntax.FuncType) { + check.openScope(ftyp, "function") + check.scope.isFunc = true + check.recordScope(ftyp, check.scope) + sig.scope = check.scope + defer check.closeScope() + + var recvTyp syntax.Expr // rewritten receiver type; valid if != nil + if recvPar != nil { + // collect generic receiver type parameters, if any + // - a receiver type parameter is like any other type parameter, except that it is declared implicitly + // - the receiver specification acts as local declaration for its type parameters, which may be blank + _, rname, rparams := check.unpackRecv(recvPar.Type, true) + if len(rparams) > 0 { + // Blank identifiers don't get declared and regular type-checking of the instantiated + // parameterized receiver type expression fails in Checker.collectParams of receiver. + // Identify blank type parameters and substitute each with a unique new identifier named + // "n_" (where n is the parameter index) and which cannot conflict with any user-defined + // name. + var smap map[*syntax.Name]*syntax.Name // substitution map from "_" to "!n" identifiers + for i, p := range rparams { + if p.Value == "_" { + new := *p + new.Value = fmt.Sprintf("%d_", i) + rparams[i] = &new // use n_ identifier instead of _ so it can be looked up + if smap == nil { + smap = make(map[*syntax.Name]*syntax.Name) + } + smap[p] = &new + } + } + if smap != nil { + // blank identifiers were found => use rewritten receiver type + recvTyp = isubst(recvPar.Type, smap) + } + // TODO(gri) rework declareTypeParams + sig.rparams = nil + for _, rparam := range rparams { + sig.rparams = check.declareTypeParam(sig.rparams, rparam) + } + // determine receiver type to get its type parameters + // and the respective type parameter bounds + var recvTParams []*TypeName + if rname != nil { + // recv should be a Named type (otherwise an error is reported elsewhere) + // Also: Don't report an error via genericType since it will be reported + // again when we type-check the signature. + // TODO(gri) maybe the receiver should be marked as invalid instead? + if recv := asNamed(check.genericType(rname, false)); recv != nil { + recvTParams = recv.tparams + } + } + // provide type parameter bounds + // - only do this if we have the right number (otherwise an error is reported elsewhere) + if len(sig.rparams) == len(recvTParams) { + // We have a list of *TypeNames but we need a list of Types. + list := make([]Type, len(sig.rparams)) + for i, t := range sig.rparams { + list[i] = t.typ + } + smap := makeSubstMap(recvTParams, list) + for i, tname := range sig.rparams { + bound := recvTParams[i].typ.(*TypeParam).bound + // bound is (possibly) parameterized in the context of the + // receiver type declaration. Substitute parameters for the + // current context. + // TODO(gri) should we assume now that bounds always exist? + // (no bound == empty interface) + if bound != nil { + bound = check.subst(tname.pos, bound, smap) + tname.typ.(*TypeParam).bound = bound + } + } + } + } + } + + if tparams != nil { + sig.tparams = check.collectTypeParams(tparams) + // Always type-check method type parameters but complain if they are not enabled. + // (A separate check is needed when type-checking interface method signatures because + // they don't have a receiver specification.) + if recvPar != nil && !acceptMethodTypeParams { + check.error(ftyp, "methods cannot have type parameters") + } + } + + // Value (non-type) parameters' scope starts in the function body. Use a temporary scope for their + // declarations and then squash that scope into the parent scope (and report any redeclarations at + // that time). + scope := NewScope(check.scope, nopos, nopos, "function body (temp. scope)") + var recvList []*Var // TODO(gri) remove the need for making a list here + if recvPar != nil { + recvList, _ = check.collectParams(scope, []*syntax.Field{recvPar}, recvTyp, false) // use rewritten receiver type, if any + } + params, variadic := check.collectParams(scope, ftyp.ParamList, nil, true) + results, _ := check.collectParams(scope, ftyp.ResultList, nil, false) + scope.Squash(func(obj, alt Object) { + var err error_ + err.errorf(obj, "%s redeclared in this block", obj.Name()) + err.recordAltDecl(alt) + check.report(&err) + }) + + if recvPar != nil { + // recv parameter list present (may be empty) + // spec: "The receiver is specified via an extra parameter section preceding the + // method name. That parameter section must declare a single parameter, the receiver." + var recv *Var + switch len(recvList) { + case 0: + // error reported by resolver + recv = NewParam(nopos, nil, "", Typ[Invalid]) // ignore recv below + default: + // more than one receiver + check.error(recvList[len(recvList)-1].Pos(), "method must have exactly one receiver") + fallthrough // continue with first receiver + case 1: + recv = recvList[0] + } + + // TODO(gri) We should delay rtyp expansion to when we actually need the + // receiver; thus all checks here should be delayed to later. + rtyp, _ := deref(recv.typ) + rtyp = expand(rtyp) + + // spec: "The receiver type must be of the form T or *T where T is a type name." + // (ignore invalid types - error was reported before) + if t := rtyp; t != Typ[Invalid] { + var err string + if T := asNamed(t); T != nil { + // spec: "The type denoted by T is called the receiver base type; it must not + // be a pointer or interface type and it must be declared in the same package + // as the method." + if T.obj.pkg != check.pkg { + err = "type not defined in this package" + if check.conf.CompilerErrorMessages { + check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ) + err = "" + } + } else { + switch u := optype(T).(type) { + case *Basic: + // unsafe.Pointer is treated like a regular pointer + if u.kind == UnsafePointer { + err = "unsafe.Pointer" + } + case *Pointer, *Interface: + err = "pointer or interface type" + } + } + } else if T := asBasic(t); T != nil { + err = "basic or unnamed type" + if check.conf.CompilerErrorMessages { + check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ) + err = "" + } + } else { + check.errorf(recv.pos, "invalid receiver type %s", recv.typ) + } + if err != "" { + check.errorf(recv.pos, "invalid receiver type %s (%s)", recv.typ, err) + // ok to continue + } + } + sig.recv = recv + } + + sig.params = NewTuple(params...) + sig.results = NewTuple(results...) + sig.variadic = variadic +} + +// collectParams declares the parameters of list in scope and returns the corresponding +// variable list. If type0 != nil, it is used instead of the first type in list. +func (check *Checker) collectParams(scope *Scope, list []*syntax.Field, type0 syntax.Expr, variadicOk bool) (params []*Var, variadic bool) { + if list == nil { + return + } + + var named, anonymous bool + + var typ Type + var prev syntax.Expr + for i, field := range list { + ftype := field.Type + // type-check type of grouped fields only once + if ftype != prev { + prev = ftype + if i == 0 && type0 != nil { + ftype = type0 + } + if t, _ := ftype.(*syntax.DotsType); t != nil { + ftype = t.Elem + if variadicOk && i == len(list)-1 { + variadic = true + } else { + check.softErrorf(t, "can only use ... with final parameter in list") + // ignore ... and continue + } + } + typ = check.varType(ftype) + } + // The parser ensures that f.Tag is nil and we don't + // care if a constructed AST contains a non-nil tag. + if field.Name != nil { + // named parameter + name := field.Name.Value + if name == "" { + check.error(field.Name, invalidAST+"anonymous parameter") + // ok to continue + } + par := NewParam(field.Name.Pos(), check.pkg, name, typ) + check.declare(scope, field.Name, par, scope.pos) + params = append(params, par) + named = true + } else { + // anonymous parameter + par := NewParam(field.Pos(), check.pkg, "", typ) + check.recordImplicit(field, par) + params = append(params, par) + anonymous = true + } + } + + if named && anonymous { + check.error(list[0], invalidAST+"list contains both named and anonymous parameters") + // ok to continue + } + + // For a variadic function, change the last parameter's type from T to []T. + // Since we type-checked T rather than ...T, we also need to retro-actively + // record the type for ...T. + if variadic { + last := params[len(params)-1] + last.typ = &Slice{elem: last.typ} + check.recordTypeAndValue(list[len(list)-1].Type, typexpr, last.typ, nil) + } + + return +} + +// isubst returns an x with identifiers substituted per the substitution map smap. +// isubst only handles the case of (valid) method receiver type expressions correctly. +func isubst(x syntax.Expr, smap map[*syntax.Name]*syntax.Name) syntax.Expr { + switch n := x.(type) { + case *syntax.Name: + if alt := smap[n]; alt != nil { + return alt + } + // case *syntax.StarExpr: + // X := isubst(n.X, smap) + // if X != n.X { + // new := *n + // new.X = X + // return &new + // } + case *syntax.Operation: + if n.Op == syntax.Mul && n.Y == nil { + X := isubst(n.X, smap) + if X != n.X { + new := *n + new.X = X + return &new + } + } + case *syntax.IndexExpr: + Index := isubst(n.Index, smap) + if Index != n.Index { + new := *n + new.Index = Index + return &new + } + case *syntax.ListExpr: + var elems []syntax.Expr + for i, elem := range n.ElemList { + new := isubst(elem, smap) + if new != elem { + if elems == nil { + elems = make([]syntax.Expr, len(n.ElemList)) + copy(elems, n.ElemList) + } + elems[i] = new + } + } + if elems != nil { + new := *n + new.ElemList = elems + return &new + } + case *syntax.ParenExpr: + return isubst(n.X, smap) // no need to keep parentheses + default: + // Other receiver type expressions are invalid. + // It's fine to ignore those here as they will + // be checked elsewhere. + } + return x +} diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index 2352030b9b1..b27b2a00df0 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -13,9 +13,6 @@ import ( "strings" ) -// Disabled by default, but enabled when running tests (via types_test.go). -var acceptMethodTypeParams bool - // ident type-checks identifier e and initializes x with the value or type of e. // If an error occurred, x.mode is set to invalid. // For the meaning of def, see Checker.definedType, below. @@ -196,238 +193,6 @@ func (check *Checker) genericType(e syntax.Expr, reportErr bool) Type { return typ } -// isubst returns an x with identifiers substituted per the substitution map smap. -// isubst only handles the case of (valid) method receiver type expressions correctly. -func isubst(x syntax.Expr, smap map[*syntax.Name]*syntax.Name) syntax.Expr { - switch n := x.(type) { - case *syntax.Name: - if alt := smap[n]; alt != nil { - return alt - } - // case *syntax.StarExpr: - // X := isubst(n.X, smap) - // if X != n.X { - // new := *n - // new.X = X - // return &new - // } - case *syntax.Operation: - if n.Op == syntax.Mul && n.Y == nil { - X := isubst(n.X, smap) - if X != n.X { - new := *n - new.X = X - return &new - } - } - case *syntax.IndexExpr: - Index := isubst(n.Index, smap) - if Index != n.Index { - new := *n - new.Index = Index - return &new - } - case *syntax.ListExpr: - var elems []syntax.Expr - for i, elem := range n.ElemList { - new := isubst(elem, smap) - if new != elem { - if elems == nil { - elems = make([]syntax.Expr, len(n.ElemList)) - copy(elems, n.ElemList) - } - elems[i] = new - } - } - if elems != nil { - new := *n - new.ElemList = elems - return &new - } - case *syntax.ParenExpr: - return isubst(n.X, smap) // no need to keep parentheses - default: - // Other receiver type expressions are invalid. - // It's fine to ignore those here as they will - // be checked elsewhere. - } - return x -} - -// funcType type-checks a function or method type. -func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []*syntax.Field, ftyp *syntax.FuncType) { - check.openScope(ftyp, "function") - check.scope.isFunc = true - check.recordScope(ftyp, check.scope) - sig.scope = check.scope - defer check.closeScope() - - var recvTyp syntax.Expr // rewritten receiver type; valid if != nil - if recvPar != nil { - // collect generic receiver type parameters, if any - // - a receiver type parameter is like any other type parameter, except that it is declared implicitly - // - the receiver specification acts as local declaration for its type parameters, which may be blank - _, rname, rparams := check.unpackRecv(recvPar.Type, true) - if len(rparams) > 0 { - // Blank identifiers don't get declared and regular type-checking of the instantiated - // parameterized receiver type expression fails in Checker.collectParams of receiver. - // Identify blank type parameters and substitute each with a unique new identifier named - // "n_" (where n is the parameter index) and which cannot conflict with any user-defined - // name. - var smap map[*syntax.Name]*syntax.Name // substitution map from "_" to "!n" identifiers - for i, p := range rparams { - if p.Value == "_" { - new := *p - new.Value = fmt.Sprintf("%d_", i) - rparams[i] = &new // use n_ identifier instead of _ so it can be looked up - if smap == nil { - smap = make(map[*syntax.Name]*syntax.Name) - } - smap[p] = &new - } - } - if smap != nil { - // blank identifiers were found => use rewritten receiver type - recvTyp = isubst(recvPar.Type, smap) - } - // TODO(gri) rework declareTypeParams - sig.rparams = nil - for _, rparam := range rparams { - sig.rparams = check.declareTypeParam(sig.rparams, rparam) - } - // determine receiver type to get its type parameters - // and the respective type parameter bounds - var recvTParams []*TypeName - if rname != nil { - // recv should be a Named type (otherwise an error is reported elsewhere) - // Also: Don't report an error via genericType since it will be reported - // again when we type-check the signature. - // TODO(gri) maybe the receiver should be marked as invalid instead? - if recv := asNamed(check.genericType(rname, false)); recv != nil { - recvTParams = recv.tparams - } - } - // provide type parameter bounds - // - only do this if we have the right number (otherwise an error is reported elsewhere) - if len(sig.rparams) == len(recvTParams) { - // We have a list of *TypeNames but we need a list of Types. - list := make([]Type, len(sig.rparams)) - for i, t := range sig.rparams { - list[i] = t.typ - } - smap := makeSubstMap(recvTParams, list) - for i, tname := range sig.rparams { - bound := recvTParams[i].typ.(*TypeParam).bound - // bound is (possibly) parameterized in the context of the - // receiver type declaration. Substitute parameters for the - // current context. - // TODO(gri) should we assume now that bounds always exist? - // (no bound == empty interface) - if bound != nil { - bound = check.subst(tname.pos, bound, smap) - tname.typ.(*TypeParam).bound = bound - } - } - } - } - } - - if tparams != nil { - sig.tparams = check.collectTypeParams(tparams) - // Always type-check method type parameters but complain if they are not enabled. - // (A separate check is needed when type-checking interface method signatures because - // they don't have a receiver specification.) - if recvPar != nil && !acceptMethodTypeParams { - check.error(ftyp, "methods cannot have type parameters") - } - } - - // Value (non-type) parameters' scope starts in the function body. Use a temporary scope for their - // declarations and then squash that scope into the parent scope (and report any redeclarations at - // that time). - scope := NewScope(check.scope, nopos, nopos, "function body (temp. scope)") - var recvList []*Var // TODO(gri) remove the need for making a list here - if recvPar != nil { - recvList, _ = check.collectParams(scope, []*syntax.Field{recvPar}, recvTyp, false) // use rewritten receiver type, if any - } - params, variadic := check.collectParams(scope, ftyp.ParamList, nil, true) - results, _ := check.collectParams(scope, ftyp.ResultList, nil, false) - scope.Squash(func(obj, alt Object) { - var err error_ - err.errorf(obj, "%s redeclared in this block", obj.Name()) - err.recordAltDecl(alt) - check.report(&err) - }) - - if recvPar != nil { - // recv parameter list present (may be empty) - // spec: "The receiver is specified via an extra parameter section preceding the - // method name. That parameter section must declare a single parameter, the receiver." - var recv *Var - switch len(recvList) { - case 0: - // error reported by resolver - recv = NewParam(nopos, nil, "", Typ[Invalid]) // ignore recv below - default: - // more than one receiver - check.error(recvList[len(recvList)-1].Pos(), "method must have exactly one receiver") - fallthrough // continue with first receiver - case 1: - recv = recvList[0] - } - - // TODO(gri) We should delay rtyp expansion to when we actually need the - // receiver; thus all checks here should be delayed to later. - rtyp, _ := deref(recv.typ) - rtyp = expand(rtyp) - - // spec: "The receiver type must be of the form T or *T where T is a type name." - // (ignore invalid types - error was reported before) - if t := rtyp; t != Typ[Invalid] { - var err string - if T := asNamed(t); T != nil { - // spec: "The type denoted by T is called the receiver base type; it must not - // be a pointer or interface type and it must be declared in the same package - // as the method." - if T.obj.pkg != check.pkg { - err = "type not defined in this package" - if check.conf.CompilerErrorMessages { - check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ) - err = "" - } - } else { - switch u := optype(T).(type) { - case *Basic: - // unsafe.Pointer is treated like a regular pointer - if u.kind == UnsafePointer { - err = "unsafe.Pointer" - } - case *Pointer, *Interface: - err = "pointer or interface type" - } - } - } else if T := asBasic(t); T != nil { - err = "basic or unnamed type" - if check.conf.CompilerErrorMessages { - check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ) - err = "" - } - } else { - check.errorf(recv.pos, "invalid receiver type %s", recv.typ) - } - if err != "" { - check.errorf(recv.pos, "invalid receiver type %s (%s)", recv.typ, err) - // ok to continue - } - } - sig.recv = recv - } - - sig.params = NewTuple(params...) - sig.results = NewTuple(results...) - sig.variadic = variadic -} - // goTypeName returns the Go type name for typ and // removes any occurrences of "types2." from that name. func goTypeName(typ Type) string { @@ -730,72 +495,3 @@ func (check *Checker) typeList(list []syntax.Expr) []Type { } return res } - -// collectParams declares the parameters of list in scope and returns the corresponding -// variable list. If type0 != nil, it is used instead of the first type in list. -func (check *Checker) collectParams(scope *Scope, list []*syntax.Field, type0 syntax.Expr, variadicOk bool) (params []*Var, variadic bool) { - if list == nil { - return - } - - var named, anonymous bool - - var typ Type - var prev syntax.Expr - for i, field := range list { - ftype := field.Type - // type-check type of grouped fields only once - if ftype != prev { - prev = ftype - if i == 0 && type0 != nil { - ftype = type0 - } - if t, _ := ftype.(*syntax.DotsType); t != nil { - ftype = t.Elem - if variadicOk && i == len(list)-1 { - variadic = true - } else { - check.softErrorf(t, "can only use ... with final parameter in list") - // ignore ... and continue - } - } - typ = check.varType(ftype) - } - // The parser ensures that f.Tag is nil and we don't - // care if a constructed AST contains a non-nil tag. - if field.Name != nil { - // named parameter - name := field.Name.Value - if name == "" { - check.error(field.Name, invalidAST+"anonymous parameter") - // ok to continue - } - par := NewParam(field.Name.Pos(), check.pkg, name, typ) - check.declare(scope, field.Name, par, scope.pos) - params = append(params, par) - named = true - } else { - // anonymous parameter - par := NewParam(field.Pos(), check.pkg, "", typ) - check.recordImplicit(field, par) - params = append(params, par) - anonymous = true - } - } - - if named && anonymous { - check.error(list[0], invalidAST+"list contains both named and anonymous parameters") - // ok to continue - } - - // For a variadic function, change the last parameter's type from T to []T. - // Since we type-checked T rather than ...T, we also need to retro-actively - // record the type for ...T. - if variadic { - last := params[len(params)-1] - last.typ = &Slice{elem: last.typ} - check.recordTypeAndValue(list[len(list)-1].Type, typexpr, last.typ, nil) - } - - return -} From 3148694f607b77731420a20ef2117ac7d0d55ba3 Mon Sep 17 00:00:00 2001 From: Tim Heckman Date: Thu, 20 May 2021 16:51:28 -0700 Subject: [PATCH 113/940] cmd/go: remove warning from module deprecation notice printing Fixes #46294 Change-Id: I50023006dab83dee455f98a702ca1c72e61764ea Reviewed-on: https://go-review.googlesource.com/c/go/+/321649 Trust: Jay Conrod Trust: Michael Matloob Run-TryBot: Jay Conrod TryBot-Result: Go Bot Reviewed-by: Jay Conrod --- src/cmd/go/internal/modget/get.go | 2 +- src/cmd/go/testdata/script/mod_deprecate_message.txt | 8 ++++---- src/cmd/go/testdata/script/mod_get_deprecated.txt | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go index 2a7fe5226fd..563f1a988f0 100644 --- a/src/cmd/go/internal/modget/get.go +++ b/src/cmd/go/internal/modget/get.go @@ -1598,7 +1598,7 @@ func (r *resolver) checkPackageProblems(ctx context.Context, pkgPatterns []strin // Report deprecations, then retractions. for _, mm := range deprecations { if mm.message != "" { - fmt.Fprintf(os.Stderr, "go: warning: module %s is deprecated: %s\n", mm.m.Path, mm.message) + fmt.Fprintf(os.Stderr, "go: module %s is deprecated: %s\n", mm.m.Path, mm.message) } } var retractPath string diff --git a/src/cmd/go/testdata/script/mod_deprecate_message.txt b/src/cmd/go/testdata/script/mod_deprecate_message.txt index 4a0674b8084..567027935dc 100644 --- a/src/cmd/go/testdata/script/mod_deprecate_message.txt +++ b/src/cmd/go/testdata/script/mod_deprecate_message.txt @@ -1,26 +1,26 @@ # When there is a short single-line message, 'go get' should print it all. go get -d short -stderr '^go: warning: module short is deprecated: short$' +stderr '^go: module short is deprecated: short$' go list -m -u -f '{{.Deprecated}}' short stdout '^short$' # When there is a multi-line message, 'go get' should print the first line. go get -d multiline -stderr '^go: warning: module multiline is deprecated: first line$' +stderr '^go: module multiline is deprecated: first line$' ! stderr 'second line' go list -m -u -f '{{.Deprecated}}' multiline stdout '^first line\nsecond line.$' # When there is a long message, 'go get' should print a placeholder. go get -d long -stderr '^go: warning: module long is deprecated: \(message omitted: too long\)$' +stderr '^go: module long is deprecated: \(message omitted: too long\)$' go list -m -u -f '{{.Deprecated}}' long stdout '^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa$' # When a message contains unprintable chracters, 'go get' should say that # without printing the message. go get -d unprintable -stderr '^go: warning: module unprintable is deprecated: \(message omitted: contains non-printable characters\)$' +stderr '^go: module unprintable is deprecated: \(message omitted: contains non-printable characters\)$' go list -m -u -f '{{.Deprecated}}' unprintable stdout '^message contains ASCII BEL\x07$' diff --git a/src/cmd/go/testdata/script/mod_get_deprecated.txt b/src/cmd/go/testdata/script/mod_get_deprecated.txt index 4633009f69b..7bdd7a58a89 100644 --- a/src/cmd/go/testdata/script/mod_get_deprecated.txt +++ b/src/cmd/go/testdata/script/mod_get_deprecated.txt @@ -4,14 +4,14 @@ go get -d ./use/nothing # 'go get pkg' should show a deprecation message for the module providing pkg. go get -d example.com/deprecated/a -stderr '^go: warning: module example.com/deprecated/a is deprecated: in example.com/deprecated/a@v1.9.0$' +stderr '^go: module example.com/deprecated/a is deprecated: in example.com/deprecated/a@v1.9.0$' go get -d example.com/deprecated/a@v1.0.0 -stderr '^go: warning: module example.com/deprecated/a is deprecated: in example.com/deprecated/a@v1.9.0$' +stderr '^go: module example.com/deprecated/a is deprecated: in example.com/deprecated/a@v1.9.0$' # 'go get pkg' should show a deprecation message for a module providing # packages directly imported by pkg. go get -d ./use/a -stderr '^go: warning: module example.com/deprecated/a is deprecated: in example.com/deprecated/a@v1.9.0$' +stderr '^go: module example.com/deprecated/a is deprecated: in example.com/deprecated/a@v1.9.0$' # 'go get pkg' may show a deprecation message for an indirectly required module # if it provides a package named on the command line. @@ -20,7 +20,7 @@ go get -d ./use/b go get -d local/use ! stderr 'module.*is deprecated' go get -d example.com/deprecated/b -stderr '^go: warning: module example.com/deprecated/b is deprecated: in example.com/deprecated/b@v1.9.0$' +stderr '^go: module example.com/deprecated/b is deprecated: in example.com/deprecated/b@v1.9.0$' # 'go get pkg' does not show a deprecation message for a module providing a # directly imported package if the module is no longer deprecated in its From ccbfbb1c3327fffe88dd6b6da550f4a0cd37db6e Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Sun, 9 May 2021 11:38:34 -0700 Subject: [PATCH 114/940] [dev.typeparams] cmd/compile: export OFUNCINST and OSELRECV2 nodes (for generic functions) Added new test typeparam/factimp.go and changed a bunch of other tests to test exporting more generic functions and types. Change-Id: I573d75431cc92482f8f908695cfbc8e84dbb36d2 Reviewed-on: https://go-review.googlesource.com/c/go/+/321749 Trust: Dan Scales Reviewed-by: Keith Randall --- src/cmd/compile/internal/typecheck/iexport.go | 20 ++++++++ src/cmd/compile/internal/typecheck/iimport.go | 20 ++++++++ test/typeparam/combine.go | 28 +++++------ test/typeparam/cons.go | 46 +++++++++---------- test/typeparam/factimp.dir/a.go | 12 +++++ test/typeparam/factimp.dir/main.go | 26 +++++++++++ test/typeparam/factimp.go | 7 +++ test/typeparam/index.go | 8 ++-- test/typeparam/listimp.dir/a.go | 4 ++ test/typeparam/listimp.dir/main.go | 4 ++ test/typeparam/lockable.go | 16 +++---- 11 files changed, 142 insertions(+), 49 deletions(-) create mode 100644 test/typeparam/factimp.dir/a.go create mode 100644 test/typeparam/factimp.dir/main.go create mode 100644 test/typeparam/factimp.go diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index e6813adbf90..d125dadd883 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -1920,6 +1920,26 @@ func (w *exportWriter) expr(n ir.Node) { // if exporting, DCLCONST should just be removed as its usage // has already been replaced with literals + case ir.OFUNCINST: + n := n.(*ir.InstExpr) + w.op(ir.OFUNCINST) + w.pos(n.Pos()) + w.expr(n.X) + w.uint64(uint64(len(n.Targs))) + for _, targ := range n.Targs { + w.typ(targ.Type()) + } + if go117ExportTypes { + w.typ(n.Type()) + } + + case ir.OSELRECV2: + n := n.(*ir.AssignListStmt) + w.op(ir.OSELRECV2) + w.pos(n.Pos()) + w.exprList(n.Lhs) + w.exprList(n.Rhs) + default: base.Fatalf("cannot export %v (%d) node\n"+ "\t==> please file an issue and assign to gri@", n.Op(), int(n.Op())) diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 778ce4be12a..3b725a226c4 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -1582,6 +1582,26 @@ func (r *importReader) node() ir.Node { case ir.OEND: return nil + case ir.OFUNCINST: + pos := r.pos() + x := r.expr() + ntargs := r.uint64() + var targs []ir.Node + if ntargs > 0 { + targs = make([]ir.Node, ntargs) + for i := range targs { + targs[i] = ir.TypeNode(r.typ()) + } + } + n := ir.NewInstExpr(pos, ir.OFUNCINST, x, targs) + if go117ExportTypes { + n.SetType(r.typ()) + } + return n + + case ir.OSELRECV2: + return ir.NewAssignListStmt(r.pos(), ir.OSELRECV2, r.exprList(), r.exprList()) + default: base.Fatalf("cannot import %v (%d) node\n"+ "\t==> please file an issue and assign to gri@", op, int(op)) diff --git a/test/typeparam/combine.go b/test/typeparam/combine.go index d4a2988a7b0..0e120cf2427 100644 --- a/test/typeparam/combine.go +++ b/test/typeparam/combine.go @@ -10,9 +10,9 @@ import ( "fmt" ) -type _Gen[A any] func() (A, bool) +type Gen[A any] func() (A, bool) -func combine[T1, T2, T any](g1 _Gen[T1], g2 _Gen[T2], join func(T1, T2) T) _Gen[T] { +func Combine[T1, T2, T any](g1 Gen[T1], g2 Gen[T2], join func(T1, T2) T) Gen[T] { return func() (T, bool) { var t T t1, ok := g1() @@ -27,38 +27,38 @@ func combine[T1, T2, T any](g1 _Gen[T1], g2 _Gen[T2], join func(T1, T2) T) _Gen[ } } -type _Pair[A, B any] struct { +type Pair[A, B any] struct { A A B B } -func _NewPair[A, B any](a A, b B) _Pair[A, B] { - return _Pair[A, B]{a, b} +func _NewPair[A, B any](a A, b B) Pair[A, B] { + return Pair[A, B]{a, b} } -func _Combine2[A, B any](ga _Gen[A], gb _Gen[B]) _Gen[_Pair[A, B]] { - return combine(ga, gb, _NewPair[A, B]) +func Combine2[A, B any](ga Gen[A], gb Gen[B]) Gen[Pair[A, B]] { + return Combine(ga, gb, _NewPair[A, B]) } func main() { - var g1 _Gen[int] = func() (int, bool) { return 3, true } - var g2 _Gen[string] = func() (string, bool) { return "x", false } - var g3 _Gen[string] = func() (string, bool) { return "y", true } + var g1 Gen[int] = func() (int, bool) { return 3, true } + var g2 Gen[string] = func() (string, bool) { return "x", false } + var g3 Gen[string] = func() (string, bool) { return "y", true } - gc := combine(g1, g2, _NewPair[int, string]) + gc := Combine(g1, g2, _NewPair[int, string]) if got, ok := gc(); ok { panic(fmt.Sprintf("got %v, %v, wanted -/false", got, ok)) } - gc2 := _Combine2(g1, g2) + gc2 := Combine2(g1, g2) if got, ok := gc2(); ok { panic(fmt.Sprintf("got %v, %v, wanted -/false", got, ok)) } - gc3 := combine(g1, g3, _NewPair[int, string]) + gc3 := Combine(g1, g3, _NewPair[int, string]) if got, ok := gc3(); !ok || got.A != 3 || got.B != "y" { panic(fmt.Sprintf("got %v, %v, wanted {3, y}, true", got, ok)) } - gc4 := _Combine2(g1, g3) + gc4 := Combine2(g1, g3) if got, ok := gc4(); !ok || got.A != 3 || got.B != "y" { panic (fmt.Sprintf("got %v, %v, wanted {3, y}, true", got, ok)) } diff --git a/test/typeparam/cons.go b/test/typeparam/cons.go index 8d255ebdb83..f20514fb66e 100644 --- a/test/typeparam/cons.go +++ b/test/typeparam/cons.go @@ -12,7 +12,7 @@ import "fmt" // argument type any interface{} -type _Function[a, b any] interface { +type Function[a, b any] interface { Apply(x a) b } @@ -29,8 +29,8 @@ func (this pos) Apply(x int) bool { } type compose[a, b, c any] struct { - f _Function[a, b] - g _Function[b, c] + f Function[a, b] + g Function[b, c] } func (this compose[a, b, c]) Apply(x a) c { @@ -47,52 +47,52 @@ func (this Int) Equal(that int) bool { return int(this) == that } -type _List[a any] interface { - Match(casenil _Function[_Nil[a], any], casecons _Function[_Cons[a], any]) any +type List[a any] interface { + Match(casenil Function[Nil[a], any], casecons Function[Cons[a], any]) any } -type _Nil[a any] struct{ +type Nil[a any] struct{ } -func (xs _Nil[a]) Match(casenil _Function[_Nil[a], any], casecons _Function[_Cons[a], any]) any { +func (xs Nil[a]) Match(casenil Function[Nil[a], any], casecons Function[Cons[a], any]) any { return casenil.Apply(xs) } -type _Cons[a any] struct { +type Cons[a any] struct { Head a - Tail _List[a] + Tail List[a] } -func (xs _Cons[a]) Match(casenil _Function[_Nil[a], any], casecons _Function[_Cons[a], any]) any { +func (xs Cons[a]) Match(casenil Function[Nil[a], any], casecons Function[Cons[a], any]) any { return casecons.Apply(xs) } type mapNil[a, b any] struct{ } -func (m mapNil[a, b]) Apply(_ _Nil[a]) any { - return _Nil[b]{} +func (m mapNil[a, b]) Apply(_ Nil[a]) any { + return Nil[b]{} } type mapCons[a, b any] struct { - f _Function[a, b] + f Function[a, b] } -func (m mapCons[a, b]) Apply(xs _Cons[a]) any { - return _Cons[b]{m.f.Apply(xs.Head), _Map[a, b](m.f, xs.Tail)} +func (m mapCons[a, b]) Apply(xs Cons[a]) any { + return Cons[b]{m.f.Apply(xs.Head), Map[a, b](m.f, xs.Tail)} } -func _Map[a, b any](f _Function[a, b], xs _List[a]) _List[b] { - return xs.Match(mapNil[a, b]{}, mapCons[a, b]{f}).(_List[b]) +func Map[a, b any](f Function[a, b], xs List[a]) List[b] { + return xs.Match(mapNil[a, b]{}, mapCons[a, b]{f}).(List[b]) } func main() { - var xs _List[int] = _Cons[int]{3, _Cons[int]{6, _Nil[int]{}}} - var ys _List[int] = _Map[int, int](incr{-5}, xs) - var xz _List[bool] = _Map[int, bool](pos{}, ys) - cs1 := xz.(_Cons[bool]) - cs2 := cs1.Tail.(_Cons[bool]) - _, ok := cs2.Tail.(_Nil[bool]) + var xs List[int] = Cons[int]{3, Cons[int]{6, Nil[int]{}}} + var ys List[int] = Map[int, int](incr{-5}, xs) + var xz List[bool] = Map[int, bool](pos{}, ys) + cs1 := xz.(Cons[bool]) + cs2 := cs1.Tail.(Cons[bool]) + _, ok := cs2.Tail.(Nil[bool]) if cs1.Head != false || cs2.Head != true || !ok { panic(fmt.Sprintf("got %v, %v, %v, expected false, true, true", cs1.Head, cs2.Head, ok)) diff --git a/test/typeparam/factimp.dir/a.go b/test/typeparam/factimp.dir/a.go new file mode 100644 index 00000000000..e11575e66e5 --- /dev/null +++ b/test/typeparam/factimp.dir/a.go @@ -0,0 +1,12 @@ +// Copyright 2021 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 a + +func Fact[T interface { type int, int64, float64 }](n T) T { + if n == T(1) { + return T(1) + } + return n * Fact(n - T(1)) +} diff --git a/test/typeparam/factimp.dir/main.go b/test/typeparam/factimp.dir/main.go new file mode 100644 index 00000000000..c2238002aeb --- /dev/null +++ b/test/typeparam/factimp.dir/main.go @@ -0,0 +1,26 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "a" + "fmt" +) + +func main() { + const want = 120 + + if got := a.Fact(5); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + if got := a.Fact[int64](5); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + if got := a.Fact(5.0); got != want { + panic(fmt.Sprintf("got %f, want %f", got, want)) + } +} diff --git a/test/typeparam/factimp.go b/test/typeparam/factimp.go new file mode 100644 index 00000000000..76930e5e4f6 --- /dev/null +++ b/test/typeparam/factimp.go @@ -0,0 +1,7 @@ +// rundir -G=3 + +// Copyright 2021 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 ignored diff --git a/test/typeparam/index.go b/test/typeparam/index.go index 83e65acdd00..cb9b2613c33 100644 --- a/test/typeparam/index.go +++ b/test/typeparam/index.go @@ -11,7 +11,7 @@ import ( ) // Index returns the index of x in s, or -1 if not found. -func index[T comparable](s []T, x T) int { +func Index[T comparable](s []T, x T) int { for i, v := range s { // v and x are type T, which has the comparable // constraint, so we can use == here. @@ -30,17 +30,17 @@ func main() { want := 2 vec1 := []string{"ab", "cd", "ef"} - if got := index(vec1, "ef"); got != want { + if got := Index(vec1, "ef"); got != want { panic(fmt.Sprintf("got %d, want %d", got, want)) } vec2 := []byte{'c', '6', '@'} - if got := index(vec2, '@'); got != want { + if got := Index(vec2, '@'); got != want { panic(fmt.Sprintf("got %d, want %d", got, want)) } vec3 := []*obj{&obj{2}, &obj{42}, &obj{1}} - if got := index(vec3, vec3[2]); got != want { + if got := Index(vec3, vec3[2]); got != want { panic(fmt.Sprintf("got %d, want %d", got, want)) } } diff --git a/test/typeparam/listimp.dir/a.go b/test/typeparam/listimp.dir/a.go index ea569751a67..a4118a0e819 100644 --- a/test/typeparam/listimp.dir/a.go +++ b/test/typeparam/listimp.dir/a.go @@ -1,3 +1,7 @@ +// Copyright 2021 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 a type Ordered interface { diff --git a/test/typeparam/listimp.dir/main.go b/test/typeparam/listimp.dir/main.go index 4c1aa3e4934..d43ad508be5 100644 --- a/test/typeparam/listimp.dir/main.go +++ b/test/typeparam/listimp.dir/main.go @@ -1,3 +1,7 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package main import ( diff --git a/test/typeparam/lockable.go b/test/typeparam/lockable.go index d53817521f3..3a03652cd8a 100644 --- a/test/typeparam/lockable.go +++ b/test/typeparam/lockable.go @@ -8,29 +8,29 @@ package main import "sync" -// A _Lockable is a value that may be safely simultaneously accessed +// A Lockable is a value that may be safely simultaneously accessed // from multiple goroutines via the Get and Set methods. -type _Lockable[T any] struct { +type Lockable[T any] struct { T mu sync.Mutex } -// Get returns the value stored in a _Lockable. -func (l *_Lockable[T]) get() T { +// Get returns the value stored in a Lockable. +func (l *Lockable[T]) get() T { l.mu.Lock() defer l.mu.Unlock() return l.T } -// set sets the value in a _Lockable. -func (l *_Lockable[T]) set(v T) { +// set sets the value in a Lockable. +func (l *Lockable[T]) set(v T) { l.mu.Lock() defer l.mu.Unlock() l.T = v } func main() { - sl := _Lockable[string]{T: "a"} + sl := Lockable[string]{T: "a"} if got := sl.get(); got != "a" { panic(got) } @@ -39,7 +39,7 @@ func main() { panic(got) } - il := _Lockable[int]{T: 1} + il := Lockable[int]{T: 1} if got := il.get(); got != 1 { panic(got) } From b1a398cf0f04ac911be204d3c0ee001a94621683 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Mon, 10 May 2021 10:17:51 -0700 Subject: [PATCH 115/940] [dev.typeparams] cmd/compile: add import/export of calls to builtin functions For generic functions, we have to leave the builtins in OCALL form, rather than transform to specific ops, since we don't know the exact types involved. Allow export/import of builtins in OCALL form. Added new export/import test mapimp.go. Change-Id: I571f8eeaa13b4f69389dbdb9afb6cc61924b9bf2 Reviewed-on: https://go-review.googlesource.com/c/go/+/321750 Trust: Dan Scales Reviewed-by: Keith Randall --- src/cmd/compile/internal/typecheck/iexport.go | 10 +++++++ src/cmd/compile/internal/typecheck/iimport.go | 4 +++ test/typeparam/mapimp.dir/a.go | 15 ++++++++++ test/typeparam/mapimp.dir/main.go | 28 +++++++++++++++++++ test/typeparam/mapimp.go | 7 +++++ 5 files changed, 64 insertions(+) create mode 100644 test/typeparam/mapimp.dir/a.go create mode 100644 test/typeparam/mapimp.dir/main.go create mode 100644 test/typeparam/mapimp.go diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index d125dadd883..802a8c3839b 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -1579,6 +1579,16 @@ func (w *exportWriter) expr(n ir.Node) { // We don't need a type here, as the type will be provided at the // declaration of n. w.op(ir.ONAME) + + // This handles the case where we haven't yet transformed a call + // to a builtin, so we must write out the builtin as a name in the + // builtin package. + isBuiltin := n.BuiltinOp != ir.OXXX + w.bool(isBuiltin) + if isBuiltin { + w.string(n.Sym().Name) + break + } w.localName(n) // case OPACK, ONONAME: diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 3b725a226c4..39b5ab09da1 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -1184,6 +1184,10 @@ func (r *importReader) node() ir.Node { return n case ir.ONAME: + isBuiltin := r.bool() + if isBuiltin { + return types.BuiltinPkg.Lookup(r.string()).Def.(*ir.Name) + } return r.localName() // case OPACK, ONONAME: diff --git a/test/typeparam/mapimp.dir/a.go b/test/typeparam/mapimp.dir/a.go new file mode 100644 index 00000000000..6835e214b8d --- /dev/null +++ b/test/typeparam/mapimp.dir/a.go @@ -0,0 +1,15 @@ +// Copyright 2021 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 a + +// Map calls the function f on every element of the slice s, +// returning a new slice of the results. +func Mapper[F, T any](s []F, f func(F) T) []T { + r := make([]T, len(s)) + for i, v := range s { + r[i] = f(v) + } + return r +} diff --git a/test/typeparam/mapimp.dir/main.go b/test/typeparam/mapimp.dir/main.go new file mode 100644 index 00000000000..4d4a4d9eb0b --- /dev/null +++ b/test/typeparam/mapimp.dir/main.go @@ -0,0 +1,28 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "a" + "fmt" + "reflect" + "strconv" +) + +func main() { + got := a.Mapper([]int{1, 2, 3}, strconv.Itoa) + want := []string{"1", "2", "3"} + if !reflect.DeepEqual(got, want) { + panic(fmt.Sprintf("got %s, want %s", got, want)) + } + + fgot := a.Mapper([]float64{2.5, 2.3, 3.5}, func(f float64) string { + return strconv.FormatFloat(f, 'f', -1, 64) + }) + fwant := []string{"2.5", "2.3", "3.5"} + if !reflect.DeepEqual(fgot, fwant) { + panic(fmt.Sprintf("got %s, want %s", fgot, fwant)) + } +} diff --git a/test/typeparam/mapimp.go b/test/typeparam/mapimp.go new file mode 100644 index 00000000000..76930e5e4f6 --- /dev/null +++ b/test/typeparam/mapimp.go @@ -0,0 +1,7 @@ +// rundir -G=3 + +// Copyright 2021 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 ignored From 5fee772c872fcbf35c059b241d0b60c0aecd0f20 Mon Sep 17 00:00:00 2001 From: Aaron Sheah Date: Tue, 18 May 2021 14:54:02 +0000 Subject: [PATCH 116/940] doc/go1.17: document archive/zip changes for Go 1.17 For #44513. Fixes #46000 Change-Id: I299d0b5657f1f96174d6e35d60daac8b36e59d29 GitHub-Last-Rev: e63461bff042a8abe79e0ec3515eefbf56ba1d82 GitHub-Pull-Request: golang/go#46235 Reviewed-on: https://go-review.googlesource.com/c/go/+/320809 Reviewed-by: Heschi Kreinick Trust: Robert Findley --- doc/go1.17.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 48b5563602a..ae9deabf654 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -272,7 +272,7 @@ Do not send CLs removing the interior tags from such phrases.
archive/zip

- TODO: https://golang.org/cl/312310: add File.OpenRaw, Writer.CreateRaw, Writer.Copy + The new methods File.OpenRaw, Writer.CreateRaw, Writer.Copy provide support for cases where performance is a primary concern.

From 8876b9bd6a8a0c206c0a5d59302ce5167f26e9f3 Mon Sep 17 00:00:00 2001 From: Adam Mitha Date: Fri, 14 May 2021 10:58:01 -0700 Subject: [PATCH 117/940] doc/go1.17: document io/fs changes for Go 1.17 For #44513 Fixes #46011 Change-Id: I862ef9a4314cd34fb8c828a8cd7d0a7b36c6f683 Reviewed-on: https://go-review.googlesource.com/c/go/+/320151 Reviewed-by: Heschi Kreinick Trust: Heschi Kreinick Trust: Robert Findley Trust: Dmitri Shuralyov --- doc/go1.17.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index ae9deabf654..4561b6ccf52 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -351,7 +351,7 @@ Do not send CLs removing the interior tags from such phrases.
io/fs

- TODO: https://golang.org/cl/293649: implement FileInfoToDirEntry + The new FileInfoToDirEntry function converts a FileInfo to a DirEntry.

From 4fda54ce3f6761104e835fc4e7847f89e34b7d6d Mon Sep 17 00:00:00 2001 From: sryoya Date: Sun, 16 May 2021 23:36:05 +0900 Subject: [PATCH 118/940] doc/go1.17: document database/sql changes for Go 1.17 For #44513 Fixes #46008 Change-Id: If80d484f73a0eb6946abdc654eb2c0d3dd6db416 Reviewed-on: https://go-review.googlesource.com/c/go/+/320251 Reviewed-by: Heschi Kreinick Trust: Robert Findley --- doc/go1.17.html | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 4561b6ccf52..3534f7be040 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -320,11 +320,19 @@ Do not send CLs removing the interior tags from such phrases.
database/sql

- TODO: https://golang.org/cl/258360: close driver.Connector if it implements io.Closer + The DB.Close method now closes + the connector field if the type in this field implements the + io.Closer interface.

- TODO: https://golang.org/cl/311572: add NullInt16 and NullByte + The new + NullInt16 + and + NullByte + structs represent the int16 and byte values that may be null. These can be used as + destinations of the Scan method, + similar to NullString.

From 4fb10b2118cb16445f2d089f79beb3d32db3db12 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Mon, 10 May 2021 18:10:18 -0400 Subject: [PATCH 119/940] cmd/go: in 'go mod download' without args, don't save module zip sums 'go mod download' without arguments is frequently used to populate the module cache. It tends to fetch a lot of extra files (for modules in the build list that aren't needed to build packages in the main module). It's annoying when sums are written for these extra files. 'go mod download mod@version' will still write sums for specific modules in the build list. 'go mod download all' still has the previous behavior. For now, all invocations of 'go mod download' still update go.mod and go.sum with changes needed to load the build list (1.15 behavior). Fixes #45332 Change-Id: I9e17d18a7466ac7271a0e1a2b663f6b3cb168c97 Reviewed-on: https://go-review.googlesource.com/c/go/+/318629 Trust: Jay Conrod Reviewed-by: Bryan C. Mills --- doc/go1.17.html | 11 ++++++ src/cmd/go/internal/modcmd/download.go | 29 +++++++++++++-- .../go/testdata/mod/rsc.io_sampler_v1.2.1.txt | 2 +- src/cmd/go/testdata/script/mod_download.txt | 37 +++++++++++++++++-- .../script/mod_get_trailing_slash.txt | 10 +++-- src/cmd/go/testdata/script/mod_query.txt | 5 ++- src/cmd/go/testdata/script/mod_retract.txt | 8 ++-- 7 files changed, 85 insertions(+), 17 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 3534f7be040..f00c649e048 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -186,6 +186,17 @@ Do not send CLs removing the interior tags from such phrases. password-protected SSH keys.

+

go mod download

+ +

+ When go mod download is invoked without + arguments, it will no longer save sums for downloaded module content to + go.sum. It may still make changes to go.mod and + go.sum needed to load the build list. This is the same as the + behavior in Go 1.15. To save sums for all modules, use go + mod download all. +

+

TODO: https://golang.org/cl/249759: cmd/cover: replace code using optimized golang.org/x/tools/cover

diff --git a/src/cmd/go/internal/modcmd/download.go b/src/cmd/go/internal/modcmd/download.go index a6c6d914e1d..42b06dbc95c 100644 --- a/src/cmd/go/internal/modcmd/download.go +++ b/src/cmd/go/internal/modcmd/download.go @@ -86,9 +86,11 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) { if !modload.HasModRoot() && len(args) == 0 { base.Fatalf("go mod download: no modules specified (see 'go help mod download')") } - if len(args) == 0 { + haveExplicitArgs := len(args) > 0 + if !haveExplicitArgs { args = []string{"all"} - } else if modload.HasModRoot() { + } + if modload.HasModRoot() { modload.LoadModFile(ctx) // to fill Target targetAtUpgrade := modload.Target.Path + "@upgrade" targetAtPatch := modload.Target.Path + "@patch" @@ -135,6 +137,18 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) { type token struct{} sem := make(chan token, runtime.GOMAXPROCS(0)) infos, infosErr := modload.ListModules(ctx, args, 0) + if !haveExplicitArgs { + // 'go mod download' is sometimes run without arguments to pre-populate + // the module cache. It may fetch modules that aren't needed to build + // packages in the main mdoule. This is usually not intended, so don't save + // sums for downloaded modules (golang.org/issue/45332). + // TODO(golang.org/issue/45551): For now, save sums needed to load the + // build list (same as 1.15 behavior). In the future, report an error if + // go.mod or go.sum need to be updated after loading the build list. + modload.WriteGoMod(ctx) + modload.DisallowWriteGoMod() + } + for _, info := range infos { if info.Replace != nil { info = info.Replace @@ -185,8 +199,15 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) { base.ExitIfErrors() } - // Update go.mod and especially go.sum if needed. - modload.WriteGoMod(ctx) + // If there were explicit arguments, update go.mod and especially go.sum. + // 'go mod download mod@version' is a useful way to add a sum without using + // 'go get mod@version', which may have other side effects. We print this in + // some error message hints. + // + // Don't save sums for 'go mod download' without arguments; see comment above. + if haveExplicitArgs { + modload.WriteGoMod(ctx) + } // If there was an error matching some of the requested packages, emit it now // (after we've written the checksums for the modules that were downloaded diff --git a/src/cmd/go/testdata/mod/rsc.io_sampler_v1.2.1.txt b/src/cmd/go/testdata/mod/rsc.io_sampler_v1.2.1.txt index 00b71bf0d59..7982cccea10 100644 --- a/src/cmd/go/testdata/mod/rsc.io_sampler_v1.2.1.txt +++ b/src/cmd/go/testdata/mod/rsc.io_sampler_v1.2.1.txt @@ -5,7 +5,7 @@ module "rsc.io/sampler" require "golang.org/x/text" v0.0.0-20170915032832-14c0d48ead0c -- .info -- -{"Version":"v1.2.1","Name":"cac3af4f8a0ab40054fa6f8d423108a63a1255bb","Short":"cac3af4f8a0a","Time":"2018-02-13T18:16:22Z"}EOF +{"Version":"v1.2.1","Name":"cac3af4f8a0ab40054fa6f8d423108a63a1255bb","Short":"cac3af4f8a0a","Time":"2018-02-13T18:16:22Z"} -- hello.go -- // Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/src/cmd/go/testdata/script/mod_download.txt b/src/cmd/go/testdata/script/mod_download.txt index 8a9faffe4e0..ad640b45de1 100644 --- a/src/cmd/go/testdata/script/mod_download.txt +++ b/src/cmd/go/testdata/script/mod_download.txt @@ -107,13 +107,28 @@ stderr '^go mod download: skipping argument m that resolves to the main module\n ! go mod download m@latest stderr '^go mod download: m@latest: malformed module path "m": missing dot in first path element$' -# download updates go.mod and populates go.sum +# download without arguments updates go.mod and go.sum after loading the +# build list, but does not save sums for downloaded zips. cd update +cp go.mod.orig go.mod ! exists go.sum go mod download +cmp go.mod.update go.mod +cmp go.sum.update go.sum +cp go.mod.orig go.mod +rm go.sum + +# download with arguments (even "all") does update go.mod and go.sum. +go mod download rsc.io/sampler +cmp go.mod.update go.mod grep '^rsc.io/sampler v1.3.0 ' go.sum -go list -m rsc.io/sampler -stdout '^rsc.io/sampler v1.3.0$' +cp go.mod.orig go.mod +rm go.sum + +go mod download all +cmp go.mod.update go.mod +grep '^rsc.io/sampler v1.3.0 ' go.sum +cd .. # allow go mod download without go.mod env GO111MODULE=auto @@ -131,7 +146,7 @@ stderr 'get '$GOPROXY -- go.mod -- module m --- update/go.mod -- +-- update/go.mod.orig -- module m go 1.16 @@ -140,3 +155,17 @@ require ( rsc.io/quote v1.5.2 rsc.io/sampler v1.2.1 // older version than in build list ) +-- update/go.mod.update -- +module m + +go 1.16 + +require ( + rsc.io/quote v1.5.2 + rsc.io/sampler v1.3.0 // older version than in build list +) +-- update/go.sum.update -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.2.1/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/src/cmd/go/testdata/script/mod_get_trailing_slash.txt b/src/cmd/go/testdata/script/mod_get_trailing_slash.txt index 3b38d8ba7d3..c5366935379 100644 --- a/src/cmd/go/testdata/script/mod_get_trailing_slash.txt +++ b/src/cmd/go/testdata/script/mod_get_trailing_slash.txt @@ -1,6 +1,3 @@ -# Populate go.sum -go mod download - # go list should succeed to load a package ending with ".go" if the path does # not correspond to an existing local file. Listing a pattern ending with # ".go/" should try to list a package regardless of whether a file exists at the @@ -31,3 +28,10 @@ module m go 1.13 require example.com/dotgo.go v1.0.0 +-- go.sum -- +example.com/dotgo.go v1.0.0 h1:XKJfs0V8x2PvY2tX8bJBCEbCDLnt15ma2onwhVpew/I= +example.com/dotgo.go v1.0.0/go.mod h1:Qi6z/X3AC5vHiuMt6HF2ICx3KhIBGrMdrA7YoPDKqR0= +-- use.go -- +package use + +import _ "example.com/dotgo.go" diff --git a/src/cmd/go/testdata/script/mod_query.txt b/src/cmd/go/testdata/script/mod_query.txt index e10185709d9..a75f86ed7c5 100644 --- a/src/cmd/go/testdata/script/mod_query.txt +++ b/src/cmd/go/testdata/script/mod_query.txt @@ -1,9 +1,7 @@ env GO111MODULE=on -# Populate go.sum. # TODO(golang.org/issue/41297): we shouldn't need go.sum. None of the commands # below depend on the build list. -go mod download go list -m -versions rsc.io/quote stdout '^rsc.io/quote v1.0.0 v1.1.0 v1.2.0 v1.2.1 v1.3.0 v1.4.0 v1.5.0 v1.5.1 v1.5.2 v1.5.3-pre1$' @@ -36,6 +34,9 @@ stdout 'no matching versions for query ">v1.5.3"' module x require rsc.io/quote v1.0.0 +-- go.sum -- +rsc.io/quote v1.0.0 h1:kQ3IZQzPTiDJxSZI98YaWgxFEhlNdYASHvh+MplbViw= +rsc.io/quote v1.0.0/go.mod h1:v83Ri/njykPcgJltBc/gEkJTmjTsNgtO1Y7vyIK1CQA= -- use.go -- package use diff --git a/src/cmd/go/testdata/script/mod_retract.txt b/src/cmd/go/testdata/script/mod_retract.txt index a52e05bc72e..4f95ece8d7a 100644 --- a/src/cmd/go/testdata/script/mod_retract.txt +++ b/src/cmd/go/testdata/script/mod_retract.txt @@ -1,8 +1,5 @@ cp go.mod go.mod.orig -# Populate go.sum. -go mod download - # 'go list pkg' does not report an error when a retracted version is used. go list -e -f '{{if .Error}}{{.Error}}{{end}}' ./use ! stdout . @@ -32,6 +29,11 @@ go 1.15 require example.com/retract v1.0.0-bad +-- go.sum -- +example.com/retract v1.0.0-bad h1:liAW69rbtjY67x2CcNzat668L/w+YGgNX3lhJsWIJis= +example.com/retract v1.0.0-bad/go.mod h1:0DvGGofJ9hr1q63cBrOY/jSY52OwhRGA0K47NE80I5Y= +example.com/retract/self/prev v1.1.0 h1:0/8I/GTG+1eJTFeDQ/fUbgrMsVHHyKhh3Z8DSZp1fuA= +example.com/retract/self/prev v1.1.0/go.mod h1:xl2EcklWuZZHVtHWcpzfSJQmnzAGpKZYpA/Wto7SZN4= -- use/use.go -- package use From e4d7525c3e119de30490550fe2516fd6958eac30 Mon Sep 17 00:00:00 2001 From: Constantin Konstantinidis Date: Fri, 14 May 2021 15:00:46 +0200 Subject: [PATCH 120/940] cmd/dist: display first class port status in json output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #38874 Change-Id: I819dd008fd6869d335888b4aa03dcf739da9a9a4 Reviewed-on: https://go-review.googlesource.com/c/go/+/320069 Run-TryBot: Dmitri Shuralyov TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor Reviewed-by: Dmitri Shuralyov Trust: Daniel Martí --- src/cmd/dist/build.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index 00e23ef179e..1abb03bcc56 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -1607,6 +1607,18 @@ var incomplete = map[string]bool{ "linux/sparc64": true, } +// List of platforms which are first class ports. See golang.org/issue/38874. +var firstClass = map[string]bool{ + "darwin/amd64": true, + "darwin/arm64": true, + "linux/386": true, + "linux/amd64": true, + "linux/arm": true, + "linux/arm64": true, + "windows/386": true, + "windows/amd64": true, +} + func needCC() bool { switch os.Getenv("CGO_ENABLED") { case "1": @@ -1743,6 +1755,7 @@ func cmdlist() { GOOS string GOARCH string CgoSupported bool + FirstClass bool } var results []jsonResult for _, p := range plats { @@ -1750,7 +1763,8 @@ func cmdlist() { results = append(results, jsonResult{ GOOS: fields[0], GOARCH: fields[1], - CgoSupported: cgoEnabled[p]}) + CgoSupported: cgoEnabled[p], + FirstClass: firstClass[p]}) } out, err := json.MarshalIndent(results, "", "\t") if err != nil { From 76b2d6afed1e22556bd6c52e74b546eb8bf9a225 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 21 May 2021 12:50:52 -0700 Subject: [PATCH 121/940] os: document that StartProcess puts files into blocking mode Fixes #43894 Change-Id: I2add7b8a4f6ae69a5ef1c48703fde21a4b74307c Reviewed-on: https://go-review.googlesource.com/c/go/+/321852 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Dmitri Shuralyov --- src/os/exec.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/os/exec.go b/src/os/exec.go index edb773a092b..bc75d4dd66c 100644 --- a/src/os/exec.go +++ b/src/os/exec.go @@ -54,6 +54,9 @@ type ProcAttr struct { // standard error. An implementation may support additional entries, // depending on the underlying operating system. A nil entry corresponds // to that file being closed when the process starts. + // On Unix systems, StartProcess will change these File values + // to blocking mode, which means that SetDeadline will stop working + // and calling Close will not interrupt a Read or Write. Files []*File // Operating system-specific process creation attributes. From 3c656445f139d8b6def40aa7beffd5da9fceccdb Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Fri, 21 May 2021 16:33:42 -0400 Subject: [PATCH 122/940] cmd/go: in TestScript/mod_replace, download an explicit module path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As of CL 318629, 'go mod download' without arguments does not save checksums for module source code. Without a checksum, 'go list' will not report the location of the source code even if it is present, in order to prevent accidental access of mismatched code. Downloading an explicit module here also more clearly expresses the intent of the test (“download this module and see where it is”), and may be somewhat more efficient (since the test doesn't need source code for the other modules in the build list). Updates #45332 Change-Id: Ic589b22478e3ed140b95365bb6729101dd598ccc Reviewed-on: https://go-review.googlesource.com/c/go/+/321956 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills Reviewed-by: Dmitri Shuralyov TryBot-Result: Go Bot --- src/cmd/go/testdata/script/mod_replace.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/go/testdata/script/mod_replace.txt b/src/cmd/go/testdata/script/mod_replace.txt index dc9667f1d0d..a0a367fb1db 100644 --- a/src/cmd/go/testdata/script/mod_replace.txt +++ b/src/cmd/go/testdata/script/mod_replace.txt @@ -48,7 +48,7 @@ stderr 'module rsc.io/quote/v3@upgrade found \(v3.0.0, replaced by ./local/rsc.i # The reported Dir and GoMod for a replaced module should be accurate. cp go.mod.orig go.mod go mod edit -replace=rsc.io/quote/v3=not-rsc.io/quote@v0.1.0-nomod -go mod download +go mod download rsc.io/quote/v3 go list -m -f '{{.Path}} {{.Version}} {{.Dir}} {{.GoMod}}{{with .Replace}} => {{.Path}} {{.Version}} {{.Dir}} {{.GoMod}}{{end}}' rsc.io/quote/v3 stdout '^rsc.io/quote/v3 v3.0.0 '$GOPATH'[/\\]pkg[/\\]mod[/\\]not-rsc.io[/\\]quote@v0.1.0-nomod '$GOPATH'[/\\]pkg[/\\]mod[/\\]cache[/\\]download[/\\]not-rsc.io[/\\]quote[/\\]@v[/\\]v0.1.0-nomod.mod => not-rsc.io/quote v0.1.0-nomod '$GOPATH'[/\\]pkg[/\\]mod[/\\]not-rsc.io[/\\]quote@v0.1.0-nomod '$GOPATH'[/\\]pkg[/\\]mod[/\\]cache[/\\]download[/\\]not-rsc.io[/\\]quote[/\\]@v[/\\]v0.1.0-nomod.mod$' From 21db1d193cc3d830e1a7d53a04271631ce1198cd Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Fri, 21 May 2021 17:00:08 -0400 Subject: [PATCH 123/940] [dev.typeparams] runtime: fix newproc arg size on ARM At runtime startup it calls newproc from assembly code to start the main goroutine. runtime.main has no arguments, so the arg size should be 0, instead of 8. While here, use clearer code sequence to open the frame. Change-Id: I2bbb26a83521ea867897530b86a85b22a3c8be9d Reviewed-on: https://go-review.googlesource.com/c/go/+/321957 Trust: Cherry Mui Run-TryBot: Cherry Mui Reviewed-by: Michael Knyszek TryBot-Result: Go Bot --- src/runtime/asm_arm.s | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index 6d3573d68fb..872e56aeb49 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -168,14 +168,14 @@ TEXT runtime·rt0_go(SB),NOSPLIT|NOFRAME|TOPFRAME,$0 BL runtime·schedinit(SB) // create a new goroutine to start program + SUB $12, R13 MOVW $runtime·mainPC(SB), R0 - MOVW.W R0, -4(R13) - MOVW $8, R0 - MOVW.W R0, -4(R13) + MOVW R0, 8(R13) // arg 2: fn MOVW $0, R0 - MOVW.W R0, -4(R13) // push $0 as guard + MOVW R0, 4(R13) // arg 1: siz + MOVW R0, 0(R13) // dummy LR BL runtime·newproc(SB) - MOVW $12(R13), R13 // pop args and LR + ADD $12, R13 // pop args and LR // start this M BL runtime·mstart(SB) From fb42fb705df4832a76165f9a36f3a8d5d7ca8f49 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 20 May 2021 18:55:47 -0400 Subject: [PATCH 124/940] [dev.typeparams] runtime: use internal/abi.FuncPCABI0 to take address of assembly functions There are a few assembly functions in the runtime that are marked as ABIInternal, solely because funcPC can get the right address. The functions themselves do not actually follow ABIInternal (or irrelevant). Now we have internal/abi.FuncPCABI0, use that, and un-mark the functions. Also un-mark assembly functions that are only called in assembly. For them, it only matters if the caller and callee are consistent. Change-Id: I240e126ac13cb362f61ff8482057ee9f53c24097 Reviewed-on: https://go-review.googlesource.com/c/go/+/321950 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/reflect/asm_amd64.s | 4 ++-- src/runtime/asm.s | 2 +- src/runtime/asm_amd64.s | 14 +++++++------- src/runtime/mkpreempt.go | 3 +-- src/runtime/os3_plan9.go | 3 ++- src/runtime/os_linux.go | 9 +++++---- src/runtime/os_windows.go | 7 ++++--- src/runtime/preempt.go | 3 ++- src/runtime/preempt_386.s | 3 +-- src/runtime/preempt_amd64.s | 3 +-- src/runtime/preempt_arm.s | 3 +-- src/runtime/preempt_arm64.s | 3 +-- src/runtime/preempt_mips64x.s | 3 +-- src/runtime/preempt_mipsx.s | 3 +-- src/runtime/preempt_ppc64x.s | 3 +-- src/runtime/preempt_riscv64.s | 3 +-- src/runtime/preempt_s390x.s | 3 +-- src/runtime/preempt_wasm.s | 3 +-- src/runtime/race.go | 3 ++- src/runtime/race_amd64.s | 4 +--- src/runtime/signal_amd64.go | 5 +++-- src/runtime/signal_unix.go | 3 ++- src/runtime/signal_windows.go | 13 +++++++------ src/runtime/sys_linux_amd64.s | 13 +++++-------- src/runtime/sys_windows_386.s | 14 +++++++------- src/runtime/sys_windows_amd64.s | 12 ++++++------ src/runtime/sys_windows_arm.s | 12 ++++++------ src/runtime/sys_windows_arm64.s | 10 +++++----- src/runtime/syscall_windows.go | 2 +- src/runtime/wincallback.go | 6 +++--- src/runtime/zcallback_windows.s | 2 +- src/runtime/zcallback_windows_arm.s | 2 +- src/runtime/zcallback_windows_arm64.s | 2 +- 33 files changed, 85 insertions(+), 93 deletions(-) diff --git a/src/reflect/asm_amd64.s b/src/reflect/asm_amd64.s index facf07516d8..86d3f4e4bf7 100644 --- a/src/reflect/asm_amd64.s +++ b/src/reflect/asm_amd64.s @@ -32,7 +32,7 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$312 // NO_LOCAL_POINTERS is a lie. The stack map for the two locals in this // frame is specially handled in the runtime. See the comment above LOCAL_RETVALID. LEAQ LOCAL_REGARGS(SP), R12 - CALL runtime·spillArgs(SB) + CALL runtime·spillArgs(SB) MOVQ DX, 24(SP) // outside of moveMakeFuncArgPtrs's arg area MOVQ DX, 0(SP) MOVQ R12, 8(SP) @@ -48,7 +48,7 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$312 MOVQ AX, 24(SP) CALL ·callReflect(SB) LEAQ LOCAL_REGARGS(SP), R12 - CALL runtime·unspillArgs(SB) + CALL runtime·unspillArgs(SB) RET // methodValueCall is the code half of the function returned by makeMethodValue. diff --git a/src/runtime/asm.s b/src/runtime/asm.s index 72c744925d8..0e14fcd3e6a 100644 --- a/src/runtime/asm.s +++ b/src/runtime/asm.s @@ -13,6 +13,6 @@ DATA runtime·no_pointers_stackmap+0x04(SB)/4, $0 GLOBL runtime·no_pointers_stackmap(SB),RODATA, $8 #ifndef GOARCH_amd64 -TEXT ·sigpanic0(SB),NOSPLIT,$0-0 +TEXT ·sigpanic0(SB),NOSPLIT,$0-0 JMP ·sigpanic(SB) #endif diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index 5990ce54c8d..96f0d3fefce 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -469,7 +469,7 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0 #ifdef GOEXPERIMENT_regabireflect // spillArgs stores return values from registers to a *internal/abi.RegArgs in R12. -TEXT ·spillArgs(SB),NOSPLIT,$0-0 +TEXT ·spillArgs(SB),NOSPLIT,$0-0 MOVQ AX, 0(R12) MOVQ BX, 8(R12) MOVQ CX, 16(R12) @@ -497,7 +497,7 @@ TEXT ·spillArgs(SB),NOSPLIT,$0-0 RET // unspillArgs loads args into registers from a *internal/abi.RegArgs in R12. -TEXT ·unspillArgs(SB),NOSPLIT,$0-0 +TEXT ·unspillArgs(SB),NOSPLIT,$0-0 MOVQ 0(R12), AX MOVQ 8(R12), BX MOVQ 16(R12), CX @@ -525,11 +525,11 @@ TEXT ·unspillArgs(SB),NOSPLIT,$0-0 RET #else // spillArgs stores return values from registers to a pointer in R12. -TEXT ·spillArgs(SB),NOSPLIT,$0-0 +TEXT ·spillArgs(SB),NOSPLIT,$0-0 RET // unspillArgs loads args into registers from a pointer in R12. -TEXT ·unspillArgs(SB),NOSPLIT,$0-0 +TEXT ·unspillArgs(SB),NOSPLIT,$0-0 RET #endif @@ -588,7 +588,7 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-48; \ REP;MOVSB; \ /* set up argument registers */ \ MOVQ regArgs+40(FP), R12; \ - CALL ·unspillArgs(SB); \ + CALL ·unspillArgs(SB); \ /* call function */ \ MOVQ f+8(FP), DX; \ PCDATA $PCDATA_StackMapIndex, $0; \ @@ -596,7 +596,7 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-48; \ CALL R12; \ /* copy register return values back */ \ MOVQ regArgs+40(FP), R12; \ - CALL ·spillArgs(SB); \ + CALL ·spillArgs(SB); \ MOVLQZX stackArgsSize+24(FP), CX; \ MOVLQZX stackRetOffset+28(FP), BX; \ MOVQ stackArgs+16(FP), DI; \ @@ -1596,7 +1596,7 @@ TEXT runtime·addmoduledata(SB),NOSPLIT,$0-0 // This function is injected from the signal handler for panicking // signals. It is quite painful to set X15 in the signal context, // so we do it here. -TEXT ·sigpanic0(SB),NOSPLIT,$0-0 +TEXT ·sigpanic0(SB),NOSPLIT,$0-0 #ifdef GOEXPERIMENT_regabig get_tls(R14) MOVQ g(R14), R14 diff --git a/src/runtime/mkpreempt.go b/src/runtime/mkpreempt.go index 6c980540f57..f2b90307cab 100644 --- a/src/runtime/mkpreempt.go +++ b/src/runtime/mkpreempt.go @@ -128,8 +128,7 @@ func header(arch string) { } fmt.Fprintf(out, "#include \"go_asm.h\"\n") fmt.Fprintf(out, "#include \"textflag.h\"\n\n") - fmt.Fprintf(out, "// Note: asyncPreempt doesn't use the internal ABI, but we must be able to inject calls to it from the signal handler, so Go code has to see the PC of this function literally.\n") - fmt.Fprintf(out, "TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0\n") + fmt.Fprintf(out, "TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0\n") } func p(f string, args ...interface{}) { diff --git a/src/runtime/os3_plan9.go b/src/runtime/os3_plan9.go index c5dc23de8b6..dacb5c23a0c 100644 --- a/src/runtime/os3_plan9.go +++ b/src/runtime/os3_plan9.go @@ -5,6 +5,7 @@ package runtime import ( + "internal/abi" "runtime/internal/sys" "unsafe" ) @@ -100,7 +101,7 @@ func sighandler(_ureg *ureg, note *byte, gp *g) int { if usesLR { c.setpc(funcPC(sigpanictramp)) } else { - c.setpc(funcPC(sigpanic0)) + c.setpc(abi.FuncPCABI0(sigpanic0)) } return _NCONT } diff --git a/src/runtime/os_linux.go b/src/runtime/os_linux.go index c8b29e396c7..235c96e45a7 100644 --- a/src/runtime/os_linux.go +++ b/src/runtime/os_linux.go @@ -5,6 +5,7 @@ package runtime import ( + "internal/abi" "runtime/internal/sys" "unsafe" ) @@ -149,7 +150,7 @@ func newosproc(mp *m) { // with signals disabled. It will enable them in minit. var oset sigset sigprocmask(_SIG_SETMASK, &sigset_all, &oset) - ret := clone(cloneFlags, stk, unsafe.Pointer(mp), unsafe.Pointer(mp.g0), unsafe.Pointer(funcPC(mstart))) + ret := clone(cloneFlags, stk, unsafe.Pointer(mp), unsafe.Pointer(mp.g0), unsafe.Pointer(abi.FuncPCABI0(mstart))) sigprocmask(_SIG_SETMASK, &oset, nil) if ret < 0 { @@ -429,13 +430,13 @@ func setsig(i uint32, fn uintptr) { // should not be used". x86_64 kernel requires it. Only use it on // x86. if GOARCH == "386" || GOARCH == "amd64" { - sa.sa_restorer = funcPC(sigreturn) + sa.sa_restorer = abi.FuncPCABI0(sigreturn) } if fn == funcPC(sighandler) { if iscgo { - fn = funcPC(cgoSigtramp) + fn = abi.FuncPCABI0(cgoSigtramp) } else { - fn = funcPC(sigtramp) + fn = abi.FuncPCABI0(sigtramp) } } sa.sa_handler = fn diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go index f0935264ac6..d82173e738a 100644 --- a/src/runtime/os_windows.go +++ b/src/runtime/os_windows.go @@ -5,6 +5,7 @@ package runtime import ( + "internal/abi" "runtime/internal/atomic" "runtime/internal/sys" "unsafe" @@ -543,7 +544,7 @@ func initLongPathSupport() { } func osinit() { - asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall)) + asmstdcallAddr = unsafe.Pointer(abi.FuncPCABI0(asmstdcall)) setBadSignalMsg() @@ -906,7 +907,7 @@ func semacreate(mp *m) { func newosproc(mp *m) { // We pass 0 for the stack size to use the default for this binary. thandle := stdcall6(_CreateThread, 0, 0, - funcPC(tstart_stdcall), uintptr(unsafe.Pointer(mp)), + abi.FuncPCABI0(tstart_stdcall), uintptr(unsafe.Pointer(mp)), 0, 0) if thandle == 0 { @@ -1385,7 +1386,7 @@ func preemptM(mp *m) { if gp != nil && wantAsyncPreempt(gp) { if ok, newpc := isAsyncSafePoint(gp, c.ip(), c.sp(), c.lr()); ok { // Inject call to asyncPreempt - targetPC := funcPC(asyncPreempt) + targetPC := abi.FuncPCABI0(asyncPreempt) switch GOARCH { default: throw("unsupported architecture") diff --git a/src/runtime/preempt.go b/src/runtime/preempt.go index 1d5aae13631..d1291c9c487 100644 --- a/src/runtime/preempt.go +++ b/src/runtime/preempt.go @@ -53,6 +53,7 @@ package runtime import ( + "internal/abi" "runtime/internal/atomic" "runtime/internal/sys" "unsafe" @@ -315,7 +316,7 @@ func asyncPreempt2() { var asyncPreemptStack = ^uintptr(0) func init() { - f := findfunc(funcPC(asyncPreempt)) + f := findfunc(abi.FuncPCABI0(asyncPreempt)) total := funcMaxSPDelta(f) f = findfunc(funcPC(asyncPreempt2)) total += funcMaxSPDelta(f) diff --git a/src/runtime/preempt_386.s b/src/runtime/preempt_386.s index a803b24dc6f..c3a5fa1f361 100644 --- a/src/runtime/preempt_386.s +++ b/src/runtime/preempt_386.s @@ -3,8 +3,7 @@ #include "go_asm.h" #include "textflag.h" -// Note: asyncPreempt doesn't use the internal ABI, but we must be able to inject calls to it from the signal handler, so Go code has to see the PC of this function literally. -TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0 +TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0 PUSHFL ADJSP $156 NOP SP diff --git a/src/runtime/preempt_amd64.s b/src/runtime/preempt_amd64.s index dc7af806d32..31f7c8b66f5 100644 --- a/src/runtime/preempt_amd64.s +++ b/src/runtime/preempt_amd64.s @@ -3,8 +3,7 @@ #include "go_asm.h" #include "textflag.h" -// Note: asyncPreempt doesn't use the internal ABI, but we must be able to inject calls to it from the signal handler, so Go code has to see the PC of this function literally. -TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0 +TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0 PUSHQ BP MOVQ SP, BP // Save flags before clobbering them diff --git a/src/runtime/preempt_arm.s b/src/runtime/preempt_arm.s index bbc9fbb1eae..8f243c0dcd6 100644 --- a/src/runtime/preempt_arm.s +++ b/src/runtime/preempt_arm.s @@ -3,8 +3,7 @@ #include "go_asm.h" #include "textflag.h" -// Note: asyncPreempt doesn't use the internal ABI, but we must be able to inject calls to it from the signal handler, so Go code has to see the PC of this function literally. -TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0 +TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0 MOVW.W R14, -188(R13) MOVW R0, 4(R13) MOVW R1, 8(R13) diff --git a/src/runtime/preempt_arm64.s b/src/runtime/preempt_arm64.s index 2b70a28479d..36ee13282c7 100644 --- a/src/runtime/preempt_arm64.s +++ b/src/runtime/preempt_arm64.s @@ -3,8 +3,7 @@ #include "go_asm.h" #include "textflag.h" -// Note: asyncPreempt doesn't use the internal ABI, but we must be able to inject calls to it from the signal handler, so Go code has to see the PC of this function literally. -TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0 +TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0 MOVD R30, -496(RSP) SUB $496, RSP #ifdef GOOS_linux diff --git a/src/runtime/preempt_mips64x.s b/src/runtime/preempt_mips64x.s index b755425bc5d..c1249e382e2 100644 --- a/src/runtime/preempt_mips64x.s +++ b/src/runtime/preempt_mips64x.s @@ -6,8 +6,7 @@ #include "go_asm.h" #include "textflag.h" -// Note: asyncPreempt doesn't use the internal ABI, but we must be able to inject calls to it from the signal handler, so Go code has to see the PC of this function literally. -TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0 +TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0 MOVV R31, -488(R29) SUBV $488, R29 MOVV R1, 8(R29) diff --git a/src/runtime/preempt_mipsx.s b/src/runtime/preempt_mipsx.s index c1bff608596..70b79e05b99 100644 --- a/src/runtime/preempt_mipsx.s +++ b/src/runtime/preempt_mipsx.s @@ -6,8 +6,7 @@ #include "go_asm.h" #include "textflag.h" -// Note: asyncPreempt doesn't use the internal ABI, but we must be able to inject calls to it from the signal handler, so Go code has to see the PC of this function literally. -TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0 +TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0 MOVW R31, -244(R29) SUB $244, R29 MOVW R1, 4(R29) diff --git a/src/runtime/preempt_ppc64x.s b/src/runtime/preempt_ppc64x.s index 70bd91982bf..7ed4021dde7 100644 --- a/src/runtime/preempt_ppc64x.s +++ b/src/runtime/preempt_ppc64x.s @@ -6,8 +6,7 @@ #include "go_asm.h" #include "textflag.h" -// Note: asyncPreempt doesn't use the internal ABI, but we must be able to inject calls to it from the signal handler, so Go code has to see the PC of this function literally. -TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0 +TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0 MOVD R31, -488(R1) MOVD LR, R31 MOVDU R31, -520(R1) diff --git a/src/runtime/preempt_riscv64.s b/src/runtime/preempt_riscv64.s index d4f9cc277f4..eb68dcba2b9 100644 --- a/src/runtime/preempt_riscv64.s +++ b/src/runtime/preempt_riscv64.s @@ -3,8 +3,7 @@ #include "go_asm.h" #include "textflag.h" -// Note: asyncPreempt doesn't use the internal ABI, but we must be able to inject calls to it from the signal handler, so Go code has to see the PC of this function literally. -TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0 +TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0 MOV X1, -472(X2) ADD $-472, X2 MOV X3, 8(X2) diff --git a/src/runtime/preempt_s390x.s b/src/runtime/preempt_s390x.s index c6f11571df7..ca9e47cde17 100644 --- a/src/runtime/preempt_s390x.s +++ b/src/runtime/preempt_s390x.s @@ -3,8 +3,7 @@ #include "go_asm.h" #include "textflag.h" -// Note: asyncPreempt doesn't use the internal ABI, but we must be able to inject calls to it from the signal handler, so Go code has to see the PC of this function literally. -TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0 +TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0 IPM R10 MOVD R14, -248(R15) ADD $-248, R15 diff --git a/src/runtime/preempt_wasm.s b/src/runtime/preempt_wasm.s index da90e8aa6dd..0cf57d3d226 100644 --- a/src/runtime/preempt_wasm.s +++ b/src/runtime/preempt_wasm.s @@ -3,7 +3,6 @@ #include "go_asm.h" #include "textflag.h" -// Note: asyncPreempt doesn't use the internal ABI, but we must be able to inject calls to it from the signal handler, so Go code has to see the PC of this function literally. -TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0 +TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0 // No async preemption on wasm UNDEF diff --git a/src/runtime/race.go b/src/runtime/race.go index cc8c5db1bd2..f1c3c3098dd 100644 --- a/src/runtime/race.go +++ b/src/runtime/race.go @@ -8,6 +8,7 @@ package runtime import ( + "internal/abi" "unsafe" ) @@ -361,7 +362,7 @@ func raceinit() (gctx, pctx uintptr) { throw("raceinit: race build must use cgo") } - racecall(&__tsan_init, uintptr(unsafe.Pointer(&gctx)), uintptr(unsafe.Pointer(&pctx)), funcPC(racecallbackthunk), 0) + racecall(&__tsan_init, uintptr(unsafe.Pointer(&gctx)), uintptr(unsafe.Pointer(&pctx)), abi.FuncPCABI0(racecallbackthunk), 0) // Round data segment to page boundaries, because it's used in mmap(). start := ^uintptr(0) diff --git a/src/runtime/race_amd64.s b/src/runtime/race_amd64.s index 8d4813eaddd..469623ff20a 100644 --- a/src/runtime/race_amd64.s +++ b/src/runtime/race_amd64.s @@ -441,9 +441,7 @@ call: // The overall effect of Go->C->Go call chain is similar to that of mcall. // RARG0 contains command code. RARG1 contains command-specific context. // See racecallback for command codes. -// Defined as ABIInternal so as to avoid introducing a wrapper, -// because its address is passed to C via funcPC. -TEXT runtime·racecallbackthunk(SB), NOSPLIT, $0-0 +TEXT runtime·racecallbackthunk(SB), NOSPLIT, $0-0 // Handle command raceGetProcCmd (0) here. // First, code below assumes that we are on curg, while raceGetProcCmd // can be executed on g0. Second, it is called frequently, so will diff --git a/src/runtime/signal_amd64.go b/src/runtime/signal_amd64.go index e45fbb4a87a..afcf4404fba 100644 --- a/src/runtime/signal_amd64.go +++ b/src/runtime/signal_amd64.go @@ -9,6 +9,7 @@ package runtime import ( + "internal/abi" "runtime/internal/sys" "unsafe" ) @@ -70,10 +71,10 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { // Go special registers. We inject sigpanic0 (instead of sigpanic), // which takes care of that. if shouldPushSigpanic(gp, pc, *(*uintptr)(unsafe.Pointer(sp))) { - c.pushCall(funcPC(sigpanic0), pc) + c.pushCall(abi.FuncPCABI0(sigpanic0), pc) } else { // Not safe to push the call. Just clobber the frame. - c.set_rip(uint64(funcPC(sigpanic0))) + c.set_rip(uint64(abi.FuncPCABI0(sigpanic0))) } } diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go index f2e526973df..6396232dd77 100644 --- a/src/runtime/signal_unix.go +++ b/src/runtime/signal_unix.go @@ -8,6 +8,7 @@ package runtime import ( + "internal/abi" "runtime/internal/atomic" "unsafe" ) @@ -329,7 +330,7 @@ func doSigPreempt(gp *g, ctxt *sigctxt) { if wantAsyncPreempt(gp) { if ok, newpc := isAsyncSafePoint(gp, ctxt.sigpc(), ctxt.sigsp(), ctxt.siglr()); ok { // Adjust the PC and inject a call to asyncPreempt. - ctxt.pushCall(funcPC(asyncPreempt), newpc) + ctxt.pushCall(abi.FuncPCABI0(asyncPreempt), newpc) } } diff --git a/src/runtime/signal_windows.go b/src/runtime/signal_windows.go index f2ce24d735c..af15709a4aa 100644 --- a/src/runtime/signal_windows.go +++ b/src/runtime/signal_windows.go @@ -5,6 +5,7 @@ package runtime import ( + "internal/abi" "runtime/internal/sys" "unsafe" ) @@ -27,15 +28,15 @@ func firstcontinuetramp() func lastcontinuetramp() func initExceptionHandler() { - stdcall2(_AddVectoredExceptionHandler, 1, funcPC(exceptiontramp)) + stdcall2(_AddVectoredExceptionHandler, 1, abi.FuncPCABI0(exceptiontramp)) if _AddVectoredContinueHandler == nil || GOARCH == "386" { // use SetUnhandledExceptionFilter for windows-386 or // if VectoredContinueHandler is unavailable. // note: SetUnhandledExceptionFilter handler won't be called, if debugging. - stdcall1(_SetUnhandledExceptionFilter, funcPC(lastcontinuetramp)) + stdcall1(_SetUnhandledExceptionFilter, abi.FuncPCABI0(lastcontinuetramp)) } else { - stdcall2(_AddVectoredContinueHandler, 1, funcPC(firstcontinuetramp)) - stdcall2(_AddVectoredContinueHandler, 0, funcPC(lastcontinuetramp)) + stdcall2(_AddVectoredContinueHandler, 1, abi.FuncPCABI0(firstcontinuetramp)) + stdcall2(_AddVectoredContinueHandler, 0, abi.FuncPCABI0(lastcontinuetramp)) } } @@ -133,7 +134,7 @@ func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 { // The exception is not from asyncPreempt, so not to push a // sigpanic call to make it look like that. Instead, just // overwrite the PC. (See issue #35773) - if r.ip() != 0 && r.ip() != funcPC(asyncPreempt) { + if r.ip() != 0 && r.ip() != abi.FuncPCABI0(asyncPreempt) { sp := unsafe.Pointer(r.sp()) delta := uintptr(sys.StackAlign) sp = add(sp, -delta) @@ -145,7 +146,7 @@ func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 { *((*uintptr)(sp)) = r.ip() } } - r.set_ip(funcPC(sigpanic0)) + r.set_ip(abi.FuncPCABI0(sigpanic0)) return _EXCEPTION_CONTINUE_EXECUTION } diff --git a/src/runtime/sys_linux_amd64.s b/src/runtime/sys_linux_amd64.s index 33cc670b641..f22b7ad9282 100644 --- a/src/runtime/sys_linux_amd64.s +++ b/src/runtime/sys_linux_amd64.s @@ -328,9 +328,8 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-32 POPQ BP RET -// Defined as ABIInternal since it does not use the stack-based Go ABI. // Called using C ABI. -TEXT runtime·sigtramp(SB),NOSPLIT,$0 +TEXT runtime·sigtramp(SB),NOSPLIT,$0 // Transition from C ABI to Go ABI. PUSH_REGS_HOST_TO_ABI0() @@ -348,8 +347,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0 // Used instead of sigtramp in programs that use cgo. // Arguments from kernel are in DI, SI, DX. -// Defined as ABIInternal since it does not use the stack-based Go ABI. -TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0 +TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0 // If no traceback function, do usual sigtramp. MOVQ runtime·cgoTraceback(SB), AX TESTQ AX, AX @@ -392,12 +390,12 @@ TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0 // The first three arguments, and the fifth, are already in registers. // Set the two remaining arguments now. MOVQ runtime·cgoTraceback(SB), CX - MOVQ $runtime·sigtramp(SB), R9 + MOVQ $runtime·sigtramp(SB), R9 MOVQ _cgo_callers(SB), AX JMP AX sigtramp: - JMP runtime·sigtramp(SB) + JMP runtime·sigtramp(SB) sigtrampnog: // Signal arrived on a non-Go thread. If this is SIGPROF, get a @@ -428,8 +426,7 @@ sigtrampnog: // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/x86_64/sigaction.c // The code that cares about the precise instructions used is: // https://gcc.gnu.org/viewcvs/gcc/trunk/libgcc/config/i386/linux-unwind.h?revision=219188&view=markup -// Defined as ABIInternal since it does not use the stack-based Go ABI. -TEXT runtime·sigreturn(SB),NOSPLIT,$0 +TEXT runtime·sigreturn(SB),NOSPLIT,$0 MOVQ $SYS_rt_sigreturn, AX SYSCALL INT $3 // not reached diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s index 0b3933502ab..cf3a439523c 100644 --- a/src/runtime/sys_windows_386.s +++ b/src/runtime/sys_windows_386.s @@ -8,7 +8,7 @@ #include "time_windows.h" // void runtime·asmstdcall(void *c); -TEXT runtime·asmstdcall(SB),NOSPLIT,$0 +TEXT runtime·asmstdcall(SB),NOSPLIT,$0 MOVL fn+0(FP), BX // SetLastError(0). @@ -147,21 +147,21 @@ done: BYTE $0xC2; WORD $4 RET // unreached; make assembler happy -TEXT runtime·exceptiontramp(SB),NOSPLIT,$0 +TEXT runtime·exceptiontramp(SB),NOSPLIT,$0 MOVL $runtime·exceptionhandler(SB), AX JMP sigtramp<>(SB) -TEXT runtime·firstcontinuetramp(SB),NOSPLIT,$0-0 +TEXT runtime·firstcontinuetramp(SB),NOSPLIT,$0-0 // is never called INT $3 -TEXT runtime·lastcontinuetramp(SB),NOSPLIT,$0-0 +TEXT runtime·lastcontinuetramp(SB),NOSPLIT,$0-0 MOVL $runtime·lastcontinuehandler(SB), AX JMP sigtramp<>(SB) GLOBL runtime·cbctxts(SB), NOPTR, $4 -TEXT runtime·callbackasm1(SB),NOSPLIT,$0 +TEXT runtime·callbackasm1(SB),NOSPLIT,$0 MOVL 0(SP), AX // will use to find our callback context // remove return address from stack, we are not returning to callbackasm, but to its caller. @@ -180,7 +180,7 @@ TEXT runtime·callbackasm1(SB),NOSPLIT,$0 CLD // determine index into runtime·cbs table - SUBL $runtime·callbackasm(SB), AX + SUBL $runtime·callbackasm(SB), AX MOVL $0, DX MOVL $5, BX // divide by 5 because each call instruction in runtime·callbacks is 5 bytes long DIVL BX @@ -250,7 +250,7 @@ TEXT tstart<>(SB),NOSPLIT,$0 RET // uint32 tstart_stdcall(M *newm); -TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0 +TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0 MOVL newm+0(FP), BX PUSHL BX diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s index e7782846b25..6cc5bba2b73 100644 --- a/src/runtime/sys_windows_amd64.s +++ b/src/runtime/sys_windows_amd64.s @@ -13,7 +13,7 @@ #define maxargs 18 // void runtime·asmstdcall(void *c); -TEXT runtime·asmstdcall(SB),NOSPLIT|NOFRAME,$0 +TEXT runtime·asmstdcall(SB),NOSPLIT|NOFRAME,$0 // asmcgocall will put first argument into CX. PUSHQ CX // save for later MOVQ libcall_fn(CX), AX @@ -179,15 +179,15 @@ done: RET -TEXT runtime·exceptiontramp(SB),NOSPLIT|NOFRAME,$0 +TEXT runtime·exceptiontramp(SB),NOSPLIT|NOFRAME,$0 MOVQ $runtime·exceptionhandler(SB), AX JMP sigtramp<>(SB) -TEXT runtime·firstcontinuetramp(SB),NOSPLIT|NOFRAME,$0-0 +TEXT runtime·firstcontinuetramp(SB),NOSPLIT|NOFRAME,$0-0 MOVQ $runtime·firstcontinuehandler(SB), AX JMP sigtramp<>(SB) -TEXT runtime·lastcontinuetramp(SB),NOSPLIT|NOFRAME,$0-0 +TEXT runtime·lastcontinuetramp(SB),NOSPLIT|NOFRAME,$0-0 MOVQ $runtime·lastcontinuehandler(SB), AX JMP sigtramp<>(SB) @@ -212,7 +212,7 @@ TEXT runtime·callbackasm1(SB),NOSPLIT,$0 ADDQ $8, SP // determine index into runtime·cbs table - MOVQ $runtime·callbackasm(SB), DX + MOVQ $runtime·callbackasm(SB), DX SUBQ DX, AX MOVQ $0, DX MOVQ $5, CX // divide by 5 because each call instruction in runtime·callbacks is 5 bytes long @@ -245,7 +245,7 @@ TEXT runtime·callbackasm1(SB),NOSPLIT,$0 RET // uint32 tstart_stdcall(M *newm); -TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0 +TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0 // Switch from the host ABI to the Go ABI. PUSH_REGS_HOST_TO_ABI0() diff --git a/src/runtime/sys_windows_arm.s b/src/runtime/sys_windows_arm.s index 48f8c7dedff..c9e96cb6522 100644 --- a/src/runtime/sys_windows_arm.s +++ b/src/runtime/sys_windows_arm.s @@ -10,7 +10,7 @@ // Note: For system ABI, R0-R3 are args, R4-R11 are callee-save. // void runtime·asmstdcall(void *c); -TEXT runtime·asmstdcall(SB),NOSPLIT|NOFRAME,$0 +TEXT runtime·asmstdcall(SB),NOSPLIT|NOFRAME,$0 MOVM.DB.W [R4, R5, R14], (R13) // push {r4, r5, lr} MOVW R0, R4 // put libcall * in r4 MOVW R13, R5 // save stack pointer in r5 @@ -222,21 +222,21 @@ TEXT sigresume<>(SB),NOSPLIT|NOFRAME,$0 MOVW R0, R13 B (R1) -TEXT runtime·exceptiontramp(SB),NOSPLIT|NOFRAME,$0 +TEXT runtime·exceptiontramp(SB),NOSPLIT|NOFRAME,$0 MOVW $runtime·exceptionhandler(SB), R1 B sigtramp<>(SB) -TEXT runtime·firstcontinuetramp(SB),NOSPLIT|NOFRAME,$0 +TEXT runtime·firstcontinuetramp(SB),NOSPLIT|NOFRAME,$0 MOVW $runtime·firstcontinuehandler(SB), R1 B sigtramp<>(SB) -TEXT runtime·lastcontinuetramp(SB),NOSPLIT|NOFRAME,$0 +TEXT runtime·lastcontinuetramp(SB),NOSPLIT|NOFRAME,$0 MOVW $runtime·lastcontinuehandler(SB), R1 B sigtramp<>(SB) GLOBL runtime·cbctxts(SB), NOPTR, $4 -TEXT runtime·callbackasm1(SB),NOSPLIT|NOFRAME,$0 +TEXT runtime·callbackasm1(SB),NOSPLIT|NOFRAME,$0 // On entry, the trampoline in zcallback_windows_arm.s left // the callback index in R12 (which is volatile in the C ABI). @@ -275,7 +275,7 @@ TEXT runtime·callbackasm1(SB),NOSPLIT|NOFRAME,$0 B (R12) // return // uint32 tstart_stdcall(M *newm); -TEXT runtime·tstart_stdcall(SB),NOSPLIT|NOFRAME,$0 +TEXT runtime·tstart_stdcall(SB),NOSPLIT|NOFRAME,$0 MOVM.DB.W [R4-R11, R14], (R13) // push {r4-r11, lr} MOVW m_g0(R0), g diff --git a/src/runtime/sys_windows_arm64.s b/src/runtime/sys_windows_arm64.s index 7a2e11f5ae2..1cf877dce90 100644 --- a/src/runtime/sys_windows_arm64.s +++ b/src/runtime/sys_windows_arm64.s @@ -18,7 +18,7 @@ // load_g and save_g (in tls_arm64.s) clobber R27 (REGTMP) and R0. // void runtime·asmstdcall(void *c); -TEXT runtime·asmstdcall(SB),NOSPLIT|NOFRAME,$0 +TEXT runtime·asmstdcall(SB),NOSPLIT|NOFRAME,$0 STP.W (R29, R30), -32(RSP) // allocate C ABI stack frame STP (R19, R20), 16(RSP) // save old R19, R20 MOVD R0, R19 // save libcall pointer @@ -290,11 +290,11 @@ TEXT sigresume<>(SB),NOSPLIT|NOFRAME,$0 MOVD R0, RSP B (R1) -TEXT runtime·exceptiontramp(SB),NOSPLIT|NOFRAME,$0 +TEXT runtime·exceptiontramp(SB),NOSPLIT|NOFRAME,$0 MOVD $runtime·exceptionhandler(SB), R1 B sigtramp<>(SB) -TEXT runtime·firstcontinuetramp(SB),NOSPLIT|NOFRAME,$0 +TEXT runtime·firstcontinuetramp(SB),NOSPLIT|NOFRAME,$0 MOVD $runtime·firstcontinuehandler(SB), R1 B sigtramp<>(SB) @@ -304,7 +304,7 @@ TEXT runtime·lastcontinuetramp(SB),NOSPLIT|NOFRAME,$0 GLOBL runtime·cbctxts(SB), NOPTR, $4 -TEXT runtime·callbackasm1(SB),NOSPLIT,$208-0 +TEXT runtime·callbackasm1(SB),NOSPLIT,$208-0 NO_LOCAL_POINTERS // On entry, the trampoline in zcallback_windows_arm64.s left @@ -356,7 +356,7 @@ TEXT runtime·callbackasm1(SB),NOSPLIT,$208-0 RET // uint32 tstart_stdcall(M *newm); -TEXT runtime·tstart_stdcall(SB),NOSPLIT,$96-0 +TEXT runtime·tstart_stdcall(SB),NOSPLIT,$96-0 SAVE_R19_TO_R28(-10*8) MOVD m_g0(R0), g diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go index 6b9195bcd52..e045e5f4bfb 100644 --- a/src/runtime/syscall_windows.go +++ b/src/runtime/syscall_windows.go @@ -224,7 +224,7 @@ func callbackasmAddr(i int) uintptr { // followed by a branch instruction entrySize = 8 } - return funcPC(callbackasm) + uintptr(i*entrySize) + return abi.FuncPCABI0(callbackasm) + uintptr(i*entrySize) } const callbackMaxFrame = 64 * sys.PtrSize diff --git a/src/runtime/wincallback.go b/src/runtime/wincallback.go index a7a787d8f6d..73f1e567cec 100644 --- a/src/runtime/wincallback.go +++ b/src/runtime/wincallback.go @@ -33,7 +33,7 @@ func genasm386Amd64() { // CALL instruction in runtime·callbackasm. This determines // which Go callback function is executed later on. -TEXT runtime·callbackasm(SB),7,$0 +TEXT runtime·callbackasm(SB),7,$0 `) for i := 0; i < maxCallback; i++ { buf.WriteString("\tCALL\truntime·callbackasm1(SB)\n") @@ -61,7 +61,7 @@ func genasmArm() { // It then calls the Go implementation for that callback. #include "textflag.h" -TEXT runtime·callbackasm(SB),NOSPLIT|NOFRAME,$0 +TEXT runtime·callbackasm(SB),NOSPLIT|NOFRAME,$0 `) for i := 0; i < maxCallback; i++ { buf.WriteString(fmt.Sprintf("\tMOVW\t$%d, R12\n", i)) @@ -89,7 +89,7 @@ func genasmArm64() { // It then calls the Go implementation for that callback. #include "textflag.h" -TEXT runtime·callbackasm(SB),NOSPLIT|NOFRAME,$0 +TEXT runtime·callbackasm(SB),NOSPLIT|NOFRAME,$0 `) for i := 0; i < maxCallback; i++ { buf.WriteString(fmt.Sprintf("\tMOVD\t$%d, R12\n", i)) diff --git a/src/runtime/zcallback_windows.s b/src/runtime/zcallback_windows.s index e451c2b9d05..561527c90d1 100644 --- a/src/runtime/zcallback_windows.s +++ b/src/runtime/zcallback_windows.s @@ -11,7 +11,7 @@ // CALL instruction in runtime·callbackasm. This determines // which Go callback function is executed later on. -TEXT runtime·callbackasm(SB),7,$0 +TEXT runtime·callbackasm(SB),7,$0 CALL runtime·callbackasm1(SB) CALL runtime·callbackasm1(SB) CALL runtime·callbackasm1(SB) diff --git a/src/runtime/zcallback_windows_arm.s b/src/runtime/zcallback_windows_arm.s index a73a813acb3..f943d84cbfe 100644 --- a/src/runtime/zcallback_windows_arm.s +++ b/src/runtime/zcallback_windows_arm.s @@ -9,7 +9,7 @@ // It then calls the Go implementation for that callback. #include "textflag.h" -TEXT runtime·callbackasm(SB),NOSPLIT|NOFRAME,$0 +TEXT runtime·callbackasm(SB),NOSPLIT|NOFRAME,$0 MOVW $0, R12 B runtime·callbackasm1(SB) MOVW $1, R12 diff --git a/src/runtime/zcallback_windows_arm64.s b/src/runtime/zcallback_windows_arm64.s index 2a6bda0990c..69fb05788cd 100644 --- a/src/runtime/zcallback_windows_arm64.s +++ b/src/runtime/zcallback_windows_arm64.s @@ -9,7 +9,7 @@ // It then calls the Go implementation for that callback. #include "textflag.h" -TEXT runtime·callbackasm(SB),NOSPLIT|NOFRAME,$0 +TEXT runtime·callbackasm(SB),NOSPLIT|NOFRAME,$0 MOVD $0, R12 B runtime·callbackasm1(SB) MOVD $1, R12 From 0e0a1f94f3bd6c34b630818ecee2bf1a395e4242 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 20 May 2021 19:04:33 -0400 Subject: [PATCH 125/940] [dev.typeparams] runtime: use ABI0 handler addresses on Windows/ARM64 The handler address is passed to sigtramp, which calls it using ABI0 calling convention. Use ABI0 symbols. Change-Id: I5c16abef5e74a992d972fa5e100fed0ffb9f090a Reviewed-on: https://go-review.googlesource.com/c/go/+/321951 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/runtime/sys_windows_arm64.s | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/runtime/sys_windows_arm64.s b/src/runtime/sys_windows_arm64.s index 1cf877dce90..e8593715089 100644 --- a/src/runtime/sys_windows_arm64.s +++ b/src/runtime/sys_windows_arm64.s @@ -291,15 +291,15 @@ TEXT sigresume<>(SB),NOSPLIT|NOFRAME,$0 B (R1) TEXT runtime·exceptiontramp(SB),NOSPLIT|NOFRAME,$0 - MOVD $runtime·exceptionhandler(SB), R1 + MOVD $runtime·exceptionhandler(SB), R1 B sigtramp<>(SB) TEXT runtime·firstcontinuetramp(SB),NOSPLIT|NOFRAME,$0 - MOVD $runtime·firstcontinuehandler(SB), R1 + MOVD $runtime·firstcontinuehandler(SB), R1 B sigtramp<>(SB) TEXT runtime·lastcontinuetramp(SB),NOSPLIT|NOFRAME,$0 - MOVD $runtime·lastcontinuehandler(SB), R1 + MOVD $runtime·lastcontinuehandler(SB), R1 B sigtramp<>(SB) GLOBL runtime·cbctxts(SB), NOPTR, $4 From 7d928460a183f4efeed97638aa29f5f1fe74e397 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 20 May 2021 21:33:01 -0400 Subject: [PATCH 126/940] [dev.typeparams] runtime: use internal/abi.FuncPCABI0 to reference ABI0 assembly symbols Use FuncPCABI0 to reference ABI0 assembly symbols. Currently, they are referenced using funcPC, which will get the ABI wrapper's address. They don't seem to affect correctness (either the wrapper is harmless, or, on non-AMD64 architectures, not enabled). They should have been converted. This CL does not yet completely eliminate funcPC. But at this point we should be able to replace all remaining uses of funcPC to internal/abi.FuncPCABIInternal. Change-Id: I383a686e11d570f757f185fe46769a42c856ab77 Reviewed-on: https://go-review.googlesource.com/c/go/+/321952 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/runtime/defs_plan9_386.go | 2 +- src/runtime/defs_plan9_amd64.go | 2 +- src/runtime/os3_plan9.go | 2 +- src/runtime/os_dragonfly.go | 4 ++-- src/runtime/os_freebsd.go | 5 +++-- src/runtime/os_linux.go | 2 +- src/runtime/os_netbsd.go | 5 +++-- src/runtime/os_netbsd_386.go | 7 +++++-- src/runtime/os_netbsd_amd64.go | 7 +++++-- src/runtime/os_netbsd_arm.go | 7 +++++-- src/runtime/os_netbsd_arm64.go | 7 +++++-- src/runtime/os_openbsd_syscall.go | 3 ++- src/runtime/proc.go | 2 +- src/runtime/sys_darwin_arm64.go | 5 +++-- src/runtime/sys_plan9_386.s | 4 ++++ src/runtime/sys_plan9_amd64.s | 4 ++++ 16 files changed, 46 insertions(+), 22 deletions(-) diff --git a/src/runtime/defs_plan9_386.go b/src/runtime/defs_plan9_386.go index 49129b3c3fc..428044df687 100644 --- a/src/runtime/defs_plan9_386.go +++ b/src/runtime/defs_plan9_386.go @@ -61,4 +61,4 @@ func dumpregs(u *ureg) { print("gs ", hex(u.gs), "\n") } -func sigpanictramp() {} +func sigpanictramp() diff --git a/src/runtime/defs_plan9_amd64.go b/src/runtime/defs_plan9_amd64.go index 00995630341..15a27fc7db9 100644 --- a/src/runtime/defs_plan9_amd64.go +++ b/src/runtime/defs_plan9_amd64.go @@ -78,4 +78,4 @@ func dumpregs(u *ureg) { print("gs ", hex(u.gs), "\n") } -func sigpanictramp() {} +func sigpanictramp() diff --git a/src/runtime/os3_plan9.go b/src/runtime/os3_plan9.go index dacb5c23a0c..ce8bc7f1034 100644 --- a/src/runtime/os3_plan9.go +++ b/src/runtime/os3_plan9.go @@ -99,7 +99,7 @@ func sighandler(_ureg *ureg, note *byte, gp *g) int { } } if usesLR { - c.setpc(funcPC(sigpanictramp)) + c.setpc(abi.FuncPCABI0(sigpanictramp)) } else { c.setpc(abi.FuncPCABI0(sigpanic0)) } diff --git a/src/runtime/os_dragonfly.go b/src/runtime/os_dragonfly.go index ab0ad4728fe..45aeaecd891 100644 --- a/src/runtime/os_dragonfly.go +++ b/src/runtime/os_dragonfly.go @@ -148,14 +148,14 @@ func lwp_start(uintptr) func newosproc(mp *m) { stk := unsafe.Pointer(mp.g0.stack.hi) if false { - print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " lwp_start=", funcPC(lwp_start), " id=", mp.id, " ostk=", &mp, "\n") + print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " lwp_start=", abi.FuncPCABI0(lwp_start), " id=", mp.id, " ostk=", &mp, "\n") } var oset sigset sigprocmask(_SIG_SETMASK, &sigset_all, &oset) params := lwpparams{ - start_func: funcPC(lwp_start), + start_func: abi.FuncPCABI0(lwp_start), arg: unsafe.Pointer(mp), stack: uintptr(stk), tid1: nil, // minit will record tid diff --git a/src/runtime/os_freebsd.go b/src/runtime/os_freebsd.go index 09dd50ce594..41feaecf6b6 100644 --- a/src/runtime/os_freebsd.go +++ b/src/runtime/os_freebsd.go @@ -5,6 +5,7 @@ package runtime import ( + "internal/abi" "runtime/internal/sys" "unsafe" ) @@ -197,11 +198,11 @@ func thr_start() func newosproc(mp *m) { stk := unsafe.Pointer(mp.g0.stack.hi) if false { - print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " thr_start=", funcPC(thr_start), " id=", mp.id, " ostk=", &mp, "\n") + print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " thr_start=", abi.FuncPCABI0(thr_start), " id=", mp.id, " ostk=", &mp, "\n") } param := thrparam{ - start_func: funcPC(thr_start), + start_func: abi.FuncPCABI0(thr_start), arg: unsafe.Pointer(mp), stack_base: mp.g0.stack.lo, stack_size: uintptr(stk) - mp.g0.stack.lo, diff --git a/src/runtime/os_linux.go b/src/runtime/os_linux.go index 235c96e45a7..9203f28351b 100644 --- a/src/runtime/os_linux.go +++ b/src/runtime/os_linux.go @@ -143,7 +143,7 @@ func newosproc(mp *m) { * note: strace gets confused if we use CLONE_PTRACE here. */ if false { - print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " clone=", funcPC(clone), " id=", mp.id, " ostk=", &mp, "\n") + print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " clone=", abi.FuncPCABI0(clone), " id=", mp.id, " ostk=", &mp, "\n") } // Disable signals during clone, so that the new thread starts diff --git a/src/runtime/os_netbsd.go b/src/runtime/os_netbsd.go index 6fbb3aa6947..0920d5293e5 100644 --- a/src/runtime/os_netbsd.go +++ b/src/runtime/os_netbsd.go @@ -5,6 +5,7 @@ package runtime import ( + "internal/abi" "runtime/internal/atomic" "runtime/internal/sys" "unsafe" @@ -215,7 +216,7 @@ func newosproc(mp *m) { var oset sigset sigprocmask(_SIG_SETMASK, &sigset_all, &oset) - lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp.g0, funcPC(netbsdMstart)) + lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp.g0, abi.FuncPCABI0(netbsdMstart)) ret := lwp_create(unsafe.Pointer(&uc), _LWP_DETACHED, unsafe.Pointer(&mp.procid)) sigprocmask(_SIG_SETMASK, &oset, nil) @@ -319,7 +320,7 @@ func setsig(i uint32, fn uintptr) { sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART sa.sa_mask = sigset_all if fn == funcPC(sighandler) { - fn = funcPC(sigtramp) + fn = abi.FuncPCABI0(sigtramp) } sa.sa_sigaction = fn sigaction(i, &sa, nil) diff --git a/src/runtime/os_netbsd_386.go b/src/runtime/os_netbsd_386.go index 037f7e36dc6..ac89b9852c7 100644 --- a/src/runtime/os_netbsd_386.go +++ b/src/runtime/os_netbsd_386.go @@ -4,11 +4,14 @@ package runtime -import "unsafe" +import ( + "internal/abi" + "unsafe" +) func lwp_mcontext_init(mc *mcontextt, stk unsafe.Pointer, mp *m, gp *g, fn uintptr) { // Machine dependent mcontext initialisation for LWP. - mc.__gregs[_REG_EIP] = uint32(funcPC(lwp_tramp)) + mc.__gregs[_REG_EIP] = uint32(abi.FuncPCABI0(lwp_tramp)) mc.__gregs[_REG_UESP] = uint32(uintptr(stk)) mc.__gregs[_REG_EBX] = uint32(uintptr(unsafe.Pointer(mp))) mc.__gregs[_REG_EDX] = uint32(uintptr(unsafe.Pointer(gp))) diff --git a/src/runtime/os_netbsd_amd64.go b/src/runtime/os_netbsd_amd64.go index 5118b0c4ffd..74eea0ceabc 100644 --- a/src/runtime/os_netbsd_amd64.go +++ b/src/runtime/os_netbsd_amd64.go @@ -4,11 +4,14 @@ package runtime -import "unsafe" +import ( + "internal/abi" + "unsafe" +) func lwp_mcontext_init(mc *mcontextt, stk unsafe.Pointer, mp *m, gp *g, fn uintptr) { // Machine dependent mcontext initialisation for LWP. - mc.__gregs[_REG_RIP] = uint64(funcPC(lwp_tramp)) + mc.__gregs[_REG_RIP] = uint64(abi.FuncPCABI0(lwp_tramp)) mc.__gregs[_REG_RSP] = uint64(uintptr(stk)) mc.__gregs[_REG_R8] = uint64(uintptr(unsafe.Pointer(mp))) mc.__gregs[_REG_R9] = uint64(uintptr(unsafe.Pointer(gp))) diff --git a/src/runtime/os_netbsd_arm.go b/src/runtime/os_netbsd_arm.go index b5ec23e45b0..5fb4e08d66a 100644 --- a/src/runtime/os_netbsd_arm.go +++ b/src/runtime/os_netbsd_arm.go @@ -4,11 +4,14 @@ package runtime -import "unsafe" +import ( + "internal/abi" + "unsafe" +) func lwp_mcontext_init(mc *mcontextt, stk unsafe.Pointer, mp *m, gp *g, fn uintptr) { // Machine dependent mcontext initialisation for LWP. - mc.__gregs[_REG_R15] = uint32(funcPC(lwp_tramp)) + mc.__gregs[_REG_R15] = uint32(abi.FuncPCABI0(lwp_tramp)) mc.__gregs[_REG_R13] = uint32(uintptr(stk)) mc.__gregs[_REG_R0] = uint32(uintptr(unsafe.Pointer(mp))) mc.__gregs[_REG_R1] = uint32(uintptr(unsafe.Pointer(gp))) diff --git a/src/runtime/os_netbsd_arm64.go b/src/runtime/os_netbsd_arm64.go index 8d21b0a430f..2dda9c9274d 100644 --- a/src/runtime/os_netbsd_arm64.go +++ b/src/runtime/os_netbsd_arm64.go @@ -4,11 +4,14 @@ package runtime -import "unsafe" +import ( + "internal/abi" + "unsafe" +) func lwp_mcontext_init(mc *mcontextt, stk unsafe.Pointer, mp *m, gp *g, fn uintptr) { // Machine dependent mcontext initialisation for LWP. - mc.__gregs[_REG_ELR] = uint64(funcPC(lwp_tramp)) + mc.__gregs[_REG_ELR] = uint64(abi.FuncPCABI0(lwp_tramp)) mc.__gregs[_REG_X31] = uint64(uintptr(stk)) mc.__gregs[_REG_X0] = uint64(uintptr(unsafe.Pointer(mp))) mc.__gregs[_REG_X1] = uint64(uintptr(unsafe.Pointer(mp.g0))) diff --git a/src/runtime/os_openbsd_syscall.go b/src/runtime/os_openbsd_syscall.go index 3cdcb6c707b..a04eb4fc4dd 100644 --- a/src/runtime/os_openbsd_syscall.go +++ b/src/runtime/os_openbsd_syscall.go @@ -8,6 +8,7 @@ package runtime import ( + "internal/abi" "runtime/internal/sys" "unsafe" ) @@ -33,7 +34,7 @@ func newosproc(mp *m) { var oset sigset sigprocmask(_SIG_SETMASK, &sigset_all, &oset) - ret := tfork(¶m, unsafe.Sizeof(param), mp, mp.g0, funcPC(mstart)) + ret := tfork(¶m, unsafe.Sizeof(param), mp, mp.g0, abi.FuncPCABI0(mstart)) sigprocmask(_SIG_SETMASK, &oset, nil) if ret < 0 { diff --git a/src/runtime/proc.go b/src/runtime/proc.go index ded406cc28d..694f456ac5e 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -2236,7 +2236,7 @@ func newm1(mp *m) { } ts.g.set(mp.g0) ts.tls = (*uint64)(unsafe.Pointer(&mp.tls[0])) - ts.fn = unsafe.Pointer(funcPC(mstart)) + ts.fn = unsafe.Pointer(abi.FuncPCABI0(mstart)) if msanenabled { msanwrite(unsafe.Pointer(&ts), unsafe.Sizeof(ts)) } diff --git a/src/runtime/sys_darwin_arm64.go b/src/runtime/sys_darwin_arm64.go index 9c14f33a1ce..7dabaca08d2 100644 --- a/src/runtime/sys_darwin_arm64.go +++ b/src/runtime/sys_darwin_arm64.go @@ -5,6 +5,7 @@ package runtime import ( + "internal/abi" "runtime/internal/sys" "unsafe" ) @@ -14,14 +15,14 @@ import ( //go:nosplit //go:cgo_unsafe_args func g0_pthread_key_create(k *pthreadkey, destructor uintptr) int32 { - return asmcgocall(unsafe.Pointer(funcPC(pthread_key_create_trampoline)), unsafe.Pointer(&k)) + return asmcgocall(unsafe.Pointer(abi.FuncPCABI0(pthread_key_create_trampoline)), unsafe.Pointer(&k)) } func pthread_key_create_trampoline() //go:nosplit //go:cgo_unsafe_args func g0_pthread_setspecific(k pthreadkey, value uintptr) int32 { - return asmcgocall(unsafe.Pointer(funcPC(pthread_setspecific_trampoline)), unsafe.Pointer(&k)) + return asmcgocall(unsafe.Pointer(abi.FuncPCABI0(pthread_setspecific_trampoline)), unsafe.Pointer(&k)) } func pthread_setspecific_trampoline() diff --git a/src/runtime/sys_plan9_386.s b/src/runtime/sys_plan9_386.s index b3d2f1376d6..bdcb98e19e0 100644 --- a/src/runtime/sys_plan9_386.s +++ b/src/runtime/sys_plan9_386.s @@ -250,3 +250,7 @@ TEXT runtime·errstr(SB),NOSPLIT,$8-8 MOVL 0(SP), AX MOVL AX, ret_base+0(FP) RET + +// never called on this platform +TEXT ·sigpanictramp(SB),NOSPLIT,$0-0 + UNDEF diff --git a/src/runtime/sys_plan9_amd64.s b/src/runtime/sys_plan9_amd64.s index 731306ab448..39fc4c68e4c 100644 --- a/src/runtime/sys_plan9_amd64.s +++ b/src/runtime/sys_plan9_amd64.s @@ -251,3 +251,7 @@ TEXT runtime·errstr(SB),NOSPLIT,$16-16 MOVQ 0(SP), AX MOVQ AX, ret_base+0(FP) RET + +// never called on this platform +TEXT ·sigpanictramp(SB),NOSPLIT,$0-0 + UNDEF From 6a81e063dd0bf28d21b7085cc1d9e76eaeb78460 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 20 May 2021 21:40:32 -0400 Subject: [PATCH 127/940] [dev.typeparams] runtime: fix misuse of funcPC funcPC expects a func value. There are places where we pass an unsafe.Pointer, which is technically undefined. In proc.go it is actually representing a func value, so the expression does the right thing. Cast to a func value so it is clearer. In os_freebsd.go it is a raw function pointer. Using funcPC on a raw function pointer is incorrect. Just use it directly instead. Change-Id: I3c5d61cea08f0abf5737834b520f9f1b583c1d34 Reviewed-on: https://go-review.googlesource.com/c/go/+/321953 Trust: Cherry Mui Reviewed-by: Michael Knyszek --- src/runtime/os_freebsd.go | 2 +- src/runtime/proc.go | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/runtime/os_freebsd.go b/src/runtime/os_freebsd.go index 41feaecf6b6..151a5fd91ab 100644 --- a/src/runtime/os_freebsd.go +++ b/src/runtime/os_freebsd.go @@ -237,7 +237,7 @@ func newosproc0(stacksize uintptr, fn unsafe.Pointer) { // However, newosproc0 is currently unreachable because builds // utilizing c-shared/c-archive force external linking. param := thrparam{ - start_func: funcPC(fn), + start_func: uintptr(fn), arg: nil, stack_base: uintptr(stack), //+stacksize? stack_size: stacksize, diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 694f456ac5e..6c896cb993e 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -6487,7 +6487,8 @@ func doInit(t *initTask) { // Load stats non-atomically since tracinit is updated only by this init goroutine. after := inittrace - pkg := funcpkgpath(findfunc(funcPC(firstFunc))) + f := *(*func())(unsafe.Pointer(&firstFunc)) + pkg := funcpkgpath(findfunc(funcPC(f))) var sbuf [24]byte print("init ", pkg, " @") From 217f5dd496e14f0e0617c9efe0509073dec95d61 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Wed, 12 May 2021 13:55:59 -0700 Subject: [PATCH 128/940] doc: document additional atomic.Value methods For #44513. Fixes #46022. Change-Id: Id1d87fbd4034461953760ce77201f87ed723ff88 Reviewed-on: https://go-review.googlesource.com/c/go/+/319549 Trust: Keith Randall Reviewed-by: Ian Lance Taylor --- doc/go1.17.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index f00c649e048..5ab99c29edb 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -507,7 +507,9 @@ Do not send CLs removing the interior tags from such phrases.
sync/atomic

- TODO: https://golang.org/cl/241678: add (*Value).Swap and (*Value).CompareAndSwap + atomic.Value now has Swap and + CompareAndSwap methods that provide + additional atomic operations.

From 626e89c261297d13ef892bb569640cd72c35b98a Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Fri, 21 May 2021 13:37:19 -0400 Subject: [PATCH 129/940] [dev.typeparams] runtime: replace funcPC with internal/abi.FuncPCABIInternal At this point all funcPC references are ABIInternal functions. Replace with the intrinsics. Change-Id: I3ba7e485c83017408749b53f92877d3727a75e27 Reviewed-on: https://go-review.googlesource.com/c/go/+/321954 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/cmd/compile/internal/test/inl_test.go | 1 - src/runtime/chan.go | 5 +++-- src/runtime/cpuprof.go | 9 ++++---- src/runtime/export_debug_test.go | 2 +- src/runtime/export_test.go | 2 -- src/runtime/iface.go | 9 ++++---- src/runtime/map.go | 19 +++++++++-------- src/runtime/map_fast32.go | 11 +++++----- src/runtime/map_fast64.go | 11 +++++----- src/runtime/map_faststr.go | 9 ++++---- src/runtime/mbarrier.go | 6 +++--- src/runtime/mprof.go | 5 +++-- src/runtime/norace_linux_test.go | 3 ++- src/runtime/os3_solaris.go | 2 +- src/runtime/os_aix.go | 3 ++- src/runtime/os_darwin.go | 2 +- src/runtime/os_dragonfly.go | 2 +- src/runtime/os_freebsd2.go | 2 +- src/runtime/os_freebsd_amd64.go | 2 +- src/runtime/os_linux.go | 2 +- src/runtime/os_netbsd.go | 2 +- src/runtime/os_openbsd.go | 2 +- src/runtime/preempt.go | 2 +- src/runtime/proc.go | 26 ++++++----------------- src/runtime/select.go | 5 +++-- src/runtime/signal_386.go | 5 +++-- src/runtime/signal_arm.go | 7 ++++-- src/runtime/signal_arm64.go | 3 ++- src/runtime/signal_linux_s390x.go | 3 ++- src/runtime/signal_mips64x.go | 3 ++- src/runtime/signal_mipsx.go | 3 ++- src/runtime/signal_ppc64x.go | 5 +++-- src/runtime/signal_riscv64.go | 3 ++- src/runtime/signal_unix.go | 8 +++---- src/runtime/slice.go | 7 +++--- src/runtime/stack.go | 2 +- src/runtime/string.go | 7 +++--- src/runtime/time.go | 3 ++- src/runtime/type.go | 7 ++++-- 39 files changed, 111 insertions(+), 99 deletions(-) diff --git a/src/cmd/compile/internal/test/inl_test.go b/src/cmd/compile/internal/test/inl_test.go index 6f100033cf5..ad4e4fee976 100644 --- a/src/cmd/compile/internal/test/inl_test.go +++ b/src/cmd/compile/internal/test/inl_test.go @@ -48,7 +48,6 @@ func TestIntendedInlining(t *testing.T) { "fastlog2", "fastrand", "float64bits", - "funcPC", "getArgInfoFast", "getm", "getMCache", diff --git a/src/runtime/chan.go b/src/runtime/chan.go index f2a75b30f44..3cdb5dce117 100644 --- a/src/runtime/chan.go +++ b/src/runtime/chan.go @@ -18,6 +18,7 @@ package runtime // c.qcount < c.dataqsiz implies that c.sendq is empty. import ( + "internal/abi" "runtime/internal/atomic" "runtime/internal/math" "unsafe" @@ -169,7 +170,7 @@ func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool { } if raceenabled { - racereadpc(c.raceaddr(), callerpc, funcPC(chansend)) + racereadpc(c.raceaddr(), callerpc, abi.FuncPCABIInternal(chansend)) } // Fast path: check for failed non-blocking operation without acquiring the lock. @@ -365,7 +366,7 @@ func closechan(c *hchan) { if raceenabled { callerpc := getcallerpc() - racewritepc(c.raceaddr(), callerpc, funcPC(closechan)) + racewritepc(c.raceaddr(), callerpc, abi.FuncPCABIInternal(closechan)) racerelease(c.raceaddr()) } diff --git a/src/runtime/cpuprof.go b/src/runtime/cpuprof.go index e5d0193b9cb..c81ab710c20 100644 --- a/src/runtime/cpuprof.go +++ b/src/runtime/cpuprof.go @@ -13,6 +13,7 @@ package runtime import ( + "internal/abi" "runtime/internal/atomic" "runtime/internal/sys" "unsafe" @@ -166,8 +167,8 @@ func (p *cpuProfile) addExtra() { if p.lostExtra > 0 { hdr := [1]uint64{p.lostExtra} lostStk := [2]uintptr{ - funcPC(_LostExternalCode) + sys.PCQuantum, - funcPC(_ExternalCode) + sys.PCQuantum, + abi.FuncPCABIInternal(_LostExternalCode) + sys.PCQuantum, + abi.FuncPCABIInternal(_ExternalCode) + sys.PCQuantum, } p.log.write(nil, 0, hdr[:], lostStk[:]) p.lostExtra = 0 @@ -176,8 +177,8 @@ func (p *cpuProfile) addExtra() { if p.lostAtomic > 0 { hdr := [1]uint64{p.lostAtomic} lostStk := [2]uintptr{ - funcPC(_LostSIGPROFDuringAtomic64) + sys.PCQuantum, - funcPC(_System) + sys.PCQuantum, + abi.FuncPCABIInternal(_LostSIGPROFDuringAtomic64) + sys.PCQuantum, + abi.FuncPCABIInternal(_System) + sys.PCQuantum, } p.log.write(nil, 0, hdr[:], lostStk[:]) p.lostAtomic = 0 diff --git a/src/runtime/export_debug_test.go b/src/runtime/export_debug_test.go index fe4c9045c10..9808fd52991 100644 --- a/src/runtime/export_debug_test.go +++ b/src/runtime/export_debug_test.go @@ -125,7 +125,7 @@ func (h *debugCallHandler) inject(info *siginfo, ctxt *sigctxt, gp2 *g) bool { h.savedFP = *h.savedRegs.fpstate h.savedRegs.fpstate = nil // Set PC to debugCallV2. - ctxt.set_rip(uint64(funcPC(debugCallV2))) + ctxt.set_rip(uint64(abi.FuncPCABIInternal(debugCallV2))) // Call injected. Switch to the debugCall protocol. testSigtrap = h.handleF case _Grunnable: diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index a6fc1e4785f..b4de497aca8 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -27,8 +27,6 @@ var Exitsyscall = exitsyscall var LockedOSThread = lockedOSThread var Xadduintptr = atomic.Xadduintptr -var FuncPC = funcPC - var Fastlog2 = fastlog2 var Atoi = atoi diff --git a/src/runtime/iface.go b/src/runtime/iface.go index cd5fead9990..b397d1ff8d4 100644 --- a/src/runtime/iface.go +++ b/src/runtime/iface.go @@ -5,6 +5,7 @@ package runtime import ( + "internal/abi" "runtime/internal/atomic" "runtime/internal/sys" "unsafe" @@ -317,7 +318,7 @@ var ( func convT2E(t *_type, elem unsafe.Pointer) (e eface) { if raceenabled { - raceReadObjectPC(t, elem, getcallerpc(), funcPC(convT2E)) + raceReadObjectPC(t, elem, getcallerpc(), abi.FuncPCABIInternal(convT2E)) } if msanenabled { msanread(elem, t.size) @@ -390,7 +391,7 @@ func convTslice(val []byte) (x unsafe.Pointer) { func convT2Enoptr(t *_type, elem unsafe.Pointer) (e eface) { if raceenabled { - raceReadObjectPC(t, elem, getcallerpc(), funcPC(convT2Enoptr)) + raceReadObjectPC(t, elem, getcallerpc(), abi.FuncPCABIInternal(convT2Enoptr)) } if msanenabled { msanread(elem, t.size) @@ -405,7 +406,7 @@ func convT2Enoptr(t *_type, elem unsafe.Pointer) (e eface) { func convT2I(tab *itab, elem unsafe.Pointer) (i iface) { t := tab._type if raceenabled { - raceReadObjectPC(t, elem, getcallerpc(), funcPC(convT2I)) + raceReadObjectPC(t, elem, getcallerpc(), abi.FuncPCABIInternal(convT2I)) } if msanenabled { msanread(elem, t.size) @@ -420,7 +421,7 @@ func convT2I(tab *itab, elem unsafe.Pointer) (i iface) { func convT2Inoptr(tab *itab, elem unsafe.Pointer) (i iface) { t := tab._type if raceenabled { - raceReadObjectPC(t, elem, getcallerpc(), funcPC(convT2Inoptr)) + raceReadObjectPC(t, elem, getcallerpc(), abi.FuncPCABIInternal(convT2Inoptr)) } if msanenabled { msanread(elem, t.size) diff --git a/src/runtime/map.go b/src/runtime/map.go index 111db56b01a..5575040f2af 100644 --- a/src/runtime/map.go +++ b/src/runtime/map.go @@ -54,6 +54,7 @@ package runtime // before the table grows. Typical tables will be somewhat less loaded. import ( + "internal/abi" "runtime/internal/atomic" "runtime/internal/math" "runtime/internal/sys" @@ -394,7 +395,7 @@ func makeBucketArray(t *maptype, b uint8, dirtyalloc unsafe.Pointer) (buckets un func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { if raceenabled && h != nil { callerpc := getcallerpc() - pc := funcPC(mapaccess1) + pc := abi.FuncPCABIInternal(mapaccess1) racereadpc(unsafe.Pointer(h), callerpc, pc) raceReadObjectPC(t.key, key, callerpc, pc) } @@ -452,7 +453,7 @@ bucketloop: func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool) { if raceenabled && h != nil { callerpc := getcallerpc() - pc := funcPC(mapaccess2) + pc := abi.FuncPCABIInternal(mapaccess2) racereadpc(unsafe.Pointer(h), callerpc, pc) raceReadObjectPC(t.key, key, callerpc, pc) } @@ -574,7 +575,7 @@ func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { } if raceenabled { callerpc := getcallerpc() - pc := funcPC(mapassign) + pc := abi.FuncPCABIInternal(mapassign) racewritepc(unsafe.Pointer(h), callerpc, pc) raceReadObjectPC(t.key, key, callerpc, pc) } @@ -685,7 +686,7 @@ done: func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) { if raceenabled && h != nil { callerpc := getcallerpc() - pc := funcPC(mapdelete) + pc := abi.FuncPCABIInternal(mapdelete) racewritepc(unsafe.Pointer(h), callerpc, pc) raceReadObjectPC(t.key, key, callerpc, pc) } @@ -802,7 +803,7 @@ search: func mapiterinit(t *maptype, h *hmap, it *hiter) { if raceenabled && h != nil { callerpc := getcallerpc() - racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapiterinit)) + racereadpc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(mapiterinit)) } if h == nil || h.count == 0 { @@ -852,7 +853,7 @@ func mapiternext(it *hiter) { h := it.h if raceenabled { callerpc := getcallerpc() - racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapiternext)) + racereadpc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(mapiternext)) } if h.flags&hashWriting != 0 { throw("concurrent map iteration and map write") @@ -978,7 +979,7 @@ next: func mapclear(t *maptype, h *hmap) { if raceenabled && h != nil { callerpc := getcallerpc() - pc := funcPC(mapclear) + pc := abi.FuncPCABIInternal(mapclear) racewritepc(unsafe.Pointer(h), callerpc, pc) } @@ -1363,7 +1364,7 @@ func reflect_maplen(h *hmap) int { } if raceenabled { callerpc := getcallerpc() - racereadpc(unsafe.Pointer(h), callerpc, funcPC(reflect_maplen)) + racereadpc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(reflect_maplen)) } return h.count } @@ -1375,7 +1376,7 @@ func reflectlite_maplen(h *hmap) int { } if raceenabled { callerpc := getcallerpc() - racereadpc(unsafe.Pointer(h), callerpc, funcPC(reflect_maplen)) + racereadpc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(reflect_maplen)) } return h.count } diff --git a/src/runtime/map_fast32.go b/src/runtime/map_fast32.go index 8d52dad217a..420a01daec1 100644 --- a/src/runtime/map_fast32.go +++ b/src/runtime/map_fast32.go @@ -5,6 +5,7 @@ package runtime import ( + "internal/abi" "runtime/internal/sys" "unsafe" ) @@ -12,7 +13,7 @@ import ( func mapaccess1_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer { if raceenabled && h != nil { callerpc := getcallerpc() - racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess1_fast32)) + racereadpc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(mapaccess1_fast32)) } if h == nil || h.count == 0 { return unsafe.Pointer(&zeroVal[0]) @@ -52,7 +53,7 @@ func mapaccess1_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer { func mapaccess2_fast32(t *maptype, h *hmap, key uint32) (unsafe.Pointer, bool) { if raceenabled && h != nil { callerpc := getcallerpc() - racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess2_fast32)) + racereadpc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(mapaccess2_fast32)) } if h == nil || h.count == 0 { return unsafe.Pointer(&zeroVal[0]), false @@ -95,7 +96,7 @@ func mapassign_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer { } if raceenabled { callerpc := getcallerpc() - racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapassign_fast32)) + racewritepc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(mapassign_fast32)) } if h.flags&hashWriting != 0 { throw("concurrent map writes") @@ -185,7 +186,7 @@ func mapassign_fast32ptr(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer } if raceenabled { callerpc := getcallerpc() - racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapassign_fast32)) + racewritepc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(mapassign_fast32)) } if h.flags&hashWriting != 0 { throw("concurrent map writes") @@ -272,7 +273,7 @@ done: func mapdelete_fast32(t *maptype, h *hmap, key uint32) { if raceenabled && h != nil { callerpc := getcallerpc() - racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapdelete_fast32)) + racewritepc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(mapdelete_fast32)) } if h == nil || h.count == 0 { return diff --git a/src/runtime/map_fast64.go b/src/runtime/map_fast64.go index f1368dc774e..cb202113ac5 100644 --- a/src/runtime/map_fast64.go +++ b/src/runtime/map_fast64.go @@ -5,6 +5,7 @@ package runtime import ( + "internal/abi" "runtime/internal/sys" "unsafe" ) @@ -12,7 +13,7 @@ import ( func mapaccess1_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer { if raceenabled && h != nil { callerpc := getcallerpc() - racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess1_fast64)) + racereadpc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(mapaccess1_fast64)) } if h == nil || h.count == 0 { return unsafe.Pointer(&zeroVal[0]) @@ -52,7 +53,7 @@ func mapaccess1_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer { func mapaccess2_fast64(t *maptype, h *hmap, key uint64) (unsafe.Pointer, bool) { if raceenabled && h != nil { callerpc := getcallerpc() - racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess2_fast64)) + racereadpc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(mapaccess2_fast64)) } if h == nil || h.count == 0 { return unsafe.Pointer(&zeroVal[0]), false @@ -95,7 +96,7 @@ func mapassign_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer { } if raceenabled { callerpc := getcallerpc() - racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapassign_fast64)) + racewritepc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(mapassign_fast64)) } if h.flags&hashWriting != 0 { throw("concurrent map writes") @@ -185,7 +186,7 @@ func mapassign_fast64ptr(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer } if raceenabled { callerpc := getcallerpc() - racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapassign_fast64)) + racewritepc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(mapassign_fast64)) } if h.flags&hashWriting != 0 { throw("concurrent map writes") @@ -272,7 +273,7 @@ done: func mapdelete_fast64(t *maptype, h *hmap, key uint64) { if raceenabled && h != nil { callerpc := getcallerpc() - racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapdelete_fast64)) + racewritepc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(mapdelete_fast64)) } if h == nil || h.count == 0 { return diff --git a/src/runtime/map_faststr.go b/src/runtime/map_faststr.go index 0673dd39c8f..ed7e46b5f68 100644 --- a/src/runtime/map_faststr.go +++ b/src/runtime/map_faststr.go @@ -5,6 +5,7 @@ package runtime import ( + "internal/abi" "runtime/internal/sys" "unsafe" ) @@ -12,7 +13,7 @@ import ( func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer { if raceenabled && h != nil { callerpc := getcallerpc() - racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess1_faststr)) + racereadpc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(mapaccess1_faststr)) } if h == nil || h.count == 0 { return unsafe.Pointer(&zeroVal[0]) @@ -107,7 +108,7 @@ dohash: func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { if raceenabled && h != nil { callerpc := getcallerpc() - racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess2_faststr)) + racereadpc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(mapaccess2_faststr)) } if h == nil || h.count == 0 { return unsafe.Pointer(&zeroVal[0]), false @@ -205,7 +206,7 @@ func mapassign_faststr(t *maptype, h *hmap, s string) unsafe.Pointer { } if raceenabled { callerpc := getcallerpc() - racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapassign_faststr)) + racewritepc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(mapassign_faststr)) } if h.flags&hashWriting != 0 { throw("concurrent map writes") @@ -300,7 +301,7 @@ done: func mapdelete_faststr(t *maptype, h *hmap, ky string) { if raceenabled && h != nil { callerpc := getcallerpc() - racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapdelete_faststr)) + racewritepc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(mapdelete_faststr)) } if h == nil || h.count == 0 { return diff --git a/src/runtime/mbarrier.go b/src/runtime/mbarrier.go index 4994347bdeb..b06ee725ddd 100644 --- a/src/runtime/mbarrier.go +++ b/src/runtime/mbarrier.go @@ -177,8 +177,8 @@ func typedmemmove(typ *_type, dst, src unsafe.Pointer) { //go:linkname reflect_typedmemmove reflect.typedmemmove func reflect_typedmemmove(typ *_type, dst, src unsafe.Pointer) { if raceenabled { - raceWriteObjectPC(typ, dst, getcallerpc(), funcPC(reflect_typedmemmove)) - raceReadObjectPC(typ, src, getcallerpc(), funcPC(reflect_typedmemmove)) + raceWriteObjectPC(typ, dst, getcallerpc(), abi.FuncPCABIInternal(reflect_typedmemmove)) + raceReadObjectPC(typ, src, getcallerpc(), abi.FuncPCABIInternal(reflect_typedmemmove)) } if msanenabled { msanwrite(dst, typ.size) @@ -254,7 +254,7 @@ func typedslicecopy(typ *_type, dstPtr unsafe.Pointer, dstLen int, srcPtr unsafe // code and needs its own instrumentation. if raceenabled { callerpc := getcallerpc() - pc := funcPC(slicecopy) + pc := abi.FuncPCABIInternal(slicecopy) racewriterangepc(dstPtr, uintptr(n)*typ.size, callerpc, pc) racereadrangepc(srcPtr, uintptr(n)*typ.size, callerpc, pc) } diff --git a/src/runtime/mprof.go b/src/runtime/mprof.go index 5235b898e4f..0ba415ba5ac 100644 --- a/src/runtime/mprof.go +++ b/src/runtime/mprof.go @@ -8,6 +8,7 @@ package runtime import ( + "internal/abi" "runtime/internal/atomic" "unsafe" ) @@ -621,7 +622,7 @@ func record(r *MemProfileRecord, b *bucket) { r.AllocObjects = int64(mp.active.allocs) r.FreeObjects = int64(mp.active.frees) if raceenabled { - racewriterangepc(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0), getcallerpc(), funcPC(MemProfile)) + racewriterangepc(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0), getcallerpc(), abi.FuncPCABIInternal(MemProfile)) } if msanenabled { msanwrite(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0)) @@ -674,7 +675,7 @@ func BlockProfile(p []BlockProfileRecord) (n int, ok bool) { } r.Cycles = bp.cycles if raceenabled { - racewriterangepc(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0), getcallerpc(), funcPC(BlockProfile)) + racewriterangepc(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0), getcallerpc(), abi.FuncPCABIInternal(BlockProfile)) } if msanenabled { msanwrite(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0)) diff --git a/src/runtime/norace_linux_test.go b/src/runtime/norace_linux_test.go index 94b7c7a4677..b199aa633c1 100644 --- a/src/runtime/norace_linux_test.go +++ b/src/runtime/norace_linux_test.go @@ -9,6 +9,7 @@ package runtime_test import ( + "internal/abi" "runtime" "testing" "time" @@ -25,7 +26,7 @@ func newOSProcCreated() { // Can't be run with -race because it inserts calls into newOSProcCreated() // that require a valid G/M. func TestNewOSProc0(t *testing.T) { - runtime.NewOSProc0(0x800000, unsafe.Pointer(runtime.FuncPC(newOSProcCreated))) + runtime.NewOSProc0(0x800000, unsafe.Pointer(abi.FuncPCABIInternal(newOSProcCreated))) check := time.NewTicker(100 * time.Millisecond) defer check.Stop() end := time.After(5 * time.Second) diff --git a/src/runtime/os3_solaris.go b/src/runtime/os3_solaris.go index 3b1a773ee24..bfd7c7eb641 100644 --- a/src/runtime/os3_solaris.go +++ b/src/runtime/os3_solaris.go @@ -242,7 +242,7 @@ func setsig(i uint32, fn uintptr) { sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART sa.sa_mask = sigset_all - if fn == funcPC(sighandler) { + if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go fn = abi.FuncPCABI0(sigtramp) } *((*uintptr)(unsafe.Pointer(&sa._funcptr))) = fn diff --git a/src/runtime/os_aix.go b/src/runtime/os_aix.go index 4fb1c8e845c..478dde2fc3f 100644 --- a/src/runtime/os_aix.go +++ b/src/runtime/os_aix.go @@ -8,6 +8,7 @@ package runtime import ( + "internal/abi" "unsafe" ) @@ -267,7 +268,7 @@ func setsig(i uint32, fn uintptr) { var sa sigactiont sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART sa.sa_mask = sigset_all - if fn == funcPC(sighandler) { + if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go fn = uintptr(unsafe.Pointer(&sigtramp)) } sa.sa_handler = fn diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go index 00139351abc..df2c0ff4a5f 100644 --- a/src/runtime/os_darwin.go +++ b/src/runtime/os_darwin.go @@ -364,7 +364,7 @@ func setsig(i uint32, fn uintptr) { var sa usigactiont sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART sa.sa_mask = ^uint32(0) - if fn == funcPC(sighandler) { // funcPC(sighandler) matches the callers in signal_unix.go + if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go if iscgo { fn = abi.FuncPCABI0(cgoSigtramp) } else { diff --git a/src/runtime/os_dragonfly.go b/src/runtime/os_dragonfly.go index 45aeaecd891..0c81ed4d7c3 100644 --- a/src/runtime/os_dragonfly.go +++ b/src/runtime/os_dragonfly.go @@ -227,7 +227,7 @@ func setsig(i uint32, fn uintptr) { var sa sigactiont sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART sa.sa_mask = sigset_all - if fn == funcPC(sighandler) { + if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go fn = abi.FuncPCABI0(sigtramp) } sa.sa_sigaction = fn diff --git a/src/runtime/os_freebsd2.go b/src/runtime/os_freebsd2.go index 53ba23b64cf..7e266dc27e2 100644 --- a/src/runtime/os_freebsd2.go +++ b/src/runtime/os_freebsd2.go @@ -15,7 +15,7 @@ func setsig(i uint32, fn uintptr) { var sa sigactiont sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART sa.sa_mask = sigset_all - if fn == funcPC(sighandler) { + if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go fn = abi.FuncPCABI0(sigtramp) } sa.sa_handler = fn diff --git a/src/runtime/os_freebsd_amd64.go b/src/runtime/os_freebsd_amd64.go index 7ae80c25060..b179383eacc 100644 --- a/src/runtime/os_freebsd_amd64.go +++ b/src/runtime/os_freebsd_amd64.go @@ -14,7 +14,7 @@ func setsig(i uint32, fn uintptr) { var sa sigactiont sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART sa.sa_mask = sigset_all - if fn == funcPC(sighandler) { + if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go if iscgo { fn = abi.FuncPCABI0(cgoSigtramp) } else { diff --git a/src/runtime/os_linux.go b/src/runtime/os_linux.go index 9203f28351b..1984bf68445 100644 --- a/src/runtime/os_linux.go +++ b/src/runtime/os_linux.go @@ -432,7 +432,7 @@ func setsig(i uint32, fn uintptr) { if GOARCH == "386" || GOARCH == "amd64" { sa.sa_restorer = abi.FuncPCABI0(sigreturn) } - if fn == funcPC(sighandler) { + if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go if iscgo { fn = abi.FuncPCABI0(cgoSigtramp) } else { diff --git a/src/runtime/os_netbsd.go b/src/runtime/os_netbsd.go index 0920d5293e5..151cd17bbe8 100644 --- a/src/runtime/os_netbsd.go +++ b/src/runtime/os_netbsd.go @@ -319,7 +319,7 @@ func setsig(i uint32, fn uintptr) { var sa sigactiont sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART sa.sa_mask = sigset_all - if fn == funcPC(sighandler) { + if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go fn = abi.FuncPCABI0(sigtramp) } sa.sa_sigaction = fn diff --git a/src/runtime/os_openbsd.go b/src/runtime/os_openbsd.go index 35995e7035f..54f36c6ebff 100644 --- a/src/runtime/os_openbsd.go +++ b/src/runtime/os_openbsd.go @@ -192,7 +192,7 @@ func setsig(i uint32, fn uintptr) { var sa sigactiont sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART sa.sa_mask = uint32(sigset_all) - if fn == funcPC(sighandler) { + if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go fn = abi.FuncPCABI0(sigtramp) } sa.sa_sigaction = fn diff --git a/src/runtime/preempt.go b/src/runtime/preempt.go index d1291c9c487..d6cdf1b8f83 100644 --- a/src/runtime/preempt.go +++ b/src/runtime/preempt.go @@ -318,7 +318,7 @@ var asyncPreemptStack = ^uintptr(0) func init() { f := findfunc(abi.FuncPCABI0(asyncPreempt)) total := funcMaxSPDelta(f) - f = findfunc(funcPC(asyncPreempt2)) + f = findfunc(abi.FuncPCABIInternal(asyncPreempt2)) total += funcMaxSPDelta(f) // Add some overhead for return PCs, etc. asyncPreemptStack = uintptr(total) + 8*sys.PtrSize diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 6c896cb993e..63eeb6c9c75 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -466,18 +466,6 @@ func releaseSudog(s *sudog) { releasem(mp) } -// funcPC returns the entry PC of the function f. -// It assumes that f is a func value. Otherwise the behavior is undefined. -// CAREFUL: In programs with plugins, funcPC can return different values -// for the same function (because there are actually multiple copies of -// the same function in the address space). To be safe, don't use the -// results of this function in any == expression. It is only safe to -// use the result as an address at which to start executing code. -//go:nosplit -func funcPC(f interface{}) uintptr { - return *(*uintptr)(efaceOf(&f).data) -} - // called from assembly func badmcall(fn func(*g)) { throw("runtime: mcall called on m->g0 stack") @@ -2043,7 +2031,7 @@ func oneNewExtraM() { gp.lockedm.set(mp) gp.goid = int64(atomic.Xadd64(&sched.goidgen, 1)) if raceenabled { - gp.racectx = racegostart(funcPC(newextram) + sys.PCQuantum) + gp.racectx = racegostart(abi.FuncPCABIInternal(newextram) + sys.PCQuantum) } // put on allg for garbage collector allgadd(gp) @@ -4741,16 +4729,16 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) { // If all of the above has failed, account it against abstract "System" or "GC". n = 2 if inVDSOPage(pc) { - pc = funcPC(_VDSO) + sys.PCQuantum + pc = abi.FuncPCABIInternal(_VDSO) + sys.PCQuantum } else if pc > firstmoduledata.etext { // "ExternalCode" is better than "etext". - pc = funcPC(_ExternalCode) + sys.PCQuantum + pc = abi.FuncPCABIInternal(_ExternalCode) + sys.PCQuantum } stk[0] = pc if mp.preemptoff != "" { - stk[1] = funcPC(_GC) + sys.PCQuantum + stk[1] = abi.FuncPCABIInternal(_GC) + sys.PCQuantum } else { - stk[1] = funcPC(_System) + sys.PCQuantum + stk[1] = abi.FuncPCABIInternal(_System) + sys.PCQuantum } } } @@ -4794,7 +4782,7 @@ func sigprofNonGoPC(pc uintptr) { if prof.hz != 0 { stk := []uintptr{ pc, - funcPC(_ExternalCode) + sys.PCQuantum, + abi.FuncPCABIInternal(_ExternalCode) + sys.PCQuantum, } cpuprof.addNonGo(stk) } @@ -6488,7 +6476,7 @@ func doInit(t *initTask) { after := inittrace f := *(*func())(unsafe.Pointer(&firstFunc)) - pkg := funcpkgpath(findfunc(funcPC(f))) + pkg := funcpkgpath(findfunc(abi.FuncPCABIInternal(f))) var sbuf [24]byte print("init ", pkg, " @") diff --git a/src/runtime/select.go b/src/runtime/select.go index e72761bfa91..74f0c291944 100644 --- a/src/runtime/select.go +++ b/src/runtime/select.go @@ -7,6 +7,7 @@ package runtime // This file contains the implementation of Go select statements. import ( + "internal/abi" "runtime/internal/atomic" "unsafe" ) @@ -22,8 +23,8 @@ type scase struct { } var ( - chansendpc = funcPC(chansend) - chanrecvpc = funcPC(chanrecv) + chansendpc = abi.FuncPCABIInternal(chansend) + chanrecvpc = abi.FuncPCABIInternal(chanrecv) ) func selectsetpc(pc *uintptr) { diff --git a/src/runtime/signal_386.go b/src/runtime/signal_386.go index 5824eaddb56..c77a9cc5224 100644 --- a/src/runtime/signal_386.go +++ b/src/runtime/signal_386.go @@ -8,6 +8,7 @@ package runtime import ( + "internal/abi" "runtime/internal/sys" "unsafe" ) @@ -42,10 +43,10 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { sp := uintptr(c.esp()) if shouldPushSigpanic(gp, pc, *(*uintptr)(unsafe.Pointer(sp))) { - c.pushCall(funcPC(sigpanic), pc) + c.pushCall(abi.FuncPCABIInternal(sigpanic), pc) } else { // Not safe to push the call. Just clobber the frame. - c.set_eip(uint32(funcPC(sigpanic))) + c.set_eip(uint32(abi.FuncPCABIInternal(sigpanic))) } } diff --git a/src/runtime/signal_arm.go b/src/runtime/signal_arm.go index 4d9c6224a29..a0780788f80 100644 --- a/src/runtime/signal_arm.go +++ b/src/runtime/signal_arm.go @@ -7,7 +7,10 @@ package runtime -import "unsafe" +import ( + "internal/abi" + "unsafe" +) func dumpregs(c *sigctxt) { print("trap ", hex(c.trap()), "\n") @@ -61,7 +64,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { // In case we are panicking from external C code c.set_r10(uint32(uintptr(unsafe.Pointer(gp)))) - c.set_pc(uint32(funcPC(sigpanic))) + c.set_pc(uint32(abi.FuncPCABIInternal(sigpanic))) } func (c *sigctxt) pushCall(targetPC, resumePC uintptr) { diff --git a/src/runtime/signal_arm64.go b/src/runtime/signal_arm64.go index f04750084f4..9d4a8b8a99d 100644 --- a/src/runtime/signal_arm64.go +++ b/src/runtime/signal_arm64.go @@ -8,6 +8,7 @@ package runtime import ( + "internal/abi" "runtime/internal/sys" "unsafe" ) @@ -77,7 +78,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { // In case we are panicking from external C code c.set_r28(uint64(uintptr(unsafe.Pointer(gp)))) - c.set_pc(uint64(funcPC(sigpanic))) + c.set_pc(uint64(abi.FuncPCABIInternal(sigpanic))) } func (c *sigctxt) pushCall(targetPC, resumePC uintptr) { diff --git a/src/runtime/signal_linux_s390x.go b/src/runtime/signal_linux_s390x.go index 12d5c315931..03c58cbbb68 100644 --- a/src/runtime/signal_linux_s390x.go +++ b/src/runtime/signal_linux_s390x.go @@ -5,6 +5,7 @@ package runtime import ( + "internal/abi" "runtime/internal/sys" "unsafe" ) @@ -107,7 +108,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { // In case we are panicking from external C code c.set_r0(0) c.set_r13(uint64(uintptr(unsafe.Pointer(gp)))) - c.set_pc(uint64(funcPC(sigpanic))) + c.set_pc(uint64(abi.FuncPCABIInternal(sigpanic))) } func (c *sigctxt) pushCall(targetPC, resumePC uintptr) { diff --git a/src/runtime/signal_mips64x.go b/src/runtime/signal_mips64x.go index 1616b570278..eebcc748864 100644 --- a/src/runtime/signal_mips64x.go +++ b/src/runtime/signal_mips64x.go @@ -9,6 +9,7 @@ package runtime import ( + "internal/abi" "runtime/internal/sys" "unsafe" ) @@ -80,7 +81,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { } // In case we are panicking from external C code - sigpanicPC := uint64(funcPC(sigpanic)) + sigpanicPC := uint64(abi.FuncPCABIInternal(sigpanic)) c.set_r28(sigpanicPC >> 32 << 32) // RSB register c.set_r30(uint64(uintptr(unsafe.Pointer(gp)))) c.set_pc(sigpanicPC) diff --git a/src/runtime/signal_mipsx.go b/src/runtime/signal_mipsx.go index dcc7f1e9dd5..5067799bd6b 100644 --- a/src/runtime/signal_mipsx.go +++ b/src/runtime/signal_mipsx.go @@ -9,6 +9,7 @@ package runtime import ( + "internal/abi" "runtime/internal/sys" "unsafe" ) @@ -78,7 +79,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { // In case we are panicking from external C code c.set_r30(uint32(uintptr(unsafe.Pointer(gp)))) - c.set_pc(uint32(funcPC(sigpanic))) + c.set_pc(uint32(abi.FuncPCABIInternal(sigpanic))) } func (c *sigctxt) pushCall(targetPC, resumePC uintptr) { diff --git a/src/runtime/signal_ppc64x.go b/src/runtime/signal_ppc64x.go index f2225da9a17..8a39d599576 100644 --- a/src/runtime/signal_ppc64x.go +++ b/src/runtime/signal_ppc64x.go @@ -9,6 +9,7 @@ package runtime import ( + "internal/abi" "runtime/internal/sys" "unsafe" ) @@ -83,8 +84,8 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { // In case we are panicking from external C code c.set_r0(0) c.set_r30(uint64(uintptr(unsafe.Pointer(gp)))) - c.set_r12(uint64(funcPC(sigpanic))) - c.set_pc(uint64(funcPC(sigpanic))) + c.set_r12(uint64(abi.FuncPCABIInternal(sigpanic))) + c.set_pc(uint64(abi.FuncPCABIInternal(sigpanic))) } func (c *sigctxt) pushCall(targetPC, resumePC uintptr) { diff --git a/src/runtime/signal_riscv64.go b/src/runtime/signal_riscv64.go index e6b1b14130e..aaaa217051b 100644 --- a/src/runtime/signal_riscv64.go +++ b/src/runtime/signal_riscv64.go @@ -8,6 +8,7 @@ package runtime import ( + "internal/abi" "runtime/internal/sys" "unsafe" ) @@ -76,7 +77,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { // In case we are panicking from external C code c.set_gp(uint64(uintptr(unsafe.Pointer(gp)))) - c.set_pc(uint64(funcPC(sigpanic))) + c.set_pc(uint64(abi.FuncPCABIInternal(sigpanic))) } func (c *sigctxt) pushCall(targetPC, resumePC uintptr) { diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go index 6396232dd77..0b3414d4578 100644 --- a/src/runtime/signal_unix.go +++ b/src/runtime/signal_unix.go @@ -144,7 +144,7 @@ func initsig(preinit bool) { } handlingSig[i] = 1 - setsig(i, funcPC(sighandler)) + setsig(i, abi.FuncPCABIInternal(sighandler)) } } @@ -195,7 +195,7 @@ func sigenable(sig uint32) { <-maskUpdatedChan if atomic.Cas(&handlingSig[sig], 0, 1) { atomic.Storeuintptr(&fwdSig[sig], getsig(sig)) - setsig(sig, funcPC(sighandler)) + setsig(sig, abi.FuncPCABIInternal(sighandler)) } } } @@ -272,7 +272,7 @@ func setProcessCPUProfiler(hz int32) { // Enable the Go signal handler if not enabled. if atomic.Cas(&handlingSig[_SIGPROF], 0, 1) { atomic.Storeuintptr(&fwdSig[_SIGPROF], getsig(_SIGPROF)) - setsig(_SIGPROF, funcPC(sighandler)) + setsig(_SIGPROF, abi.FuncPCABIInternal(sighandler)) } var it itimerval @@ -844,7 +844,7 @@ func raisebadsignal(sig uint32, c *sigctxt) { // We may receive another instance of the signal before we // restore the Go handler, but that is not so bad: we know // that the Go program has been ignoring the signal. - setsig(sig, funcPC(sighandler)) + setsig(sig, abi.FuncPCABIInternal(sighandler)) } //go:nosplit diff --git a/src/runtime/slice.go b/src/runtime/slice.go index f9d4154acfd..7a470f09b6c 100644 --- a/src/runtime/slice.go +++ b/src/runtime/slice.go @@ -5,6 +5,7 @@ package runtime import ( + "internal/abi" "runtime/internal/math" "runtime/internal/sys" "unsafe" @@ -68,7 +69,7 @@ func makeslicecopy(et *_type, tolen int, fromlen int, from unsafe.Pointer) unsaf if raceenabled { callerpc := getcallerpc() - pc := funcPC(makeslicecopy) + pc := abi.FuncPCABIInternal(makeslicecopy) racereadrangepc(from, copymem, callerpc, pc) } if msanenabled { @@ -144,7 +145,7 @@ func panicunsafeslicelen() { func growslice(et *_type, old slice, cap int) slice { if raceenabled { callerpc := getcallerpc() - racereadrangepc(old.array, uintptr(old.len*int(et.size)), callerpc, funcPC(growslice)) + racereadrangepc(old.array, uintptr(old.len*int(et.size)), callerpc, abi.FuncPCABIInternal(growslice)) } if msanenabled { msanread(old.array, uintptr(old.len*int(et.size))) @@ -280,7 +281,7 @@ func slicecopy(toPtr unsafe.Pointer, toLen int, fromPtr unsafe.Pointer, fromLen size := uintptr(n) * width if raceenabled { callerpc := getcallerpc() - pc := funcPC(slicecopy) + pc := abi.FuncPCABIInternal(slicecopy) racereadrangepc(fromPtr, size, callerpc, pc) racewriterangepc(toPtr, size, callerpc, pc) } diff --git a/src/runtime/stack.go b/src/runtime/stack.go index b21c9c95182..622de45f25a 100644 --- a/src/runtime/stack.go +++ b/src/runtime/stack.go @@ -1112,7 +1112,7 @@ func gostartcallfn(gobuf *gobuf, fv *funcval) { if fv != nil { fn = unsafe.Pointer(fv.fn) } else { - fn = unsafe.Pointer(funcPC(nilfunc)) + fn = unsafe.Pointer(abi.FuncPCABIInternal(nilfunc)) } gostartcall(gobuf, fn, unsafe.Pointer(fv)) } diff --git a/src/runtime/string.go b/src/runtime/string.go index d6030a1dca4..3c215d37540 100644 --- a/src/runtime/string.go +++ b/src/runtime/string.go @@ -5,6 +5,7 @@ package runtime import ( + "internal/abi" "internal/bytealg" "runtime/internal/sys" "unsafe" @@ -88,7 +89,7 @@ func slicebytetostring(buf *tmpBuf, ptr *byte, n int) (str string) { racereadrangepc(unsafe.Pointer(ptr), uintptr(n), getcallerpc(), - funcPC(slicebytetostring)) + abi.FuncPCABIInternal(slicebytetostring)) } if msanenabled { msanread(unsafe.Pointer(ptr), uintptr(n)) @@ -152,7 +153,7 @@ func slicebytetostringtmp(ptr *byte, n int) (str string) { racereadrangepc(unsafe.Pointer(ptr), uintptr(n), getcallerpc(), - funcPC(slicebytetostringtmp)) + abi.FuncPCABIInternal(slicebytetostringtmp)) } if msanenabled && n > 0 { msanread(unsafe.Pointer(ptr), uintptr(n)) @@ -203,7 +204,7 @@ func slicerunetostring(buf *tmpBuf, a []rune) string { racereadrangepc(unsafe.Pointer(&a[0]), uintptr(len(a))*unsafe.Sizeof(a[0]), getcallerpc(), - funcPC(slicerunetostring)) + abi.FuncPCABIInternal(slicerunetostring)) } if msanenabled && len(a) > 0 { msanread(unsafe.Pointer(&a[0]), uintptr(len(a))*unsafe.Sizeof(a[0])) diff --git a/src/runtime/time.go b/src/runtime/time.go index dee6a674e4c..90e9b1139f8 100644 --- a/src/runtime/time.go +++ b/src/runtime/time.go @@ -7,6 +7,7 @@ package runtime import ( + "internal/abi" "runtime/internal/atomic" "runtime/internal/sys" "unsafe" @@ -856,7 +857,7 @@ func runOneTimer(pp *p, t *timer, now int64) { if raceenabled { ppcur := getg().m.p.ptr() if ppcur.timerRaceCtx == 0 { - ppcur.timerRaceCtx = racegostart(funcPC(runtimer) + sys.PCQuantum) + ppcur.timerRaceCtx = racegostart(abi.FuncPCABIInternal(runtimer) + sys.PCQuantum) } raceacquirectx(ppcur.timerRaceCtx, unsafe.Pointer(t)) } diff --git a/src/runtime/type.go b/src/runtime/type.go index 335fc57f4b9..52e65a3bd23 100644 --- a/src/runtime/type.go +++ b/src/runtime/type.go @@ -6,7 +6,10 @@ package runtime -import "unsafe" +import ( + "internal/abi" + "unsafe" +) // tflag is documented in reflect/type.go. // @@ -262,7 +265,7 @@ func (t *_type) textOff(off textOff) unsafe.Pointer { if off == -1 { // -1 is the sentinel value for unreachable code. // See cmd/link/internal/ld/data.go:relocsym. - return unsafe.Pointer(funcPC(unreachableMethod)) + return unsafe.Pointer(abi.FuncPCABIInternal(unreachableMethod)) } base := uintptr(unsafe.Pointer(t)) var md *moduledata From 8d2b4cb6cc3100f337e08cc7342f42823fa1dc9a Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Mon, 10 May 2021 16:23:35 -0700 Subject: [PATCH 130/940] [dev.typeparams] cmd/compile: fixing import of comm clauses/closures in generic functions Improvements: - Fix export/import of the default case of a select statement (was not dealing with nil Comm case) - Set properly the name of closure functions in imported generic functions Added new test exporting/importing a reasonably large channel package, chansimp.go. Change-Id: If2ee12bd749e5df415f48ec4b629a2fa68a79dcb Reviewed-on: https://go-review.googlesource.com/c/go/+/321734 Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall Trust: Dan Scales --- src/cmd/compile/internal/typecheck/iexport.go | 7 +- src/cmd/compile/internal/typecheck/iimport.go | 14 +- test/typeparam/chansimp.dir/a.go | 232 ++++++++++++++++++ test/typeparam/chansimp.dir/main.go | 189 ++++++++++++++ test/typeparam/chansimp.go | 7 + 5 files changed, 447 insertions(+), 2 deletions(-) create mode 100644 test/typeparam/chansimp.dir/a.go create mode 100644 test/typeparam/chansimp.dir/main.go create mode 100644 test/typeparam/chansimp.go diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index 802a8c3839b..d956ada3c53 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -1523,7 +1523,12 @@ func (w *exportWriter) commList(cases []*ir.CommClause) { w.uint64(uint64(len(cases))) for _, cas := range cases { w.pos(cas.Pos()) - w.node(cas.Comm) + defaultCase := cas.Comm == nil + w.bool(defaultCase) + if !defaultCase { + // Only call w.node for non-default cause (cas.Comm is non-nil) + w.node(cas.Comm) + } w.stmtList(cas.Body) } } diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 39b5ab09da1..966e865630a 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -1121,7 +1121,13 @@ func (r *importReader) caseList(switchExpr ir.Node) []*ir.CaseClause { func (r *importReader) commList() []*ir.CommClause { cases := make([]*ir.CommClause, r.uint64()) for i := range cases { - cases[i] = ir.NewCommStmt(r.pos(), r.node(), r.stmtList()) + pos := r.pos() + defaultCase := r.bool() + var comm ir.Node + if !defaultCase { + comm = r.node() + } + cases[i] = ir.NewCommStmt(pos, comm, r.stmtList()) } return cases } @@ -1257,6 +1263,12 @@ func (r *importReader) node() ir.Node { if go117ExportTypes { clo.SetType(typ) } + if r.curfn.Type().HasTParam() { + // Generic functions aren't inlined, so give the closure a + // function name now, which is then available for use + // (after appending the type args) for each stenciling. + fn.Nname.SetSym(ClosureName(r.curfn)) + } return clo diff --git a/test/typeparam/chansimp.dir/a.go b/test/typeparam/chansimp.dir/a.go new file mode 100644 index 00000000000..a3f73b21996 --- /dev/null +++ b/test/typeparam/chansimp.dir/a.go @@ -0,0 +1,232 @@ +// Copyright 2021 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 a + +import ( + "context" + "runtime" +) + +// Equal reports whether two slices are equal: the same length and all +// elements equal. All floating point NaNs are considered equal. +func SliceEqual[Elem comparable](s1, s2 []Elem) bool { + if len(s1) != len(s2) { + return false + } + for i, v1 := range s1 { + v2 := s2[i] + if v1 != v2 { + isNaN := func(f Elem) bool { return f != f } + if !isNaN(v1) || !isNaN(v2) { + return false + } + } + } + return true +} + +// ReadAll reads from c until the channel is closed or the context is +// canceled, returning all the values read. +func ReadAll[Elem any](ctx context.Context, c <-chan Elem) []Elem { + var r []Elem + for { + select { + case <-ctx.Done(): + return r + case v, ok := <-c: + if !ok { + return r + } + r = append(r, v) + } + } +} + +// Merge merges two channels into a single channel. +// This will leave a goroutine running until either both channels are closed +// or the context is canceled, at which point the returned channel is closed. +func Merge[Elem any](ctx context.Context, c1, c2 <-chan Elem) <-chan Elem { + r := make(chan Elem) + go func(ctx context.Context, c1, c2 <-chan Elem, r chan<- Elem) { + defer close(r) + for c1 != nil || c2 != nil { + select { + case <-ctx.Done(): + return + case v1, ok := <-c1: + if ok { + r <- v1 + } else { + c1 = nil + } + case v2, ok := <-c2: + if ok { + r <- v2 + } else { + c2 = nil + } + } + } + }(ctx, c1, c2, r) + return r +} + +// Filter calls f on each value read from c. If f returns true the value +// is sent on the returned channel. This will leave a goroutine running +// until c is closed or the context is canceled, at which point the +// returned channel is closed. +func Filter[Elem any](ctx context.Context, c <-chan Elem, f func(Elem) bool) <-chan Elem { + r := make(chan Elem) + go func(ctx context.Context, c <-chan Elem, f func(Elem) bool, r chan<- Elem) { + defer close(r) + for { + select { + case <-ctx.Done(): + return + case v, ok := <-c: + if !ok { + return + } + if f(v) { + r <- v + } + } + } + }(ctx, c, f, r) + return r +} + +// Sink returns a channel that discards all values sent to it. +// This will leave a goroutine running until the context is canceled +// or the returned channel is closed. +func Sink[Elem any](ctx context.Context) chan<- Elem { + r := make(chan Elem) + go func(ctx context.Context, r <-chan Elem) { + for { + select { + case <-ctx.Done(): + return + case _, ok := <-r: + if !ok { + return + } + } + } + }(ctx, r) + return r +} + +// An Exclusive is a value that may only be used by a single goroutine +// at a time. This is implemented using channels rather than a mutex. +type Exclusive[Val any] struct { + c chan Val +} + +// MakeExclusive makes an initialized exclusive value. +func MakeExclusive[Val any](initial Val) *Exclusive[Val] { + r := &Exclusive[Val]{ + c: make(chan Val, 1), + } + r.c <- initial + return r +} + +// Acquire acquires the exclusive value for private use. +// It must be released using the Release method. +func (e *Exclusive[Val]) Acquire() Val { + return <-e.c +} + +// TryAcquire attempts to acquire the value. The ok result reports whether +// the value was acquired. If the value is acquired, it must be released +// using the Release method. +func (e *Exclusive[Val]) TryAcquire() (v Val, ok bool) { + select { + case r := <-e.c: + return r, true + default: + return v, false + } +} + +// Release updates and releases the value. +// This method panics if the value has not been acquired. +func (e *Exclusive[Val]) Release(v Val) { + select { + case e.c <- v: + default: + panic("Exclusive Release without Acquire") + } +} + +// Ranger returns a Sender and a Receiver. The Receiver provides a +// Next method to retrieve values. The Sender provides a Send method +// to send values and a Close method to stop sending values. The Next +// method indicates when the Sender has been closed, and the Send +// method indicates when the Receiver has been freed. +// +// This is a convenient way to exit a goroutine sending values when +// the receiver stops reading them. +func Ranger[Elem any]() (*Sender[Elem], *Receiver[Elem]) { + c := make(chan Elem) + d := make(chan struct{}) + s := &Sender[Elem]{ + values: c, + done: d, + } + r := &Receiver[Elem] { + values: c, + done: d, + } + runtime.SetFinalizer(r, (*Receiver[Elem]).finalize) + return s, r +} + +// A Sender is used to send values to a Receiver. +type Sender[Elem any] struct { + values chan<- Elem + done <-chan struct{} +} + +// Send sends a value to the receiver. It reports whether the value was sent. +// The value will not be sent if the context is closed or the receiver +// is freed. +func (s *Sender[Elem]) Send(ctx context.Context, v Elem) bool { + select { + case <-ctx.Done(): + return false + case s.values <- v: + return true + case <-s.done: + return false + } +} + +// Close tells the receiver that no more values will arrive. +// After Close is called, the Sender may no longer be used. +func (s *Sender[Elem]) Close() { + close(s.values) +} + +// A Receiver receives values from a Sender. +type Receiver[Elem any] struct { + values <-chan Elem + done chan<- struct{} +} + +// Next returns the next value from the channel. The bool result indicates +// whether the value is valid. +func (r *Receiver[Elem]) Next(ctx context.Context) (v Elem, ok bool) { + select { + case <-ctx.Done(): + case v, ok = <-r.values: + } + return v, ok +} + +// finalize is a finalizer for the receiver. +func (r *Receiver[Elem]) finalize() { + close(r.done) +} diff --git a/test/typeparam/chansimp.dir/main.go b/test/typeparam/chansimp.dir/main.go new file mode 100644 index 00000000000..ca271675982 --- /dev/null +++ b/test/typeparam/chansimp.dir/main.go @@ -0,0 +1,189 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "a" + "context" + "fmt" + "runtime" + "sort" + "sync" + "time" +) + +func TestReadAll() { + c := make(chan int) + go func() { + c <- 4 + c <- 2 + c <- 5 + close(c) + }() + got := a.ReadAll(context.Background(), c) + want := []int{4, 2, 5} + if !a.SliceEqual(got, want) { + panic(fmt.Sprintf("ReadAll returned %v, want %v", got, want)) + } +} + +func TestMerge() { + c1 := make(chan int) + c2 := make(chan int) + go func() { + c1 <- 1 + c1 <- 3 + c1 <- 5 + close(c1) + }() + go func() { + c2 <- 2 + c2 <- 4 + c2 <- 6 + close(c2) + }() + ctx := context.Background() + got := a.ReadAll(ctx, a.Merge(ctx, c1, c2)) + sort.Ints(got) + want := []int{1, 2, 3, 4, 5, 6} + if !a.SliceEqual(got, want) { + panic(fmt.Sprintf("Merge returned %v, want %v", got, want)) + } +} + +func TestFilter() { + c := make(chan int) + go func() { + c <- 1 + c <- 2 + c <- 3 + close(c) + }() + even := func(i int) bool { return i%2 == 0 } + ctx := context.Background() + got := a.ReadAll(ctx, a.Filter(ctx, c, even)) + want := []int{2} + if !a.SliceEqual(got, want) { + panic(fmt.Sprintf("Filter returned %v, want %v", got, want)) + } +} + +func TestSink() { + c := a.Sink[int](context.Background()) + after := time.NewTimer(time.Minute) + defer after.Stop() + send := func(v int) { + select { + case c <- v: + case <-after.C: + panic("timed out sending to Sink") + } + } + send(1) + send(2) + send(3) + close(c) +} + +func TestExclusive() { + val := 0 + ex := a.MakeExclusive(&val) + + var wg sync.WaitGroup + f := func() { + defer wg.Done() + for i := 0; i < 10; i++ { + p := ex.Acquire() + (*p)++ + ex.Release(p) + } + } + + wg.Add(2) + go f() + go f() + + wg.Wait() + if val != 20 { + panic(fmt.Sprintf("after Acquire/Release loop got %d, want 20", val)) + } +} + +func TestExclusiveTry() { + s := "" + ex := a.MakeExclusive(&s) + p, ok := ex.TryAcquire() + if !ok { + panic("TryAcquire failed") + } + *p = "a" + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + _, ok := ex.TryAcquire() + if ok { + panic(fmt.Sprintf("TryAcquire succeeded unexpectedly")) + } + }() + wg.Wait() + + ex.Release(p) + + p, ok = ex.TryAcquire() + if !ok { + panic(fmt.Sprintf("TryAcquire failed")) + } +} + +func TestRanger() { + s, r := a.Ranger[int]() + + ctx := context.Background() + go func() { + // Receive one value then exit. + v, ok := r.Next(ctx) + if !ok { + panic(fmt.Sprintf("did not receive any values")) + } else if v != 1 { + panic(fmt.Sprintf("received %d, want 1", v)) + } + }() + + c1 := make(chan bool) + c2 := make(chan bool) + go func() { + defer close(c2) + if !s.Send(ctx, 1) { + panic(fmt.Sprintf("Send failed unexpectedly")) + } + close(c1) + if s.Send(ctx, 2) { + panic(fmt.Sprintf("Send succeeded unexpectedly")) + } + }() + + <-c1 + + // Force a garbage collection to try to get the finalizers to run. + runtime.GC() + + select { + case <-c2: + case <-time.After(time.Minute): + panic("Ranger Send should have failed, but timed out") + } +} + +func main() { + TestReadAll() + TestMerge() + TestFilter() + TestSink() + TestExclusive() + TestExclusiveTry() + TestRanger() +} diff --git a/test/typeparam/chansimp.go b/test/typeparam/chansimp.go new file mode 100644 index 00000000000..76930e5e4f6 --- /dev/null +++ b/test/typeparam/chansimp.go @@ -0,0 +1,7 @@ +// rundir -G=3 + +// Copyright 2021 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 ignored From 5b1120fac7e234af44c09ec0db1982aa2c7b7357 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Tue, 11 May 2021 14:14:30 -0700 Subject: [PATCH 131/940] [dev.typeparams] cmd/compile: fix handling of Nname field in (*subster).tstruct. We want to keep the Nname references for external function references in tstruct (not remove them, as is currently happening). We only change the Nname reference (translate it) when it appears in subst.vars[]. New export/import test sliceimp.go which includes some of these external function references. Change-Id: Ie3d73bd989a16082f0cebfb566e0a7faeda55e60 Reviewed-on: https://go-review.googlesource.com/c/go/+/321735 Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall Trust: Dan Scales --- src/cmd/compile/internal/noder/stencil.go | 26 ++-- test/typeparam/sliceimp.dir/a.go | 141 +++++++++++++++++ test/typeparam/sliceimp.dir/main.go | 179 ++++++++++++++++++++++ test/typeparam/sliceimp.go | 7 + 4 files changed, 343 insertions(+), 10 deletions(-) create mode 100644 test/typeparam/sliceimp.dir/a.go create mode 100644 test/typeparam/sliceimp.dir/main.go create mode 100644 test/typeparam/sliceimp.go diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 7a7c05280d7..1626ab9dd31 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -565,10 +565,10 @@ func (subst *subster) list(l []ir.Node) []ir.Node { } // tstruct substitutes type params in types of the fields of a structure type. For -// each field, if Nname is set, tstruct also translates the Nname using -// subst.vars, if Nname is in subst.vars. To always force the creation of a new -// (top-level) struct, regardless of whether anything changed with the types or -// names of the struct's fields, set force to true. +// each field, tstruct copies the Nname, and translates it if Nname is in +// subst.vars. To always force the creation of a new (top-level) struct, +// regardless of whether anything changed with the types or names of the struct's +// fields, set force to true. func (subst *subster) tstruct(t *types.Type, force bool) *types.Type { if t.NumFields() == 0 { if t.HasTParam() { @@ -597,15 +597,21 @@ func (subst *subster) tstruct(t *types.Type, force bool) *types.Type { // the type param, not the instantiated type). newfields[i] = types.NewField(f.Pos, f.Sym, t2) if f.Nname != nil { - // f.Nname may not be in subst.vars[] if this is - // a function name or a function instantiation type - // that we are translating v := subst.vars[f.Nname.(*ir.Name)] - // Be careful not to put a nil var into Nname, - // since Nname is an interface, so it would be a - // non-nil interface. if v != nil { + // This is the case where we are + // translating the type of the function we + // are substituting, so its dcls are in + // the subst.vars table, and we want to + // change to reference the new dcl. newfields[i].Nname = v + } else { + // This is the case where we are + // translating the type of a function + // reference inside the function we are + // substituting, so we leave the Nname + // value as is. + newfields[i].Nname = f.Nname } } } diff --git a/test/typeparam/sliceimp.dir/a.go b/test/typeparam/sliceimp.dir/a.go new file mode 100644 index 00000000000..2b58d1c29e1 --- /dev/null +++ b/test/typeparam/sliceimp.dir/a.go @@ -0,0 +1,141 @@ +// Copyright 2021 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 a + +type Ordered interface { + type int, int8, int16, int32, int64, + uint, uint8, uint16, uint32, uint64, uintptr, + float32, float64, + string +} + +// Max returns the maximum of two values of some ordered type. +func Max[T Ordered](a, b T) T { + if a > b { + return a + } + return b +} + +// Min returns the minimum of two values of some ordered type. +func Min[T Ordered](a, b T) T { + if a < b { + return a + } + return b +} + +// Equal reports whether two slices are equal: the same length and all +// elements equal. All floating point NaNs are considered equal. +func Equal[Elem comparable](s1, s2 []Elem) bool { + if len(s1) != len(s2) { + return false + } + for i, v1 := range s1 { + v2 := s2[i] + if v1 != v2 { + isNaN := func(f Elem) bool { return f != f } + if !isNaN(v1) || !isNaN(v2) { + return false + } + } + } + return true +} + +// EqualFn reports whether two slices are equal using a comparision +// function on each element. +func EqualFn[Elem any](s1, s2 []Elem, eq func(Elem, Elem) bool) bool { + if len(s1) != len(s2) { + return false + } + for i, v1 := range s1 { + v2 := s2[i] + if !eq(v1, v2) { + return false + } + } + return true +} + +// Map turns a []Elem1 to a []Elem2 using a mapping function. +func Map[Elem1, Elem2 any](s []Elem1, f func(Elem1) Elem2) []Elem2 { + r := make([]Elem2, len(s)) + for i, v := range s { + r[i] = f(v) + } + return r +} + +// Reduce reduces a []Elem1 to a single value of type Elem2 using +// a reduction function. +func Reduce[Elem1, Elem2 any](s []Elem1, initializer Elem2, f func(Elem2, Elem1) Elem2) Elem2 { + r := initializer + for _, v := range s { + r = f(r, v) + } + return r +} + +// Filter filters values from a slice using a filter function. +func Filter[Elem any](s []Elem, f func(Elem) bool) []Elem { + var r []Elem + for _, v := range s { + if f(v) { + r = append(r, v) + } + } + return r +} + +// Max returns the maximum element in a slice of some ordered type. +// If the slice is empty it returns the zero value of the element type. +func SliceMax[Elem Ordered](s []Elem) Elem { + if len(s) == 0 { + var zero Elem + return zero + } + return Reduce(s[1:], s[0], Max[Elem]) +} + +// Min returns the minimum element in a slice of some ordered type. +// If the slice is empty it returns the zero value of the element type. +func SliceMin[Elem Ordered](s []Elem) Elem { + if len(s) == 0 { + var zero Elem + return zero + } + return Reduce(s[1:], s[0], Min[Elem]) +} + +// Append adds values to the end of a slice, returning a new slice. +// This is like the predeclared append function; it's an example +// of how to write it using generics. We used to write code like +// this before append was added to the language, but we had to write +// a separate copy for each type. +func Append[T any](s []T, t ...T) []T { + lens := len(s) + tot := lens + len(t) + if tot <= cap(s) { + s = s[:tot] + } else { + news := make([]T, tot, tot + tot/2) + Copy(news, s) + s = news + } + Copy(s[lens:tot], t) + return s +} + +// Copy copies values from t to s, stopping when either slice is full, +// returning the number of values copied. This is like the predeclared +// copy function; it's an example of how to write it using generics. +func Copy[T any](s, t []T) int { + i := 0 + for ; i < len(s) && i < len(t); i++ { + s[i] = t[i] + } + return i +} diff --git a/test/typeparam/sliceimp.dir/main.go b/test/typeparam/sliceimp.dir/main.go new file mode 100644 index 00000000000..0a8e756b26c --- /dev/null +++ b/test/typeparam/sliceimp.dir/main.go @@ -0,0 +1,179 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "a" + "fmt" + "math" + "strings" +) + +type Integer interface { + type int, int8, int16, int32, int64, + uint, uint8, uint16, uint32, uint64, uintptr +} + +func TestEqual() { + s1 := []int{1, 2, 3} + if !a.Equal(s1, s1) { + panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", s1, s1)) + } + s2 := []int{1, 2, 3} + if !a.Equal(s1, s2) { + panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", s1, s2)) + } + s2 = append(s2, 4) + if a.Equal(s1, s2) { + panic(fmt.Sprintf("a.Equal(%v, %v) = true, want false", s1, s2)) + } + + s3 := []float64{1, 2, math.NaN()} + if !a.Equal(s3, s3) { + panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", s3, s3)) + } + + if a.Equal(s1, nil) { + panic(fmt.Sprintf("a.Equal(%v, nil) = true, want false", s1)) + } + if a.Equal(nil, s1) { + panic(fmt.Sprintf("a.Equal(nil, %v) = true, want false", s1)) + } + if !a.Equal(s1[:0], nil) { + panic(fmt.Sprintf("a.Equal(%v, nil = false, want true", s1[:0])) + } +} + +func offByOne[Elem Integer](a, b Elem) bool { + return a == b + 1 || a == b - 1 +} + +func TestEqualFn() { + s1 := []int{1, 2, 3} + s2 := []int{2, 3, 4} + if a.EqualFn(s1, s1, offByOne[int]) { + panic(fmt.Sprintf("a.EqualFn(%v, %v, offByOne) = true, want false", s1, s1)) + } + if !a.EqualFn(s1, s2, offByOne[int]) { + panic(fmt.Sprintf("a.EqualFn(%v, %v, offByOne) = false, want true", s1, s2)) + } + + if !a.EqualFn(s1[:0], nil, offByOne[int]) { + panic(fmt.Sprintf("a.EqualFn(%v, nil, offByOne) = false, want true", s1[:0])) + } + + s3 := []string{"a", "b", "c"} + s4 := []string{"A", "B", "C"} + if !a.EqualFn(s3, s4, strings.EqualFold) { + panic(fmt.Sprintf("a.EqualFn(%v, %v, strings.EqualFold) = false, want true", s3, s4)) + } +} + +func TestMap() { + s1 := []int{1, 2, 3} + s2 := a.Map(s1, func(i int) float64 { return float64(i) * 2.5 }) + if want := []float64{2.5, 5, 7.5}; !a.Equal(s2, want) { + panic(fmt.Sprintf("a.Map(%v, ...) = %v, want %v", s1, s2, want)) + } + + s3 := []string{"Hello", "World"} + s4 := a.Map(s3, strings.ToLower) + if want := []string{"hello", "world"}; !a.Equal(s4, want) { + panic(fmt.Sprintf("a.Map(%v, strings.ToLower) = %v, want %v", s3, s4, want)) + } + + s5 := a.Map(nil, func(i int) int { return i }) + if len(s5) != 0 { + panic(fmt.Sprintf("a.Map(nil, identity) = %v, want empty slice", s5)) + } +} + +func TestReduce() { + s1 := []int{1, 2, 3} + r := a.Reduce(s1, 0, func(f float64, i int) float64 { return float64(i) * 2.5 + f }) + if want := 15.0; r != want { + panic(fmt.Sprintf("a.Reduce(%v, 0, ...) = %v, want %v", s1, r, want)) + } + + if got := a.Reduce(nil, 0, func(i, j int) int { return i + j}); got != 0 { + panic(fmt.Sprintf("a.Reduce(nil, 0, add) = %v, want 0", got)) + } +} + +func TestFilter() { + s1 := []int{1, 2, 3} + s2 := a.Filter(s1, func(i int) bool { return i%2 == 0 }) + if want := []int{2}; !a.Equal(s2, want) { + panic(fmt.Sprintf("a.Filter(%v, even) = %v, want %v", s1, s2, want)) + } + + if s3 := a.Filter(s1[:0], func(i int) bool { return true }); len(s3) > 0 { + panic(fmt.Sprintf("a.Filter(%v, identity) = %v, want empty slice", s1[:0], s3)) + } +} + +func TestMax() { + s1 := []int{1, 2, 3, -5} + if got, want := a.SliceMax(s1), 3; got != want { + panic(fmt.Sprintf("a.Max(%v) = %d, want %d", s1, got, want)) + } + + s2 := []string{"aaa", "a", "aa", "aaaa"} + if got, want := a.SliceMax(s2), "aaaa"; got != want { + panic(fmt.Sprintf("a.Max(%v) = %q, want %q", s2, got, want)) + } + + if got, want := a.SliceMax(s2[:0]), ""; got != want { + panic(fmt.Sprintf("a.Max(%v) = %q, want %q", s2[:0], got, want)) + } +} + +func TestMin() { + s1 := []int{1, 2, 3, -5} + if got, want := a.SliceMin(s1), -5; got != want { + panic(fmt.Sprintf("a.Min(%v) = %d, want %d", s1, got, want)) + } + + s2 := []string{"aaa", "a", "aa", "aaaa"} + if got, want := a.SliceMin(s2), "a"; got != want { + panic(fmt.Sprintf("a.Min(%v) = %q, want %q", s2, got, want)) + } + + if got, want := a.SliceMin(s2[:0]), ""; got != want { + panic(fmt.Sprintf("a.Min(%v) = %q, want %q", s2[:0], got, want)) + } +} + +func TestAppend() { + s := []int{1, 2, 3} + s = a.Append(s, 4, 5, 6) + want := []int{1, 2, 3, 4, 5, 6} + if !a.Equal(s, want) { + panic(fmt.Sprintf("after a.Append got %v, want %v", s, want)) + } +} + +func TestCopy() { + s1 := []int{1, 2, 3} + s2 := []int{4, 5} + if got := a.Copy(s1, s2); got != 2 { + panic(fmt.Sprintf("a.Copy returned %d, want 2", got)) + } + want := []int{4, 5, 3} + if !a.Equal(s1, want) { + panic(fmt.Sprintf("after a.Copy got %v, want %v", s1, want)) + } +} +func main() { + TestEqual() + TestEqualFn() + TestMap() + TestReduce() + TestFilter() + TestMax() + TestMin() + TestAppend() + TestCopy() +} diff --git a/test/typeparam/sliceimp.go b/test/typeparam/sliceimp.go new file mode 100644 index 00000000000..76930e5e4f6 --- /dev/null +++ b/test/typeparam/sliceimp.go @@ -0,0 +1,7 @@ +// rundir -G=3 + +// Copyright 2021 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 ignored From f87194cbd7e79eef07c897a6240fbf2dc115f9ff Mon Sep 17 00:00:00 2001 From: ian woolf Date: Fri, 7 May 2021 16:31:00 +0800 Subject: [PATCH 132/940] doc/go1.17: document changes to net/http package Changes include: * ReadRequest function now returns an error when a request has multiple Host headers. For #44513. Updates #46015. Change-Id: I48ea7c5cee3f1d1a247035fd37191362a53d1f04 Reviewed-on: https://go-review.googlesource.com/c/go/+/317914 Reviewed-by: Dmitri Shuralyov Trust: Heschi Kreinick --- doc/go1.17.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 5ab99c29edb..46ee1da6fa6 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -423,7 +423,8 @@ Do not send CLs removing the interior tags from such phrases.

- TODO: https://golang.org/cl/308952: make ReadRequest return an error when requests have multiple Host headers + The ReadRequest function + now returns an error when the request has multiple Host headers.

From cca23a73733ff166722c69359f0bb45e12ccaa2b Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Fri, 21 May 2021 10:53:10 -0400 Subject: [PATCH 133/940] cmd/compile: revert CL/316890 This is a revert of https://go-review.googlesource.com/c/go/+/316890, which has positive effects on debugging + DWARF variable locations for register parameters when the reg abi is in effect, but also turns out to interact badly with the register allocator. Fixes #46304. Change-Id: I624bd980493411a9cde45d44fcd3c46cad796909 Reviewed-on: https://go-review.googlesource.com/c/go/+/321830 Trust: Than McIntosh Run-TryBot: Than McIntosh Reviewed-by: Cherry Mui TryBot-Result: Go Bot --- src/cmd/compile/internal/ssa/expand_calls.go | 16 ----- test/fixedbugs/issue46304.go | 76 ++++++++++++++++++++ 2 files changed, 76 insertions(+), 16 deletions(-) create mode 100644 test/fixedbugs/issue46304.go diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index d37d06f8e71..7e973ab2059 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -1717,22 +1717,6 @@ func (x *expandState) newArgToMemOrRegs(baseArg, toReplace *Value, offset int64, } else { w = baseArg.Block.NewValue0IA(pos, op, t, auxInt, aux) } - // If we are creating an OpArgIntReg/OpArgFloatReg that - // corresponds to an in-param that fits entirely in a register, - // then enter it into the name/value table. The LocalSlot - // is somewhat fictitious, since there is no incoming live - // memory version of the parameter, but we need an entry in - // NamedValues in order for ssa debug tracking to include - // the value in the tracking analysis. - if len(pa.Registers) == 1 { - loc := LocalSlot{N: aux.Name, Type: t, Off: 0} - values, ok := x.f.NamedValues[loc] - if !ok { - ploc := x.f.localSlotAddr(loc) - x.f.Names = append(x.f.Names, ploc) - } - x.f.NamedValues[loc] = append(values, w) - } x.commonArgs[key] = w if toReplace != nil { toReplace.copyOf(w) diff --git a/test/fixedbugs/issue46304.go b/test/fixedbugs/issue46304.go new file mode 100644 index 00000000000..b8ecfc93a59 --- /dev/null +++ b/test/fixedbugs/issue46304.go @@ -0,0 +1,76 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This testcase caused a crash when the register ABI was in effect, +// on amd64 (problem with register allocation). + +package main + +type Op struct { + tag string + _x []string + _q [20]uint64 + plist []P +} + +type P struct { + tag string + _x [10]uint64 + b bool +} + +type M int + +//go:noinline +func (w *M) walkP(p *P) *P { + np := &P{} + *np = *p + np.tag += "new" + return np +} + +func (w *M) walkOp(op *Op) *Op { + if op == nil { + return nil + } + + orig := op + cloned := false + clone := func() { + if !cloned { + cloned = true + op = &Op{} + *op = *orig + } + } + + pCloned := false + for i := range op.plist { + if s := w.walkP(&op.plist[i]); s != &op.plist[i] { + if !pCloned { + pCloned = true + clone() + op.plist = make([]P, len(orig.plist)) + copy(op.plist, orig.plist) + } + op.plist[i] = *s + } + } + + return op +} + +func main() { + var ww M + w := &ww + p1 := P{tag: "a"} + p1._x[1] = 9 + o := Op{tag: "old", plist: []P{p1}} + no := w.walkOp(&o) + if no.plist[0].tag != "anew" { + panic("bad") + } +} From 05819bc104c3021d20ad21aa685fb6b4db35ceb0 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Fri, 14 May 2021 23:14:22 -0400 Subject: [PATCH 134/940] cmd/go/internal/modcmd: factor out a type for flags whose arguments are Go versions For #46141 Updates #45094 Change-Id: I6553600c69273762a81795ef021c66f4e0872b6b Reviewed-on: https://go-review.googlesource.com/c/go/+/321069 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Jay Conrod --- src/cmd/go/internal/modcmd/edit.go | 2 +- src/cmd/go/internal/modcmd/tidy.go | 42 ++++++++++++++----- src/cmd/go/internal/modload/init.go | 10 ++--- src/cmd/go/internal/modload/load.go | 4 +- src/cmd/go/internal/modload/modfile.go | 2 +- .../go/testdata/script/mod_tidy_version.txt | 12 +++++- 6 files changed, 52 insertions(+), 20 deletions(-) diff --git a/src/cmd/go/internal/modcmd/edit.go b/src/cmd/go/internal/modcmd/edit.go index 79a93ca44b9..e856e7c6304 100644 --- a/src/cmd/go/internal/modcmd/edit.go +++ b/src/cmd/go/internal/modcmd/edit.go @@ -196,7 +196,7 @@ func runEdit(ctx context.Context, cmd *base.Command, args []string) { if *editGo != "" { if !modfile.GoVersionRE.MatchString(*editGo) { - base.Fatalf(`go mod: invalid -go option; expecting something like "-go 1.12"`) + base.Fatalf(`go mod: invalid -go option; expecting something like "-go %s"`, modload.LatestGoVersion()) } } diff --git a/src/cmd/go/internal/modcmd/tidy.go b/src/cmd/go/internal/modcmd/tidy.go index c72ec30a572..9af624028a3 100644 --- a/src/cmd/go/internal/modcmd/tidy.go +++ b/src/cmd/go/internal/modcmd/tidy.go @@ -12,8 +12,10 @@ import ( "cmd/go/internal/imports" "cmd/go/internal/modload" "context" + "fmt" "golang.org/x/mod/modfile" + "golang.org/x/mod/semver" ) var cmdTidy = &base.Command{ @@ -44,28 +46,48 @@ See https://golang.org/ref/mod#go-mod-tidy for more about 'go mod tidy'. } var ( - tidyE bool // if true, report errors but proceed anyway. - tidyGo string // go version to write to the tidied go.mod file (toggles lazy loading) + tidyE bool // if true, report errors but proceed anyway. + tidyGo goVersionFlag // go version to write to the tidied go.mod file (toggles lazy loading) ) func init() { cmdTidy.Flag.BoolVar(&cfg.BuildV, "v", false, "") cmdTidy.Flag.BoolVar(&tidyE, "e", false, "") - cmdTidy.Flag.StringVar(&tidyGo, "go", "", "") + cmdTidy.Flag.Var(&tidyGo, "go", "") base.AddModCommonFlags(&cmdTidy.Flag) } +// A goVersionFlag is a flag.Value representing a supported Go version. +// +// (Note that the -go argument to 'go mod edit' is *not* a goVersionFlag. +// It intentionally allows newer-than-supported versions as arguments.) +type goVersionFlag struct { + v string +} + +func (f *goVersionFlag) String() string { return f.v } +func (f *goVersionFlag) Get() interface{} { return f.v } + +func (f *goVersionFlag) Set(s string) error { + if s != "" { + latest := modload.LatestGoVersion() + if !modfile.GoVersionRE.MatchString(s) { + return fmt.Errorf("expecting a Go version like %q", latest) + } + if semver.Compare("v"+s, "v"+latest) > 0 { + return fmt.Errorf("maximum supported Go version is %s", latest) + } + } + + f.v = s + return nil +} + func runTidy(ctx context.Context, cmd *base.Command, args []string) { if len(args) > 0 { base.Fatalf("go mod tidy: no arguments allowed") } - if tidyGo != "" { - if !modfile.GoVersionRE.MatchString(tidyGo) { - base.Fatalf(`go mod: invalid -go option %q; expecting something like "-go 1.17"`, tidyGo) - } - } - // Tidy aims to make 'go test' reproducible for any package in 'all', so we // need to include test dependencies. For modules that specify go 1.15 or // earlier this is a no-op (because 'all' saturates transitive test @@ -80,7 +102,7 @@ func runTidy(ctx context.Context, cmd *base.Command, args []string) { modload.RootMode = modload.NeedRoot modload.LoadPackages(ctx, modload.PackageOpts{ - GoVersion: tidyGo, + GoVersion: tidyGo.String(), Tags: imports.AnyTags(), Tidy: true, VendorModulesInGOROOTSrc: true, diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go index 5cdea12cd3e..e358230e748 100644 --- a/src/cmd/go/internal/modload/init.go +++ b/src/cmd/go/internal/modload/init.go @@ -405,7 +405,7 @@ func loadModFile(ctx context.Context) (rs *Requirements, needCommit bool) { if modRoot == "" { Target = module.Version{Path: "command-line-arguments"} targetPrefix = "command-line-arguments" - goVersion := latestGoVersion() + goVersion := LatestGoVersion() rawGoVersion.Store(Target, goVersion) requirements = newRequirements(modDepthFromGoVersion(goVersion), nil, nil) return requirements, false @@ -448,7 +448,7 @@ func loadModFile(ctx context.Context) (rs *Requirements, needCommit bool) { // TODO(#45551): Do something more principled instead of checking // cfg.CmdName directly here. if cfg.BuildMod == "mod" && cfg.CmdName != "mod graph" && cfg.CmdName != "mod why" { - addGoStmt(latestGoVersion()) + addGoStmt(LatestGoVersion()) if go117EnableLazyLoading { // We need to add a 'go' version to the go.mod file, but we must assume // that its existing contents match something between Go 1.11 and 1.16. @@ -500,7 +500,7 @@ func CreateModFile(ctx context.Context, modPath string) { modFile = new(modfile.File) modFile.AddModuleStmt(modPath) initTarget(modFile.Module.Mod) - addGoStmt(latestGoVersion()) // Add the go directive before converted module requirements. + addGoStmt(LatestGoVersion()) // Add the go directive before converted module requirements. convertedFrom, err := convertLegacyConfig(modPath) if convertedFrom != "" { @@ -793,9 +793,9 @@ func addGoStmt(v string) { rawGoVersion.Store(Target, v) } -// latestGoVersion returns the latest version of the Go language supported by +// LatestGoVersion returns the latest version of the Go language supported by // this toolchain, like "1.17". -func latestGoVersion() string { +func LatestGoVersion() string { tags := build.Default.ReleaseTags version := tags[len(tags)-1] if !strings.HasPrefix(version, "go") || !modfile.GoVersionRE.MatchString(version[2:]) { diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go index 83fc7c09c37..23ee3824f31 100644 --- a/src/cmd/go/internal/modload/load.go +++ b/src/cmd/go/internal/modload/load.go @@ -931,8 +931,8 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader { ld.allClosesOverTests = true } - if ld.Tidy && semver.Compare(goVersionV, "v"+latestGoVersion()) > 0 { - ld.errorf("go mod tidy: go.mod file indicates go %s, but maximum supported version is %s\n", params.GoVersion, latestGoVersion()) + if ld.Tidy && semver.Compare(goVersionV, "v"+LatestGoVersion()) > 0 { + ld.errorf("go mod tidy: go.mod file indicates go %s, but maximum supported version is %s\n", params.GoVersion, LatestGoVersion()) base.ExitIfErrors() } diff --git a/src/cmd/go/internal/modload/modfile.go b/src/cmd/go/internal/modload/modfile.go index bafff3e080e..a9c3a91d35d 100644 --- a/src/cmd/go/internal/modload/modfile.go +++ b/src/cmd/go/internal/modload/modfile.go @@ -55,7 +55,7 @@ var modFile *modfile.File // in modFile are intepreted, or the latest Go version if modFile is nil. func modFileGoVersion() string { if modFile == nil { - return latestGoVersion() + return LatestGoVersion() } if modFile.Go == nil || modFile.Go.Version == "" { // The main module necessarily has a go.mod file, and that file lacks a diff --git a/src/cmd/go/testdata/script/mod_tidy_version.txt b/src/cmd/go/testdata/script/mod_tidy_version.txt index 5441d9cc06f..eaa6ee7b0db 100644 --- a/src/cmd/go/testdata/script/mod_tidy_version.txt +++ b/src/cmd/go/testdata/script/mod_tidy_version.txt @@ -32,12 +32,22 @@ cp go.mod go.mod.orig + # An invalid argument should be rejected. ! go mod tidy -go=bananas -stderr '^go mod: invalid -go option "bananas"; expecting something like "-go 1.17"$' +stderr '^invalid value "bananas" for flag -go: expecting a Go version like "'$goversion'"$' cmp go.mod go.mod.orig +! go mod tidy -go=0.9 +stderr '^invalid value "0.9" for flag -go: expecting a Go version like "'$goversion'"$' + +! go mod tidy -go=2000.0 +stderr '^invalid value "2000.0" for flag -go: maximum supported Go version is '$goversion'$' + + +# Supported versions should change the go.mod file to be tidy according to the +# indicated version. go mod tidy -go=1.15 cmp go.mod go.mod.115 From 52d7033ff6d56094b7fa852bbdf51b4525bd6bb2 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Fri, 14 May 2021 16:51:57 -0400 Subject: [PATCH 135/940] cmd/go/internal/modload: set the default GoVersion in a single location For #46141 Updates #36460 Change-Id: Ie4c13c73a451650d1e8abb8e5cebfc30d0a71a70 Reviewed-on: https://go-review.googlesource.com/c/go/+/321070 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Jay Conrod --- src/cmd/go/internal/modload/load.go | 41 ++++++++++++----------------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go index 23ee3824f31..37b0032d43e 100644 --- a/src/cmd/go/internal/modload/load.go +++ b/src/cmd/go/internal/modload/load.go @@ -314,10 +314,6 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma initialRS, _ := loadModFile(ctx) // Ignore needCommit — we're going to commit at the end regardless. - if opts.GoVersion == "" { - opts.GoVersion = modFileGoVersion() - } - ld := loadFromRoots(ctx, loaderParams{ PackageOpts: opts, requirements: initialRS, @@ -380,7 +376,7 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma // Success! Update go.mod and go.sum (if needed) and return the results. loaded = ld - commitRequirements(ctx, opts.GoVersion, loaded.requirements) + commitRequirements(ctx, loaded.GoVersion, loaded.requirements) for _, pkg := range ld.pkgs { if !pkg.isTest() { @@ -605,10 +601,8 @@ func ImportFromFiles(ctx context.Context, gofiles []string) { base.Fatalf("go: %v", err) } - goVersion := modFileGoVersion() loaded = loadFromRoots(ctx, loaderParams{ PackageOpts: PackageOpts{ - GoVersion: goVersion, Tags: tags, ResolveMissingImports: true, SilencePackageErrors: true, @@ -620,7 +614,7 @@ func ImportFromFiles(ctx context.Context, gofiles []string) { return roots }, }) - commitRequirements(ctx, goVersion, loaded.requirements) + commitRequirements(ctx, loaded.GoVersion, loaded.requirements) } // DirImportPath returns the effective import path for dir, @@ -921,26 +915,25 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader { work: par.NewQueue(runtime.GOMAXPROCS(0)), } - if params.GoVersion != "" { - goVersionV := "v" + params.GoVersion - if semver.Compare(goVersionV, narrowAllVersionV) < 0 && !ld.UseVendorAll { - // The module's go version explicitly predates the change in "all" for lazy - // loading, so continue to use the older interpretation. - // (If params.GoVersion is empty, we are probably not in any module at all - // and should use the latest semantics.) - ld.allClosesOverTests = true - } + if ld.GoVersion == "" { + ld.GoVersion = modFileGoVersion() - if ld.Tidy && semver.Compare(goVersionV, "v"+LatestGoVersion()) > 0 { - ld.errorf("go mod tidy: go.mod file indicates go %s, but maximum supported version is %s\n", params.GoVersion, LatestGoVersion()) + if ld.Tidy && semver.Compare("v"+ld.GoVersion, "v"+LatestGoVersion()) > 0 { + ld.errorf("go mod tidy: go.mod file indicates go %s, but maximum supported version is %s\n", ld.GoVersion, LatestGoVersion()) base.ExitIfErrors() } + } - var err error - ld.requirements, err = convertDepth(ctx, ld.requirements, modDepthFromGoVersion(params.GoVersion)) - if err != nil { - ld.errorf("go: %v\n", err) - } + if semver.Compare("v"+ld.GoVersion, narrowAllVersionV) < 0 && !ld.UseVendorAll { + // The module's go version explicitly predates the change in "all" for lazy + // loading, so continue to use the older interpretation. + ld.allClosesOverTests = true + } + + var err error + ld.requirements, err = convertDepth(ctx, ld.requirements, modDepthFromGoVersion(ld.GoVersion)) + if err != nil { + ld.errorf("go: %v\n", err) } if ld.requirements.depth == eager { From b18b2d372e263dda8862c1eafef739403ba4521d Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Fri, 21 May 2021 20:09:55 -0700 Subject: [PATCH 136/940] [dev.typeparams] cmd/compile: fix case where we were copying a raw Node Replace the raw Node copy with the creation of a new node, and the copying of the needed flags and fields. Change-Id: I636bf228ba28c0d5dc25f8366d82379d86ecd731 Reviewed-on: https://go-review.googlesource.com/c/go/+/322189 Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky Trust: Dan Scales --- src/cmd/compile/internal/inline/inl.go | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go index a6829e9835f..bd453e40a5e 100644 --- a/src/cmd/compile/internal/inline/inl.go +++ b/src/cmd/compile/internal/inline/inl.go @@ -1153,17 +1153,21 @@ func (subst *inlsubst) fields(oldt *types.Type) []*types.Field { // clovar creates a new ONAME node for a local variable or param of a closure // inside a function being inlined. func (subst *inlsubst) clovar(n *ir.Name) *ir.Name { - // TODO(danscales): want to get rid of this shallow copy, with code like the - // following, but it is hard to copy all the necessary flags in a maintainable way. - // m := ir.NewNameAt(n.Pos(), n.Sym()) - // m.Class = n.Class - // m.SetType(n.Type()) - // m.SetTypecheck(1) - //if n.IsClosureVar() { - // m.SetIsClosureVar(true) - //} - m := &ir.Name{} - *m = *n + m := ir.NewNameAt(n.Pos(), n.Sym()) + m.Class = n.Class + m.SetType(n.Type()) + m.SetTypecheck(1) + if n.IsClosureVar() { + m.SetIsClosureVar(true) + } + if n.Addrtaken() { + m.SetAddrtaken(true) + } + if n.Used() { + m.SetUsed(true) + } + m.Defn = n.Defn + m.Curfn = subst.newclofn switch defn := n.Defn.(type) { From 4356e7e85fcd8f59de6bc1fd1db6e4f01a92f19e Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Fri, 21 May 2021 20:30:02 +0000 Subject: [PATCH 137/940] runtime: account for spill slots in Windows callback compilation The Go ABI, as it stands, requires spill space to be reserved for register arguments. syscall.NewCallback (because of compileCallback) does not actually reserve this space, leading to issues if the Go code it invokes actually makes use of it. Fixes #46301. Change-Id: Idbc3578accaaaa29e4ba32291ef08d464da0b7b0 Reviewed-on: https://go-review.googlesource.com/c/go/+/322029 Trust: Michael Knyszek Run-TryBot: Michael Knyszek TryBot-Result: Go Bot Reviewed-by: Egon Elbre Reviewed-by: Cherry Mui --- src/runtime/syscall_windows.go | 23 ++++++++++++++++++++--- src/runtime/syscall_windows_test.go | 15 +++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go index 6b9195bcd52..4763a440e7e 100644 --- a/src/runtime/syscall_windows.go +++ b/src/runtime/syscall_windows.go @@ -64,6 +64,7 @@ type abiDesc struct { srcStackSize uintptr // stdcall/fastcall stack space tracking dstStackSize uintptr // Go stack space used + dstSpill uintptr // Extra stack space for argument spill slots dstRegisters int // Go ABI int argument registers used // retOffset is the offset of the uintptr-sized result in the Go @@ -110,7 +111,14 @@ func (p *abiDesc) assignArg(t *_type) { // arguments. The same is true on arm. oldParts := p.parts - if !p.tryRegAssignArg(t, 0) { + if p.tryRegAssignArg(t, 0) { + // Account for spill space. + // + // TODO(mknyszek): Remove this when we no longer have + // caller reserved spill space. + p.dstSpill = alignUp(p.dstSpill, uintptr(t.align)) + p.dstSpill += t.size + } else { // Register assignment failed. // Undo the work and stack assign. p.parts = oldParts @@ -277,7 +285,11 @@ func compileCallback(fn eface, cdecl bool) (code uintptr) { abiMap.dstStackSize += sys.PtrSize } - if abiMap.dstStackSize > callbackMaxFrame { + // TODO(mknyszek): Remove dstSpill from this calculation when we no longer have + // caller reserved spill space. + frameSize := alignUp(abiMap.dstStackSize, sys.PtrSize) + frameSize += abiMap.dstSpill + if frameSize > callbackMaxFrame { panic("compileCallback: function argument frame too large") } @@ -356,9 +368,14 @@ func callbackWrap(a *callbackArgs) { } } + // TODO(mknyszek): Remove this when we no longer have + // caller reserved spill space. + frameSize := alignUp(c.abiMap.dstStackSize, sys.PtrSize) + frameSize += c.abiMap.dstSpill + // Even though this is copying back results, we can pass a nil // type because those results must not require write barriers. - reflectcall(nil, unsafe.Pointer(c.fn), noescape(goArgs), uint32(c.abiMap.dstStackSize), uint32(c.abiMap.retOffset), uint32(c.abiMap.dstStackSize), ®s) + reflectcall(nil, unsafe.Pointer(c.fn), noescape(goArgs), uint32(c.abiMap.dstStackSize), uint32(c.abiMap.retOffset), uint32(frameSize), ®s) // Extract the result. // diff --git a/src/runtime/syscall_windows_test.go b/src/runtime/syscall_windows_test.go index 5e9694d444c..e3f772ac4bb 100644 --- a/src/runtime/syscall_windows_test.go +++ b/src/runtime/syscall_windows_test.go @@ -389,6 +389,10 @@ var cbFuncs = []cbFunc{ {func(i1, i2, i3, i4, i5 uint8Pair) uintptr { return uintptr(i1.x + i1.y + i2.x + i2.y + i3.x + i3.y + i4.x + i4.y + i5.x + i5.y) }}, + {func(i1, i2, i3, i4, i5, i6, i7, i8, i9 uint32) uintptr { + runtime.GC() + return uintptr(i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9) + }}, } //go:registerparams @@ -461,6 +465,16 @@ func sum5andPair(i1, i2, i3, i4, i5 uint8Pair) uintptr { return uintptr(i1.x + i1.y + i2.x + i2.y + i3.x + i3.y + i4.x + i4.y + i5.x + i5.y) } +// This test forces a GC. The idea is to have enough arguments +// that insufficient spill slots allocated (according to the ABI) +// may cause compiler-generated spills to clobber the return PC. +// Then, the GC stack scanning will catch that. +//go:registerparams +func sum9andGC(i1, i2, i3, i4, i5, i6, i7, i8, i9 uint32) uintptr { + runtime.GC() + return uintptr(i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9) +} + // TODO(register args): Remove this once we switch to using the register // calling convention by default, since this is redundant with the existing // tests. @@ -479,6 +493,7 @@ var cbFuncsRegABI = []cbFunc{ {sum9int8}, {sum5mix}, {sum5andPair}, + {sum9andGC}, } func getCallbackTestFuncs() []cbFunc { From ae26b451136a20cb29ac171b1b0dee6ccd06e6eb Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 13 May 2021 12:40:21 -0400 Subject: [PATCH 138/940] [dev.typeparams] cmd/compile/abi-internal.md: specify ARM64 register-based ABI The ABI is similar to the AMD64 ABI, just uses different registers and stack layout. The stack layout is compatible with the current stack-based ABI0. To be implemented in Go 1.18. Change-Id: If9c5e664574947f959d3427e3bed769e05d2d673 Reviewed-on: https://go-review.googlesource.com/c/go/+/319829 Trust: Cherry Mui Reviewed-by: Than McIntosh --- src/cmd/compile/abi-internal.md | 122 ++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/src/cmd/compile/abi-internal.md b/src/cmd/compile/abi-internal.md index 1ae3c2538ff..7aed7efe979 100644 --- a/src/cmd/compile/abi-internal.md +++ b/src/cmd/compile/abi-internal.md @@ -505,6 +505,128 @@ control bits specified by the ELF AMD64 ABI. The x87 floating-point control word is not used by Go on amd64. +### arm64 architecture + +The arm64 architecture uses R0 – R15 for integer arguments and results. + +It uses F0 – F15 for floating-point arguments and results. + +*Rationale*: 16 integer registers and 16 floating-point registers are +more than enough for passing arguments and results for practically all +functions (see Appendix). While there are more registers available, +using more registers provides little benefit. Additionally, it will add +overhead on code paths where the number of arguments are not statically +known (e.g. reflect call), and will consume more stack space when there +is only limited stack space available to fit in the nosplit limit. + +Registers R16 and R17 are permanent scratch registers. They are also +used as scratch registers by the linker (Go linker and external +linker) in trampolines. + +Register R18 is reserved and never used. It is reserved for the OS +on some platforms (e.g. macOS). + +Registers R19 – R25 are permanent scratch registers. In addition, +R27 is a permanent scratch register used by the assembler when +expanding instructions. + +Floating-point registers F16 – F31 are also permanent scratch +registers. + +Special-purpose registers are as follows: + +| Register | Call meaning | Return meaning | Body meaning | +| --- | --- | --- | --- | +| RSP | Stack pointer | Same | Same | +| R30 | Link register | Same | Scratch (non-leaf functions) | +| R29 | Frame pointer | Same | Same | +| R28 | Current goroutine | Same | Same | +| R27 | Scratch | Scratch | Scratch | +| R26 | Closure context pointer | Scratch | Scratch | +| R18 | Reserved (not used) | Same | Same | +| ZR | Zero value | Same | Same | + +*Rationale*: These register meanings are compatible with Go’s +stack-based calling convention. + +*Rationale*: The link register, R30, holds the function return +address at the function entry. For functions that have frames +(including most non-leaf functions), R30 is saved to stack in the +function prologue and restored in the epilogue. Within the function +body, R30 can be used as a scratch register. + +*Implementation note*: Registers with fixed meaning at calls but not +in function bodies must be initialized by "injected" calls such as +signal-based panics. + +#### Stack layout + +The stack pointer, RSP, grows down and is always aligned to 16 bytes. + +*Rationale*: The arm64 architecture requires the stack pointer to be +16-byte aligned. + +A function's stack frame, after the frame is created, is laid out as +follows: + + +------------------------------+ + | ... locals ... | + | ... outgoing arguments ... | + | return PC | ← RSP points to + | frame pointer on entry | + +------------------------------+ ↓ lower addresses + +The "return PC" is loaded to the link register, R30, as part of the +arm64 `CALL` operation. + +On entry, a function subtracts from RSP to open its stack frame, and +saves the values of R30 and R29 at the bottom of the frame. +Specifically, R30 is saved at 0(RSP) and R29 is saved at -8(RSP), +after RSP is updated. + +A leaf function that does not require any stack space may omit the +saved R30 and R29. + +The Go ABI's use of R29 as a frame pointer register is compatible with +arm64 architecture requirement so that Go can inter-operate with platform +debuggers and profilers. + +This stack layout is used by both register-based (ABIInternal) and +stack-based (ABI0) calling conventions. + +#### Flags + +The arithmetic status flags (NZCV) are treated like scratch registers +and not preserved across calls. +All other bits in PSTATE are system flags and are not modified by Go. + +The floating-point status register (FPSR) is treated like scratch +registers and not preserved across calls. + +At calls, the floating-point control register (FPCR) bits are always +set as follows: + +| Flag | Bit | Value | Meaning | +| --- | --- | --- | --- | +| DN | 25 | 0 | Propagate NaN operands | +| FZ | 24 | 0 | Do not flush to zero | +| RC | 23/22 | 0 (RN) | Round to nearest, choose even if tied | +| IDE | 15 | 0 | Denormal operations trap disabled | +| IXE | 12 | 0 | Inexact trap disabled | +| UFE | 11 | 0 | Underflow trap disabled | +| OFE | 10 | 0 | Overflow trap disabled | +| DZE | 9 | 0 | Divide-by-zero trap disabled | +| IOE | 8 | 0 | Invalid operations trap disabled | +| NEP | 2 | 0 | Scalar operations do not affect higher elements in vector registers | +| AH | 1 | 0 | No alternate handling of de-normal inputs | +| FIZ | 0 | 0 | Do not zero de-normals | + +*Rationale*: Having a fixed FPCR control configuration allows Go +functions to use floating-point and vector (SIMD) operations without +modifying or saving the FPCR. +Functions are allowed to modify it between calls (as long as they +restore it), but as of this writing Go code never does. + ## Future directions ### Spill path improvements From a22e3172200d4bdd0afcbbe6564dbb67fea4b03a Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Sat, 22 May 2021 21:59:00 -0700 Subject: [PATCH 139/940] cmd/compile: always include underlying type for map types This is a different fix for #37716. Should help make the fix for #46283 easier, since we will no longer need to keep compiler-generated hash functions and the runtime hash function in sync. Change-Id: I84cb93144e425dcd03afc552b5fbd0f2d2cc6d39 Reviewed-on: https://go-review.googlesource.com/c/go/+/322150 Trust: Keith Randall Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- .../compile/internal/reflectdata/reflect.go | 9 +++ src/cmd/internal/objabi/reloctype.go | 3 + src/cmd/internal/objabi/reloctype_string.go | 71 ++++++++++--------- src/runtime/alg.go | 19 +---- src/runtime/export_test.go | 25 ------- src/runtime/hash_test.go | 49 ------------- 6 files changed, 49 insertions(+), 127 deletions(-) diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index 8c0e33f6df1..b3688fca673 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -1112,6 +1112,15 @@ func writeType(t *types.Type) *obj.LSym { } ot = objw.Uint32(lsym, ot, flags) ot = dextratype(lsym, ot, t, 0) + if u := t.Underlying(); u != t { + // If t is a named map type, also keep the underlying map + // type live in the binary. This is important to make sure that + // a named map and that same map cast to its underlying type via + // reflection, use the same hash function. See issue 37716. + r := obj.Addrel(lsym) + r.Sym = writeType(u) + r.Type = objabi.R_KEEP + } case types.TPTR: if t.Elem().Kind() == types.TANY { diff --git a/src/cmd/internal/objabi/reloctype.go b/src/cmd/internal/objabi/reloctype.go index ea55fa3b0ad..52827a6deee 100644 --- a/src/cmd/internal/objabi/reloctype.go +++ b/src/cmd/internal/objabi/reloctype.go @@ -101,6 +101,9 @@ const ( // *rtype, and may be set to zero by the linker if it determines the method // text is unreachable by the linked program. R_METHODOFF + // R_KEEP tells the linker to keep the referred-to symbol in the final binary + // if the symbol containing the R_KEEP relocation is in the final binary. + R_KEEP R_POWER_TOC R_GOTPCREL // R_JMPMIPS (only used on mips64) resolves to non-PC-relative target address diff --git a/src/cmd/internal/objabi/reloctype_string.go b/src/cmd/internal/objabi/reloctype_string.go index 8882d19f883..4638ef14d91 100644 --- a/src/cmd/internal/objabi/reloctype_string.go +++ b/src/cmd/internal/objabi/reloctype_string.go @@ -34,44 +34,45 @@ func _() { _ = x[R_USEIFACE-24] _ = x[R_USEIFACEMETHOD-25] _ = x[R_METHODOFF-26] - _ = x[R_POWER_TOC-27] - _ = x[R_GOTPCREL-28] - _ = x[R_JMPMIPS-29] - _ = x[R_DWARFSECREF-30] - _ = x[R_DWARFFILEREF-31] - _ = x[R_ARM64_TLS_LE-32] - _ = x[R_ARM64_TLS_IE-33] - _ = x[R_ARM64_GOTPCREL-34] - _ = x[R_ARM64_GOT-35] - _ = x[R_ARM64_PCREL-36] - _ = x[R_ARM64_LDST8-37] - _ = x[R_ARM64_LDST16-38] - _ = x[R_ARM64_LDST32-39] - _ = x[R_ARM64_LDST64-40] - _ = x[R_ARM64_LDST128-41] - _ = x[R_POWER_TLS_LE-42] - _ = x[R_POWER_TLS_IE-43] - _ = x[R_POWER_TLS-44] - _ = x[R_ADDRPOWER_DS-45] - _ = x[R_ADDRPOWER_GOT-46] - _ = x[R_ADDRPOWER_PCREL-47] - _ = x[R_ADDRPOWER_TOCREL-48] - _ = x[R_ADDRPOWER_TOCREL_DS-49] - _ = x[R_RISCV_PCREL_ITYPE-50] - _ = x[R_RISCV_PCREL_STYPE-51] - _ = x[R_RISCV_TLS_IE_ITYPE-52] - _ = x[R_RISCV_TLS_IE_STYPE-53] - _ = x[R_PCRELDBL-54] - _ = x[R_ADDRMIPSU-55] - _ = x[R_ADDRMIPSTLS-56] - _ = x[R_ADDRCUOFF-57] - _ = x[R_WASMIMPORT-58] - _ = x[R_XCOFFREF-59] + _ = x[R_KEEP-27] + _ = x[R_POWER_TOC-28] + _ = x[R_GOTPCREL-29] + _ = x[R_JMPMIPS-30] + _ = x[R_DWARFSECREF-31] + _ = x[R_DWARFFILEREF-32] + _ = x[R_ARM64_TLS_LE-33] + _ = x[R_ARM64_TLS_IE-34] + _ = x[R_ARM64_GOTPCREL-35] + _ = x[R_ARM64_GOT-36] + _ = x[R_ARM64_PCREL-37] + _ = x[R_ARM64_LDST8-38] + _ = x[R_ARM64_LDST16-39] + _ = x[R_ARM64_LDST32-40] + _ = x[R_ARM64_LDST64-41] + _ = x[R_ARM64_LDST128-42] + _ = x[R_POWER_TLS_LE-43] + _ = x[R_POWER_TLS_IE-44] + _ = x[R_POWER_TLS-45] + _ = x[R_ADDRPOWER_DS-46] + _ = x[R_ADDRPOWER_GOT-47] + _ = x[R_ADDRPOWER_PCREL-48] + _ = x[R_ADDRPOWER_TOCREL-49] + _ = x[R_ADDRPOWER_TOCREL_DS-50] + _ = x[R_RISCV_PCREL_ITYPE-51] + _ = x[R_RISCV_PCREL_STYPE-52] + _ = x[R_RISCV_TLS_IE_ITYPE-53] + _ = x[R_RISCV_TLS_IE_STYPE-54] + _ = x[R_PCRELDBL-55] + _ = x[R_ADDRMIPSU-56] + _ = x[R_ADDRMIPSTLS-57] + _ = x[R_ADDRCUOFF-58] + _ = x[R_WASMIMPORT-59] + _ = x[R_XCOFFREF-60] } -const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CALLRISCVR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_USEIFACEMETHODR_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_LDST8R_ARM64_LDST16R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_RISCV_TLS_IE_ITYPER_RISCV_TLS_IE_STYPER_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF" +const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CALLRISCVR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_USEIFACEMETHODR_METHODOFFR_KEEPR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_LDST8R_ARM64_LDST16R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_RISCV_TLS_IE_ITYPER_RISCV_TLS_IE_STYPER_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF" -var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 53, 59, 68, 79, 88, 99, 109, 120, 127, 134, 142, 150, 158, 164, 170, 176, 186, 195, 205, 221, 232, 243, 253, 262, 275, 289, 303, 317, 333, 344, 357, 370, 384, 398, 412, 427, 441, 455, 466, 480, 495, 512, 530, 551, 570, 589, 609, 629, 639, 650, 663, 674, 686, 696} +var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 53, 59, 68, 79, 88, 99, 109, 120, 127, 134, 142, 150, 158, 164, 170, 176, 186, 195, 205, 221, 232, 238, 249, 259, 268, 281, 295, 309, 323, 339, 350, 363, 376, 390, 404, 418, 433, 447, 461, 472, 486, 501, 518, 536, 557, 576, 595, 615, 635, 645, 656, 669, 680, 692, 702} func (i RelocType) String() string { i -= 1 diff --git a/src/runtime/alg.go b/src/runtime/alg.go index 1b3bf1180d9..39c74268421 100644 --- a/src/runtime/alg.go +++ b/src/runtime/alg.go @@ -178,28 +178,11 @@ func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr { return h case kindStruct: s := (*structtype)(unsafe.Pointer(t)) - memStart := uintptr(0) - memEnd := uintptr(0) for _, f := range s.fields { - if memEnd > memStart && (f.name.isBlank() || f.offset() != memEnd || f.typ.tflag&tflagRegularMemory == 0) { - // flush any pending regular memory hashing - h = memhash(add(p, memStart), h, memEnd-memStart) - memStart = memEnd - } if f.name.isBlank() { continue } - if f.typ.tflag&tflagRegularMemory == 0 { - h = typehash(f.typ, add(p, f.offset()), h) - continue - } - if memStart == memEnd { - memStart = f.offset() - } - memEnd = f.offset() + f.typ.size - } - if memEnd > memStart { - h = memhash(add(p, memStart), h, memEnd-memStart) + h = typehash(f.typ, add(p, f.offset()), h) } return h default: diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index a6fc1e4785f..c8d01fbb157 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -1148,31 +1148,6 @@ func SemNwait(addr *uint32) uint32 { return atomic.Load(&root.nwait) } -// MapHashCheck computes the hash of the key k for the map m, twice. -// Method 1 uses the built-in hasher for the map. -// Method 2 uses the typehash function (the one used by reflect). -// Returns the two hash values, which should always be equal. -func MapHashCheck(m interface{}, k interface{}) (uintptr, uintptr) { - // Unpack m. - mt := (*maptype)(unsafe.Pointer(efaceOf(&m)._type)) - mh := (*hmap)(efaceOf(&m).data) - - // Unpack k. - kt := efaceOf(&k)._type - var p unsafe.Pointer - if isDirectIface(kt) { - q := efaceOf(&k).data - p = unsafe.Pointer(&q) - } else { - p = efaceOf(&k).data - } - - // Compute the hash functions. - x := mt.hasher(noescape(p), uintptr(mh.hash0)) - y := typehash(kt, noescape(p), uintptr(mh.hash0)) - return x, y -} - // mspan wrapper for testing. //go:notinheap type MSpan mspan diff --git a/src/runtime/hash_test.go b/src/runtime/hash_test.go index 502383557b8..7048874a71f 100644 --- a/src/runtime/hash_test.go +++ b/src/runtime/hash_test.go @@ -8,7 +8,6 @@ import ( "fmt" "math" "math/rand" - "reflect" . "runtime" "strings" "testing" @@ -49,54 +48,6 @@ func TestMemHash64Equality(t *testing.T) { } } -func TestCompilerVsRuntimeHash(t *testing.T) { - // Test to make sure the compiler's hash function and the runtime's hash function agree. - // See issue 37716. - for _, m := range []interface{}{ - map[bool]int{}, - map[int8]int{}, - map[uint8]int{}, - map[int16]int{}, - map[uint16]int{}, - map[int32]int{}, - map[uint32]int{}, - map[int64]int{}, - map[uint64]int{}, - map[int]int{}, - map[uint]int{}, - map[uintptr]int{}, - map[*byte]int{}, - map[chan int]int{}, - map[unsafe.Pointer]int{}, - map[float32]int{}, - map[float64]int{}, - map[complex64]int{}, - map[complex128]int{}, - map[string]int{}, - //map[interface{}]int{}, - //map[interface{F()}]int{}, - map[[8]uint64]int{}, - map[[8]string]int{}, - map[struct{ a, b, c, d int32 }]int{}, // Note: tests AMEM128 - map[struct{ a, b, _, d int32 }]int{}, - map[struct { - a, b int32 - c float32 - d, e [8]byte - }]int{}, - map[struct { - a int16 - b int64 - }]int{}, - } { - k := reflect.New(reflect.TypeOf(m).Key()).Elem().Interface() // the zero key - x, y := MapHashCheck(m, k) - if x != y { - t.Errorf("hashes did not match (%x vs %x) for map %T", x, y, m) - } - } -} - // Smhasher is a torture test for hash functions. // https://code.google.com/p/smhasher/ // This code is a port of some of the Smhasher tests to Go. From b83610699a4ea7da22a146c0eefe0ae4d5ac4610 Mon Sep 17 00:00:00 2001 From: Alessandro Arzilli Date: Sun, 9 May 2021 09:05:45 +0200 Subject: [PATCH 140/940] cmd/compile: record regabi status in DW_AT_producer Records if regabi was enabled during compilation in the DW_AT_producer attribute of each compile unit. This is useful to debuggers that support the debugCall protocol. Change-Id: I5ad2c48ebf126aeb8bfb459b53a1a5304550036a Reviewed-on: https://go-review.googlesource.com/c/go/+/318050 Trust: Dmitri Shuralyov Reviewed-by: Than McIntosh Reviewed-by: Cherry Mui Run-TryBot: Than McIntosh TryBot-Result: Go Bot --- src/cmd/compile/internal/dwarfgen/dwarf.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/cmd/compile/internal/dwarfgen/dwarf.go b/src/cmd/compile/internal/dwarfgen/dwarf.go index 5d7dc320aa8..0e22b61bc3f 100644 --- a/src/cmd/compile/internal/dwarfgen/dwarf.go +++ b/src/cmd/compile/internal/dwarfgen/dwarf.go @@ -531,6 +531,14 @@ func RecordFlags(flags ...string) { fmt.Fprintf(&cmd, " -%s=%v", f.Name, getter.Get()) } + // Adds flag to producer string singalling whether regabi is turned on or + // off. + // Once regabi is turned on across the board and the relative GOEXPERIMENT + // knobs no longer exist this code should be removed. + if buildcfg.Experiment.RegabiArgs { + cmd.Write([]byte(" regabi")) + } + if cmd.Len() == 0 { return } From 873401df5b202a751523b8cbd92bf3a8aaf989c8 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Sun, 23 May 2021 12:38:59 -0700 Subject: [PATCH 141/940] cmd/compile: ensure equal functions don't do unaligned loads On architectures which don't support unaligned loads, make sure we don't generate code that requires them. Generated hash functions also matter in this respect, but they all look ok. Update #37716 Fixes #46283 Change-Id: I6197fdfe04da4428092c99bd871d93738789e16b Reviewed-on: https://go-review.googlesource.com/c/go/+/322151 Trust: Keith Randall Trust: Josh Bleecher Snyder Run-TryBot: Keith Randall Reviewed-by: Cherry Mui Reviewed-by: Josh Bleecher Snyder Reviewed-by: eric fang TryBot-Result: Go Bot --- src/cmd/compile/internal/reflectdata/alg.go | 20 +++++ src/cmd/compile/internal/test/align_test.go | 96 +++++++++++++++++++++ src/cmd/internal/sys/arch.go | 19 ++++ 3 files changed, 135 insertions(+) create mode 100644 src/cmd/compile/internal/test/align_test.go diff --git a/src/cmd/compile/internal/reflectdata/alg.go b/src/cmd/compile/internal/reflectdata/alg.go index d12d9ca0a7d..0707e0b61ca 100644 --- a/src/cmd/compile/internal/reflectdata/alg.go +++ b/src/cmd/compile/internal/reflectdata/alg.go @@ -6,6 +6,7 @@ package reflectdata import ( "fmt" + "math/bits" "sort" "cmd/compile/internal/base" @@ -47,6 +48,11 @@ func eqCanPanic(t *types.Type) bool { func AlgType(t *types.Type) types.AlgKind { a, _ := types.AlgType(t) if a == types.AMEM { + if t.Alignment() < int64(base.Ctxt.Arch.Alignment) && t.Alignment() < t.Width { + // For example, we can't treat [2]int16 as an int32 if int32s require + // 4-byte alignment. See issue 46283. + return a + } switch t.Width { case 0: return types.AMEM0 @@ -769,6 +775,20 @@ func memrun(t *types.Type, start int) (size int64, next int) { if f := t.Field(next); f.Sym.IsBlank() || !isRegularMemory(f.Type) { break } + // For issue 46283, don't combine fields if the resulting load would + // require a larger alignment than the component fields. + if base.Ctxt.Arch.Alignment > 1 { + align := t.Alignment() + if off := t.Field(start).Offset; off&(align-1) != 0 { + // Offset is less aligned than the containing type. + // Use offset to determine alignment. + align = 1 << uint(bits.TrailingZeros64(uint64(off))) + } + size := t.Field(next).End() - t.Field(start).Offset + if size > align { + break + } + } } return t.Field(next-1).End() - t.Field(start).Offset, next } diff --git a/src/cmd/compile/internal/test/align_test.go b/src/cmd/compile/internal/test/align_test.go new file mode 100644 index 00000000000..32afc929736 --- /dev/null +++ b/src/cmd/compile/internal/test/align_test.go @@ -0,0 +1,96 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test to make sure that equality functions (and hash +// functions) don't do unaligned reads on architectures +// that can't do unaligned reads. See issue 46283. + +package test + +import "testing" + +type T1 struct { + x float32 + a, b, c, d int16 // memequal64 +} +type T2 struct { + x float32 + a, b, c, d int32 // memequal128 +} + +type A2 [2]byte // eq uses a 2-byte load +type A4 [4]byte // eq uses a 4-byte load +type A8 [8]byte // eq uses an 8-byte load + +//go:noinline +func cmpT1(p, q *T1) { + if *p != *q { + panic("comparison test wrong") + } +} + +//go:noinline +func cmpT2(p, q *T2) { + if *p != *q { + panic("comparison test wrong") + } +} + +//go:noinline +func cmpA2(p, q *A2) { + if *p != *q { + panic("comparison test wrong") + } +} + +//go:noinline +func cmpA4(p, q *A4) { + if *p != *q { + panic("comparison test wrong") + } +} + +//go:noinline +func cmpA8(p, q *A8) { + if *p != *q { + panic("comparison test wrong") + } +} + +func TestAlignEqual(t *testing.T) { + cmpT1(&T1{}, &T1{}) + cmpT2(&T2{}, &T2{}) + + m1 := map[T1]bool{} + m1[T1{}] = true + m1[T1{}] = false + if len(m1) != 1 { + t.Fatalf("len(m1)=%d, want 1", len(m1)) + } + m2 := map[T2]bool{} + m2[T2{}] = true + m2[T2{}] = false + if len(m2) != 1 { + t.Fatalf("len(m2)=%d, want 1", len(m2)) + } + + type X2 struct { + y byte + z A2 + } + var x2 X2 + cmpA2(&x2.z, &A2{}) + type X4 struct { + y byte + z A4 + } + var x4 X4 + cmpA4(&x4.z, &A4{}) + type X8 struct { + y byte + z A8 + } + var x8 X8 + cmpA8(&x8.z, &A8{}) +} diff --git a/src/cmd/internal/sys/arch.go b/src/cmd/internal/sys/arch.go index e8687363def..a3e39768b6f 100644 --- a/src/cmd/internal/sys/arch.go +++ b/src/cmd/internal/sys/arch.go @@ -40,6 +40,12 @@ type Arch struct { // MinLC is the minimum length of an instruction code. MinLC int + + // Alignment is maximum alignment required by the architecture + // for any (compiler-generated) load or store instruction. + // Loads or stores smaller than Alignment must be naturally aligned. + // Loads or stores larger than Alignment need only be Alignment-aligned. + Alignment int8 } // InFamily reports whether a is a member of any of the specified @@ -60,6 +66,7 @@ var Arch386 = &Arch{ PtrSize: 4, RegSize: 4, MinLC: 1, + Alignment: 1, } var ArchAMD64 = &Arch{ @@ -69,6 +76,7 @@ var ArchAMD64 = &Arch{ PtrSize: 8, RegSize: 8, MinLC: 1, + Alignment: 1, } var ArchARM = &Arch{ @@ -78,6 +86,7 @@ var ArchARM = &Arch{ PtrSize: 4, RegSize: 4, MinLC: 4, + Alignment: 4, // TODO: just for arm5? } var ArchARM64 = &Arch{ @@ -87,6 +96,7 @@ var ArchARM64 = &Arch{ PtrSize: 8, RegSize: 8, MinLC: 4, + Alignment: 1, } var ArchMIPS = &Arch{ @@ -96,6 +106,7 @@ var ArchMIPS = &Arch{ PtrSize: 4, RegSize: 4, MinLC: 4, + Alignment: 4, } var ArchMIPSLE = &Arch{ @@ -105,6 +116,7 @@ var ArchMIPSLE = &Arch{ PtrSize: 4, RegSize: 4, MinLC: 4, + Alignment: 4, } var ArchMIPS64 = &Arch{ @@ -114,6 +126,7 @@ var ArchMIPS64 = &Arch{ PtrSize: 8, RegSize: 8, MinLC: 4, + Alignment: 8, } var ArchMIPS64LE = &Arch{ @@ -123,6 +136,7 @@ var ArchMIPS64LE = &Arch{ PtrSize: 8, RegSize: 8, MinLC: 4, + Alignment: 8, } var ArchPPC64 = &Arch{ @@ -132,6 +146,7 @@ var ArchPPC64 = &Arch{ PtrSize: 8, RegSize: 8, MinLC: 4, + Alignment: 1, } var ArchPPC64LE = &Arch{ @@ -141,6 +156,7 @@ var ArchPPC64LE = &Arch{ PtrSize: 8, RegSize: 8, MinLC: 4, + Alignment: 1, } var ArchRISCV64 = &Arch{ @@ -150,6 +166,7 @@ var ArchRISCV64 = &Arch{ PtrSize: 8, RegSize: 8, MinLC: 4, + Alignment: 8, // riscv unaligned loads work, but are really slow (trap + simulated by OS) } var ArchS390X = &Arch{ @@ -159,6 +176,7 @@ var ArchS390X = &Arch{ PtrSize: 8, RegSize: 8, MinLC: 2, + Alignment: 1, } var ArchWasm = &Arch{ @@ -168,6 +186,7 @@ var ArchWasm = &Arch{ PtrSize: 8, RegSize: 8, MinLC: 1, + Alignment: 1, } var Archs = [...]*Arch{ From 15d9d4a009e3d2c9f1ad501143ed97a8b2c6f2c4 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Fri, 14 May 2021 16:01:17 -0400 Subject: [PATCH 142/940] cmd/go: add tests illustrating what happens when Go 1.16 is used in a Go 1.17 main module For #46141 Updates #46160 Change-Id: Ib22435b8051aaf3fa74d43d3b7f2d091e67f05e2 Reviewed-on: https://go-review.googlesource.com/c/go/+/320172 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Jay Conrod --- .../go/testdata/script/mod_tidy_compat.txt | 100 +++++++++++++++ .../script/mod_tidy_compat_implicit.txt | 120 ++++++++++++++++++ .../script/mod_tidy_compat_incompatible.txt | 116 +++++++++++++++++ .../script/mod_tidy_compat_irrelevant.txt | 105 +++++++++++++++ 4 files changed, 441 insertions(+) create mode 100644 src/cmd/go/testdata/script/mod_tidy_compat.txt create mode 100644 src/cmd/go/testdata/script/mod_tidy_compat_implicit.txt create mode 100644 src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt create mode 100644 src/cmd/go/testdata/script/mod_tidy_compat_irrelevant.txt diff --git a/src/cmd/go/testdata/script/mod_tidy_compat.txt b/src/cmd/go/testdata/script/mod_tidy_compat.txt new file mode 100644 index 00000000000..e6f88dc7798 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_compat.txt @@ -0,0 +1,100 @@ +# https://golang.org/issue/46141: 'go mod tidy' for a Go 1.17 module should by +# default preserve enough checksums for the module to be used by Go 1.16. +# +# We don't have a copy of Go 1.16 handy, but we can simulate it by editing the +# 'go' version in the go.mod file to 1.16, without actually updating the +# requirements to match. + +[short] skip + +env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}' + + +# This module has the same module dependency graph in Go 1.16 as in Go 1.17, +# but in 1.16 requires (checksums for) additional (irrelevant) go.mod files. +# +# The module graph under both versions looks like: +# +# m ---- example.com/version v1.1.0 +# | +# + ---- example.net/lazy v0.1.0 ---- example.com/version v1.0.1 +# +# Go 1.17 avoids loading the go.mod file for example.com/version v1.0.1 +# (because it is lower than the verison explicitly required by m, +# and the module that requires it — m — specifies 'go 1.17'). +# +# That go.mod file happens not to affect the final 1.16 module graph anyway, +# so the pruned graph is equivalent to the unpruned one. + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod go.mod.orig + +go list -m all +cmp stdout m_all.txt + +go mod edit -go=1.16 +! go list -m all +stderr '^go list -m: example.net/lazy@v0.1.0 requires\n\texample.com/version@v1.0.1: missing go.sum entry; to add it:\n\tgo mod download example.com/version$' + + +# If we combine a Go 1.16 go.sum file... +go mod tidy -go=1.16 + +# ...with a Go 1.17 go.mod file... +cp go.mod.orig go.mod + +# ...then Go 1.17 continues to work... +go list -m all +cmp stdout m_all.txt + +# ...and now 1.16 can load the same build list! +go mod edit -go=1.16 +go list -m all +cmp stdout m_all.txt + + +# TODO(#46141): Add a cleaner way to tidy a Go 1.17 module while preserving +# the checksums needed to work within it with Go 1.16. + + +-- go.mod -- +// Module m happens to have the exact same build list as what would be +// selected under Go 1.16, but computes that build list without looking at +// as many go.mod files. +module example.com/m + +go 1.17 + +replace example.net/lazy v0.1.0 => ./lazy + +require ( + example.com/version v1.1.0 + example.net/lazy v0.1.0 +) +-- m_all.txt -- +example.com/m +example.com/version v1.1.0 +example.net/lazy v0.1.0 => ./lazy +-- compatible.go -- +package compatible + +import ( + _ "example.com/version" + _ "example.net/lazy" +) +-- lazy/go.mod -- +// Module lazy requires example.com/version v1.0.1. +// +// However, since this module is lazy, its dependents +// should not need checksums for that version of the module +// unless they actually import packages from it. +module example.net/lazy + +go 1.17 + +require example.com/version v1.0.1 +-- lazy/lazy.go -- +package lazy + +import _ "example.com/version" diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_implicit.txt b/src/cmd/go/testdata/script/mod_tidy_compat_implicit.txt new file mode 100644 index 00000000000..baaa5d63e31 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_compat_implicit.txt @@ -0,0 +1,120 @@ +# https://golang.org/issue/46141: 'go mod tidy' for a Go 1.17 module should by +# default preserve enough checksums for the module to be used by Go 1.16. +# +# We don't have a copy of Go 1.16 handy, but we can simulate it by editing the +# 'go' version in the go.mod file to 1.16, without actually updating the +# requirements to match. + +[short] skip + +env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}' + + +# For this module, Go 1.16 selects the same versions of all explicit dependencies +# as Go 1.17 does. However, Go 1.16 selects a higher version of an *implicit* +# dependency, imported by a test of one of the (external) imported packages. +# As a result, Go 1.16 also needs checksums for the module sources for that higher +# version. +# +# The Go 1.16 module graph looks like: +# +# m ---- lazy v0.1.0 ---- incompatible v1.0.0 +# | +# + ------------- requireincompatible v0.1.0 ---- incompatible v2.0.0+incompatible +# +# The Go 1.17 module graph is the same except that the dependencies of +# requireincompatible are pruned out (because the module that requires +# it — lazy v0.1.0 — specifies 'go 1.17', and it is not otherwise relevant to +# the main module). + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod go.mod.orig + +go list -deps -test -f $MODFMT all +stdout '^example\.com/retract/incompatible v1\.0\.0$' + +go mod edit -go=1.16 +! go list -deps -test -f $MODFMT all + + # TODO(#46160): -count=1 instead of -count=2. +stderr -count=2 '^go: example\.net/lazy@v0\.1\.0 requires\n\texample\.com/retract/incompatible@v1\.0\.0: missing go\.sum entry; to add it:\n\tgo mod download example\.com/retract/incompatible$' + + +# If we combine a Go 1.16 go.sum file... +go mod tidy -go=1.16 + +# ...with a Go 1.17 go.mod file... +cp go.mod.orig go.mod + +# ...then Go 1.17 no longer works. 😞 +! go list -deps -test -f $MODFMT all +stderr -count=1 '^can''t load test package: lazy/lazy_test.go:3:8: missing go\.sum entry for module providing package example\.com/retract/incompatible \(imported by example\.net/lazy\); to add:\n\tgo get -t example.net/lazy@v0\.1\.0$' + + +# However, if we take the union of the go.sum files... +go list -mod=mod -deps -test all +cmp go.mod go.mod.orig + +# ...then Go 1.17 continues to work... +go list -deps -test -f $MODFMT all +stdout '^example\.com/retract/incompatible v1\.0\.0$' + +# ...and 1.16 also works(‽), but selects a different version for the +# external-test dependency. +go mod edit -go=1.16 +go list -deps -test -f $MODFMT all +stdout '^example\.com/retract/incompatible v2\.0\.0\+incompatible$' + + +# TODO(#46100): In compatibility mode, should we reject the above difference as +# incompatible, or save checksums for both possible versions of the test +# dependency? + + +-- go.mod -- +// Module m imports packages from the same versions under Go 1.17 +// as under Go 1.16, but under 1.16 its (implicit) external test dependencies +// are higher. +module example.com/m + +go 1.17 + +replace ( + example.net/lazy v0.1.0 => ./lazy + example.net/requireincompatible v0.1.0 => ./requireincompatible +) + +require example.net/lazy v0.1.0 +-- implicit.go -- +package implicit + +import _ "example.net/lazy" +-- lazy/go.mod -- +// Module lazy requires example.com/retract/incompatible v1.0.0. +// +// When viewed from the outside it also has a transitive dependency +// on v2.0.0+incompatible, but in lazy mode that transitive dependency +// is pruned out. +module example.net/lazy + +go 1.17 + +exclude example.com/retract/incompatible v2.0.0+incompatible + +require ( + example.com/retract/incompatible v1.0.0 + example.net/requireincompatible v0.1.0 +) +-- lazy/lazy.go -- +package lazy +-- lazy/lazy_test.go -- +package lazy_test + +import _ "example.com/retract/incompatible" +-- requireincompatible/go.mod -- +module example.net/requireincompatible + +go 1.15 + +require example.com/retract/incompatible v2.0.0+incompatible diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt b/src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt new file mode 100644 index 00000000000..08613524082 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt @@ -0,0 +1,116 @@ +# https://golang.org/issue/46141: 'go mod tidy' for a Go 1.17 module should by +# default preserve enough checksums for the module to be used by Go 1.16. +# +# We don't have a copy of Go 1.16 handy, but we can simulate it by editing the +# 'go' version in the go.mod file to 1.16, without actually updating the +# requirements to match. + +[short] skip + +env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}' + + +# For this module, Go 1.17 prunes out a (transitive and otherwise-irrelevant) +# requirement on a retracted higher version of a dependency. +# However, when Go 1.16 reads the same requirements from the go.mod file, +# it does not prune out that requirement, and selects the retracted version. +# +# The Go 1.16 module graph looks like: +# +# m ---- lazy v0.1.0 ---- requireincompatible v0.1.0 ---- incompatible v2.0.0+incompatible +# | | +# + -------+------------- incompatible v1.0.0 +# +# The Go 1.17 module graph is the same except that the dependencies of +# requireincompatible are pruned out (because the module that requires +# it — lazy v0.1.0 — specifies 'go 1.17', and it is not otherwise relevant to +# the main module). + + +# TODO(#46141): 'go mod tidy' should by default diagnose the difference in +# dependencies as an error, but it should still be possible to simply drop +# compatibility with Go 1.16 by passing an appropriate '-compat' flag. + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod go.mod.orig + +go mod edit -go=1.16 +! go list -f $MODFMT -deps ./... + # TODO(#46160): -count=1 instead of -count=2. +stderr -count=2 '^go: example\.net/lazy@v0\.1\.0 requires\n\texample\.net/requireincompatible@v0\.1\.0 requires\n\texample\.com/retract/incompatible@v2\.0\.0\+incompatible: missing go.sum entry; to add it:\n\tgo mod download example.com/retract/incompatible$' + + +# There are two ways for the module author to bring the two into alignment. +# One is to *explicitly* 'exclude' the version that is already *implicitly* +# pruned out under 1.17. +go mod edit -exclude=example.com/retract/incompatible@v2.0.0+incompatible +go list -f $MODFMT -deps ./... +stdout '^example.com/retract/incompatible v1\.0\.0$' +! stdout 'v2\.0\.0' + + +# The other is to explicitly upgrade the version required under Go 1.17 +# to match the version selected by Go 1.16. +cp go.mod.orig go.mod + +go get -d example.com/retract/incompatible@v2.0.0+incompatible + # Note that we are not running 'go mod tidy' here: we need to preserve + # the checksum for v1.0.0 because it is also still in the module graph + # as seen by Go 1.16. + +go mod edit -go=1.16 +go list -f $MODFMT -deps ./... +stdout '^example.com/retract/incompatible v2\.0\.0\+incompatible$' +! stdout 'v1\.0\.0' + + +-- go.mod -- +// Module m indirectly imports a package from +// example.com/retract/incompatible. Its selected version of +// that module is lower under Go 1.17 semantics than under Go 1.16. +module example.com/m + +go 1.17 + +replace ( + example.net/lazy v0.1.0 => ./lazy + example.net/requireincompatible v0.1.0 => ./requireincompatible +) + +require ( + example.com/retract/incompatible v1.0.0 // indirect + example.net/lazy v0.1.0 +) +-- incompatible.go -- +package incompatible + +import _ "example.net/lazy" + +-- lazy/go.mod -- +// Module lazy requires example.com/retract/incompatible v1.0.0. +// +// When viewed from the outside it also has a transitive dependency +// on v2.0.0+incompatible, but in lazy mode that transitive dependency +// is pruned out. +module example.net/lazy + +go 1.17 + +exclude example.com/retract/incompatible v2.0.0+incompatible + +require ( + example.com/retract/incompatible v1.0.0 + example.net/requireincompatible v0.1.0 +) +-- lazy/lazy.go -- +package lazy + +import _ "example.com/retract/incompatible" + +-- requireincompatible/go.mod -- +module example.net/requireincompatible + +go 1.15 + +require example.com/retract/incompatible v2.0.0+incompatible diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_irrelevant.txt b/src/cmd/go/testdata/script/mod_tidy_compat_irrelevant.txt new file mode 100644 index 00000000000..d4371e0f7d4 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_compat_irrelevant.txt @@ -0,0 +1,105 @@ +# https://golang.org/issue/46141: 'go mod tidy' for a Go 1.17 module should by +# default preserve enough checksums for the module to be used by Go 1.16. +# +# We don't have a copy of Go 1.16 handy, but we can simulate it by editing the +# 'go' version in the go.mod file to 1.16, without actually updating the +# requirements to match. + +[short] skip + +env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}' + + +# This module selects the same versions in Go 1.16 and 1.17 for all modules +# that provide packages (or test dependencies of packages) imported by the +# main module. However, in Go 1.16 it selects a higher version of a +# transitive module dependency that is not otherwise relevant to the main module. +# As a result, Go 1.16 needs an additional checksum for the go.mod file of +# that irrelevant dependency. +# +# The Go 1.16 module graph looks like: +# +# m ---- lazy v0.1.0 ---- incompatible v1.0.0 +# | +# + ------------- requireincompatible v0.1.0 ---- incompatible v2.0.0+incompatible + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod go.mod.orig + +go list -m all +stdout '^example\.com/retract/incompatible v1\.0\.0$' + +go mod edit -go=1.16 +! go list -deps -test -f $MODFMT all + # TODO(#46160): -count=1 instead of -count=2. +stderr -count=2 '^go: example.net/lazy@v0.1.0 requires\n\texample.com/retract/incompatible@v1.0.0: missing go.sum entry; to add it:\n\tgo mod download example.com/retract/incompatible$' + + +# If we combine a Go 1.16 go.sum file... +go mod tidy -go=1.16 + +# ...with a Go 1.17 go.mod file... +cp go.mod.orig go.mod + +# ...then Go 1.17 continues to work... +go list -deps -test -f $MODFMT all +cp stdout out-117.txt + +# ...and 1.16 also works, and selects the same versions for all packages +# even remotely relevant to the main module. +go mod edit -go=1.16 +go list -deps -test -f $MODFMT all +cmp stdout out-117.txt + + +# TODO(#46160): Add a cleaner way to tidy a Go 1.17 module while preserving +# the checksums needed to work within it with Go 1.16. + + +-- go.mod -- +// Module m imports packages from the same versions under Go 1.17 +// as under Go 1.16, but under 1.16 its (implicit) external test dependencies +// are higher. +module example.com/m + +go 1.17 + +replace ( + example.net/lazy v0.1.0 => ./lazy + example.net/requireincompatible v0.1.0 => ./requireincompatible +) + +require example.net/lazy v0.1.0 +-- m.go -- +package m + +import _ "example.net/lazy" +-- lazy/go.mod -- +// Module lazy requires example.com/retract/incompatible v1.0.0. +// +// When viewed from the outside it also has a transitive dependency +// on v2.0.0+incompatible, but in lazy mode that transitive dependency +// is pruned out. +module example.net/lazy + +go 1.17 + +exclude example.com/retract/incompatible v2.0.0+incompatible + +require ( + example.com/retract/incompatible v1.0.0 + example.net/requireincompatible v0.1.0 +) +-- lazy/lazy.go -- +package lazy +-- lazy/unimported/unimported.go -- +package unimported + +import _ "example.com/retract/incompatible" +-- requireincompatible/go.mod -- +module example.net/requireincompatible + +go 1.15 + +require example.com/retract/incompatible v2.0.0+incompatible From 32b73ae18026e8a9dc4c5aa49999b1ea445bc68c Mon Sep 17 00:00:00 2001 From: Constantin Konstantinidis Date: Sun, 16 May 2021 11:03:34 +0200 Subject: [PATCH 143/940] cmd/go: align checks of module path during initialization. Fixes #45025. Change-Id: I70c2b745f764484e4b3a2824adc470f168fb2c50 Reviewed-on: https://go-review.googlesource.com/c/go/+/320310 Trust: Jay Conrod Trust: Bryan C. Mills Run-TryBot: Jay Conrod Reviewed-by: Bryan C. Mills Reviewed-by: Jay Conrod TryBot-Result: Go Bot --- src/cmd/go/internal/modload/init.go | 68 ++++--------------- src/cmd/go/testdata/script/mod_init_path.txt | 2 +- .../go/testdata/script/mod_invalid_path.txt | 9 +-- 3 files changed, 19 insertions(+), 60 deletions(-) diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go index e358230e748..df9f48e8ea0 100644 --- a/src/cmd/go/internal/modload/init.go +++ b/src/cmd/go/internal/modload/init.go @@ -432,7 +432,10 @@ func loadModFile(ctx context.Context) (rs *Requirements, needCommit bool) { initTarget(f.Module.Mod) index = indexModFile(data, f, fixed) - if err := checkModulePathLax(f.Module.Mod.Path); err != nil { + if err := module.CheckImportPath(f.Module.Mod.Path); err != nil { + if pathErr, ok := err.(*module.InvalidPathError); ok { + pathErr.Kind = "module" + } base.Fatalf("go: %v", err) } @@ -492,7 +495,15 @@ func CreateModFile(ctx context.Context, modPath string) { if err != nil { base.Fatalf("go: %v", err) } - } else if err := checkModulePathLax(modPath); err != nil { + } else if err := module.CheckImportPath(modPath); err != nil { + if pathErr, ok := err.(*module.InvalidPathError); ok { + pathErr.Kind = "module" + // Same as build.IsLocalPath() + if pathErr.Path == "." || pathErr.Path == ".." || + strings.HasPrefix(pathErr.Path, "./") || strings.HasPrefix(pathErr.Path, "../") { + pathErr.Err = errors.New("is a local import path") + } + } base.Fatalf("go: %v", err) } @@ -536,49 +547,6 @@ func CreateModFile(ctx context.Context, modPath string) { } } -// checkModulePathLax checks that the path meets some minimum requirements -// to avoid confusing users or the module cache. The requirements are weaker -// than those of module.CheckPath to allow room for weakening module path -// requirements in the future, but strong enough to help users avoid significant -// problems. -func checkModulePathLax(p string) error { - // TODO(matloob): Replace calls of this function in this CL with calls - // to module.CheckImportPath once it's been laxened, if it becomes laxened. - // See golang.org/issue/29101 for a discussion about whether to make CheckImportPath - // more lax or more strict. - - errorf := func(format string, args ...interface{}) error { - return fmt.Errorf("invalid module path %q: %s", p, fmt.Sprintf(format, args...)) - } - - // Disallow shell characters " ' * < > ? ` | to avoid triggering bugs - // with file systems and subcommands. Disallow file path separators : and \ - // because path separators other than / will confuse the module cache. - // See fileNameOK in golang.org/x/mod/module/module.go. - shellChars := "`" + `"'*<>?|` - fsChars := `\:` - if i := strings.IndexAny(p, shellChars); i >= 0 { - return errorf("contains disallowed shell character %q", p[i]) - } - if i := strings.IndexAny(p, fsChars); i >= 0 { - return errorf("contains disallowed path separator character %q", p[i]) - } - - // Ensure path.IsAbs and build.IsLocalImport are false, and that the path is - // invariant under path.Clean, also to avoid confusing the module cache. - if path.IsAbs(p) { - return errorf("is an absolute path") - } - if build.IsLocalImport(p) { - return errorf("is a local import path") - } - if path.Clean(p) != p { - return errorf("is not clean") - } - - return nil -} - // fixVersion returns a modfile.VersionFixer implemented using the Query function. // // It resolves commit hashes and branch names to versions, @@ -918,14 +886,8 @@ func findModulePath(dir string) (string, error) { } if rel := search.InDir(dir, filepath.Join(gpdir, "src")); rel != "" && rel != "." { path := filepath.ToSlash(rel) - // TODO(matloob): replace this with module.CheckImportPath - // once it's been laxened. - // Only checkModulePathLax here. There are some unpublishable - // module names that are compatible with checkModulePathLax - // but they already work in GOPATH so don't break users - // trying to do a build with modules. gorelease will alert users - // publishing their modules to fix their paths. - if err := checkModulePathLax(path); err != nil { + // gorelease will alert users publishing their modules to fix their paths. + if err := module.CheckImportPath(path); err != nil { badPathErr = err break } diff --git a/src/cmd/go/testdata/script/mod_init_path.txt b/src/cmd/go/testdata/script/mod_init_path.txt index ccdfc923175..e5fd4ddbcb9 100644 --- a/src/cmd/go/testdata/script/mod_init_path.txt +++ b/src/cmd/go/testdata/script/mod_init_path.txt @@ -1,7 +1,7 @@ env GO111MODULE=on ! go mod init . -stderr '^go: invalid module path "\.": is a local import path$' +stderr '^go: malformed module path ".": is a local import path$' cd x go mod init example.com/x diff --git a/src/cmd/go/testdata/script/mod_invalid_path.txt b/src/cmd/go/testdata/script/mod_invalid_path.txt index c8c075daaef..333a3ffa35c 100644 --- a/src/cmd/go/testdata/script/mod_invalid_path.txt +++ b/src/cmd/go/testdata/script/mod_invalid_path.txt @@ -8,11 +8,8 @@ stderr '^go: no module declaration in go.mod. To specify the module path:\n\tgo # Test that go mod init in GOPATH doesn't add a module declaration # with a path that can't possibly be a module path, because # it isn't even a valid import path. -# The single quote and backtick are the only characters we don't allow -# in checkModulePathLax, but is allowed in a Windows file name. -# TODO(matloob): choose a different character once -# module.CheckImportPath is laxened and replaces -# checkModulePathLax. +# The single quote and backtick are the only characters which are not allowed +# but are a valid Windows file name. cd $WORK/'gopath/src/m''d' ! go mod init stderr 'cannot determine module path' @@ -21,7 +18,7 @@ stderr 'cannot determine module path' # possibly be a module path, because it isn't even a valid import path cd $WORK/gopath/src/badname ! go list . -stderr 'invalid module path' +stderr 'malformed module path' # Test that an import path containing an element with a leading dot is valid, # but such a module path is not. From e0844acfc8baa57541a8efef723937c2733e0c99 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Fri, 21 May 2021 18:13:04 -0400 Subject: [PATCH 144/940] [dev.typeparams] runtime/pprof: replace funcPC with internal/abi.FuncPCABIInternal All funcPC references are ABIInternal functions. Replace with the intrinsics. Change-Id: I2266bb6d2b713eb63b6a09846e9f9c423cab6e9b Reviewed-on: https://go-review.googlesource.com/c/go/+/322349 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/runtime/pprof/pprof.go | 3 ++- src/runtime/pprof/pprof_test.go | 3 ++- src/runtime/pprof/proto.go | 8 ++------ src/runtime/pprof/proto_test.go | 9 +++++---- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/runtime/pprof/pprof.go b/src/runtime/pprof/pprof.go index 99eda10f1c1..000abf935c2 100644 --- a/src/runtime/pprof/pprof.go +++ b/src/runtime/pprof/pprof.go @@ -76,6 +76,7 @@ import ( "bufio" "bytes" "fmt" + "internal/abi" "io" "runtime" "sort" @@ -289,7 +290,7 @@ func (p *Profile) Add(value interface{}, skip int) { stk = stk[:n] if len(stk) == 0 { // The value for skip is too large, and there's no stack trace to record. - stk = []uintptr{funcPC(lostProfileEvent)} + stk = []uintptr{abi.FuncPCABIInternal(lostProfileEvent)} } p.mu.Lock() diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go index 7cbb4fc7ae4..cfcf379d1f4 100644 --- a/src/runtime/pprof/pprof_test.go +++ b/src/runtime/pprof/pprof_test.go @@ -11,6 +11,7 @@ import ( "bytes" "context" "fmt" + "internal/abi" "internal/profile" "internal/testenv" "io" @@ -116,7 +117,7 @@ func containsInlinedCall(f interface{}, maxBytes int) bool { // findInlinedCall returns the PC of an inlined function call within // the function body for the function f if any. func findInlinedCall(f interface{}, maxBytes int) (pc uint64, found bool) { - fFunc := runtime.FuncForPC(uintptr(funcPC(f))) + fFunc := runtime.FuncForPC(uintptr(abi.FuncPCABIInternal(f))) if fFunc == nil || fFunc.Entry() == 0 { panic("failed to locate function entry") } diff --git a/src/runtime/pprof/proto.go b/src/runtime/pprof/proto.go index bdb4454b6e1..68625139566 100644 --- a/src/runtime/pprof/proto.go +++ b/src/runtime/pprof/proto.go @@ -8,6 +8,7 @@ import ( "bytes" "compress/gzip" "fmt" + "internal/abi" "io" "os" "runtime" @@ -21,11 +22,6 @@ import ( // (The name shows up in the pprof graphs.) func lostProfileEvent() { lostProfileEvent() } -// funcPC returns the PC for the func value f. -func funcPC(f interface{}) uintptr { - return *(*[2]*uintptr)(unsafe.Pointer(&f))[1] -} - // A profileBuilder writes a profile incrementally from a // stream of profile samples delivered by the runtime. type profileBuilder struct { @@ -325,7 +321,7 @@ func (b *profileBuilder) addCPUData(data []uint64, tags []unsafe.Pointer) error // gentraceback guarantees that PCs in the // stack can be unconditionally decremented and // still be valid, so we must do the same. - uint64(funcPC(lostProfileEvent) + 1), + uint64(abi.FuncPCABIInternal(lostProfileEvent) + 1), } } b.m.lookup(stk, tag).count += int64(count) diff --git a/src/runtime/pprof/proto_test.go b/src/runtime/pprof/proto_test.go index 5eb1aab1401..d052b9fa421 100644 --- a/src/runtime/pprof/proto_test.go +++ b/src/runtime/pprof/proto_test.go @@ -8,6 +8,7 @@ import ( "bytes" "encoding/json" "fmt" + "internal/abi" "internal/profile" "internal/testenv" "os" @@ -97,11 +98,11 @@ func testPCs(t *testing.T) (addr1, addr2 uint64, map1, map2 *profile.Mapping) { map2 = mprof.Mapping[1] map2.BuildID, _ = elfBuildID(map2.File) case "js": - addr1 = uint64(funcPC(f1)) - addr2 = uint64(funcPC(f2)) + addr1 = uint64(abi.FuncPCABIInternal(f1)) + addr2 = uint64(abi.FuncPCABIInternal(f2)) default: - addr1 = uint64(funcPC(f1)) - addr2 = uint64(funcPC(f2)) + addr1 = uint64(abi.FuncPCABIInternal(f1)) + addr2 = uint64(abi.FuncPCABIInternal(f2)) // Fake mapping - HasFunctions will be true because two PCs from Go // will be fully symbolized. fake := &profile.Mapping{ID: 1, HasFunctions: true} From f6427426787b292ec28cfd826615e3ae9a66b54a Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Fri, 21 May 2021 18:28:25 -0400 Subject: [PATCH 145/940] [dev.typeparams] reflect: use internal/abi.FuncPCABI0 to take address of assembly functions makeFuncStub and methodValueCall on AMD64 are marked as ABIInternal, so Go code can get their (unwrapped) addresses (using open-coded funcPC). Ues internal/abi.FuncPCABI0 instead, and un-mark the functions. Change-Id: Id28b6101ec7e55bc5a357d4236482cec70cd7e5d Reviewed-on: https://go-review.googlesource.com/c/go/+/322350 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/reflect/asm_amd64.s | 8 ++------ src/reflect/makefunc.go | 12 ++---------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/src/reflect/asm_amd64.s b/src/reflect/asm_amd64.s index 86d3f4e4bf7..7491c772acd 100644 --- a/src/reflect/asm_amd64.s +++ b/src/reflect/asm_amd64.s @@ -24,10 +24,8 @@ // See the comment on the declaration of makeFuncStub in makefunc.go // for more details. // No arg size here; runtime pulls arg map out of the func value. -// makeFuncStub must be ABIInternal because it is placed directly -// in function values. // This frame contains two locals. See the comment above LOCAL_RETVALID. -TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$312 +TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$312 NO_LOCAL_POINTERS // NO_LOCAL_POINTERS is a lie. The stack map for the two locals in this // frame is specially handled in the runtime. See the comment above LOCAL_RETVALID. @@ -55,10 +53,8 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$312 // See the comment on the declaration of methodValueCall in makefunc.go // for more details. // No arg size here; runtime pulls arg map out of the func value. -// methodValueCall must be ABIInternal because it is placed directly -// in function values. // This frame contains two locals. See the comment above LOCAL_RETVALID. -TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$312 +TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$312 NO_LOCAL_POINTERS // NO_LOCAL_POINTERS is a lie. The stack map for the two locals in this // frame is specially handled in the runtime. See the comment above LOCAL_RETVALID. diff --git a/src/reflect/makefunc.go b/src/reflect/makefunc.go index d53e68a3594..588be8bcc15 100644 --- a/src/reflect/makefunc.go +++ b/src/reflect/makefunc.go @@ -52,11 +52,7 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value { t := typ.common() ftyp := (*funcType)(unsafe.Pointer(t)) - // Indirect Go func value (dummy) to obtain - // actual code address. (A Go func value is a pointer - // to a C function pointer. https://golang.org/s/go11func.) - dummy := makeFuncStub - code := **(**uintptr)(unsafe.Pointer(&dummy)) + code := abi.FuncPCABI0(makeFuncStub) // makeFuncImpl contains a stack map for use by the runtime _, _, abi := funcLayout(ftyp, nil) @@ -111,11 +107,7 @@ func makeMethodValue(op string, v Value) Value { // v.Type returns the actual type of the method value. ftyp := (*funcType)(unsafe.Pointer(v.Type().(*rtype))) - // Indirect Go func value (dummy) to obtain - // actual code address. (A Go func value is a pointer - // to a C function pointer. https://golang.org/s/go11func.) - dummy := methodValueCall - code := **(**uintptr)(unsafe.Pointer(&dummy)) + code := abi.FuncPCABI0(methodValueCall) // methodValue contains a stack map for use by the runtime _, _, abi := funcLayout(ftyp, nil) From dcaf785add683fdda9bd0e53395c17c55779a8ac Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 20 May 2021 18:03:49 -0400 Subject: [PATCH 146/940] [dev.typeparams] internal/buildcfg: enable defer/go wrapping everywhere For register ABI, we wrap deferred/go'd function with arguments or results in an argumentless closure, so the runtime can call the function without knowing how to marshal the arguments, or reserving frame for arguments and results. The wrapping mechanism works everywhere, regardless of whether the register ABI is used. And wrapping will simplify the compiler and runtime's implementation for defer and go calls. For example, the compiler will not need to marshal arguments for defer/go calls, the opendefer metadata will not need to contain argument information, and _defer record will be fixed-sized. Enable wrapping everywhere. Change-Id: I2032ba87249ceb686310dc640fb00696669ae912 Reviewed-on: https://go-review.googlesource.com/c/go/+/321958 Trust: Cherry Mui Run-TryBot: Cherry Mui Reviewed-by: Michael Knyszek TryBot-Result: Go Bot --- src/internal/buildcfg/exp.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/internal/buildcfg/exp.go b/src/internal/buildcfg/exp.go index 417d87cf4af..11cd05f2ed0 100644 --- a/src/internal/buildcfg/exp.go +++ b/src/internal/buildcfg/exp.go @@ -29,7 +29,7 @@ var experimentBaseline = goexperiment.Flags{ RegabiWrappers: regabiSupported, RegabiG: regabiSupported, RegabiReflect: regabiSupported, - RegabiDefer: regabiSupported, + RegabiDefer: true, RegabiArgs: regabiSupported, } @@ -103,7 +103,6 @@ func parseExperiments() goexperiment.Flags { flags.RegabiWrappers = false flags.RegabiG = false flags.RegabiReflect = false - flags.RegabiDefer = false flags.RegabiArgs = false } // Check regabi dependencies. From 08a8fa9c471603c7ec44895392c6bfa31a8ddcb6 Mon Sep 17 00:00:00 2001 From: Richard Musiol Date: Sun, 23 May 2021 23:06:43 +0200 Subject: [PATCH 147/940] misc/wasm: ensure correct stack pointer in catch clauses The stack pointer may have changed after a call from JavaScript into Go code because of stack growth. The normal case already updated the sp variable accordingly, but the catch case did not yet. Fixes #45433 Change-Id: I3e0a33381929626f6b21902948935eb5ffb26c96 Reviewed-on: https://go-review.googlesource.com/c/go/+/321936 Trust: Richard Musiol Run-TryBot: Richard Musiol TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- misc/wasm/wasm_exec.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/misc/wasm/wasm_exec.js b/misc/wasm/wasm_exec.js index 3e41e628ef9..231185a123e 100644 --- a/misc/wasm/wasm_exec.js +++ b/misc/wasm/wasm_exec.js @@ -401,6 +401,7 @@ storeValue(sp + 56, result); this.mem.setUint8(sp + 64, 1); } catch (err) { + sp = this._inst.exports.getsp() >>> 0; // see comment above storeValue(sp + 56, err); this.mem.setUint8(sp + 64, 0); } @@ -417,6 +418,7 @@ storeValue(sp + 40, result); this.mem.setUint8(sp + 48, 1); } catch (err) { + sp = this._inst.exports.getsp() >>> 0; // see comment above storeValue(sp + 40, err); this.mem.setUint8(sp + 48, 0); } @@ -433,6 +435,7 @@ storeValue(sp + 40, result); this.mem.setUint8(sp + 48, 1); } catch (err) { + sp = this._inst.exports.getsp() >>> 0; // see comment above storeValue(sp + 40, err); this.mem.setUint8(sp + 48, 0); } From 4c50721cda74abbf7732638f39a23dfbf6271a48 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Tue, 11 May 2021 19:29:10 -0700 Subject: [PATCH 148/940] [dev.typeparams] cmd/compile: Fix handling of Name nodes during stenciling The name substitution for stenciling was incorrectly handling non-local names. Made changes to explicitly built the vars[] name substitution map based on the local variables (similar to what inlining substitution does). Then, we we are stenciling a name node, we do NOT make a copy of the name node if it is not in vars[], since it is then a reference to an external name. Added new function localvar() to create the new nodes for the local variables and put them in the vars[] map. New test listimp2.go, added missing test calls in list2.go Change-Id: I8946478250c7bf2bd31c3247089bd50cfeeda0fd Reviewed-on: https://go-review.googlesource.com/c/go/+/322190 Trust: Dan Scales Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/noder/stencil.go | 51 ++-- test/typeparam/list2.go | 9 + test/typeparam/listimp2.dir/a.go | 298 ++++++++++++++++++++ test/typeparam/listimp2.dir/main.go | 316 ++++++++++++++++++++++ test/typeparam/listimp2.go | 7 + 5 files changed, 656 insertions(+), 25 deletions(-) create mode 100644 test/typeparam/listimp2.dir/a.go create mode 100644 test/typeparam/listimp2.dir/main.go create mode 100644 test/typeparam/listimp2.go diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 1626ab9dd31..67580add735 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -289,7 +289,7 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*type newf.Dcl = make([]*ir.Name, len(gf.Dcl)) for i, n := range gf.Dcl { - newf.Dcl[i] = subst.node(n).(*ir.Name) + newf.Dcl[i] = subst.localvar(n) } // Replace the types in the function signature. @@ -315,9 +315,28 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*type return newf } -// node is like DeepCopy(), but creates distinct ONAME nodes, and also descends -// into closures. It substitutes type arguments for type parameters in all the new -// nodes. +// localvar creates a new name node for the specified local variable and enters it +// in subst.vars. It substitutes type arguments for type parameters in the type of +// name as needed. +func (subst *subster) localvar(name *ir.Name) *ir.Name { + m := ir.NewNameAt(name.Pos(), name.Sym()) + if name.IsClosureVar() { + m.SetIsClosureVar(true) + } + m.SetType(subst.typ(name.Type())) + m.BuiltinOp = name.BuiltinOp + m.Curfn = subst.newf + m.Class = name.Class + assert(name.Class != ir.PEXTERN && name.Class != ir.PFUNC) + m.Func = name.Func + subst.vars[name] = m + m.SetTypecheck(1) + return m +} + +// node is like DeepCopy(), but substitutes ONAME nodes based on subst.vars, and +// also descends into closures. It substitutes type arguments for type parameters +// in all the new nodes. func (subst *subster) node(n ir.Node) ir.Node { // Use closure to capture all state needed by the ir.EditChildren argument. var edit func(ir.Node) ir.Node @@ -327,28 +346,10 @@ func (subst *subster) node(n ir.Node) ir.Node { return ir.TypeNode(subst.typ(x.Type())) case ir.ONAME: - name := x.(*ir.Name) - if v := subst.vars[name]; v != nil { + if v := subst.vars[x.(*ir.Name)]; v != nil { return v } - m := ir.NewNameAt(name.Pos(), name.Sym()) - if name.IsClosureVar() { - m.SetIsClosureVar(true) - } - t := x.Type() - if t == nil { - assert(name.BuiltinOp != 0) - } else { - newt := subst.typ(t) - m.SetType(newt) - } - m.BuiltinOp = name.BuiltinOp - m.Curfn = subst.newf - m.Class = name.Class - m.Func = name.Func - subst.vars[name] = m - m.SetTypecheck(1) - return m + return x case ir.OLITERAL, ir.ONIL: if x.Sym() != nil { return x @@ -545,7 +546,7 @@ func (subst *subster) node(n ir.Node) ir.Node { func (subst *subster) namelist(l []*ir.Name) []*ir.Name { s := make([]*ir.Name, len(l)) for i, n := range l { - s[i] = subst.node(n).(*ir.Name) + s[i] = subst.localvar(n) if n.Defn != nil { s[i].Defn = subst.node(n.Defn) } diff --git a/test/typeparam/list2.go b/test/typeparam/list2.go index 385193d8765..32023cf319d 100644 --- a/test/typeparam/list2.go +++ b/test/typeparam/list2.go @@ -597,5 +597,14 @@ func TestTransform() { func main() { TestList() + TestExtending() + TestRemove() + TestIssue4103() + TestIssue6349() + TestMove() + TestZeroList() + TestInsertBeforeUnknownMark() + TestInsertAfterUnknownMark() + TestTransform() } diff --git a/test/typeparam/listimp2.dir/a.go b/test/typeparam/listimp2.dir/a.go new file mode 100644 index 00000000000..76ad669767a --- /dev/null +++ b/test/typeparam/listimp2.dir/a.go @@ -0,0 +1,298 @@ +// Copyright 2021 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 a + +import ( + "fmt" +) + +// Element is an element of a linked list. +type Element[T any] struct { + // Next and previous pointers in the doubly-linked list of elements. + // To simplify the implementation, internally a list l is implemented + // as a ring, such that &l.root is both the next element of the last + // list element (l.Back()) and the previous element of the first list + // element (l.Front()). + next, prev *Element[T] + + // The list to which this element belongs. + list *List[T] + + // The value stored with this element. + Value T +} + +// Next returns the next list element or nil. +func (e *Element[T]) Next() *Element[T] { + if p := e.next; e.list != nil && p != &e.list.root { + return p + } + return nil +} + +// Prev returns the previous list element or nil. +func (e *Element[T]) Prev() *Element[T] { + if p := e.prev; e.list != nil && p != &e.list.root { + return p + } + return nil +} + +// List represents a doubly linked list. +// The zero value for List is an empty list ready to use. +type List[T any] struct { + root Element[T] // sentinel list element, only &root, root.prev, and root.next are used + len int // current list length excluding (this) sentinel element +} + +// Init initializes or clears list l. +func (l *List[T]) Init() *List[T] { + l.root.next = &l.root + l.root.prev = &l.root + l.len = 0 + return l +} + +// New returns an initialized list. +func New[T any]() *List[T] { return new(List[T]).Init() } + +// Len returns the number of elements of list l. +// The complexity is O(1). +func (l *List[_]) Len() int { return l.len } + +// Front returns the first element of list l or nil if the list is empty. +func (l *List[T]) Front() *Element[T] { + if l.len == 0 { + return nil + } + return l.root.next +} + +// Back returns the last element of list l or nil if the list is empty. +func (l *List[T]) Back() *Element[T] { + if l.len == 0 { + return nil + } + return l.root.prev +} + +// lazyInit lazily initializes a zero List value. +func (l *List[_]) lazyInit() { + if l.root.next == nil { + l.Init() + } +} + +// insert inserts e after at, increments l.len, and returns e. +func (l *List[T]) insert(e, at *Element[T]) *Element[T] { + e.prev = at + e.next = at.next + e.prev.next = e + e.next.prev = e + e.list = l + l.len++ + return e +} + +// insertValue is a convenience wrapper for insert(&Element[T]{Value: v}, at). +func (l *List[T]) insertValue(v T, at *Element[T]) *Element[T] { + return l.insert(&Element[T]{Value: v}, at) +} + +// remove removes e from its list, decrements l.len, and returns e. +func (l *List[T]) remove(e *Element[T]) *Element[T] { + e.prev.next = e.next + e.next.prev = e.prev + e.next = nil // avoid memory leaks + e.prev = nil // avoid memory leaks + e.list = nil + l.len-- + return e +} + +// move moves e to next to at and returns e. +func (l *List[T]) move(e, at *Element[T]) *Element[T] { + if e == at { + return e + } + e.prev.next = e.next + e.next.prev = e.prev + + e.prev = at + e.next = at.next + e.prev.next = e + e.next.prev = e + + return e +} + +// Remove removes e from l if e is an element of list l. +// It returns the element value e.Value. +// The element must not be nil. +func (l *List[T]) Remove(e *Element[T]) T { + if e.list == l { + // if e.list == l, l must have been initialized when e was inserted + // in l or l == nil (e is a zero Element) and l.remove will crash + l.remove(e) + } + return e.Value +} + +// PushFront inserts a new element e with value v at the front of list l and returns e. +func (l *List[T]) PushFront(v T) *Element[T] { + l.lazyInit() + return l.insertValue(v, &l.root) +} + +// PushBack inserts a new element e with value v at the back of list l and returns e. +func (l *List[T]) PushBack(v T) *Element[T] { + l.lazyInit() + return l.insertValue(v, l.root.prev) +} + +// InsertBefore inserts a new element e with value v immediately before mark and returns e. +// If mark is not an element of l, the list is not modified. +// The mark must not be nil. +func (l *List[T]) InsertBefore(v T, mark *Element[T]) *Element[T] { + if mark.list != l { + return nil + } + // see comment in List.Remove about initialization of l + return l.insertValue(v, mark.prev) +} + +// InsertAfter inserts a new element e with value v immediately after mark and returns e. +// If mark is not an element of l, the list is not modified. +// The mark must not be nil. +func (l *List[T]) InsertAfter(v T, mark *Element[T]) *Element[T] { + if mark.list != l { + return nil + } + // see comment in List.Remove about initialization of l + return l.insertValue(v, mark) +} + +// MoveToFront moves element e to the front of list l. +// If e is not an element of l, the list is not modified. +// The element must not be nil. +func (l *List[T]) MoveToFront(e *Element[T]) { + if e.list != l || l.root.next == e { + return + } + // see comment in List.Remove about initialization of l + l.move(e, &l.root) +} + +// MoveToBack moves element e to the back of list l. +// If e is not an element of l, the list is not modified. +// The element must not be nil. +func (l *List[T]) MoveToBack(e *Element[T]) { + if e.list != l || l.root.prev == e { + return + } + // see comment in List.Remove about initialization of l + l.move(e, l.root.prev) +} + +// MoveBefore moves element e to its new position before mark. +// If e or mark is not an element of l, or e == mark, the list is not modified. +// The element and mark must not be nil. +func (l *List[T]) MoveBefore(e, mark *Element[T]) { + if e.list != l || e == mark || mark.list != l { + return + } + l.move(e, mark.prev) +} + +// MoveAfter moves element e to its new position after mark. +// If e or mark is not an element of l, or e == mark, the list is not modified. +// The element and mark must not be nil. +func (l *List[T]) MoveAfter(e, mark *Element[T]) { + if e.list != l || e == mark || mark.list != l { + return + } + l.move(e, mark) +} + +// PushBackList inserts a copy of an other list at the back of list l. +// The lists l and other may be the same. They must not be nil. +func (l *List[T]) PushBackList(other *List[T]) { + l.lazyInit() + for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() { + l.insertValue(e.Value, l.root.prev) + } +} + +// PushFrontList inserts a copy of an other list at the front of list l. +// The lists l and other may be the same. They must not be nil. +func (l *List[T]) PushFrontList(other *List[T]) { + l.lazyInit() + for i, e := other.Len(), other.Back(); i > 0; i, e = i-1, e.Prev() { + l.insertValue(e.Value, &l.root) + } +} + +// Transform runs a transform function on a list returning a new list. +func Transform[TElem1, TElem2 any](lst *List[TElem1], f func(TElem1) TElem2) *List[TElem2] { + ret := New[TElem2]() + for p := lst.Front(); p != nil; p = p.Next() { + ret.PushBack(f(p.Value)) + } + return ret +} + +func CheckListLen[T any](l *List[T], len int) bool { + if n := l.Len(); n != len { + panic(fmt.Sprintf("l.Len() = %d, want %d", n, len)) + return false + } + return true +} + +func CheckListPointers[T any](l *List[T], es []*Element[T]) { + root := &l.root + + if !CheckListLen(l, len(es)) { + return + } + + // zero length lists must be the zero value or properly initialized (sentinel circle) + if len(es) == 0 { + if l.root.next != nil && l.root.next != root || l.root.prev != nil && l.root.prev != root { + panic(fmt.Sprintf("l.root.next = %p, l.root.prev = %p; both should both be nil or %p", l.root.next, l.root.prev, root)) + } + return + } + // len(es) > 0 + + // check internal and external prev/next connections + for i, e := range es { + prev := root + Prev := (*Element[T])(nil) + if i > 0 { + prev = es[i-1] + Prev = prev + } + if p := e.prev; p != prev { + panic(fmt.Sprintf("elt[%d](%p).prev = %p, want %p", i, e, p, prev)) + } + if p := e.Prev(); p != Prev { + panic(fmt.Sprintf("elt[%d](%p).Prev() = %p, want %p", i, e, p, Prev)) + } + + next := root + Next := (*Element[T])(nil) + if i < len(es)-1 { + next = es[i+1] + Next = next + } + if n := e.next; n != next { + panic(fmt.Sprintf("elt[%d](%p).next = %p, want %p", i, e, n, next)) + } + if n := e.Next(); n != Next { + panic(fmt.Sprintf("elt[%d](%p).Next() = %p, want %p", i, e, n, Next)) + } + } +} diff --git a/test/typeparam/listimp2.dir/main.go b/test/typeparam/listimp2.dir/main.go new file mode 100644 index 00000000000..0c2c38e3995 --- /dev/null +++ b/test/typeparam/listimp2.dir/main.go @@ -0,0 +1,316 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "a" + "fmt" + "strconv" +) + +func TestList() { + l := a.New[string]() + a.CheckListPointers(l, []*(a.Element[string]){}) + + // Single element list + e := l.PushFront("a") + a.CheckListPointers(l, []*(a.Element[string]){e}) + l.MoveToFront(e) + a.CheckListPointers(l, []*(a.Element[string]){e}) + l.MoveToBack(e) + a.CheckListPointers(l, []*(a.Element[string]){e}) + l.Remove(e) + a.CheckListPointers(l, []*(a.Element[string]){}) + + // Bigger list + l2 := a.New[int]() + e2 := l2.PushFront(2) + e1 := l2.PushFront(1) + e3 := l2.PushBack(3) + e4 := l2.PushBack(600) + a.CheckListPointers(l2, []*(a.Element[int]){e1, e2, e3, e4}) + + l2.Remove(e2) + a.CheckListPointers(l2, []*(a.Element[int]){e1, e3, e4}) + + l2.MoveToFront(e3) // move from middle + a.CheckListPointers(l2, []*(a.Element[int]){e3, e1, e4}) + + l2.MoveToFront(e1) + l2.MoveToBack(e3) // move from middle + a.CheckListPointers(l2, []*(a.Element[int]){e1, e4, e3}) + + l2.MoveToFront(e3) // move from back + a.CheckListPointers(l2, []*(a.Element[int]){e3, e1, e4}) + l2.MoveToFront(e3) // should be no-op + a.CheckListPointers(l2, []*(a.Element[int]){e3, e1, e4}) + + l2.MoveToBack(e3) // move from front + a.CheckListPointers(l2, []*(a.Element[int]){e1, e4, e3}) + l2.MoveToBack(e3) // should be no-op + a.CheckListPointers(l2, []*(a.Element[int]){e1, e4, e3}) + + e2 = l2.InsertBefore(2, e1) // insert before front + a.CheckListPointers(l2, []*(a.Element[int]){e2, e1, e4, e3}) + l2.Remove(e2) + e2 = l2.InsertBefore(2, e4) // insert before middle + a.CheckListPointers(l2, []*(a.Element[int]){e1, e2, e4, e3}) + l2.Remove(e2) + e2 = l2.InsertBefore(2, e3) // insert before back + a.CheckListPointers(l2, []*(a.Element[int]){e1, e4, e2, e3}) + l2.Remove(e2) + + e2 = l2.InsertAfter(2, e1) // insert after front + a.CheckListPointers(l2, []*(a.Element[int]){e1, e2, e4, e3}) + l2.Remove(e2) + e2 = l2.InsertAfter(2, e4) // insert after middle + a.CheckListPointers(l2, []*(a.Element[int]){e1, e4, e2, e3}) + l2.Remove(e2) + e2 = l2.InsertAfter(2, e3) // insert after back + a.CheckListPointers(l2, []*(a.Element[int]){e1, e4, e3, e2}) + l2.Remove(e2) + + // Check standard iteration. + sum := 0 + for e := l2.Front(); e != nil; e = e.Next() { + sum += e.Value + } + if sum != 604 { + panic(fmt.Sprintf("sum over l = %d, want 604", sum)) + } + + // Clear all elements by iterating + var next *a.Element[int] + for e := l2.Front(); e != nil; e = next { + next = e.Next() + l2.Remove(e) + } + a.CheckListPointers(l2, []*(a.Element[int]){}) +} + +func checkList[T comparable](l *a.List[T], es []interface{}) { + if !a.CheckListLen(l, len(es)) { + return + } + + i := 0 + for e := l.Front(); e != nil; e = e.Next() { + le := e.Value + // Comparison between a generically-typed variable le and an interface. + if le != es[i] { + panic(fmt.Sprintf("elt[%d].Value = %v, want %v", i, le, es[i])) + } + i++ + } +} + +func TestExtending() { + l1 := a.New[int]() + l2 := a.New[int]() + + l1.PushBack(1) + l1.PushBack(2) + l1.PushBack(3) + + l2.PushBack(4) + l2.PushBack(5) + + l3 := a.New[int]() + l3.PushBackList(l1) + checkList(l3, []interface{}{1, 2, 3}) + l3.PushBackList(l2) + checkList(l3, []interface{}{1, 2, 3, 4, 5}) + + l3 = a.New[int]() + l3.PushFrontList(l2) + checkList(l3, []interface{}{4, 5}) + l3.PushFrontList(l1) + checkList(l3, []interface{}{1, 2, 3, 4, 5}) + + checkList(l1, []interface{}{1, 2, 3}) + checkList(l2, []interface{}{4, 5}) + + l3 = a.New[int]() + l3.PushBackList(l1) + checkList(l3, []interface{}{1, 2, 3}) + l3.PushBackList(l3) + checkList(l3, []interface{}{1, 2, 3, 1, 2, 3}) + + l3 = a.New[int]() + l3.PushFrontList(l1) + checkList(l3, []interface{}{1, 2, 3}) + l3.PushFrontList(l3) + checkList(l3, []interface{}{1, 2, 3, 1, 2, 3}) + + l3 = a.New[int]() + l1.PushBackList(l3) + checkList(l1, []interface{}{1, 2, 3}) + l1.PushFrontList(l3) + checkList(l1, []interface{}{1, 2, 3}) +} + +func TestRemove() { + l := a.New[int]() + e1 := l.PushBack(1) + e2 := l.PushBack(2) + a.CheckListPointers(l, []*(a.Element[int]){e1, e2}) + e := l.Front() + l.Remove(e) + a.CheckListPointers(l, []*(a.Element[int]){e2}) + l.Remove(e) + a.CheckListPointers(l, []*(a.Element[int]){e2}) +} + +func TestIssue4103() { + l1 := a.New[int]() + l1.PushBack(1) + l1.PushBack(2) + + l2 := a.New[int]() + l2.PushBack(3) + l2.PushBack(4) + + e := l1.Front() + l2.Remove(e) // l2 should not change because e is not an element of l2 + if n := l2.Len(); n != 2 { + panic(fmt.Sprintf("l2.Len() = %d, want 2", n)) + } + + l1.InsertBefore(8, e) + if n := l1.Len(); n != 3 { + panic(fmt.Sprintf("l1.Len() = %d, want 3", n)) + } +} + +func TestIssue6349() { + l := a.New[int]() + l.PushBack(1) + l.PushBack(2) + + e := l.Front() + l.Remove(e) + if e.Value != 1 { + panic(fmt.Sprintf("e.value = %d, want 1", e.Value)) + } + if e.Next() != nil { + panic(fmt.Sprintf("e.Next() != nil")) + } + if e.Prev() != nil { + panic(fmt.Sprintf("e.Prev() != nil")) + } +} + +func TestMove() { + l := a.New[int]() + e1 := l.PushBack(1) + e2 := l.PushBack(2) + e3 := l.PushBack(3) + e4 := l.PushBack(4) + + l.MoveAfter(e3, e3) + a.CheckListPointers(l, []*(a.Element[int]){e1, e2, e3, e4}) + l.MoveBefore(e2, e2) + a.CheckListPointers(l, []*(a.Element[int]){e1, e2, e3, e4}) + + l.MoveAfter(e3, e2) + a.CheckListPointers(l, []*(a.Element[int]){e1, e2, e3, e4}) + l.MoveBefore(e2, e3) + a.CheckListPointers(l, []*(a.Element[int]){e1, e2, e3, e4}) + + l.MoveBefore(e2, e4) + a.CheckListPointers(l, []*(a.Element[int]){e1, e3, e2, e4}) + e2, e3 = e3, e2 + + l.MoveBefore(e4, e1) + a.CheckListPointers(l, []*(a.Element[int]){e4, e1, e2, e3}) + e1, e2, e3, e4 = e4, e1, e2, e3 + + l.MoveAfter(e4, e1) + a.CheckListPointers(l, []*(a.Element[int]){e1, e4, e2, e3}) + e2, e3, e4 = e4, e2, e3 + + l.MoveAfter(e2, e3) + a.CheckListPointers(l, []*(a.Element[int]){e1, e3, e2, e4}) + e2, e3 = e3, e2 +} + +// Test PushFront, PushBack, PushFrontList, PushBackList with uninitialized a.List +func TestZeroList() { + var l1 = new(a.List[int]) + l1.PushFront(1) + checkList(l1, []interface{}{1}) + + var l2 = new(a.List[int]) + l2.PushBack(1) + checkList(l2, []interface{}{1}) + + var l3 = new(a.List[int]) + l3.PushFrontList(l1) + checkList(l3, []interface{}{1}) + + var l4 = new(a.List[int]) + l4.PushBackList(l2) + checkList(l4, []interface{}{1}) +} + +// Test that a list l is not modified when calling InsertBefore with a mark that is not an element of l. +func TestInsertBeforeUnknownMark() { + var l a.List[int] + l.PushBack(1) + l.PushBack(2) + l.PushBack(3) + l.InsertBefore(1, new(a.Element[int])) + checkList(&l, []interface{}{1, 2, 3}) +} + +// Test that a list l is not modified when calling InsertAfter with a mark that is not an element of l. +func TestInsertAfterUnknownMark() { + var l a.List[int] + l.PushBack(1) + l.PushBack(2) + l.PushBack(3) + l.InsertAfter(1, new(a.Element[int])) + checkList(&l, []interface{}{1, 2, 3}) +} + +// Test that a list l is not modified when calling MoveAfter or MoveBefore with a mark that is not an element of l. +func TestMoveUnknownMark() { + var l1 a.List[int] + e1 := l1.PushBack(1) + + var l2 a.List[int] + e2 := l2.PushBack(2) + + l1.MoveAfter(e1, e2) + checkList(&l1, []interface{}{1}) + checkList(&l2, []interface{}{2}) + + l1.MoveBefore(e1, e2) + checkList(&l1, []interface{}{1}) + checkList(&l2, []interface{}{2}) +} + +// Test the Transform function. +func TestTransform() { + l1 := a.New[int]() + l1.PushBack(1) + l1.PushBack(2) + l2 := a.Transform(l1, strconv.Itoa) + checkList(l2, []interface{}{"1", "2"}) +} + + +func main() { + TestList() + TestExtending() + TestRemove() + TestIssue4103() + TestIssue6349() + TestMove() + TestZeroList() + TestInsertBeforeUnknownMark() + TestInsertAfterUnknownMark() + TestTransform() +} diff --git a/test/typeparam/listimp2.go b/test/typeparam/listimp2.go new file mode 100644 index 00000000000..76930e5e4f6 --- /dev/null +++ b/test/typeparam/listimp2.go @@ -0,0 +1,7 @@ +// rundir -G=3 + +// Copyright 2021 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 ignored From d48f6d9f6f1ee7099ad129552507903e191ad589 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Fri, 14 May 2021 16:35:04 -0700 Subject: [PATCH 149/940] [dev.typeparams] Don't check typecheck(3) on transform, so no need to export/import it We have a value typecheck(3) that indicates that a node in a generic function still needs transformation (via the functions in transform.go). But it is not very desirable to export/import the value of typecheck(3). So, I changed the stenciling code to just try to transform all relevant node types during node copy. Almost all tranform functions were already idempotent. I only had to add an extra if check before calling transformAssign() in the OAS case. We still use the typecheck(3) in noder to determine when higher-nodes have to delay transformation because one or more of their args are delaying transformation. Added new test mapsimp.go that required these tranformations after import. As an additional change, export/import of OINDEX requires exporting the type using w.exoticType() rather than w.typ(), in order to handle generic functions. Since generic functions can have pre-transform operations, the index operation can have a tuple type (multiple return from a map lookup). Added printing of imported function bodies in -W=3 debug mode. Change-Id: I220e2428dc5f2741e91db146f075eb5b6045f451 Reviewed-on: https://go-review.googlesource.com/c/go/+/322191 Trust: Dan Scales Run-TryBot: Dan Scales Reviewed-by: Keith Randall TryBot-Result: Go Bot --- src/cmd/compile/internal/noder/stencil.go | 62 ++++--- src/cmd/compile/internal/typecheck/iexport.go | 2 +- src/cmd/compile/internal/typecheck/iimport.go | 6 +- test/typeparam/mapsimp.dir/a.go | 108 ++++++++++++ test/typeparam/mapsimp.dir/main.go | 156 ++++++++++++++++++ test/typeparam/mapsimp.go | 7 + 6 files changed, 307 insertions(+), 34 deletions(-) create mode 100644 test/typeparam/mapsimp.dir/a.go create mode 100644 test/typeparam/mapsimp.dir/main.go create mode 100644 test/typeparam/mapsimp.go diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 67580add735..e273a80b20f 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -374,45 +374,43 @@ func (subst *subster) node(n ir.Node) ir.Node { } ir.EditChildren(m, edit) - if x.Typecheck() == 3 { - // These are nodes whose transforms were delayed until - // their instantiated type was known. - m.SetTypecheck(1) - if typecheck.IsCmp(x.Op()) { - transformCompare(m.(*ir.BinaryExpr)) - } else { - switch x.Op() { - case ir.OSLICE, ir.OSLICE3: - transformSlice(m.(*ir.SliceExpr)) + m.SetTypecheck(1) + if typecheck.IsCmp(x.Op()) { + transformCompare(m.(*ir.BinaryExpr)) + } else { + switch x.Op() { + case ir.OSLICE, ir.OSLICE3: + transformSlice(m.(*ir.SliceExpr)) - case ir.OADD: - m = transformAdd(m.(*ir.BinaryExpr)) + case ir.OADD: + m = transformAdd(m.(*ir.BinaryExpr)) - case ir.OINDEX: - transformIndex(m.(*ir.IndexExpr)) + case ir.OINDEX: + transformIndex(m.(*ir.IndexExpr)) - case ir.OAS2: - as2 := m.(*ir.AssignListStmt) - transformAssign(as2, as2.Lhs, as2.Rhs) + case ir.OAS2: + as2 := m.(*ir.AssignListStmt) + transformAssign(as2, as2.Lhs, as2.Rhs) - case ir.OAS: - as := m.(*ir.AssignStmt) + case ir.OAS: + as := m.(*ir.AssignStmt) + if as.Y != nil { + // transformAssign doesn't handle the case + // of zeroing assignment of a dcl (rhs[0] is nil). lhs, rhs := []ir.Node{as.X}, []ir.Node{as.Y} transformAssign(as, lhs, rhs) - - case ir.OASOP: - as := m.(*ir.AssignOpStmt) - transformCheckAssign(as, as.X) - - case ir.ORETURN: - transformReturn(m.(*ir.ReturnStmt)) - - case ir.OSEND: - transformSend(m.(*ir.SendStmt)) - - default: - base.Fatalf("Unexpected node with Typecheck() == 3") } + + case ir.OASOP: + as := m.(*ir.AssignOpStmt) + transformCheckAssign(as, as.X) + + case ir.ORETURN: + transformReturn(m.(*ir.ReturnStmt)) + + case ir.OSEND: + transformSend(m.(*ir.SendStmt)) + } } diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index d956ada3c53..292bb2c409a 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -1735,7 +1735,7 @@ func (w *exportWriter) expr(n ir.Node) { w.expr(n.X) w.expr(n.Index) if go117ExportTypes { - w.typ(n.Type()) + w.exoticType(n.Type()) if n.Op() == ir.OINDEXMAP { w.bool(n.Assigned) } diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 966e865630a..d5b549483d8 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -1025,6 +1025,10 @@ func (r *importReader) funcBody(fn *ir.Func) { fn.Inl.Body = body r.curfn = outerfn + if base.Flag.W >= 3 { + fmt.Printf("Imported for %v", fn) + ir.DumpList("", fn.Inl.Body) + } } func (r *importReader) readNames(fn *ir.Func) []*ir.Name { @@ -1349,7 +1353,7 @@ func (r *importReader) node() ir.Node { n := ir.NewIndexExpr(r.pos(), r.expr(), r.expr()) if go117ExportTypes { n.SetOp(op) - n.SetType(r.typ()) + n.SetType(r.exoticType()) if op == ir.OINDEXMAP { n.Assigned = r.bool() } diff --git a/test/typeparam/mapsimp.dir/a.go b/test/typeparam/mapsimp.dir/a.go new file mode 100644 index 00000000000..696e2a56801 --- /dev/null +++ b/test/typeparam/mapsimp.dir/a.go @@ -0,0 +1,108 @@ +// Copyright 2021 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 a + +// SliceEqual reports whether two slices are equal: the same length and all +// elements equal. All floating point NaNs are considered equal. +func SliceEqual[Elem comparable](s1, s2 []Elem) bool { + if len(s1) != len(s2) { + return false + } + for i, v1 := range s1 { + v2 := s2[i] + if v1 != v2 { + isNaN := func(f Elem) bool { return f != f } + if !isNaN(v1) || !isNaN(v2) { + return false + } + } + } + return true +} + +// Keys returns the keys of the map m. +// The keys will be an indeterminate order. +func Keys[K comparable, V any](m map[K]V) []K { + r := make([]K, 0, len(m)) + for k := range m { + r = append(r, k) + } + return r +} + +// Values returns the values of the map m. +// The values will be in an indeterminate order. +func Values[K comparable, V any](m map[K]V) []V { + r := make([]V, 0, len(m)) + for _, v := range m { + r = append(r, v) + } + return r +} + +// Equal reports whether two maps contain the same key/value pairs. +// Values are compared using ==. +func Equal[K, V comparable](m1, m2 map[K]V) bool { + if len(m1) != len(m2) { + return false + } + for k, v1 := range m1 { + if v2, ok := m2[k]; !ok || v1 != v2 { + return false + } + } + return true +} + +// Copy returns a copy of m. +func Copy[K comparable, V any](m map[K]V) map[K]V { + r := make(map[K]V, len(m)) + for k, v := range m { + r[k] = v + } + return r +} + +// Add adds all key/value pairs in m2 to m1. Keys in m2 that are already +// present in m1 will be overwritten with the value in m2. +func Add[K comparable, V any](m1, m2 map[K]V) { + for k, v := range m2 { + m1[k] = v + } +} + +// Sub removes all keys in m2 from m1. Keys in m2 that are not present +// in m1 are ignored. The values in m2 are ignored. +func Sub[K comparable, V any](m1, m2 map[K]V) { + for k := range m2 { + delete(m1, k) + } +} + +// Intersect removes all keys from m1 that are not present in m2. +// Keys in m2 that are not in m1 are ignored. The values in m2 are ignored. +func Intersect[K comparable, V any](m1, m2 map[K]V) { + for k := range m1 { + if _, ok := m2[k]; !ok { + delete(m1, k) + } + } +} + +// Filter deletes any key/value pairs from m for which f returns false. +func Filter[K comparable, V any](m map[K]V, f func(K, V) bool) { + for k, v := range m { + if !f(k, v) { + delete(m, k) + } + } +} + +// TransformValues applies f to each value in m. The keys remain unchanged. +func TransformValues[K comparable, V any](m map[K]V, f func(V) V) { + for k, v := range m { + m[k] = f(v) + } +} diff --git a/test/typeparam/mapsimp.dir/main.go b/test/typeparam/mapsimp.dir/main.go new file mode 100644 index 00000000000..873660e4cd5 --- /dev/null +++ b/test/typeparam/mapsimp.dir/main.go @@ -0,0 +1,156 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "a" + "fmt" + "math" + "sort" +) + +var m1 = map[int]int{1: 2, 2: 4, 4: 8, 8: 16} +var m2 = map[int]string{1: "2", 2: "4", 4: "8", 8: "16"} + +func TestKeys() { + want := []int{1, 2, 4, 8} + + got1 := a.Keys(m1) + sort.Ints(got1) + if !a.SliceEqual(got1, want) { + panic(fmt.Sprintf("a.Keys(%v) = %v, want %v", m1, got1, want)) + } + + got2 := a.Keys(m2) + sort.Ints(got2) + if !a.SliceEqual(got2, want) { + panic(fmt.Sprintf("a.Keys(%v) = %v, want %v", m2, got2, want)) + } +} + +func TestValues() { + got1 := a.Values(m1) + want1 := []int{2, 4, 8, 16} + sort.Ints(got1) + if !a.SliceEqual(got1, want1) { + panic(fmt.Sprintf("a.Values(%v) = %v, want %v", m1, got1, want1)) + } + + got2 := a.Values(m2) + want2 := []string{"16", "2", "4", "8"} + sort.Strings(got2) + if !a.SliceEqual(got2, want2) { + panic(fmt.Sprintf("a.Values(%v) = %v, want %v", m2, got2, want2)) + } +} + +func TestEqual() { + if !a.Equal(m1, m1) { + panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", m1, m1)) + } + if a.Equal(m1, nil) { + panic(fmt.Sprintf("a.Equal(%v, nil) = true, want false", m1)) + } + if a.Equal(nil, m1) { + panic(fmt.Sprintf("a.Equal(nil, %v) = true, want false", m1)) + } + if !a.Equal[int, int](nil, nil) { + panic("a.Equal(nil, nil) = false, want true") + } + if ms := map[int]int{1: 2}; a.Equal(m1, ms) { + panic(fmt.Sprintf("a.Equal(%v, %v) = true, want false", m1, ms)) + } + + // Comparing NaN for equality is expected to fail. + mf := map[int]float64{1: 0, 2: math.NaN()} + if a.Equal(mf, mf) { + panic(fmt.Sprintf("a.Equal(%v, %v) = true, want false", mf, mf)) + } +} + +func TestCopy() { + m2 := a.Copy(m1) + if !a.Equal(m1, m2) { + panic(fmt.Sprintf("a.Copy(%v) = %v, want %v", m1, m2, m1)) + } + m2[16] = 32 + if a.Equal(m1, m2) { + panic(fmt.Sprintf("a.Equal(%v, %v) = true, want false", m1, m2)) + } +} + +func TestAdd() { + mc := a.Copy(m1) + a.Add(mc, mc) + if !a.Equal(mc, m1) { + panic(fmt.Sprintf("a.Add(%v, %v) = %v, want %v", m1, m1, mc, m1)) + } + a.Add(mc, map[int]int{16: 32}) + want := map[int]int{1: 2, 2: 4, 4: 8, 8: 16, 16: 32} + if !a.Equal(mc, want) { + panic(fmt.Sprintf("a.Add result = %v, want %v", mc, want)) + } +} + +func TestSub() { + mc := a.Copy(m1) + a.Sub(mc, mc) + if len(mc) > 0 { + panic(fmt.Sprintf("a.Sub(%v, %v) = %v, want empty map", m1, m1, mc)) + } + mc = a.Copy(m1) + a.Sub(mc, map[int]int{1: 0}) + want := map[int]int{2: 4, 4: 8, 8: 16} + if !a.Equal(mc, want) { + panic(fmt.Sprintf("a.Sub result = %v, want %v", mc, want)) + } +} + +func TestIntersect() { + mc := a.Copy(m1) + a.Intersect(mc, mc) + if !a.Equal(mc, m1) { + panic(fmt.Sprintf("a.Intersect(%v, %v) = %v, want %v", m1, m1, mc, m1)) + } + a.Intersect(mc, map[int]int{1: 0, 2: 0}) + want := map[int]int{1: 2, 2: 4} + if !a.Equal(mc, want) { + panic(fmt.Sprintf("a.Intersect result = %v, want %v", mc, want)) + } +} + +func TestFilter() { + mc := a.Copy(m1) + a.Filter(mc, func(int, int) bool { return true }) + if !a.Equal(mc, m1) { + panic(fmt.Sprintf("a.Filter(%v, true) = %v, want %v", m1, mc, m1)) + } + a.Filter(mc, func(k, v int) bool { return k < 3 }) + want := map[int]int{1: 2, 2: 4} + if !a.Equal(mc, want) { + panic(fmt.Sprintf("a.Filter result = %v, want %v", mc, want)) + } +} + +func TestTransformValues() { + mc := a.Copy(m1) + a.TransformValues(mc, func(i int) int { return i / 2 }) + want := map[int]int{1: 1, 2: 2, 4: 4, 8: 8} + if !a.Equal(mc, want) { + panic(fmt.Sprintf("a.TransformValues result = %v, want %v", mc, want)) + } +} + +func main() { + TestKeys() + TestValues() + TestEqual() + TestCopy() + TestAdd() + TestSub() + TestIntersect() + TestFilter() + TestTransformValues() +} diff --git a/test/typeparam/mapsimp.go b/test/typeparam/mapsimp.go new file mode 100644 index 00000000000..76930e5e4f6 --- /dev/null +++ b/test/typeparam/mapsimp.go @@ -0,0 +1,7 @@ +// rundir -G=3 + +// Copyright 2021 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 ignored From c89f1224a544cde464fcb86e78ebb0cc97eedba2 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Mon, 17 May 2021 10:06:51 -0700 Subject: [PATCH 150/940] net: verify results from Lookup* are valid domain names For the methods LookupCNAME, LookupSRV, LookupMX, LookupNS, and LookupAddr check that the returned domain names are in fact valid DNS names using the existing isDomainName function. Thanks to Philipp Jeitner and Haya Shulman from Fraunhofer SIT for reporting this issue. Fixes #46241 Fixes CVE-2021-33195 Change-Id: Icf231acd93178a3b6aec3f178cff7e693f74ef8c Reviewed-on: https://go-review.googlesource.com/c/go/+/320949 Trust: Roland Shoemaker Trust: Katie Hockman Run-TryBot: Roland Shoemaker TryBot-Result: Go Bot Reviewed-by: Katie Hockman --- src/net/dnsclient_unix_test.go | 121 +++++++++++++++++++++++++++++++++ src/net/lookup.go | 98 +++++++++++++++++++++++--- 2 files changed, 211 insertions(+), 8 deletions(-) diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go index ec690a1c0cf..69a9b972f08 100644 --- a/src/net/dnsclient_unix_test.go +++ b/src/net/dnsclient_unix_test.go @@ -1799,3 +1799,124 @@ func TestPTRandNonPTR(t *testing.T) { t.Errorf("names = %q; want %q", names, want) } } + +func TestCVE202133195(t *testing.T) { + fake := fakeDNSServer{ + rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) { + r := dnsmessage.Message{ + Header: dnsmessage.Header{ + ID: q.Header.ID, + Response: true, + RCode: dnsmessage.RCodeSuccess, + RecursionAvailable: true, + }, + Questions: q.Questions, + } + switch q.Questions[0].Type { + case dnsmessage.TypeCNAME: + r.Answers = []dnsmessage.Resource{} + case dnsmessage.TypeA: // CNAME lookup uses a A/AAAA as a proxy + r.Answers = append(r.Answers, + dnsmessage.Resource{ + Header: dnsmessage.ResourceHeader{ + Name: dnsmessage.MustNewName(".golang.org."), + Type: dnsmessage.TypeA, + Class: dnsmessage.ClassINET, + Length: 4, + }, + Body: &dnsmessage.AResource{ + A: TestAddr, + }, + }, + ) + case dnsmessage.TypeSRV: + n := q.Questions[0].Name + if n.String() == "_hdr._tcp.golang.org." { + n = dnsmessage.MustNewName(".golang.org.") + } + r.Answers = append(r.Answers, + dnsmessage.Resource{ + Header: dnsmessage.ResourceHeader{ + Name: n, + Type: dnsmessage.TypeSRV, + Class: dnsmessage.ClassINET, + Length: 4, + }, + Body: &dnsmessage.SRVResource{ + Target: dnsmessage.MustNewName(".golang.org."), + }, + }, + ) + case dnsmessage.TypeMX: + r.Answers = append(r.Answers, + dnsmessage.Resource{ + Header: dnsmessage.ResourceHeader{ + Name: dnsmessage.MustNewName(".golang.org."), + Type: dnsmessage.TypeMX, + Class: dnsmessage.ClassINET, + Length: 4, + }, + Body: &dnsmessage.MXResource{ + MX: dnsmessage.MustNewName(".golang.org."), + }, + }, + ) + case dnsmessage.TypeNS: + r.Answers = append(r.Answers, + dnsmessage.Resource{ + Header: dnsmessage.ResourceHeader{ + Name: dnsmessage.MustNewName(".golang.org."), + Type: dnsmessage.TypeNS, + Class: dnsmessage.ClassINET, + Length: 4, + }, + Body: &dnsmessage.NSResource{ + NS: dnsmessage.MustNewName(".golang.org."), + }, + }, + ) + case dnsmessage.TypePTR: + r.Answers = append(r.Answers, + dnsmessage.Resource{ + Header: dnsmessage.ResourceHeader{ + Name: dnsmessage.MustNewName(".golang.org."), + Type: dnsmessage.TypePTR, + Class: dnsmessage.ClassINET, + Length: 4, + }, + Body: &dnsmessage.PTRResource{ + PTR: dnsmessage.MustNewName(".golang.org."), + }, + }, + ) + } + return r, nil + }, + } + r := Resolver{PreferGo: true, Dial: fake.DialContext} + + _, err := r.LookupCNAME(context.Background(), "golang.org") + if expected := "lookup golang.org: CNAME target is invalid"; err.Error() != expected { + t.Errorf("LookupCNAME returned unexpected error, got %q, want %q", err.Error(), expected) + } + _, _, err = r.LookupSRV(context.Background(), "target", "tcp", "golang.org") + if expected := "lookup golang.org: SRV target is invalid"; err.Error() != expected { + t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected) + } + _, _, err = r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org") + if expected := "lookup golang.org: SRV header name is invalid"; err.Error() != expected { + t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected) + } + _, err = r.LookupMX(context.Background(), "golang.org") + if expected := "lookup golang.org: MX target is invalid"; err.Error() != expected { + t.Errorf("LookupMX returned unexpected error, got %q, want %q", err.Error(), expected) + } + _, err = r.LookupNS(context.Background(), "golang.org") + if expected := "lookup golang.org: NS target is invalid"; err.Error() != expected { + t.Errorf("LookupNS returned unexpected error, got %q, want %q", err.Error(), expected) + } + _, err = r.LookupAddr(context.Background(), "1.2.3.4") + if expected := "lookup 1.2.3.4: PTR target is invalid"; err.Error() != expected { + t.Errorf("LookupAddr returned unexpected error, got %q, want %q", err.Error(), expected) + } +} diff --git a/src/net/lookup.go b/src/net/lookup.go index 03599503bd1..39d33796d5b 100644 --- a/src/net/lookup.go +++ b/src/net/lookup.go @@ -396,6 +396,9 @@ func (r *Resolver) LookupPort(ctx context.Context, network, service string) (por // contain DNS "CNAME" records, as long as host resolves to // address records. // +// The returned canonical name is validated to be a properly +// formatted presentation-format domain name. +// // LookupCNAME uses context.Background internally; to specify the context, use // Resolver.LookupCNAME. func LookupCNAME(host string) (cname string, err error) { @@ -412,8 +415,18 @@ func LookupCNAME(host string) (cname string, err error) { // LookupCNAME does not return an error if host does not // contain DNS "CNAME" records, as long as host resolves to // address records. -func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, err error) { - return r.lookupCNAME(ctx, host) +// +// The returned canonical name is validated to be a properly +// formatted presentation-format domain name. +func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error) { + cname, err := r.lookupCNAME(ctx, host) + if err != nil { + return "", err + } + if !isDomainName(cname) { + return "", &DNSError{Err: "CNAME target is invalid", Name: host} + } + return cname, nil } // LookupSRV tries to resolve an SRV query of the given service, @@ -425,6 +438,9 @@ func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, // That is, it looks up _service._proto.name. To accommodate services // publishing SRV records under non-standard names, if both service // and proto are empty strings, LookupSRV looks up name directly. +// +// The returned service names are validated to be properly +// formatted presentation-format domain names. func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { return DefaultResolver.lookupSRV(context.Background(), service, proto, name) } @@ -438,12 +454,33 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err // That is, it looks up _service._proto.name. To accommodate services // publishing SRV records under non-standard names, if both service // and proto are empty strings, LookupSRV looks up name directly. -func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) { - return r.lookupSRV(ctx, service, proto, name) +// +// The returned service names are validated to be properly +// formatted presentation-format domain names. +func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) { + cname, addrs, err := r.lookupSRV(ctx, service, proto, name) + if err != nil { + return "", nil, err + } + if cname != "" && !isDomainName(cname) { + return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name} + } + for _, addr := range addrs { + if addr == nil { + continue + } + if !isDomainName(addr.Target) { + return "", nil, &DNSError{Err: "SRV target is invalid", Name: name} + } + } + return cname, addrs, nil } // LookupMX returns the DNS MX records for the given domain name sorted by preference. // +// The returned mail server names are validated to be properly +// formatted presentation-format domain names. +// // LookupMX uses context.Background internally; to specify the context, use // Resolver.LookupMX. func LookupMX(name string) ([]*MX, error) { @@ -451,12 +488,30 @@ func LookupMX(name string) ([]*MX, error) { } // LookupMX returns the DNS MX records for the given domain name sorted by preference. +// +// The returned mail server names are validated to be properly +// formatted presentation-format domain names. func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) { - return r.lookupMX(ctx, name) + records, err := r.lookupMX(ctx, name) + if err != nil { + return nil, err + } + for _, mx := range records { + if mx == nil { + continue + } + if !isDomainName(mx.Host) { + return nil, &DNSError{Err: "MX target is invalid", Name: name} + } + } + return records, nil } // LookupNS returns the DNS NS records for the given domain name. // +// The returned name server names are validated to be properly +// formatted presentation-format domain names. +// // LookupNS uses context.Background internally; to specify the context, use // Resolver.LookupNS. func LookupNS(name string) ([]*NS, error) { @@ -464,8 +519,23 @@ func LookupNS(name string) ([]*NS, error) { } // LookupNS returns the DNS NS records for the given domain name. +// +// The returned name server names are validated to be properly +// formatted presentation-format domain names. func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) { - return r.lookupNS(ctx, name) + records, err := r.lookupNS(ctx, name) + if err != nil { + return nil, err + } + for _, ns := range records { + if ns == nil { + continue + } + if !isDomainName(ns.Host) { + return nil, &DNSError{Err: "NS target is invalid", Name: name} + } + } + return records, nil } // LookupTXT returns the DNS TXT records for the given domain name. @@ -495,6 +565,18 @@ func LookupAddr(addr string) (names []string, err error) { // LookupAddr performs a reverse lookup for the given address, returning a list // of names mapping to that address. -func (r *Resolver) LookupAddr(ctx context.Context, addr string) (names []string, err error) { - return r.lookupAddr(ctx, addr) +// +// The returned names are validated to be properly +// formatted presentation-format domain names. +func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) { + names, err := r.lookupAddr(ctx, addr) + if err != nil { + return nil, err + } + for _, name := range names { + if !isDomainName(name) { + return nil, &DNSError{Err: "PTR target is invalid", Name: addr} + } + } + return names, nil } From 1608577e0503be1739631d60576a07bdf1bbb49e Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 20 May 2021 21:24:36 -0700 Subject: [PATCH 151/940] [dev.typeparams] cmd/compile/internal/types2: re-use existing code for Interface.Complete Change-Id: I0fa07e49651aa086c2edbd1162332608c400250f Reviewed-on: https://go-review.googlesource.com/c/go/+/321751 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/interface.go | 47 +++++++++++++-- src/cmd/compile/internal/types2/type.go | 60 +------------------- 2 files changed, 44 insertions(+), 63 deletions(-) diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go index bbd25cbd094..21968b34aa7 100644 --- a/src/cmd/compile/internal/types2/interface.go +++ b/src/cmd/compile/internal/types2/interface.go @@ -6,6 +6,7 @@ package types2 import ( "cmd/compile/internal/syntax" + "fmt" "sort" ) @@ -139,7 +140,13 @@ func (check *Checker) completeInterface(pos syntax.Pos, ityp *Interface) { panic("internal error: incomplete interface") } - if check.conf.Trace { + completeInterface(check, pos, ityp) +} + +func completeInterface(check *Checker, pos syntax.Pos, ityp *Interface) { + assert(ityp.allMethods == nil) + + if check != nil && check.conf.Trace { // Types don't generally have position information. // If we don't have a valid pos provided, try to use // one close enough. @@ -175,6 +182,7 @@ func (check *Checker) completeInterface(pos syntax.Pos, ityp *Interface) { // we can get rid of the mpos map below and simply use the cloned method's // position. + var todo []*Func var seen objset var methods []*Func mpos := make(map[*Func]syntax.Pos) // method specification or method embedding position, for good error messages @@ -184,6 +192,9 @@ func (check *Checker) completeInterface(pos syntax.Pos, ityp *Interface) { methods = append(methods, m) mpos[m] = pos case explicit: + if check == nil { + panic(fmt.Sprintf("%s: duplicate method %s", m.pos, m.name)) + } var err error_ err.errorf(pos, "duplicate method %s", m.name) err.errorf(mpos[other.(*Func)], "other declaration of %s", m.name) @@ -194,6 +205,11 @@ func (check *Checker) completeInterface(pos syntax.Pos, ityp *Interface) { // If we're pre-go1.14 (overlapping embeddings are not permitted), report that // error here as well (even though we could do it eagerly) because it's the same // error message. + if check == nil { + // check method signatures after all locally embedded interfaces are computed + todo = append(todo, m, other.(*Func)) + break + } check.later(func() { if !check.allowVersion(m.pkg, 1, 14) || !check.identical(m.typ, other.Type()) { var err error_ @@ -212,9 +228,15 @@ func (check *Checker) completeInterface(pos syntax.Pos, ityp *Interface) { // collect types allTypes := ityp.types - posList := check.posMap[ityp] + var posList []syntax.Pos + if check != nil { + posList = check.posMap[ityp] + } for i, typ := range ityp.embeddeds { - pos := posList[i] // embedding position + var pos syntax.Pos // embedding position + if posList != nil { + pos = posList[i] + } utyp := under(typ) etyp := asInterface(utyp) if etyp == nil { @@ -225,17 +247,32 @@ func (check *Checker) completeInterface(pos syntax.Pos, ityp *Interface) { } else { format = "%s is not an interface" } - check.errorf(pos, format, typ) + if check != nil { + check.errorf(pos, format, typ) + } else { + panic(fmt.Sprintf("%s: "+format, pos, typ)) + } } continue } - check.completeInterface(pos, etyp) + if etyp.allMethods == nil { + completeInterface(check, pos, etyp) + } for _, m := range etyp.allMethods { addMethod(pos, m, false) // use embedding position pos rather than m.pos } allTypes = intersect(allTypes, etyp.allTypes) } + // process todo's (this only happens if check == nil) + for i := 0; i < len(todo); i += 2 { + m := todo[i] + other := todo[i+1] + if !Identical(m.typ, other.typ) { + panic(fmt.Sprintf("%s: duplicate method %s", m.pos, m.name)) + } + } + if methods != nil { sortMethods(methods) ityp.allMethods = methods diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index 55c2f336ce8..db955a8509d 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -6,7 +6,6 @@ package types2 import ( "cmd/compile/internal/syntax" - "fmt" "sync/atomic" ) @@ -544,64 +543,9 @@ func (t *Interface) isSatisfiedBy(typ Type) bool { // form other types. The interface must not contain duplicate methods or a // panic occurs. Complete returns the receiver. func (t *Interface) Complete() *Interface { - // TODO(gri) consolidate this method with Checker.completeInterface - if t.allMethods != nil { - return t + if t.allMethods == nil { + completeInterface(nil, nopos, t) } - - t.allMethods = markComplete // avoid infinite recursion - - var todo []*Func - var methods []*Func - var seen objset - addMethod := func(m *Func, explicit bool) { - switch other := seen.insert(m); { - case other == nil: - methods = append(methods, m) - case explicit: - panic("duplicate method " + m.name) - default: - // check method signatures after all locally embedded interfaces are computed - todo = append(todo, m, other.(*Func)) - } - } - - for _, m := range t.methods { - addMethod(m, true) - } - - allTypes := t.types - - for _, typ := range t.embeddeds { - utyp := under(typ) - etyp := asInterface(utyp) - if etyp == nil { - if utyp != Typ[Invalid] { - panic(fmt.Sprintf("%s is not an interface", typ)) - } - continue - } - etyp.Complete() - for _, m := range etyp.allMethods { - addMethod(m, false) - } - allTypes = intersect(allTypes, etyp.allTypes) - } - - for i := 0; i < len(todo); i += 2 { - m := todo[i] - other := todo[i+1] - if !Identical(m.typ, other.typ) { - panic("duplicate method " + m.name) - } - } - - if methods != nil { - sortMethods(methods) - t.allMethods = methods - } - t.allTypes = allTypes - return t } From cc7ceea5859beb5569d1a278e389ae7dd7d13f8b Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 21 May 2021 09:46:40 -0700 Subject: [PATCH 152/940] [dev.typeparams] cmd/compile/internal/types2: simplify Interface accessors Change-Id: Ia97cf88d94de044d61ce2bd364a858bd608c050a Reviewed-on: https://go-review.googlesource.com/c/go/+/321850 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/type.go | 62 +++++-------------------- 1 file changed, 12 insertions(+), 50 deletions(-) diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index db955a8509d..e54f7601bee 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -427,79 +427,41 @@ func (t *Interface) EmbeddedType(i int) Type { return t.embeddeds[i] } // NumMethods returns the total number of methods of interface t. // The interface must have been completed. -func (t *Interface) NumMethods() int { t.assertCompleteness(); return len(t.allMethods) } - -func (t *Interface) assertCompleteness() { - if t.allMethods == nil { - panic("interface is incomplete") - } -} +func (t *Interface) NumMethods() int { t.Complete(); return len(t.allMethods) } // Method returns the i'th method of interface t for 0 <= i < t.NumMethods(). // The methods are ordered by their unique Id. // The interface must have been completed. -func (t *Interface) Method(i int) *Func { t.assertCompleteness(); return t.allMethods[i] } +func (t *Interface) Method(i int) *Func { t.Complete(); return t.allMethods[i] } // Empty reports whether t is the empty interface. func (t *Interface) Empty() bool { - if t.allMethods != nil { - // interface is complete - quick test - // A non-nil allTypes may still be empty and represents the bottom type. - return len(t.allMethods) == 0 && t.allTypes == nil - } - return !t.iterate(func(t *Interface) bool { - return len(t.methods) > 0 || t.types != nil - }, nil) + t.Complete() + // A non-nil allTypes may still have length 0 but represents the bottom type. + return len(t.allMethods) == 0 && t.allTypes == nil } // HasTypeList reports whether interface t has a type list, possibly from an embedded type. func (t *Interface) HasTypeList() bool { - if t.allMethods != nil { - // interface is complete - quick test - return t.allTypes != nil - } - - return t.iterate(func(t *Interface) bool { - return t.types != nil - }, nil) + t.Complete() + return t.allTypes != nil } // IsComparable reports whether interface t is or embeds the predeclared interface "comparable". func (t *Interface) IsComparable() bool { - if t.allMethods != nil { - // interface is complete - quick test - _, m := lookupMethod(t.allMethods, nil, "==") - return m != nil - } - - return t.iterate(func(t *Interface) bool { - _, m := lookupMethod(t.methods, nil, "==") - return m != nil - }, nil) + t.Complete() + _, m := lookupMethod(t.allMethods, nil, "==") + return m != nil } // IsConstraint reports t.HasTypeList() || t.IsComparable(). func (t *Interface) IsConstraint() bool { - if t.allMethods != nil { - // interface is complete - quick test - if t.allTypes != nil { - return true - } - _, m := lookupMethod(t.allMethods, nil, "==") - return m != nil - } - - return t.iterate(func(t *Interface) bool { - if t.types != nil { - return true - } - _, m := lookupMethod(t.methods, nil, "==") - return m != nil - }, nil) + return t.HasTypeList() || t.IsComparable() } // iterate calls f with t and then with any embedded interface of t, recursively, until f returns true. // iterate reports whether any call to f returned true. +// TODO(gri) This is now only used by infer.go - see if we can eliminate it. func (t *Interface) iterate(f func(*Interface) bool, seen map[*Interface]bool) bool { if f(t) { return true From 5770d7a63743ddfd0e78877f162cbbf18ffb9c1d Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 20 May 2021 15:13:04 -0700 Subject: [PATCH 153/940] [dev.typeparams] cmd/compile/internal/types2: accept embedded interface elements Accept embedded interface elements of the form ~T or A|B and treat them like type lists: for now the elements of a union cannot be interfaces. Also, translate existing style "type"- lists in interfaces into interface elements: "type a, b, c" becomes a union element "~a|~b|~c" which in turn is handled internally like a type list. For now, "~" is still ignored and type lists are mapped to Sum types as before, thus ensuring that all existing tests work as before (with some minor adjustments). Introduced a new Union type to represent union elements. For now they don't make it past interface completion where they are represented as a Sum type. Thus, except for printing (and the respective tests) and substitution for interfaces, the various type switches ignore Union types. In a next step, we'll replace Sum types with union types and then consider the ~ functionality as well. Because union elements are no different from embedded interfaces we don't need a separate Interface.types field anymore. Removed. For #45346. Change-Id: I98ac3286aea9d706e98aee80241d4712ed99af08 Reviewed-on: https://go-review.googlesource.com/c/go/+/321689 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/noder/types.go | 18 +- src/cmd/compile/internal/types2/builtins.go | 2 +- src/cmd/compile/internal/types2/index.go | 2 +- src/cmd/compile/internal/types2/infer.go | 5 +- src/cmd/compile/internal/types2/interface.go | 223 +++++++++--------- src/cmd/compile/internal/types2/predicates.go | 3 + src/cmd/compile/internal/types2/sanitize.go | 8 +- .../compile/internal/types2/sizeof_test.go | 3 +- src/cmd/compile/internal/types2/sizes.go | 2 + src/cmd/compile/internal/types2/subst.go | 16 +- .../internal/types2/testdata/check/decls0.src | 2 +- .../internal/types2/testdata/check/issues.src | 2 +- .../types2/testdata/check/typeinst2.go2 | 6 +- .../types2/testdata/examples/constraints.go2 | 25 ++ .../types2/testdata/fixedbugs/issue39634.go2 | 2 +- .../types2/testdata/fixedbugs/issue39693.go2 | 17 +- .../types2/testdata/fixedbugs/issue39711.go2 | 4 +- .../types2/testdata/fixedbugs/issue39723.go2 | 2 +- .../types2/testdata/fixedbugs/issue39948.go2 | 8 +- src/cmd/compile/internal/types2/type.go | 1 - src/cmd/compile/internal/types2/typestring.go | 21 +- .../internal/types2/typestring_test.go | 4 +- src/cmd/compile/internal/types2/unify.go | 3 + src/cmd/compile/internal/types2/union.go | 105 +++++++++ 24 files changed, 325 insertions(+), 159 deletions(-) create mode 100644 src/cmd/compile/internal/types2/testdata/examples/constraints.go2 create mode 100644 src/cmd/compile/internal/types2/union.go diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go index 7fdad29e163..16d664f5380 100644 --- a/src/cmd/compile/internal/noder/types.go +++ b/src/cmd/compile/internal/noder/types.go @@ -187,14 +187,18 @@ func (g *irgen) typ0(typ types2.Type) *types.Type { for i := range embeddeds { // TODO(mdempsky): Get embedding position. e := typ.EmbeddedType(i) - if t := types2.AsInterface(e); t != nil && t.IsComparable() { - // Ignore predefined type 'comparable', since it - // doesn't resolve and it doesn't have any - // relevant methods. - continue + if t := types2.AsInterface(e); t != nil { + if t.IsComparable() { + // Ignore predefined type 'comparable', since it + // doesn't resolve and it doesn't have any + // relevant methods. + continue + } + embeddeds[j] = types.NewField(src.NoXPos, nil, g.typ1(e)) + j++ } - embeddeds[j] = types.NewField(src.NoXPos, nil, g.typ1(e)) - j++ + // Ignore embedded non-interface types - they correspond + // to type lists which we currently don't handle here. } embeddeds = embeddeds[:j] diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index b9e178dd576..94fb506d801 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -769,7 +769,7 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { tpar := NewTypeName(nopos, nil /* = Universe pkg */, "", nil) ptyp := check.NewTypeParam(tpar, 0, &emptyInterface) // assigns type to tpar as a side-effect tsum := NewSum(rtypes) - ptyp.bound = &Interface{types: tsum, allMethods: markComplete, allTypes: tsum} + ptyp.bound = &Interface{allMethods: markComplete, allTypes: tsum} return ptyp } diff --git a/src/cmd/compile/internal/types2/index.go b/src/cmd/compile/internal/types2/index.go index c94017a8fb9..33e79aac3eb 100644 --- a/src/cmd/compile/internal/types2/index.go +++ b/src/cmd/compile/internal/types2/index.go @@ -126,7 +126,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo case *TypeParam: check.errorf(x, "type of %s contains a type parameter - cannot index (implementation restriction)", x) case *instance: - panic("unimplemented") + unimplemented() } if e == nil || telem != nil && !Identical(e, telem) { return false diff --git a/src/cmd/compile/internal/types2/infer.go b/src/cmd/compile/internal/types2/infer.go index f37d7f6477e..d8865784a5c 100644 --- a/src/cmd/compile/internal/types2/infer.go +++ b/src/cmd/compile/internal/types2/infer.go @@ -320,6 +320,9 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { // Thus, we only need to look at the input and result parameters. return w.isParameterized(t.params) || w.isParameterized(t.results) + case *Union: + unimplemented() + case *Interface: if t.allMethods != nil { // interface is complete - quick test @@ -337,7 +340,7 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { return true } } - return w.isParameterizedList(unpack(t.types)) + return w.isParameterizedList(t.embeddeds) }, nil) case *Map: diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go index 21968b34aa7..d590066ad60 100644 --- a/src/cmd/compile/internal/types2/interface.go +++ b/src/cmd/compile/internal/types2/interface.go @@ -11,72 +11,84 @@ import ( ) func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType, def *Named) { - var tname *syntax.Name // most recent "type" name - var types []syntax.Expr + var tlist []syntax.Expr // types collected from all type lists + var tname *syntax.Name // most recent "type" name + for _, f := range iface.MethodList { - if f.Name != nil { - // We have a method with name f.Name, or a type - // of a type list (f.Name.Value == "type"). - name := f.Name.Value - if name == "_" { - if check.conf.CompilerErrorMessages { - check.error(f.Name, "methods must have a unique non-blank name") - } else { - check.error(f.Name, "invalid method name _") - } - continue // ignore - } - - if name == "type" { - // Always collect all type list entries, even from - // different type lists, under the assumption that - // the author intended to include all types. - types = append(types, f.Type) - if tname != nil && tname != f.Name { - check.error(f.Name, "cannot have multiple type lists in an interface") - } - tname = f.Name - continue - } - - typ := check.typ(f.Type) - sig, _ := typ.(*Signature) - if sig == nil { - if typ != Typ[Invalid] { - check.errorf(f.Type, invalidAST+"%s is not a method signature", typ) - } - continue // ignore - } - - // Always type-check method type parameters but complain if they are not enabled. - // (This extra check is needed here because interface method signatures don't have - // a receiver specification.) - if sig.tparams != nil && !acceptMethodTypeParams { - check.error(f.Type, "methods cannot have type parameters") - } - - // use named receiver type if available (for better error messages) - var recvTyp Type = ityp - if def != nil { - recvTyp = def - } - sig.recv = NewVar(f.Name.Pos(), check.pkg, "", recvTyp) - - m := NewFunc(f.Name.Pos(), check.pkg, name, sig) - check.recordDef(f.Name, m) - ityp.methods = append(ityp.methods, m) - } else { - // We have an embedded type. completeInterface will - // eventually verify that we have an interface. - ityp.embeddeds = append(ityp.embeddeds, check.typ(f.Type)) + if f.Name == nil { + // We have an embedded type; possibly a union of types. + ityp.embeddeds = append(ityp.embeddeds, parseUnion(check, flattenUnion(nil, f.Type))) check.posMap[ityp] = append(check.posMap[ityp], f.Type.Pos()) + continue } + // f.Name != nil + + // We have a method with name f.Name, or a type of a type list (f.Name.Value == "type"). + name := f.Name.Value + if name == "_" { + if check.conf.CompilerErrorMessages { + check.error(f.Name, "methods must have a unique non-blank name") + } else { + check.error(f.Name, "invalid method name _") + } + continue // ignore + } + + if name == "type" { + // For now, collect all type list entries as if it + // were a single union, where each union element is + // of the form ~T. + // TODO(gri) remove once we disallow type lists + op := new(syntax.Operation) + // We should also set the position (but there is no setter); + // we don't care because this code will eventually go away. + op.Op = syntax.Tilde + op.X = f.Type + tlist = append(tlist, op) + if tname != nil && tname != f.Name { + check.error(f.Name, "cannot have multiple type lists in an interface") + } + tname = f.Name + continue + } + + typ := check.typ(f.Type) + sig, _ := typ.(*Signature) + if sig == nil { + if typ != Typ[Invalid] { + check.errorf(f.Type, invalidAST+"%s is not a method signature", typ) + } + continue // ignore + } + + // Always type-check method type parameters but complain if they are not enabled. + // (This extra check is needed here because interface method signatures don't have + // a receiver specification.) + if sig.tparams != nil && !acceptMethodTypeParams { + check.error(f.Type, "methods cannot have type parameters") + } + + // use named receiver type if available (for better error messages) + var recvTyp Type = ityp + if def != nil { + recvTyp = def + } + sig.recv = NewVar(f.Name.Pos(), check.pkg, "", recvTyp) + + m := NewFunc(f.Name.Pos(), check.pkg, name, sig) + check.recordDef(f.Name, m) + ityp.methods = append(ityp.methods, m) } - // type constraints - ityp.types = NewSum(check.collectTypeConstraints(iface.Pos(), types)) + // If we saw a type list, add it like an embedded union. + if tlist != nil { + ityp.embeddeds = append(ityp.embeddeds, parseUnion(check, tlist)) + // Types T in a type list are added as ~T expressions but we don't + // have the position of the '~'. Use the first type position instead. + check.posMap[ityp] = append(check.posMap[ityp], tlist[0].(*syntax.Operation).X.Pos()) + } - if len(ityp.methods) == 0 && ityp.types == nil && len(ityp.embeddeds) == 0 { + if len(ityp.methods) == 0 && len(ityp.embeddeds) == 0 { // empty interface ityp.allMethods = markComplete return @@ -89,32 +101,12 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType check.later(func() { check.completeInterface(iface.Pos(), ityp) }) } -func (check *Checker) collectTypeConstraints(pos syntax.Pos, types []syntax.Expr) []Type { - list := make([]Type, 0, len(types)) // assume all types are correct - for _, texpr := range types { - if texpr == nil { - check.error(pos, invalidAST+"missing type constraint") - continue - } - list = append(list, check.varType(texpr)) +func flattenUnion(list []syntax.Expr, x syntax.Expr) []syntax.Expr { + if o, _ := x.(*syntax.Operation); o != nil && o.Op == syntax.Or { + list = flattenUnion(list, o.X) + x = o.Y } - - // Ensure that each type is only present once in the type list. Types may be - // interfaces, which may not be complete yet. It's ok to do this check at the - // end because it's not a requirement for correctness of the code. - // Note: This is a quadratic algorithm, but type lists tend to be short. - check.later(func() { - for i, t := range list { - if t := asInterface(t); t != nil { - check.completeInterface(types[i].Pos(), t) - } - if includes(list[:i], t) { - check.softErrorf(types[i], "duplicate type %s in type list", t) - } - } - }) - - return list + return append(list, x) } // includes reports whether typ is in list @@ -143,6 +135,7 @@ func (check *Checker) completeInterface(pos syntax.Pos, ityp *Interface) { completeInterface(check, pos, ityp) } +// completeInterface may be called with check == nil. func completeInterface(check *Checker, pos syntax.Pos, ityp *Interface) { assert(ityp.allMethods == nil) @@ -195,6 +188,7 @@ func completeInterface(check *Checker, pos syntax.Pos, ityp *Interface) { if check == nil { panic(fmt.Sprintf("%s: duplicate method %s", m.pos, m.name)) } + // check != nil var err error_ err.errorf(pos, "duplicate method %s", m.name) err.errorf(mpos[other.(*Func)], "other declaration of %s", m.name) @@ -210,6 +204,7 @@ func completeInterface(check *Checker, pos syntax.Pos, ityp *Interface) { todo = append(todo, m, other.(*Func)) break } + // check != nil check.later(func() { if !check.allowVersion(m.pkg, 1, 14) || !check.identical(m.typ, other.Type()) { var err error_ @@ -225,9 +220,8 @@ func completeInterface(check *Checker, pos syntax.Pos, ityp *Interface) { addMethod(m.pos, m, true) } - // collect types - allTypes := ityp.types - + // collect embedded elements + var allTypes Type var posList []syntax.Pos if check != nil { posList = check.posMap[ityp] @@ -237,31 +231,36 @@ func completeInterface(check *Checker, pos syntax.Pos, ityp *Interface) { if posList != nil { pos = posList[i] } - utyp := under(typ) - etyp := asInterface(utyp) - if etyp == nil { - if utyp != Typ[Invalid] { - var format string - if _, ok := utyp.(*TypeParam); ok { - format = "%s is a type parameter, not an interface" - } else { - format = "%s is not an interface" - } - if check != nil { - check.errorf(pos, format, typ) - } else { - panic(fmt.Sprintf("%s: "+format, pos, typ)) - } + var types Type + switch t := under(typ).(type) { + case *Interface: + if t.allMethods == nil { + completeInterface(check, pos, t) } - continue + for _, m := range t.allMethods { + addMethod(pos, m, false) // use embedding position pos rather than m.pos + } + types = t.allTypes + case *Union: + types = NewSum(t.terms) + // TODO(gri) don't ignore tilde information + case *TypeParam: + if check != nil && !check.allowVersion(check.pkg, 1, 18) { + check.errorf(pos, "%s is a type parameter, not an interface", typ) + continue + } + types = t + default: + if t == Typ[Invalid] { + continue + } + if check != nil && !check.allowVersion(check.pkg, 1, 18) { + check.errorf(pos, "%s is not an interface", typ) + continue + } + types = t } - if etyp.allMethods == nil { - completeInterface(check, pos, etyp) - } - for _, m := range etyp.allMethods { - addMethod(pos, m, false) // use embedding position pos rather than m.pos - } - allTypes = intersect(allTypes, etyp.allTypes) + allTypes = intersect(allTypes, types) } // process todo's (this only happens if check == nil) @@ -281,7 +280,7 @@ func completeInterface(check *Checker, pos syntax.Pos, ityp *Interface) { } // intersect computes the intersection of the types x and y. -// Note: A incomming nil type stands for the top type. A top +// Note: An incomming nil type stands for the top type. A top // type result is returned as nil. func intersect(x, y Type) (r Type) { defer func() { diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go index ae186a0b5d1..ab0a4572767 100644 --- a/src/cmd/compile/internal/types2/predicates.go +++ b/src/cmd/compile/internal/types2/predicates.go @@ -284,6 +284,9 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { return true } + case *Union: + unimplemented() + case *Interface: // Two interface types are identical if they have the same set of methods with // the same names and identical function types. Lower-case method names from diff --git a/src/cmd/compile/internal/types2/sanitize.go b/src/cmd/compile/internal/types2/sanitize.go index 64a2dedc7d8..9fad52e2242 100644 --- a/src/cmd/compile/internal/types2/sanitize.go +++ b/src/cmd/compile/internal/types2/sanitize.go @@ -109,11 +109,11 @@ func (s sanitizer) typ(typ Type) Type { case *Sum: s.typeList(t.types) + case *Union: + s.typeList(t.terms) + case *Interface: s.funcList(t.methods) - if types := s.typ(t.types); types != t.types { - t.types = types - } s.typeList(t.embeddeds) s.funcList(t.allMethods) if allTypes := s.typ(t.allTypes); allTypes != t.allTypes { @@ -153,7 +153,7 @@ func (s sanitizer) typ(typ Type) Type { s[t] = typ default: - panic("unimplemented") + unimplemented() } return typ diff --git a/src/cmd/compile/internal/types2/sizeof_test.go b/src/cmd/compile/internal/types2/sizeof_test.go index 236feb0404e..552f3488cd8 100644 --- a/src/cmd/compile/internal/types2/sizeof_test.go +++ b/src/cmd/compile/internal/types2/sizeof_test.go @@ -28,7 +28,8 @@ func TestSizeof(t *testing.T) { {Tuple{}, 12, 24}, {Signature{}, 44, 88}, {Sum{}, 12, 24}, - {Interface{}, 60, 120}, + {Union{}, 24, 48}, + {Interface{}, 52, 104}, {Map{}, 16, 32}, {Chan{}, 12, 24}, {Named{}, 68, 136}, diff --git a/src/cmd/compile/internal/types2/sizes.go b/src/cmd/compile/internal/types2/sizes.go index aa0fbf40fce..c6b807cd065 100644 --- a/src/cmd/compile/internal/types2/sizes.go +++ b/src/cmd/compile/internal/types2/sizes.go @@ -150,6 +150,8 @@ func (s *StdSizes) Sizeof(T Type) int64 { return offsets[n-1] + s.Sizeof(t.fields[n-1].typ) case *Sum: panic("Sizeof unimplemented for type sum") + case *Union: + unimplemented() case *Interface: return s.WordSize * 2 } diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index c8e428c1832..04a3527d6d7 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -299,15 +299,19 @@ func (subst *subster) typ(typ Type) Type { return NewSum(types) } + case *Union: + terms, copied := subst.typeList(t.terms) + if copied { + // TODO(gri) Do we need to remove duplicates that may have + // crept in after substitution? It may not matter. + return newUnion(terms, t.tilde) + } + case *Interface: methods, mcopied := subst.funcList(t.methods) - types := t.types - if t.types != nil { - types = subst.typ(t.types) - } embeddeds, ecopied := subst.typeList(t.embeddeds) - if mcopied || types != t.types || ecopied { - iface := &Interface{methods: methods, types: types, embeddeds: embeddeds} + if mcopied || ecopied { + iface := &Interface{methods: methods, embeddeds: embeddeds} if subst.check == nil { panic("internal error: cannot instantiate interfaces yet") } diff --git a/src/cmd/compile/internal/types2/testdata/check/decls0.src b/src/cmd/compile/internal/types2/testdata/check/decls0.src index 80bf4ebb3db..f051a4f2acb 100644 --- a/src/cmd/compile/internal/types2/testdata/check/decls0.src +++ b/src/cmd/compile/internal/types2/testdata/check/decls0.src @@ -4,7 +4,7 @@ // type declarations -package decls0 +package go1_17 // don't permit non-interface elements in interfaces import "unsafe" diff --git a/src/cmd/compile/internal/types2/testdata/check/issues.src b/src/cmd/compile/internal/types2/testdata/check/issues.src index 21aa208cc76..60d23b3c3bc 100644 --- a/src/cmd/compile/internal/types2/testdata/check/issues.src +++ b/src/cmd/compile/internal/types2/testdata/check/issues.src @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package issues +package go1_17 // don't permit non-interface elements in interfaces import ( "fmt" diff --git a/src/cmd/compile/internal/types2/testdata/check/typeinst2.go2 b/src/cmd/compile/internal/types2/testdata/check/typeinst2.go2 index 6e2104a5150..1096bb42eb7 100644 --- a/src/cmd/compile/internal/types2/testdata/check/typeinst2.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/typeinst2.go2 @@ -164,12 +164,12 @@ type _ interface { // for them to be all in a single list, and we report the error // as well.) type _ interface { - type int, int /* ERROR duplicate type int */ - type /* ERROR multiple type lists */ int /* ERROR duplicate type int */ + type int, int /* ERROR duplicate term int */ + type /* ERROR multiple type lists */ int /* ERROR duplicate term int */ } type _ interface { - type struct{f int}, struct{g int}, struct /* ERROR duplicate type */ {f int} + type struct{f int}, struct{g int}, struct /* ERROR duplicate term */ {f int} } // Interface type lists can contain any type, incl. *Named types. diff --git a/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 b/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 new file mode 100644 index 00000000000..e8b3912884c --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 @@ -0,0 +1,25 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file shows some examples of generic constraint interfaces. + +package p + +type ( + // Arbitrary types may be embedded like interfaces. + _ interface{int} + _ interface{~int} + + // Types may be combined into a union. + _ interface{int|~string} + + // Union terms must be unique independent of whether they are ~ or not. + _ interface{int|int /* ERROR duplicate term int */ } + _ interface{int|~ /* ERROR duplicate term int */ int } + _ interface{~int|~ /* ERROR duplicate term int */ int } + + // For now we do not permit interfaces with ~ or in unions. + _ interface{~ /* ERROR cannot use interface */ interface{}} + _ interface{int|interface /* ERROR cannot use interface */ {}} +) diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2 index 2c1299feb09..92ea3054795 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2 @@ -36,7 +36,7 @@ func bar8[A foo8[A]](a A) {} func main8() {} // crash 9 -type foo9[A any] interface { type foo9 /* ERROR interface contains type constraints */ [A] } +type foo9[A any] interface { type foo9 /* ERROR cannot use interface */ [A] } func _() { var _ = new(foo9 /* ERROR interface contains type constraints */ [int]) } // crash 12 diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39693.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39693.go2 index 316ab1982e8..301c13be41c 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39693.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39693.go2 @@ -4,11 +4,20 @@ package p -type Number interface { - int /* ERROR int is not an interface */ - float64 /* ERROR float64 is not an interface */ +type Number1 interface { + // embedding non-interface types is permitted + int + float64 } -func Add[T Number](a, b T) T { +func Add1[T Number1](a, b T) T { return a /* ERROR not defined */ + b } + +type Number2 interface { + int|float64 +} + +func Add2[T Number2](a, b T) T { + return a + b +} diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39711.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39711.go2 index df621a4c173..85eb0a78fe2 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39711.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39711.go2 @@ -7,5 +7,7 @@ package p // Do not report a duplicate type error for this type list. // (Check types after interfaces have been completed.) type _ interface { - type interface{ Error() string }, interface{ String() string } + // TODO(gri) Once we have full type sets we can enable this again. + // Fow now we don't permit interfaces in type lists. + // type interface{ Error() string }, interface{ String() string } } diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39723.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39723.go2 index 55464e6b775..61bc6067892 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39723.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39723.go2 @@ -6,4 +6,4 @@ package p // A constraint must be an interface; it cannot // be a type parameter, for instance. -func _[A interface{ type interface{} }, B A /* ERROR not an interface */ ]() +func _[A interface{ type int }, B A /* ERROR not an interface */ ]() diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39948.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39948.go2 index c2b460902cc..6372397ed92 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39948.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39948.go2 @@ -2,7 +2,13 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package p +// TODO(gri) Eventually, once we disallow type lists, we need to +// adjust this code: for 1.17 we don't accept type parameters, +// and for 1.18 this code is valid. +// Leaving for now so we can see that existing errors +// are being reported. + +package go1_17 // don't permit non-interface elements in interfaces type T[P any] interface{ P // ERROR P is a type parameter, not an interface diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index e54f7601bee..79a8f3cd7f4 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -311,7 +311,6 @@ func (s *Sum) is(pred func(Type) bool) bool { // An Interface represents an interface type. type Interface struct { methods []*Func // ordered list of explicitly declared methods - types Type // (possibly a Sum) type declared with a type list (TODO(gri) need better field name) embeddeds []Type // ordered list of explicitly embedded types allMethods []*Func // ordered list of methods declared with or embedded in this interface (TODO(gri): replace with mset) diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go index c534b041308..55858b7b42a 100644 --- a/src/cmd/compile/internal/types2/typestring.go +++ b/src/cmd/compile/internal/types2/typestring.go @@ -158,11 +158,17 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { writeSignature(buf, t, qf, visited) case *Sum: - for i, t := range t.types { + writeTypeList(buf, t.types, qf, visited) + + case *Union: + for i, e := range t.terms { if i > 0 { - buf.WriteString(", ") + buf.WriteString("|") } - writeType(buf, t, qf, visited) + if t.tilde[i] { + buf.WriteByte('~') + } + writeType(buf, e, qf, visited) } case *Interface: @@ -207,14 +213,6 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { writeSignature(buf, m.typ.(*Signature), qf, visited) empty = false } - if !empty && t.types != nil { - buf.WriteString("; ") - } - if t.types != nil { - buf.WriteString("type ") - writeType(buf, t.types, qf, visited) - empty = false - } if !empty && len(t.embeddeds) > 0 { buf.WriteString("; ") } @@ -307,6 +305,7 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { default: // For externally defined implementations of Type. + // Note: In this case cycles won't be caught. buf.WriteString(t.String()) } } diff --git a/src/cmd/compile/internal/types2/typestring_test.go b/src/cmd/compile/internal/types2/typestring_test.go index 618fdc0757d..8d0ca760bfc 100644 --- a/src/cmd/compile/internal/types2/typestring_test.go +++ b/src/cmd/compile/internal/types2/typestring_test.go @@ -91,7 +91,9 @@ var independentTestTypes = []testEntry{ dup("interface{}"), dup("interface{m()}"), dup(`interface{String() string; m(int) float32}`), - dup(`interface{type int, float32, complex128}`), + {"interface{type int, float32, complex128}", "interface{~int|~float32|~complex128}"}, + dup("interface{int|float32|complex128}"), + dup("interface{int|~float32|~complex128}"), // maps dup("map[string]int"), diff --git a/src/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go index e1832bbb2a3..f1630b75d0e 100644 --- a/src/cmd/compile/internal/types2/unify.go +++ b/src/cmd/compile/internal/types2/unify.go @@ -356,6 +356,9 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool { // This should not happen with the current internal use of sum types. panic("type inference across sum types not implemented") + case *Union: + unimplemented() + case *Interface: // Two interface types are identical if they have the same set of methods with // the same names and identical function types. Lower-case method names from diff --git a/src/cmd/compile/internal/types2/union.go b/src/cmd/compile/internal/types2/union.go new file mode 100644 index 00000000000..70dc3bc360b --- /dev/null +++ b/src/cmd/compile/internal/types2/union.go @@ -0,0 +1,105 @@ +// Copyright 2021 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 types2 + +import "cmd/compile/internal/syntax" + +// ---------------------------------------------------------------------------- +// API + +// A Union represents a union of terms. +// A term is a type, possibly with a ~ (tilde) indication. +type Union struct { + terms []Type // terms are unique + tilde []bool // if tilde[i] is set, terms[i] is of the form ~T +} + +func NewUnion(terms []Type, tilde []bool) Type { return newUnion(terms, tilde) } + +func (u *Union) NumTerms() int { return len(u.terms) } +func (u *Union) Term(i int) (Type, bool) { return u.terms[i], u.tilde[i] } + +func (u *Union) Underlying() Type { return u } +func (u *Union) String() string { return TypeString(u, nil) } + +// ---------------------------------------------------------------------------- +// Implementation + +func newUnion(terms []Type, tilde []bool) Type { + assert(len(terms) == len(tilde)) + if terms == nil { + return nil + } + t := new(Union) + t.terms = terms + t.tilde = tilde + return t +} + +func parseUnion(check *Checker, tlist []syntax.Expr) Type { + var terms []Type + var tilde []bool + for _, x := range tlist { + t, d := parseTilde(check, x) + if len(tlist) == 1 && !d { + return t // single type + } + terms = append(terms, t) + tilde = append(tilde, d) + } + + // Ensure that each type is only present once in the type list. + // It's ok to do this check at the end because it's not a requirement + // for correctness of the code. + // Note: This is a quadratic algorithm, but unions tend to be short. + check.later(func() { + for i, t := range terms { + t := expand(t) + if t == Typ[Invalid] { + continue + } + + x := tlist[i] + pos := syntax.StartPos(x) + // We may not know the position of x if it was a typechecker- + // introduced ~T type of a type list entry T. Use the position + // of T instead. + // TODO(gri) remove this test once we don't support type lists anymore + if !pos.IsKnown() { + if op, _ := x.(*syntax.Operation); op != nil { + pos = syntax.StartPos(op.X) + } + } + + u := under(t) + if tilde[i] { + // TODO(gri) enable this check once we have converted tests + // if !Identical(u, t) { + // check.errorf(x, "invalid use of ~ (underlying type of %s is %s)", t, u) + // } + } + if _, ok := u.(*Interface); ok { + check.errorf(pos, "cannot use interface %s with ~ or inside a union (implementation restriction)", t) + } + + // Complain about duplicate entries a|a, but also a|~a, and ~a|~a. + if includes(terms[:i], t) { + // TODO(gri) this currently doesn't print the ~ if present + check.softErrorf(pos, "duplicate term %s in union element", t) + } + } + }) + + return newUnion(terms, tilde) +} + +func parseTilde(check *Checker, x syntax.Expr) (Type, bool) { + tilde := false + if op, _ := x.(*syntax.Operation); op != nil && op.Op == syntax.Tilde { + x = op.X + tilde = true + } + return check.anyType(x), tilde +} From 155dc0e541368bbd208bfcf12985f58fb375dd5c Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 21 May 2021 19:46:45 -0700 Subject: [PATCH 154/940] [dev.typeparams] cmd/compile/internal/types2: factor out constraint satisfaction check This is a simple move of a block of inlined code into a function to make instantiation more manageable and easier to understand. There is no change in functionality or behavior. Change-Id: I46e7a9ea03527731e1f0219b3402eb03949627c5 Reviewed-on: https://go-review.googlesource.com/c/go/+/322070 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/subst.go | 156 ++++++++++++----------- 1 file changed, 82 insertions(+), 74 deletions(-) diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index 04a3527d6d7..a2b81ba0cc0 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -119,85 +119,13 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, poslis // check bounds for i, tname := range tparams { - tpar := tname.typ.(*TypeParam) - iface := tpar.Bound() - if iface.Empty() { - continue // no type bound - } - - targ := targs[i] - // best position for error reporting pos := pos if i < len(poslist) { pos = poslist[i] } - - // The type parameter bound is parameterized with the same type parameters - // as the instantiated type; before we can use it for bounds checking we - // need to instantiate it with the type arguments with which we instantiate - // the parameterized type. - iface = check.subst(pos, iface, smap).(*Interface) - - // targ must implement iface (methods) - // - check only if we have methods - check.completeInterface(nopos, iface) - if len(iface.allMethods) > 0 { - // If the type argument is a pointer to a type parameter, the type argument's - // method set is empty. - // TODO(gri) is this what we want? (spec question) - if base, isPtr := deref(targ); isPtr && asTypeParam(base) != nil { - check.errorf(pos, "%s has no methods", targ) - break - } - if m, wrong := check.missingMethod(targ, iface, true); m != nil { - // TODO(gri) needs to print updated name to avoid major confusion in error message! - // (print warning for now) - // Old warning: - // check.softErrorf(pos, "%s does not satisfy %s (warning: name not updated) = %s (missing method %s)", targ, tpar.bound, iface, m) - if m.name == "==" { - // We don't want to report "missing method ==". - check.softErrorf(pos, "%s does not satisfy comparable", targ) - } else if wrong != nil { - // TODO(gri) This can still report uninstantiated types which makes the error message - // more difficult to read then necessary. - check.softErrorf(pos, - "%s does not satisfy %s: wrong method signature\n\tgot %s\n\twant %s", - targ, tpar.bound, wrong, m, - ) - } else { - check.softErrorf(pos, "%s does not satisfy %s (missing method %s)", targ, tpar.bound, m.name) - } - break - } - } - - // targ's underlying type must also be one of the interface types listed, if any - if iface.allTypes == nil { - continue // nothing to do - } - - // If targ is itself a type parameter, each of its possible types, but at least one, must be in the - // list of iface types (i.e., the targ type list must be a non-empty subset of the iface types). - if targ := asTypeParam(targ); targ != nil { - targBound := targ.Bound() - if targBound.allTypes == nil { - check.softErrorf(pos, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ) - break - } - for _, t := range unpack(targBound.allTypes) { - if !iface.isSatisfiedBy(t) { - // TODO(gri) match this error message with the one below (or vice versa) - check.softErrorf(pos, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, t, iface.allTypes) - break - } - } - break - } - - // Otherwise, targ's type or underlying type must also be one of the interface types listed, if any. - if !iface.isSatisfiedBy(targ) { - check.softErrorf(pos, "%s does not satisfy %s (%s not found in %s)", targ, tpar.bound, under(targ), iface.allTypes) + // stop checking bounds after the first failure + if !check.satisfies(pos, targs[i], tname.typ.(*TypeParam), smap) { break } } @@ -205,6 +133,86 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, poslis return check.subst(pos, typ, smap) } +// satisfies reports whether the type argument targ satisfies the constraint of type parameter +// parameter tpar (after any of its type parameters have been substituted through smap). +// A suitable error is reported if the result is false. +func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap *substMap) bool { + iface := tpar.Bound() + if iface.Empty() { + return true // no type bound + } + + // The type parameter bound is parameterized with the same type parameters + // as the instantiated type; before we can use it for bounds checking we + // need to instantiate it with the type arguments with which we instantiate + // the parameterized type. + iface = check.subst(pos, iface, smap).(*Interface) + + // targ must implement iface (methods) + // - check only if we have methods + check.completeInterface(nopos, iface) + if len(iface.allMethods) > 0 { + // If the type argument is a pointer to a type parameter, the type argument's + // method set is empty. + // TODO(gri) is this what we want? (spec question) + if base, isPtr := deref(targ); isPtr && asTypeParam(base) != nil { + check.errorf(pos, "%s has no methods", targ) + return false + } + if m, wrong := check.missingMethod(targ, iface, true); m != nil { + // TODO(gri) needs to print updated name to avoid major confusion in error message! + // (print warning for now) + // Old warning: + // check.softErrorf(pos, "%s does not satisfy %s (warning: name not updated) = %s (missing method %s)", targ, tpar.bound, iface, m) + if m.name == "==" { + // We don't want to report "missing method ==". + check.softErrorf(pos, "%s does not satisfy comparable", targ) + } else if wrong != nil { + // TODO(gri) This can still report uninstantiated types which makes the error message + // more difficult to read then necessary. + check.softErrorf(pos, + "%s does not satisfy %s: wrong method signature\n\tgot %s\n\twant %s", + targ, tpar.bound, wrong, m, + ) + } else { + check.softErrorf(pos, "%s does not satisfy %s (missing method %s)", targ, tpar.bound, m.name) + } + return false + } + } + + // targ's underlying type must also be one of the interface types listed, if any + if iface.allTypes == nil { + return true // nothing to do + } + + // If targ is itself a type parameter, each of its possible types, but at least one, must be in the + // list of iface types (i.e., the targ type list must be a non-empty subset of the iface types). + if targ := asTypeParam(targ); targ != nil { + targBound := targ.Bound() + if targBound.allTypes == nil { + check.softErrorf(pos, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ) + return false + } + for _, t := range unpack(targBound.allTypes) { + if !iface.isSatisfiedBy(t) { + // TODO(gri) match this error message with the one below (or vice versa) + check.softErrorf(pos, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, t, iface.allTypes) + return false + } + } + return false + } + + // Otherwise, targ's type or underlying type must also be one of the interface types listed, if any. + if !iface.isSatisfiedBy(targ) { + check.softErrorf(pos, "%s does not satisfy %s (%s not found in %s)", targ, tpar.bound, under(targ), iface.allTypes) + return false + } + + return true +} + // subst returns the type typ with its type parameters tpars replaced by // the corresponding type arguments targs, recursively. // subst is functional in the sense that it doesn't modify the incoming From 8b462d75670dcd8b6a08cf9af225eb8e7628d412 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Fri, 14 May 2021 16:53:06 -0400 Subject: [PATCH 155/940] cmd/go: add a -compat flag to 'go mod tidy' Fixes #46141 Change-Id: I9d4032e75252ade9eaa937389ea97ef3fb287499 Reviewed-on: https://go-review.googlesource.com/c/go/+/321071 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Jay Conrod --- doc/go1.17.html | 5 + src/cmd/go.sum | 23 ++ src/cmd/go/alldocs.go | 10 +- src/cmd/go/internal/modcmd/tidy.go | 17 +- src/cmd/go/internal/modload/init.go | 24 +- src/cmd/go/internal/modload/load.go | 254 +++++++++++++++++- .../go/testdata/script/mod_tidy_compat.txt | 35 ++- .../testdata/script/mod_tidy_compat_added.txt | 105 ++++++++ .../script/mod_tidy_compat_ambiguous.txt | 98 +++++++ .../script/mod_tidy_compat_deleted.txt | 128 +++++++++ .../script/mod_tidy_compat_implicit.txt | 23 +- .../script/mod_tidy_compat_incompatible.txt | 37 ++- .../script/mod_tidy_compat_irrelevant.txt | 34 +-- src/cmd/go/testdata/script/mod_tidy_oldgo.txt | 21 ++ src/go.sum | 7 + 15 files changed, 758 insertions(+), 63 deletions(-) create mode 100644 src/cmd/go/testdata/script/mod_tidy_compat_added.txt create mode 100644 src/cmd/go/testdata/script/mod_tidy_compat_ambiguous.txt create mode 100644 src/cmd/go/testdata/script/mod_tidy_compat_deleted.txt create mode 100644 src/cmd/go/testdata/script/mod_tidy_oldgo.txt diff --git a/doc/go1.17.html b/doc/go1.17.html index 46ee1da6fa6..6dd1d0d1db5 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -106,6 +106,11 @@ Do not send CLs removing the interior tags from such phrases. go mod tidy -go=1.17 +

+ TODO: Describe the -compat flag + for go mod tidy. +

+

Module deprecation comments

diff --git a/src/cmd/go.sum b/src/cmd/go.sum index 9af4978d669..eeb625fcf8a 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -5,18 +5,41 @@ github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a h1:jmAp/2PZAScNd62lTD github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 h1:mV02weKRL81bEnm8A0HT1/CAelMQDBuQIfLw8n+d6xI= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e h1:pv3V0NlNSh5Q6AX/StwGLBjcLS7UN4m4Gq+V+uSecqM= golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI= golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.3-0.20210512182355-6088ed88cecd h1:CuRnpyMrCCBulv0d/y0CswR4K0vGydgE3DZ2wYPIOo8= golang.org/x/mod v0.4.3-0.20210512182355-6088ed88cecd/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 h1:yhBbb4IRs2HS9PPlAg6DMC6mUOKexJBNsLf4Z+6En1Q= golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.2-0.20210519160823-49064d2332f9 h1:2XlR/j4I4xz5GQZI7zBjqTfezYyRIE2jD5IMousB2rg= golang.org/x/tools v0.1.2-0.20210519160823-49064d2332f9/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index fcc7f36335e..bad2b7f16ef 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -1221,7 +1221,7 @@ // // Usage: // -// go mod tidy [-e] [-v] [-go=version] +// go mod tidy [-e] [-v] [-go=version] [-compat=version] // // Tidy makes sure go.mod matches the source code in the module. // It adds any missing modules necessary to build the current module's @@ -1241,6 +1241,14 @@ // (Go versions 1.17 and higher retain more requirements in order to // support lazy module loading.) // +// The -compat flag preserves any additional checksums needed for the +// 'go' command from the indicated major Go release to successfully load +// the module graph, and causes tidy to error out if that version of the +// 'go' command would load any imported package from a different module +// version. By default, tidy acts as if the -compat flag were set to the +// version prior to the one indicated by the 'go' directive in the go.mod +// file. +// // See https://golang.org/ref/mod#go-mod-tidy for more about 'go mod tidy'. // // diff --git a/src/cmd/go/internal/modcmd/tidy.go b/src/cmd/go/internal/modcmd/tidy.go index 9af624028a3..fe25507e94f 100644 --- a/src/cmd/go/internal/modcmd/tidy.go +++ b/src/cmd/go/internal/modcmd/tidy.go @@ -19,7 +19,7 @@ import ( ) var cmdTidy = &base.Command{ - UsageLine: "go mod tidy [-e] [-v] [-go=version]", + UsageLine: "go mod tidy [-e] [-v] [-go=version] [-compat=version]", Short: "add missing and remove unused modules", Long: ` Tidy makes sure go.mod matches the source code in the module. @@ -40,20 +40,30 @@ are retained as explicit requirements in the go.mod file. (Go versions 1.17 and higher retain more requirements in order to support lazy module loading.) +The -compat flag preserves any additional checksums needed for the +'go' command from the indicated major Go release to successfully load +the module graph, and causes tidy to error out if that version of the +'go' command would load any imported package from a different module +version. By default, tidy acts as if the -compat flag were set to the +version prior to the one indicated by the 'go' directive in the go.mod +file. + See https://golang.org/ref/mod#go-mod-tidy for more about 'go mod tidy'. `, Run: runTidy, } var ( - tidyE bool // if true, report errors but proceed anyway. - tidyGo goVersionFlag // go version to write to the tidied go.mod file (toggles lazy loading) + tidyE bool // if true, report errors but proceed anyway. + tidyGo goVersionFlag // go version to write to the tidied go.mod file (toggles lazy loading) + tidyCompat goVersionFlag // go version for which the tidied go.mod and go.sum files should be “compatible” ) func init() { cmdTidy.Flag.BoolVar(&cfg.BuildV, "v", false, "") cmdTidy.Flag.BoolVar(&tidyE, "e", false, "") cmdTidy.Flag.Var(&tidyGo, "go", "") + cmdTidy.Flag.Var(&tidyCompat, "compat", "") base.AddModCommonFlags(&cmdTidy.Flag) } @@ -105,6 +115,7 @@ func runTidy(ctx context.Context, cmd *base.Command, args []string) { GoVersion: tidyGo.String(), Tags: imports.AnyTags(), Tidy: true, + TidyCompatibleVersion: tidyCompat.String(), VendorModulesInGOROOTSrc: true, ResolveMissingImports: true, LoadTests: true, diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go index df9f48e8ea0..86c0db3fe4f 100644 --- a/src/cmd/go/internal/modload/init.go +++ b/src/cmd/go/internal/modload/init.go @@ -767,11 +767,33 @@ func LatestGoVersion() string { tags := build.Default.ReleaseTags version := tags[len(tags)-1] if !strings.HasPrefix(version, "go") || !modfile.GoVersionRE.MatchString(version[2:]) { - base.Fatalf("go: unrecognized default version %q", version) + base.Fatalf("go: internal error: unrecognized default version %q", version) } return version[2:] } +// priorGoVersion returns the Go major release immediately preceding v, +// or v itself if v is the first Go major release (1.0) or not a supported +// Go version. +func priorGoVersion(v string) string { + vTag := "go" + v + tags := build.Default.ReleaseTags + for i, tag := range tags { + if tag == vTag { + if i == 0 { + return v + } + + version := tags[i-1] + if !strings.HasPrefix(version, "go") || !modfile.GoVersionRE.MatchString(version[2:]) { + base.Fatalf("go: internal error: unrecognized version %q", version) + } + return version[2:] + } + } + return v +} + var altConfigs = []string{ "Gopkg.lock", diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go index 37b0032d43e..a9d1777125e 100644 --- a/src/cmd/go/internal/modload/load.go +++ b/src/cmd/go/internal/modload/load.go @@ -152,6 +152,13 @@ type PackageOpts struct { // packages. Tidy bool + // TidyCompatibleVersion is the oldest Go version that must be able to + // reproducibly reload the requested packages. + // + // If empty, the compatible version is the Go version immediately prior to the + // 'go' version listed in the go.mod file. + TidyCompatibleVersion string + // VendorModulesInGOROOTSrc indicates that if we are within a module in // GOROOT/src, packages in the module's vendor directory should be resolved as // actual module dependencies (instead of standard-library packages). @@ -371,7 +378,26 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma } } - modfetch.TrimGoSum(keepSums(ctx, ld, ld.requirements, loadedZipSumsOnly)) + keep := keepSums(ctx, ld, ld.requirements, loadedZipSumsOnly) + if compatDepth := modDepthFromGoVersion(ld.TidyCompatibleVersion); compatDepth != ld.requirements.depth { + compatRS := newRequirements(compatDepth, ld.requirements.rootModules, ld.requirements.direct) + ld.checkTidyCompatibility(ctx, compatRS) + + for m := range keepSums(ctx, ld, compatRS, loadedZipSumsOnly) { + keep[m] = true + } + } + + if allowWriteGoMod { + modfetch.TrimGoSum(keep) + + // commitRequirements below will also call WriteGoSum, but the "keep" map + // we have here could be strictly larger: commitRequirements only commits + // loaded.requirements, but here we may have also loaded (and want to + // preserve checksums for) additional entities from compatRS, which are + // only needed for compatibility with ld.TidyCompatibleVersion. + modfetch.WriteGoSum(keep) + } } // Success! Update go.mod and go.sum (if needed) and return the results. @@ -924,6 +950,17 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader { } } + if ld.Tidy { + if ld.TidyCompatibleVersion == "" { + ld.TidyCompatibleVersion = priorGoVersion(ld.GoVersion) + } else if semver.Compare("v"+ld.TidyCompatibleVersion, "v"+ld.GoVersion) > 0 { + // Each version of the Go toolchain knows how to interpret go.mod and + // go.sum files produced by all previous versions, so a compatibility + // version higher than the go.mod version adds nothing. + ld.TidyCompatibleVersion = ld.GoVersion + } + } + if semver.Compare("v"+ld.GoVersion, narrowAllVersionV) < 0 && !ld.UseVendorAll { // The module's go version explicitly predates the change in "all" for lazy // loading, so continue to use the older interpretation. @@ -1072,7 +1109,7 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader { // If that is not the case, there is a bug in the loading loop above. for _, m := range rs.rootModules { if v, ok := ld.requirements.rootSelected(m.Path); !ok || v != m.Version { - ld.errorf("go: internal error: a requirement on %v is needed but was not added during package loading\n", m) + ld.errorf("go mod tidy: internal error: a requirement on %v is needed but was not added during package loading\n", m) base.ExitIfErrors() } } @@ -1743,6 +1780,219 @@ func (ld *loader) checkMultiplePaths() { } } +// checkTidyCompatibility emits an error if any package would be loaded from a +// different module under rs than under ld.requirements. +func (ld *loader) checkTidyCompatibility(ctx context.Context, rs *Requirements) { + suggestUpgrade := false + suggestEFlag := false + suggestFixes := func() { + if ld.AllowErrors { + // The user is explicitly ignoring these errors, so don't bother them with + // other options. + return + } + + // We print directly to os.Stderr because this information is advice about + // how to fix errors, not actually an error itself. + // (The actual errors should have been logged already.) + + fmt.Fprintln(os.Stderr) + + goFlag := "" + if ld.GoVersion != modFileGoVersion() { + goFlag = " -go=" + ld.GoVersion + } + + compatFlag := "" + if ld.TidyCompatibleVersion != priorGoVersion(ld.GoVersion) { + compatFlag = " -compat=" + ld.TidyCompatibleVersion + } + if suggestUpgrade { + eDesc := "" + eFlag := "" + if suggestEFlag { + eDesc = ", leaving some packages unresolved" + eFlag = " -e" + } + fmt.Fprintf(os.Stderr, "To upgrade to the versions selected by go %s%s:\n\tgo mod tidy%s -go=%s && go mod tidy%s -go=%s%s\n", ld.TidyCompatibleVersion, eDesc, eFlag, ld.TidyCompatibleVersion, eFlag, ld.GoVersion, compatFlag) + } else if suggestEFlag { + // If some packages are missing but no package is upgraded, then we + // shouldn't suggest upgrading to the Go 1.16 versions explicitly — that + // wouldn't actually fix anything for Go 1.16 users, and *would* break + // something for Go 1.17 users. + fmt.Fprintf(os.Stderr, "To proceed despite packages unresolved in go %s:\n\tgo mod tidy -e%s%s\n", ld.TidyCompatibleVersion, goFlag, compatFlag) + } + + fmt.Fprintf(os.Stderr, "If reproducibility with go %s is not needed:\n\tgo mod tidy%s -compat=%s\n", ld.TidyCompatibleVersion, goFlag, ld.GoVersion) + + // TODO(#46141): Populate the linked wiki page. + fmt.Fprintf(os.Stderr, "For other options, see:\n\thttps://golang.org/wiki/PruningModules\n") + } + + mg, err := rs.Graph(ctx) + if err != nil { + ld.errorf("go mod tidy: error loading go %s module graph: %v\n", ld.TidyCompatibleVersion, err) + suggestFixes() + return + } + + // Re-resolve packages in parallel. + // + // We re-resolve each package — rather than just checking versions — to ensure + // that we have fetched module source code (and, importantly, checksums for + // that source code) for all modules that are necessary to ensure that imports + // are unambiguous. That also produces clearer diagnostics, since we can say + // exactly what happened to the package if it became ambiguous or disappeared + // entirely. + // + // We re-resolve the packages in parallel because this process involves disk + // I/O to check for package sources, and because the process of checking for + // ambiguous imports may require us to download additional modules that are + // otherwise pruned out in Go 1.17 — we don't want to block progress on other + // packages while we wait for a single new download. + type mismatch struct { + mod module.Version + err error + } + mismatchMu := make(chan map[*loadPkg]mismatch, 1) + mismatchMu <- map[*loadPkg]mismatch{} + for _, pkg := range ld.pkgs { + if pkg.mod.Path == "" && pkg.err == nil { + // This package is from the standard library (which does not vary based on + // the module graph). + continue + } + + pkg := pkg + ld.work.Add(func() { + mod, _, err := importFromModules(ctx, pkg.path, rs, mg) + if mod != pkg.mod { + mismatches := <-mismatchMu + mismatches[pkg] = mismatch{mod: mod, err: err} + mismatchMu <- mismatches + } + }) + } + <-ld.work.Idle() + + mismatches := <-mismatchMu + if len(mismatches) == 0 { + // Since we're running as part of 'go mod tidy', the roots of the module + // graph should contain only modules that are relevant to some package in + // the package graph. We checked every package in the package graph and + // didn't find any mismatches, so that must mean that all of the roots of + // the module graph are also consistent. + // + // If we're wrong, Go 1.16 in -mod=readonly mode will error out with + // "updates to go.mod needed", which would be very confusing. So instead, + // we'll double-check that our reasoning above actually holds — if it + // doesn't, we'll emit an internal error and hopefully the user will report + // it as a bug. + for _, m := range ld.requirements.rootModules { + if v := mg.Selected(m.Path); v != m.Version { + fmt.Fprintln(os.Stderr) + base.Fatalf("go: internal error: failed to diagnose selected-version mismatch for module %s: go %s selects %s, but go %s selects %s\n\tPlease report this at https://golang.org/issue.", m.Path, ld.GoVersion, m.Version, ld.TidyCompatibleVersion, v) + } + } + return + } + + // Iterate over the packages (instead of the mismatches map) to emit errors in + // deterministic order. + for _, pkg := range ld.pkgs { + mismatch, ok := mismatches[pkg] + if !ok { + continue + } + + if pkg.isTest() { + // We already did (or will) report an error for the package itself, + // so don't report a duplicate (and more vebose) error for its test. + if _, ok := mismatches[pkg.testOf]; !ok { + base.Fatalf("go: internal error: mismatch recorded for test %s, but not its non-test package", pkg.path) + } + continue + } + + switch { + case mismatch.err != nil: + // pkg resolved successfully, but errors out using the requirements in rs. + // + // This could occur because the import is provided by a single lazy root + // (and is thus unambiguous in lazy mode) and also one or more + // transitive dependencies (and is ambiguous in eager mode). + // + // It could also occur because some transitive dependency upgrades the + // module that previously provided the package to a version that no + // longer does, or to a version for which the module source code (but + // not the go.mod file in isolation) has a checksum error. + if missing := (*ImportMissingError)(nil); errors.As(mismatch.err, &missing) { + selected := module.Version{ + Path: pkg.mod.Path, + Version: mg.Selected(pkg.mod.Path), + } + ld.errorf("%s loaded from %v,\n\tbut go %s would fail to locate it in %s\n", pkg.stackText(), pkg.mod, ld.TidyCompatibleVersion, selected) + } else { + if ambiguous := (*AmbiguousImportError)(nil); errors.As(mismatch.err, &ambiguous) { + // TODO: Is this check needed? + } + ld.errorf("%s loaded from %v,\n\tbut go %s would fail to locate it:\n\t%v\n", pkg.stackText(), pkg.mod, ld.TidyCompatibleVersion, mismatch.err) + } + + suggestEFlag = true + + // Even if we press ahead with the '-e' flag, the older version will + // error out in readonly mode if it thinks the go.mod file contains + // any *explicit* dependency that is not at its selected version, + // even if that dependency is not relevant to any package being loaded. + // + // We check for that condition here. If all of the roots are consistent + // the '-e' flag suffices, but otherwise we need to suggest an upgrade. + if !suggestUpgrade { + for _, m := range ld.requirements.rootModules { + if v := mg.Selected(m.Path); v != m.Version { + suggestUpgrade = true + break + } + } + } + + case pkg.err != nil: + // pkg had an error in lazy mode (presumably suppressed with the -e flag), + // but not in eager mode. + // + // This is possible, if, say, the import is unresolved in lazy mode + // (because the "latest" version of each candidate module either is + // unavailable or does not contain the package), but is resolved in + // eager mode due to a newer-than-latest dependency that is normally + // runed out of the module graph. + // + // This could also occur if the source code for the module providing the + // package in lazy mode has a checksum error, but eager mode upgrades + // that module to a version with a correct checksum. + // + // pkg.err should have already been logged elsewhere — along with a + // stack trace — so log only the import path and non-error info here. + suggestUpgrade = true + ld.errorf("%s failed to load from any module,\n\tbut go %s would load it from %v\n", pkg.path, ld.TidyCompatibleVersion, mismatch.mod) + + case pkg.mod != mismatch.mod: + // The package is loaded successfully by both Go versions, but from a + // different module in each. This could lead to subtle (and perhaps even + // unnoticed!) variations in behavior between builds with different + // toolchains. + suggestUpgrade = true + ld.errorf("%s loaded from %v,\n\tbut go %s would select %v\n", pkg.stackText(), pkg.mod, ld.TidyCompatibleVersion, mismatch.mod.Version) + + default: + base.Fatalf("go: internal error: mismatch recorded for package %s, but no differences found", pkg.path) + } + } + + suggestFixes() + base.ExitIfErrors() +} + // scanDir is like imports.ScanDir but elides known magic imports from the list, // so that we do not go looking for packages that don't really exist. // diff --git a/src/cmd/go/testdata/script/mod_tidy_compat.txt b/src/cmd/go/testdata/script/mod_tidy_compat.txt index e6f88dc7798..e6edef5ee3b 100644 --- a/src/cmd/go/testdata/script/mod_tidy_compat.txt +++ b/src/cmd/go/testdata/script/mod_tidy_compat.txt @@ -33,31 +33,26 @@ cmp go.mod go.mod.orig go list -m all cmp stdout m_all.txt +go mod edit -go=1.16 +go list -m all +cmp stdout m_all.txt + + +# If we explicitly drop compatibility with 1.16, we retain fewer checksums, +# which gives a cleaner go.sum file but causes 1.16 to fail in readonly mode. + +cp go.mod.orig go.mod +go mod tidy -compat=1.17 +cmp go.mod go.mod.orig + +go list -m all +cmp stdout m_all.txt + go mod edit -go=1.16 ! go list -m all stderr '^go list -m: example.net/lazy@v0.1.0 requires\n\texample.com/version@v1.0.1: missing go.sum entry; to add it:\n\tgo mod download example.com/version$' -# If we combine a Go 1.16 go.sum file... -go mod tidy -go=1.16 - -# ...with a Go 1.17 go.mod file... -cp go.mod.orig go.mod - -# ...then Go 1.17 continues to work... -go list -m all -cmp stdout m_all.txt - -# ...and now 1.16 can load the same build list! -go mod edit -go=1.16 -go list -m all -cmp stdout m_all.txt - - -# TODO(#46141): Add a cleaner way to tidy a Go 1.17 module while preserving -# the checksums needed to work within it with Go 1.16. - - -- go.mod -- // Module m happens to have the exact same build list as what would be // selected under Go 1.16, but computes that build list without looking at diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_added.txt b/src/cmd/go/testdata/script/mod_tidy_compat_added.txt new file mode 100644 index 00000000000..94fa79bc9f5 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_compat_added.txt @@ -0,0 +1,105 @@ +# https://golang.org/issue/46141: 'go mod tidy' for a Go 1.17 module should by +# default preserve enough checksums for the module to be used by Go 1.16. +# +# We don't have a copy of Go 1.16 handy, but we can simulate it by editing the +# 'go' version in the go.mod file to 1.16, without actually updating the +# requirements to match. + +[short] skip + +env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}' + + +# For this module, Go 1.17 produces an error for one module, and Go 1.16 +# produces a different error for a different module. + +cp go.mod go.mod.orig + +! go mod tidy + +stderr '^example\.com/m imports\n\texample\.net/added: module example\.net/added@latest found \(v0\.3\.0, replaced by \./a1\), but does not contain package example\.net/added$' + +cmp go.mod go.mod.orig + + +# When we run 'go mod tidy -e', we should proceed past the first error and follow +# it with a second error describing the version descrepancy. +# +# We should not provide advice on how to push past the version descrepancy, +# because the '-e' flag should already do that, writing out an otherwise-tidied +# go.mod file. + +go mod tidy -e + +stderr '^example\.com/m imports\n\texample\.net/added: module example\.net/added@latest found \(v0\.3\.0, replaced by \./a1\), but does not contain package example\.net/added\nexample\.net/added failed to load from any module,\n\tbut go 1\.16 would load it from example\.net/added@v0\.2\.0$' + +! stderr '\n\tgo mod tidy' + +cmp go.mod go.mod.tidy + + +-- go.mod -- +module example.com/m + +go 1.17 + +replace ( + example.net/added v0.1.0 => ./a1 + example.net/added v0.2.0 => ./a2 + example.net/added v0.3.0 => ./a1 + example.net/lazy v0.1.0 => ./lazy + example.net/pruned v0.1.0 => ./pruned +) + +require ( + example.net/added v0.1.0 + example.net/lazy v0.1.0 +) +-- go.mod.tidy -- +module example.com/m + +go 1.17 + +replace ( + example.net/added v0.1.0 => ./a1 + example.net/added v0.2.0 => ./a2 + example.net/added v0.3.0 => ./a1 + example.net/lazy v0.1.0 => ./lazy + example.net/pruned v0.1.0 => ./pruned +) + +require example.net/lazy v0.1.0 +-- m.go -- +package m + +import ( + _ "example.net/added" + _ "example.net/lazy" +) + +-- a1/go.mod -- +module example.net/added + +go 1.17 +-- a2/go.mod -- +module example.net/added + +go 1.17 +-- a2/added.go -- +package added + +-- lazy/go.mod -- +module example.net/lazy + +go 1.17 + +require example.net/pruned v0.1.0 +-- lazy/lazy.go -- +package lazy + +-- pruned/go.mod -- +module example.net/pruned + +go 1.17 + +require example.net/added v0.2.0 diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_ambiguous.txt b/src/cmd/go/testdata/script/mod_tidy_compat_ambiguous.txt new file mode 100644 index 00000000000..ed1dd53eff1 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_compat_ambiguous.txt @@ -0,0 +1,98 @@ +# https://golang.org/issue/46141: 'go mod tidy' for a Go 1.17 module should by +# default preserve enough checksums for the module to be used by Go 1.16. +# +# We don't have a copy of Go 1.16 handy, but we can simulate it by editing the +# 'go' version in the go.mod file to 1.16, without actually updating the +# requirements to match. + +[short] skip + +env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}' + +# For this module, the dependency providing package +# example.net/ambiguous/nested/pkg is unambiguous in Go 1.17 (because only one +# root of the module graph contains the package), whereas it is ambiguous in +# Go 1.16 (because two different modules contain plausible packages and Go 1.16 +# does not privilege roots above other dependencies). +# +# However, the overall build list is identical for both versions. + +cp go.mod go.mod.orig + +! go mod tidy + +stderr '^example\.com/m imports\n\texample\.net/indirect imports\n\texample\.net/ambiguous/nested/pkg loaded from example\.net/ambiguous/nested@v0\.1\.0,\n\tbut go 1.16 would fail to locate it:\n\tambiguous import: found package example\.net/ambiguous/nested/pkg in multiple modules:\n\texample\.net/ambiguous v0.1.0 \(.*\)\n\texample\.net/ambiguous/nested v0.1.0 \(.*\)\n\n' + +stderr '\n\nTo proceed despite packages unresolved in go 1\.16:\n\tgo mod tidy -e\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1\.17\nFor other options, see:\n\thttps://golang\.org/wiki/PruningModules\n' + +cmp go.mod go.mod.orig + + +# If we run 'go mod tidy -e', we should still save enough checksums to run +# 'go list -m all' reproducibly with go 1.16, even though we can't list +# the specific package. + +go mod tidy -e +! stderr '\n\tgo mod tidy' +cmp go.mod go.mod.orig + +go list -m all +cmp stdout all-m.txt + +go list -f $MODFMT example.net/ambiguous/nested/pkg +stdout '^example.net/ambiguous/nested v0\.1\.0$' +! stderr . + +go mod edit -go=1.16 +go list -m all +cmp stdout all-m.txt + +! go list -f $MODFMT example.net/ambiguous/nested/pkg +stderr '^ambiguous import: found package example\.net/ambiguous/nested/pkg in multiple modules:\n\texample\.net/ambiguous v0\.1\.0 \(.*\)\n\texample\.net/ambiguous/nested v0\.1\.0 \(.*\)\n' + + +# On the other hand, if we use -compat=1.17, 1.16 can't even load +# the build list (due to missing checksums). + +cp go.mod.orig go.mod +go mod tidy -compat=1.17 +! stderr . +go list -m all +cmp stdout all-m.txt + +go mod edit -go=1.16 +! go list -m all +stderr '^go list -m: example\.net/indirect@v0\.1\.0 requires\n\texample\.net/ambiguous@v0\.1\.0: missing go\.sum entry; to add it:\n\tgo mod download example\.net/ambiguous\n' + + +-- go.mod -- +module example.com/m + +go 1.17 + +replace example.net/indirect v0.1.0 => ./indirect + +require ( + example.net/ambiguous/nested v0.1.0 // indirect + example.net/indirect v0.1.0 +) +-- all-m.txt -- +example.com/m +example.net/ambiguous v0.1.0 +example.net/ambiguous/nested v0.1.0 +example.net/indirect v0.1.0 => ./indirect +-- m.go -- +package m + +import _ "example.net/indirect" + +-- indirect/go.mod -- +module example.net/indirect + +go 1.17 + +require example.net/ambiguous v0.1.0 +-- indirect/indirect.go -- +package indirect + +import _ "example.net/ambiguous/nested/pkg" diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_deleted.txt b/src/cmd/go/testdata/script/mod_tidy_compat_deleted.txt new file mode 100644 index 00000000000..3aacde2025d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_compat_deleted.txt @@ -0,0 +1,128 @@ +# https://golang.org/issue/46141: 'go mod tidy' for a Go 1.17 module should by +# default preserve enough checksums for the module to be used by Go 1.16. +# +# We don't have a copy of Go 1.16 handy, but we can simulate it by editing the +# 'go' version in the go.mod file to 1.16, without actually updating the +# requirements to match. + +[short] skip + +env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}' + + +# For this module, the "deleted" dependency contains an imported package, but +# Go 1.16 selects a higher version (in which that package has been deleted). + +cp go.mod go.mod.orig + +! go mod tidy + +stderr '^example\.com/m imports\n\texample\.net/deleted loaded from example\.net/deleted@v0\.1\.0,\n\tbut go 1\.16 would fail to locate it in example\.net/deleted@v0\.2\.0\n\n' + +stderr '\n\nTo upgrade to the versions selected by go 1.16, leaving some packages unresolved:\n\tgo mod tidy -e -go=1\.16 && go mod tidy -e -go=1\.17\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1\.17\nFor other options, see:\n\thttps://golang\.org/wiki/PruningModules\n' + + +# The suggested 'go mod tidy -e' command should proceed anyway. + +go mod tidy -e +cmp go.mod go.mod.tidy + + +# In 'go 1.16' mode we should error out in the way we claimed. + +cd 116-outside +! go list -deps -f $MODFMT example.com/m +stderr '^\.\.[/\\]m\.go:4:2: no required module provides package example\.net/deleted; to add it:\n\tgo get example\.net/deleted$' +cd .. + +go mod edit -go=1.16 +! go list -deps -f $MODFMT example.com/m +stderr '^go: updates to go\.mod needed; to update it:\n\tgo mod tidy$' + +! go mod tidy +stderr '^example\.com/m imports\n\texample\.net/deleted: module example\.net/deleted@latest found \(v0\.2\.0, replaced by \./d2\), but does not contain package example\.net/deleted$' + + +-- go.mod -- +module example.com/m + +go 1.17 + +replace ( + example.net/deleted v0.1.0 => ./d1 + example.net/deleted v0.2.0 => ./d2 + example.net/lazy v0.1.0 => ./lazy + example.net/pruned v0.1.0 => ./pruned +) + +require ( + example.net/deleted v0.1.0 + example.net/deleted v0.1.0 // redundant + example.net/lazy v0.1.0 +) +-- go.mod.tidy -- +module example.com/m + +go 1.17 + +replace ( + example.net/deleted v0.1.0 => ./d1 + example.net/deleted v0.2.0 => ./d2 + example.net/lazy v0.1.0 => ./lazy + example.net/pruned v0.1.0 => ./pruned +) + +require ( + example.net/deleted v0.1.0 + example.net/lazy v0.1.0 +) +-- 116-outside/go.mod -- +module outside + +go 1.16 + +replace ( + example.com/m => ../ + example.net/deleted v0.1.0 => ../d1 + example.net/deleted v0.2.0 => ../d2 + example.net/lazy v0.1.0 => ../lazy + example.net/pruned v0.1.0 => ../pruned +) + +require example.com/m v0.1.0 +-- m.go -- +package m + +import ( + _ "example.net/deleted" + _ "example.net/lazy" +) + +-- d1/go.mod -- +module example.net/deleted + +go 1.17 +-- d1/deleted.go -- +package deleted +-- d2/go.mod -- +module example.net/deleted + +go 1.17 +-- d2/README -- +There is no longer a Go package here. + +-- lazy/go.mod -- +module example.net/lazy + +go 1.17 + +require example.net/pruned v0.1.0 +-- lazy/lazy.go -- +package lazy + +-- pruned/go.mod -- +module example.net/pruned + +go 1.17 + +require example.net/deleted v0.2.0 diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_implicit.txt b/src/cmd/go/testdata/script/mod_tidy_compat_implicit.txt index baaa5d63e31..e00aea930ee 100644 --- a/src/cmd/go/testdata/script/mod_tidy_compat_implicit.txt +++ b/src/cmd/go/testdata/script/mod_tidy_compat_implicit.txt @@ -27,8 +27,22 @@ env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}' # it — lazy v0.1.0 — specifies 'go 1.17', and it is not otherwise relevant to # the main module). +# 'go mod tidy' should by default diagnose the difference in dependencies as an +# error, with useful suggestions about how to resolve it. + cp go.mod go.mod.orig -go mod tidy +! go mod tidy +stderr '^example\.com/m imports\n\texample\.net/lazy tested by\n\texample\.net/lazy.test imports\n\texample\.com/retract/incompatible loaded from example\.com/retract/incompatible@v1\.0\.0,\n\tbut go 1\.16 would select v2\.0\.0\+incompatible\n\n' +stderr '\n\nTo upgrade to the versions selected by go 1\.16:\n\tgo mod tidy -go=1\.16 && go mod tidy -go=1\.17\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1.17\nFor other options, see:\n\thttps://golang\.org/wiki/PruningModules\n' + +cmp go.mod go.mod.orig + +# The suggested '-compat' flag to ignore differences should silence the error +# and leave go.mod unchanged, resulting in checksum errors when Go 1.16 tries +# to load a module pruned out by Go 1.17. + +go mod tidy -compat=1.17 +! stderr . cmp go.mod go.mod.orig go list -deps -test -f $MODFMT all @@ -49,7 +63,7 @@ cp go.mod.orig go.mod # ...then Go 1.17 no longer works. 😞 ! go list -deps -test -f $MODFMT all -stderr -count=1 '^can''t load test package: lazy/lazy_test.go:3:8: missing go\.sum entry for module providing package example\.com/retract/incompatible \(imported by example\.net/lazy\); to add:\n\tgo get -t example.net/lazy@v0\.1\.0$' +stderr -count=1 '^can''t load test package: lazy[/\\]lazy_test.go:3:8: missing go\.sum entry for module providing package example\.com/retract/incompatible \(imported by example\.net/lazy\); to add:\n\tgo get -t example.net/lazy@v0\.1\.0$' # However, if we take the union of the go.sum files... @@ -67,11 +81,6 @@ go list -deps -test -f $MODFMT all stdout '^example\.com/retract/incompatible v2\.0\.0\+incompatible$' -# TODO(#46100): In compatibility mode, should we reject the above difference as -# incompatible, or save checksums for both possible versions of the test -# dependency? - - -- go.mod -- // Module m imports packages from the same versions under Go 1.17 // as under Go 1.16, but under 1.16 its (implicit) external test dependencies diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt b/src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt index 08613524082..2d8726544a3 100644 --- a/src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt +++ b/src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt @@ -27,12 +27,23 @@ env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}' # the main module). -# TODO(#46141): 'go mod tidy' should by default diagnose the difference in -# dependencies as an error, but it should still be possible to simply drop -# compatibility with Go 1.16 by passing an appropriate '-compat' flag. +# 'go mod tidy' should by default diagnose the difference in dependencies as an +# error, with useful suggestions about how to resolve it. cp go.mod go.mod.orig -go mod tidy +! go mod tidy +stderr '^example\.com/m imports\n\texample\.net/lazy imports\n\texample\.com/retract/incompatible loaded from example\.com/retract/incompatible@v1\.0\.0,\n\tbut go 1\.16 would select v2\.0\.0\+incompatible\n\n' +stderr '\n\nTo upgrade to the versions selected by go 1\.16:\n\tgo mod tidy -go=1\.16 && go mod tidy -go=1\.17\nIf reproducibility with go 1\.16 is not needed:\n\tgo mod tidy -compat=1.17\nFor other options, see:\n\thttps://golang\.org/wiki/PruningModules\n' + +cmp go.mod go.mod.orig + + +# The suggested '-compat' flag to ignore differences should silence the error +# and leave go.mod unchanged, resulting in checksum errors when Go 1.16 tries +# to load a module pruned out by Go 1.17. + +go mod tidy -compat=1.17 +! stderr . cmp go.mod go.mod.orig go mod edit -go=1.16 @@ -44,6 +55,7 @@ stderr -count=2 '^go: example\.net/lazy@v0\.1\.0 requires\n\texample\.net/requir # There are two ways for the module author to bring the two into alignment. # One is to *explicitly* 'exclude' the version that is already *implicitly* # pruned out under 1.17. + go mod edit -exclude=example.com/retract/incompatible@v2.0.0+incompatible go list -f $MODFMT -deps ./... stdout '^example.com/retract/incompatible v1\.0\.0$' @@ -51,13 +63,20 @@ stdout '^example.com/retract/incompatible v1\.0\.0$' # The other is to explicitly upgrade the version required under Go 1.17 -# to match the version selected by Go 1.16. +# to match the version selected by Go 1.16. The commands suggested by +# 'go mod tidy' should do exactly that. + cp go.mod.orig go.mod -go get -d example.com/retract/incompatible@v2.0.0+incompatible - # Note that we are not running 'go mod tidy' here: we need to preserve - # the checksum for v1.0.0 because it is also still in the module graph - # as seen by Go 1.16. +go mod tidy -go=1.16 +go list -f $MODFMT -deps ./... +stdout '^example.com/retract/incompatible v2\.0\.0\+incompatible$' +! stdout 'v1\.0\.0' + +go mod tidy -go=1.17 +go list -f $MODFMT -deps ./... +stdout '^example.com/retract/incompatible v2\.0\.0\+incompatible$' +! stdout 'v1\.0\.0' go mod edit -go=1.16 go list -f $MODFMT -deps ./... diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_irrelevant.txt b/src/cmd/go/testdata/script/mod_tidy_compat_irrelevant.txt index d4371e0f7d4..7c22fca6c0f 100644 --- a/src/cmd/go/testdata/script/mod_tidy_compat_irrelevant.txt +++ b/src/cmd/go/testdata/script/mod_tidy_compat_irrelevant.txt @@ -27,34 +27,28 @@ cp go.mod go.mod.orig go mod tidy cmp go.mod go.mod.orig -go list -m all -stdout '^example\.com/retract/incompatible v1\.0\.0$' - -go mod edit -go=1.16 -! go list -deps -test -f $MODFMT all - # TODO(#46160): -count=1 instead of -count=2. -stderr -count=2 '^go: example.net/lazy@v0.1.0 requires\n\texample.com/retract/incompatible@v1.0.0: missing go.sum entry; to add it:\n\tgo mod download example.com/retract/incompatible$' - - -# If we combine a Go 1.16 go.sum file... -go mod tidy -go=1.16 - -# ...with a Go 1.17 go.mod file... -cp go.mod.orig go.mod - -# ...then Go 1.17 continues to work... go list -deps -test -f $MODFMT all cp stdout out-117.txt -# ...and 1.16 also works, and selects the same versions for all packages -# even remotely relevant to the main module. go mod edit -go=1.16 go list -deps -test -f $MODFMT all cmp stdout out-117.txt -# TODO(#46160): Add a cleaner way to tidy a Go 1.17 module while preserving -# the checksums needed to work within it with Go 1.16. +# If we explicitly drop compatibility with 1.16, we retain fewer checksums, +# which gives a cleaner go.sum file but causes 1.16 to fail in readonly mode. + +cp go.mod.orig go.mod +go mod tidy -compat=1.17 +cmp go.mod go.mod.orig + +go list -deps -test -f $MODFMT all +cmp stdout out-117.txt + +go mod edit -go=1.16 +! go list -deps -test -f $MODFMT all + # TODO(#46160): -count=1 instead of -count=2. +stderr -count=2 '^go: example.net/lazy@v0.1.0 requires\n\texample.com/retract/incompatible@v1.0.0: missing go.sum entry; to add it:\n\tgo mod download example.com/retract/incompatible$' -- go.mod -- diff --git a/src/cmd/go/testdata/script/mod_tidy_oldgo.txt b/src/cmd/go/testdata/script/mod_tidy_oldgo.txt new file mode 100644 index 00000000000..0e88b068a76 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_oldgo.txt @@ -0,0 +1,21 @@ +# Modules were introduced in Go 1.11, but for various reasons users may +# decide to declare a (much!) older go version in their go.mod file. +# Modules with very old versions should not be rejected, and should have +# the same module-graph semantics as in Go 1.11. + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod go.mod.orig + +-- go.mod -- +module example.com/legacy/go1 + +go 1.0 + +require golang.org/x/text v0.3.0 +-- main.go -- +package main + +import _ "golang.org/x/text/language" + +func main() {} diff --git a/src/go.sum b/src/go.sum index b3de6c526c9..6e869b96f71 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,8 +1,15 @@ golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI= golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I= golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 h1:yhBbb4IRs2HS9PPlAg6DMC6mUOKexJBNsLf4Z+6En1Q= golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f h1:yQJrRE0hDxDFmZLlRaw+3vusO4fwNHgHIjUOMO7bHYI= golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From f22ec51debeddc0903096e66bfaf641568bede3b Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Sat, 22 May 2021 13:40:20 -0700 Subject: [PATCH 156/940] doc: add Go 1.17 release note about inlining functions with closures Fixes #45781 Change-Id: Ia5bc2845f7f94aff4f3f0ff15533feb148223adb Reviewed-on: https://go-review.googlesource.com/c/go/+/322089 Trust: Dan Scales Reviewed-by: Cherry Mui --- doc/go1.17.html | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 6dd1d0d1db5..c2317a40352 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -228,7 +228,14 @@ Do not send CLs removing the interior tags from such phrases.

Compiler

-

+

+ + Functions containing closures can now be inlined. One effect of this change is + that a function with a closure may actually produce a distinct closure function + for each place that the function is inlined. Hence, this change could reveal + bugs where Go functions are compared (incorrectly) by pointer value. Go + functions are by definition not comparable. + TODO: complete the Compiler section, or delete if not needed

From 6c9e1c58bc7661638ee084e40a3b6fc907825496 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 25 May 2021 14:06:56 -0700 Subject: [PATCH 157/940] [dev.typeparams] test: fix and update run.go's generics testing In a late change to golang.org/cl/320609, while going back and forth on the meaning of the boolean result value for "checkFlags", I got one of the cases wrong. As a result, rather than testing both default flags and -G=3, we were (redundanly) testing default flags and -G=0. I ran into this because in my local dev tree, I'm using types2 even for -G=0, and evidently one of the recent types2 CLs changed the error message in fixedbugs/issue10975.go. Fortunately, there haven't been any other regressions despite lacking test coverage. So this CL cleans things up a bit: 1. Fixes that test to use -lang=go1.17, so types2 reports the old error message again. 2. Renames "checkFlags" to "validForGLevel" so the boolean result is harder to get wrong. 3. Removes the blanket deny list of all -m tests, and instead adds the specific tests that are still failing. This effectively extends -G=3 coverage to another 27 tests that were using -m but already passing, so we can make sure they don't regress again. 4. Adds a -f flag to force running tests even if they're in the deny list, to make it easier to test whether they're still failing without having to edit run.go. Change-Id: I058d9d90d81a92189e54c6f591d95fb617fede53 Reviewed-on: https://go-review.googlesource.com/c/go/+/322612 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky Reviewed-by: Robert Griesemer --- test/fixedbugs/issue10975.go | 2 +- test/run.go | 109 ++++++++++++++++++++++------------- 2 files changed, 71 insertions(+), 40 deletions(-) diff --git a/test/fixedbugs/issue10975.go b/test/fixedbugs/issue10975.go index 89ef23c1a86..876ea58ef97 100644 --- a/test/fixedbugs/issue10975.go +++ b/test/fixedbugs/issue10975.go @@ -1,4 +1,4 @@ -// errorcheck +// errorcheck -lang=go1.17 // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/test/run.go b/test/run.go index 506380a7a5a..ef243968092 100644 --- a/test/run.go +++ b/test/run.go @@ -43,6 +43,7 @@ var ( updateErrors = flag.Bool("update_errors", false, "update error messages in test file based on compiler output") runoutputLimit = flag.Int("l", defaultRunOutputLimit(), "number of parallel runoutput tests to run") generics = flag.String("G", "0,3", "a comma-separated list of -G compiler flags to test with") + force = flag.Bool("f", false, "run expected-failure generics tests rather than skipping them") shard = flag.Int("shard", 0, "shard index to run. Only applicable if -shards is non-zero.") shards = flag.Int("shards", 0, "number of shards. If 0, all tests are run. This is used by the continuous build.") @@ -518,7 +519,7 @@ func (t *test) run() { close(t.donec) }() - if t.glevel > 0 { + if t.glevel > 0 && !*force { // Files excluded from generics testing. filename := strings.Replace(t.goFileName(), "\\", "/", -1) // goFileName() uses \ on Windows if excludedFiles[filename] { @@ -657,33 +658,37 @@ func (t *test) run() { Compile ) - // checkFlags reports whether the current test configuration should - // be skipped because flags (which should be an arguments list for - // "go tool compile", not "go build") contains an excluded flag. - // It will also update flags as appropriate. - checkFlags := func(tool Tool) bool { - if t.glevel > 0 { + // validForGLevel reports whether the current test is valid to run + // at the specified -G level. If so, it may update flags as + // necessary to test with -G. + validForGLevel := func(tool Tool) bool { + if t.glevel == 0 { + // default -G level; always valid return true } + for _, flag := range flags { + if strings.Contains(flag, "-G") { + // test provides explicit -G flag already + if *verbose { + fmt.Printf("excl\t%s\n", t.goFileName()) + } + return false + } + } + switch tool { case Build, Run: // ok; handled in goGcflags case Compile: - for _, flag := range flags { - for _, pattern := range excludedFlags { - if strings.Contains(flag, pattern) { - if *verbose { - fmt.Printf("excl\t%s\t%s\n", t.goFileName(), flags) - } - return true // cannot handle flag - } - } - } flags = append(flags, fmt.Sprintf("-G=%v", t.glevel)) default: + // we don't know how to add -G for this test yet + if *verbose { + fmt.Printf("excl\t%s\n", t.goFileName()) + } return false } @@ -766,7 +771,7 @@ func (t *test) run() { t.err = fmt.Errorf("unimplemented action %q", action) case "asmcheck": - if !checkFlags(AsmCheck) { + if !validForGLevel(AsmCheck) { return } @@ -824,7 +829,7 @@ func (t *test) run() { return case "errorcheck": - if !checkFlags(Compile) { + if !validForGLevel(Compile) { return } @@ -858,7 +863,7 @@ func (t *test) run() { t.err = t.errorCheck(string(out), wantAuto, long, t.gofile) case "compile": - if !checkFlags(Compile) { + if !validForGLevel(Compile) { return } @@ -866,7 +871,7 @@ func (t *test) run() { _, t.err = compileFile(runcmd, long, flags) case "compiledir": - if !checkFlags(Compile) { + if !validForGLevel(Compile) { return } @@ -885,7 +890,7 @@ func (t *test) run() { } case "errorcheckdir", "errorcheckandrundir": - if !checkFlags(Compile) { + if !validForGLevel(Compile) { return } @@ -934,7 +939,7 @@ func (t *test) run() { fallthrough case "rundir": - if !checkFlags(Run) { + if !validForGLevel(Run) { return } @@ -996,7 +1001,7 @@ func (t *test) run() { } case "runindir": - if !checkFlags(Run) { + if !validForGLevel(Run) { return } @@ -1039,7 +1044,7 @@ func (t *test) run() { t.checkExpectedOutput(out) case "build": - if !checkFlags(Build) { + if !validForGLevel(Build) { return } @@ -1050,7 +1055,7 @@ func (t *test) run() { } case "builddir", "buildrundir": - if !checkFlags(Build) { + if !validForGLevel(Build) { return } @@ -1133,7 +1138,7 @@ func (t *test) run() { } case "buildrun": - if !checkFlags(Build) { + if !validForGLevel(Build) { return } @@ -1162,7 +1167,7 @@ func (t *test) run() { t.checkExpectedOutput(out) case "run": - if !checkFlags(Run) { + if !validForGLevel(Run) { return } @@ -1209,7 +1214,7 @@ func (t *test) run() { t.checkExpectedOutput(out) case "runoutput": - if !checkFlags(Run) { + if !validForGLevel(Run) { return } @@ -1248,7 +1253,7 @@ func (t *test) run() { t.checkExpectedOutput(out) case "errorcheckoutput": - if !checkFlags(Compile) { + if !validForGLevel(Compile) { return } @@ -2015,15 +2020,6 @@ func overlayDir(dstRoot, srcRoot string) error { // checking are also excluded since these phases are not running yet. // We can get rid of this code once types2 is fully plugged in. -// For now we skip tests when we can't handle the file or some of the flags. -// The first goal is to eliminate the excluded list; the second goal is to -// eliminate the flag list. - -var excludedFlags = []string{ - "-G", // skip redundant testing - "-m", -} - // List of files that the compiler cannot errorcheck with the new typechecker (compiler -G option). // Temporary scaffolding until we pass all the tests at which point this map can be removed. var excludedFiles = map[string]bool{ @@ -2101,4 +2097,39 @@ var excludedFiles = map[string]bool{ "fixedbugs/issue7525e.go": true, // types2 reports init cycle error on different line - ok otherwise "fixedbugs/issue7525.go": true, // types2 reports init cycle error on different line - ok otherwise "fixedbugs/issue9691.go": true, // "cannot assign to int(.autotmp_4)" (probably irgen's fault) + + // tests that rely on -m diagnostics, which currently differ with -G=3 + // + // TODO(mdempsky): Triage, though most of the issues seem to fall into: + // - Anonymous result parameters given different names (e.g., ~r0 vs ~r1) + // - Some escape analysis diagnostics being printed without position information + // - Some expressions printed differently (e.g., "int(100)" instead + // of "100" or "&composite literal" instead of "&[4]int{...}"). + "closure3.go": true, + "escape2.go": true, + "escape2n.go": true, + "escape4.go": true, + "escape5.go": true, + "escape_array.go": true, + "escape_calls.go": true, + "escape_field.go": true, + "escape_iface.go": true, + "escape_indir.go": true, + "escape_level.go": true, + "escape_map.go": true, + "escape_param.go": true, + "escape_slice.go": true, + "escape_struct_param1.go": true, + "escape_struct_param2.go": true, + "fixedbugs/issue12006.go": true, + "fixedbugs/issue13799.go": true, + "fixedbugs/issue21709.go": true, + "fixedbugs/issue24651a.go": true, + "fixedbugs/issue24651b.go": true, + "fixedbugs/issue27557.go": true, + "fixedbugs/issue31573.go": true, + "fixedbugs/issue37837.go": true, + "fixedbugs/issue39292.go": true, + "fixedbugs/issue7921.go": true, + "inline.go": true, } From 74242baa4136c7a9132a8ccd9881354442788c8c Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Tue, 11 May 2021 11:31:31 -0700 Subject: [PATCH 158/940] archive/zip: only preallocate File slice if reasonably sized Since the number of files in the EOCD record isn't validated, it isn't safe to preallocate Reader.Files using that field. A malformed archive can indicate it contains up to 1 << 128 - 1 files. We can still safely preallocate the slice by checking if the specified number of files in the archive is reasonable, given the size of the archive. Thanks to the OSS-Fuzz project for discovering this issue and to Emmanuel Odeke for reporting it. Fixes #46242 Fixes CVE-2021-33196 Change-Id: I3c76d8eec178468b380d87fdb4a3f2cb06f0ee76 Reviewed-on: https://go-review.googlesource.com/c/go/+/318909 Trust: Roland Shoemaker Trust: Katie Hockman Trust: Joe Tsai Run-TryBot: Roland Shoemaker TryBot-Result: Go Bot Reviewed-by: Katie Hockman Reviewed-by: Joe Tsai --- src/archive/zip/reader.go | 10 +++++- src/archive/zip/reader_test.go | 59 ++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/src/archive/zip/reader.go b/src/archive/zip/reader.go index 808cf274cad..2d53f4c7231 100644 --- a/src/archive/zip/reader.go +++ b/src/archive/zip/reader.go @@ -96,7 +96,15 @@ func (z *Reader) init(r io.ReaderAt, size int64) error { return err } z.r = r - z.File = make([]*File, 0, end.directoryRecords) + // Since the number of directory records is not validated, it is not + // safe to preallocate z.File without first checking that the specified + // number of files is reasonable, since a malformed archive may + // indicate it contains up to 1 << 128 - 1 files. Since each file has a + // header which will be _at least_ 30 bytes we can safely preallocate + // if (data size / 30) >= end.directoryRecords. + if (uint64(size)-end.directorySize)/30 >= end.directoryRecords { + z.File = make([]*File, 0, end.directoryRecords) + } z.Comment = end.comment rs := io.NewSectionReader(r, 0, size) if _, err = rs.Seek(int64(end.directoryOffset), io.SeekStart); err != nil { diff --git a/src/archive/zip/reader_test.go b/src/archive/zip/reader_test.go index 35e681ec699..37dafe6c8e7 100644 --- a/src/archive/zip/reader_test.go +++ b/src/archive/zip/reader_test.go @@ -1325,3 +1325,62 @@ func TestReadDataDescriptor(t *testing.T) { }) } } + +func TestCVE202133196(t *testing.T) { + // Archive that indicates it has 1 << 128 -1 files, + // this would previously cause a panic due to attempting + // to allocate a slice with 1 << 128 -1 elements. + data := []byte{ + 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x08, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x62, 0x61, 0x65, 0x03, 0x04, 0x00, 0x00, + 0xff, 0xff, 0x50, 0x4b, 0x07, 0x08, 0xbe, 0x20, + 0x5c, 0x6c, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, + 0x14, 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xbe, 0x20, 0x5c, 0x6c, 0x09, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x02, 0x03, 0x50, 0x4b, 0x06, 0x06, 0x2c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, + 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x31, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x50, 0x4b, 0x06, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, + 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, + } + _, err := NewReader(bytes.NewReader(data), int64(len(data))) + if err != ErrFormat { + t.Fatalf("unexpected error, got: %v, want: %v", err, ErrFormat) + } + + // Also check that an archive containing a handful of empty + // files doesn't cause an issue + b := bytes.NewBuffer(nil) + w := NewWriter(b) + for i := 0; i < 5; i++ { + _, err := w.Create("") + if err != nil { + t.Fatalf("Writer.Create failed: %s", err) + } + } + if err := w.Close(); err != nil { + t.Fatalf("Writer.Close failed: %s", err) + } + r, err := NewReader(bytes.NewReader(b.Bytes()), int64(b.Len())) + if err != nil { + t.Fatalf("NewReader failed: %s", err) + } + if len(r.File) != 5 { + t.Errorf("Archive has unexpected number of files, got %d, want 5", len(r.File)) + } +} From d050238bb653711b47335583c5425c9efec30e4e Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 25 May 2021 10:33:02 +0200 Subject: [PATCH 159/940] doc/go1.17: fix formatting for time changes Also add a link to the time.Time type and adjust the wording a bit. Change-Id: I2f4210ada6d253eb5804e6327b2432487beb8a05 Reviewed-on: https://go-review.googlesource.com/c/go/+/321811 Trust: Tobias Klauser Reviewed-by: Ian Lance Taylor --- doc/go1.17.html | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index c2317a40352..bdde26bd108 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -558,9 +558,10 @@ Do not send CLs removing the interior tags from such phrases.
time

- time.Time now has a GoString - method that will return a more useful value for times when printed with - the "%#v" format specifier in the fmt package. + The Time type now has a + GoString method that + will return a more useful value for times when printed with the + %#v format specifier in the fmt package.

From e4615ad74d5becdd1fcee4879775a6d4118583c5 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 12 May 2021 23:04:25 -0400 Subject: [PATCH 160/940] math/big: move division into natdiv.go Code moved and functions reordered to be in a consistent top-down dependency order, but otherwise unchanged. First step toward commenting division algorithms. Change-Id: Ib5e604fb5b2867edff3a228ba4e57b5cb32c4137 Reviewed-on: https://go-review.googlesource.com/c/go/+/321077 Trust: Russ Cox Trust: Katie Hockman Trust: Robert Griesemer Run-TryBot: Russ Cox TryBot-Result: Go Bot Reviewed-by: Katie Hockman Reviewed-by: Robert Griesemer --- src/math/big/arith.go | 14 -- src/math/big/nat.go | 325 -------------------------------------- src/math/big/natdiv.go | 346 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 346 insertions(+), 339 deletions(-) create mode 100644 src/math/big/natdiv.go diff --git a/src/math/big/arith.go b/src/math/big/arith.go index e1947936d49..8f55c195d4b 100644 --- a/src/math/big/arith.go +++ b/src/math/big/arith.go @@ -267,20 +267,6 @@ func divWW(x1, x0, y, m Word) (q, r Word) { return Word(qq), Word(r0 >> s) } -func divWVW(z []Word, xn Word, x []Word, y Word) (r Word) { - r = xn - if len(x) == 1 { - qq, rr := bits.Div(uint(r), uint(x[0]), uint(y)) - z[0] = Word(qq) - return Word(rr) - } - rec := reciprocalWord(y) - for i := len(z) - 1; i >= 0; i-- { - z[i], r = divWW(r, x[i], y, rec) - } - return r -} - // reciprocalWord return the reciprocal of the divisor. rec = floor(( _B^2 - 1 ) / u - _B). u = d1 << nlz(d1). func reciprocalWord(d1 Word) Word { u := uint(d1 << nlz(d1)) diff --git a/src/math/big/nat.go b/src/math/big/nat.go index bbd6c8850b6..140c619c8ca 100644 --- a/src/math/big/nat.go +++ b/src/math/big/nat.go @@ -631,48 +631,6 @@ func (z nat) mulRange(a, b uint64) nat { return z.mul(nat(nil).mulRange(a, m), nat(nil).mulRange(m+1, b)) } -// q = (x-r)/y, with 0 <= r < y -func (z nat) divW(x nat, y Word) (q nat, r Word) { - m := len(x) - switch { - case y == 0: - panic("division by zero") - case y == 1: - q = z.set(x) // result is x - return - case m == 0: - q = z[:0] // result is 0 - return - } - // m > 0 - z = z.make(m) - r = divWVW(z, 0, x, y) - q = z.norm() - return -} - -func (z nat) div(z2, u, v nat) (q, r nat) { - if len(v) == 0 { - panic("division by zero") - } - - if u.cmp(v) < 0 { - q = z[:0] - r = z2.set(u) - return - } - - if len(v) == 1 { - var r2 Word - q, r2 = z.divW(u, v[0]) - r = z2.setWord(r2) - return - } - - q, r = z.divLarge(z2, u, v) - return -} - // getNat returns a *nat of len n. The contents may not be zero. // The pool holds *nat to avoid allocation when converting to interface{}. func getNat(n int) *nat { @@ -693,276 +651,6 @@ func putNat(x *nat) { var natPool sync.Pool -// q = (uIn-r)/vIn, with 0 <= r < vIn -// Uses z as storage for q, and u as storage for r if possible. -// See Knuth, Volume 2, section 4.3.1, Algorithm D. -// Preconditions: -// len(vIn) >= 2 -// len(uIn) >= len(vIn) -// u must not alias z -func (z nat) divLarge(u, uIn, vIn nat) (q, r nat) { - n := len(vIn) - m := len(uIn) - n - - // D1. - shift := nlz(vIn[n-1]) - // do not modify vIn, it may be used by another goroutine simultaneously - vp := getNat(n) - v := *vp - shlVU(v, vIn, shift) - - // u may safely alias uIn or vIn, the value of uIn is used to set u and vIn was already used - u = u.make(len(uIn) + 1) - u[len(uIn)] = shlVU(u[0:len(uIn)], uIn, shift) - - // z may safely alias uIn or vIn, both values were used already - if alias(z, u) { - z = nil // z is an alias for u - cannot reuse - } - q = z.make(m + 1) - - if n < divRecursiveThreshold { - q.divBasic(u, v) - } else { - q.divRecursive(u, v) - } - putNat(vp) - - q = q.norm() - shrVU(u, u, shift) - r = u.norm() - - return q, r -} - -// divBasic performs word-by-word division of u by v. -// The quotient is written in pre-allocated q. -// The remainder overwrites input u. -// -// Precondition: -// - q is large enough to hold the quotient u / v -// which has a maximum length of len(u)-len(v)+1. -func (q nat) divBasic(u, v nat) { - n := len(v) - m := len(u) - n - - qhatvp := getNat(n + 1) - qhatv := *qhatvp - - // D2. - vn1 := v[n-1] - rec := reciprocalWord(vn1) - for j := m; j >= 0; j-- { - // D3. - qhat := Word(_M) - var ujn Word - if j+n < len(u) { - ujn = u[j+n] - } - if ujn != vn1 { - var rhat Word - qhat, rhat = divWW(ujn, u[j+n-1], vn1, rec) - - // x1 | x2 = q̂v_{n-2} - vn2 := v[n-2] - x1, x2 := mulWW(qhat, vn2) - // test if q̂v_{n-2} > br̂ + u_{j+n-2} - ujn2 := u[j+n-2] - for greaterThan(x1, x2, rhat, ujn2) { - qhat-- - prevRhat := rhat - rhat += vn1 - // v[n-1] >= 0, so this tests for overflow. - if rhat < prevRhat { - break - } - x1, x2 = mulWW(qhat, vn2) - } - } - - // D4. - // Compute the remainder u - (q̂*v) << (_W*j). - // The subtraction may overflow if q̂ estimate was off by one. - qhatv[n] = mulAddVWW(qhatv[0:n], v, qhat, 0) - qhl := len(qhatv) - if j+qhl > len(u) && qhatv[n] == 0 { - qhl-- - } - c := subVV(u[j:j+qhl], u[j:], qhatv) - if c != 0 { - c := addVV(u[j:j+n], u[j:], v) - // If n == qhl, the carry from subVV and the carry from addVV - // cancel out and don't affect u[j+n]. - if n < qhl { - u[j+n] += c - } - qhat-- - } - - if j == m && m == len(q) && qhat == 0 { - continue - } - q[j] = qhat - } - - putNat(qhatvp) -} - -const divRecursiveThreshold = 100 - -// divRecursive performs word-by-word division of u by v. -// The quotient is written in pre-allocated z. -// The remainder overwrites input u. -// -// Precondition: -// - len(z) >= len(u)-len(v) -// -// See Burnikel, Ziegler, "Fast Recursive Division", Algorithm 1 and 2. -func (z nat) divRecursive(u, v nat) { - // Recursion depth is less than 2 log2(len(v)) - // Allocate a slice of temporaries to be reused across recursion. - recDepth := 2 * bits.Len(uint(len(v))) - // large enough to perform Karatsuba on operands as large as v - tmp := getNat(3 * len(v)) - temps := make([]*nat, recDepth) - z.clear() - z.divRecursiveStep(u, v, 0, tmp, temps) - for _, n := range temps { - if n != nil { - putNat(n) - } - } - putNat(tmp) -} - -// divRecursiveStep computes the division of u by v. -// - z must be large enough to hold the quotient -// - the quotient will overwrite z -// - the remainder will overwrite u -func (z nat) divRecursiveStep(u, v nat, depth int, tmp *nat, temps []*nat) { - u = u.norm() - v = v.norm() - - if len(u) == 0 { - z.clear() - return - } - n := len(v) - if n < divRecursiveThreshold { - z.divBasic(u, v) - return - } - m := len(u) - n - if m < 0 { - return - } - - // Produce the quotient by blocks of B words. - // Division by v (length n) is done using a length n/2 division - // and a length n/2 multiplication for each block. The final - // complexity is driven by multiplication complexity. - B := n / 2 - - // Allocate a nat for qhat below. - if temps[depth] == nil { - temps[depth] = getNat(n) - } else { - *temps[depth] = temps[depth].make(B + 1) - } - - j := m - for j > B { - // Divide u[j-B:j+n] by vIn. Keep remainder in u - // for next block. - // - // The following property will be used (Lemma 2): - // if u = u1 << s + u0 - // v = v1 << s + v0 - // then floor(u1/v1) >= floor(u/v) - // - // Moreover, the difference is at most 2 if len(v1) >= len(u/v) - // We choose s = B-1 since len(v)-s >= B+1 >= len(u/v) - s := (B - 1) - // Except for the first step, the top bits are always - // a division remainder, so the quotient length is <= n. - uu := u[j-B:] - - qhat := *temps[depth] - qhat.clear() - qhat.divRecursiveStep(uu[s:B+n], v[s:], depth+1, tmp, temps) - qhat = qhat.norm() - // Adjust the quotient: - // u = u_h << s + u_l - // v = v_h << s + v_l - // u_h = q̂ v_h + rh - // u = q̂ (v - v_l) + rh << s + u_l - // After the above step, u contains a remainder: - // u = rh << s + u_l - // and we need to subtract q̂ v_l - // - // But it may be a bit too large, in which case q̂ needs to be smaller. - qhatv := tmp.make(3 * n) - qhatv.clear() - qhatv = qhatv.mul(qhat, v[:s]) - for i := 0; i < 2; i++ { - e := qhatv.cmp(uu.norm()) - if e <= 0 { - break - } - subVW(qhat, qhat, 1) - c := subVV(qhatv[:s], qhatv[:s], v[:s]) - if len(qhatv) > s { - subVW(qhatv[s:], qhatv[s:], c) - } - addAt(uu[s:], v[s:], 0) - } - if qhatv.cmp(uu.norm()) > 0 { - panic("impossible") - } - c := subVV(uu[:len(qhatv)], uu[:len(qhatv)], qhatv) - if c > 0 { - subVW(uu[len(qhatv):], uu[len(qhatv):], c) - } - addAt(z, qhat, j-B) - j -= B - } - - // Now u < (v< 0 { - subVW(qhat, qhat, 1) - c := subVV(qhatv[:s], qhatv[:s], v[:s]) - if len(qhatv) > s { - subVW(qhatv[s:], qhatv[s:], c) - } - addAt(u[s:], v[s:], 0) - } - } - if qhatv.cmp(u.norm()) > 0 { - panic("impossible") - } - c := subVV(u[0:len(qhatv)], u[0:len(qhatv)], qhatv) - if c > 0 { - c = subVW(u[len(qhatv):], u[len(qhatv):], c) - } - if c > 0 { - panic("impossible") - } - - // Done! - addAt(z, qhat.norm(), 0) -} - // Length of x in bits. x must be normalized. func (x nat) bitLen() int { if i := len(x) - 1; i >= 0 { @@ -1170,19 +858,6 @@ func (z nat) xor(x, y nat) nat { return z.norm() } -// greaterThan reports whether (x1<<_W + x2) > (y1<<_W + y2) -func greaterThan(x1, x2, y1, y2 Word) bool { - return x1 > y1 || x1 == y1 && x2 > y2 -} - -// modW returns x % d. -func (x nat) modW(d Word) (r Word) { - // TODO(agl): we don't actually need to store the q value. - var q nat - q = q.make(len(x)) - return divWVW(q, 0, x, d) -} - // random creates a random integer in [0..limit), using the space in z if // possible. n is the bit length of limit. func (z nat) random(rand *rand.Rand, limit nat, n int) nat { diff --git a/src/math/big/natdiv.go b/src/math/big/natdiv.go new file mode 100644 index 00000000000..1330990c2cd --- /dev/null +++ b/src/math/big/natdiv.go @@ -0,0 +1,346 @@ +// Copyright 2009 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 big + +import "math/bits" + +func (z nat) div(z2, u, v nat) (q, r nat) { + if len(v) == 0 { + panic("division by zero") + } + + if u.cmp(v) < 0 { + q = z[:0] + r = z2.set(u) + return + } + + if len(v) == 1 { + var r2 Word + q, r2 = z.divW(u, v[0]) + r = z2.setWord(r2) + return + } + + q, r = z.divLarge(z2, u, v) + return +} + +// q = (x-r)/y, with 0 <= r < y +func (z nat) divW(x nat, y Word) (q nat, r Word) { + m := len(x) + switch { + case y == 0: + panic("division by zero") + case y == 1: + q = z.set(x) // result is x + return + case m == 0: + q = z[:0] // result is 0 + return + } + // m > 0 + z = z.make(m) + r = divWVW(z, 0, x, y) + q = z.norm() + return +} + +// modW returns x % d. +func (x nat) modW(d Word) (r Word) { + // TODO(agl): we don't actually need to store the q value. + var q nat + q = q.make(len(x)) + return divWVW(q, 0, x, d) +} + +func divWVW(z []Word, xn Word, x []Word, y Word) (r Word) { + r = xn + if len(x) == 1 { + qq, rr := bits.Div(uint(r), uint(x[0]), uint(y)) + z[0] = Word(qq) + return Word(rr) + } + rec := reciprocalWord(y) + for i := len(z) - 1; i >= 0; i-- { + z[i], r = divWW(r, x[i], y, rec) + } + return r +} + +// q = (uIn-r)/vIn, with 0 <= r < vIn +// Uses z as storage for q, and u as storage for r if possible. +// See Knuth, Volume 2, section 4.3.1, Algorithm D. +// Preconditions: +// len(vIn) >= 2 +// len(uIn) >= len(vIn) +// u must not alias z +func (z nat) divLarge(u, uIn, vIn nat) (q, r nat) { + n := len(vIn) + m := len(uIn) - n + + // D1. + shift := nlz(vIn[n-1]) + // do not modify vIn, it may be used by another goroutine simultaneously + vp := getNat(n) + v := *vp + shlVU(v, vIn, shift) + + // u may safely alias uIn or vIn, the value of uIn is used to set u and vIn was already used + u = u.make(len(uIn) + 1) + u[len(uIn)] = shlVU(u[0:len(uIn)], uIn, shift) + + // z may safely alias uIn or vIn, both values were used already + if alias(z, u) { + z = nil // z is an alias for u - cannot reuse + } + q = z.make(m + 1) + + if n < divRecursiveThreshold { + q.divBasic(u, v) + } else { + q.divRecursive(u, v) + } + putNat(vp) + + q = q.norm() + shrVU(u, u, shift) + r = u.norm() + + return q, r +} + +// divBasic performs word-by-word division of u by v. +// The quotient is written in pre-allocated q. +// The remainder overwrites input u. +// +// Precondition: +// - q is large enough to hold the quotient u / v +// which has a maximum length of len(u)-len(v)+1. +func (q nat) divBasic(u, v nat) { + n := len(v) + m := len(u) - n + + qhatvp := getNat(n + 1) + qhatv := *qhatvp + + // D2. + vn1 := v[n-1] + rec := reciprocalWord(vn1) + for j := m; j >= 0; j-- { + // D3. + qhat := Word(_M) + var ujn Word + if j+n < len(u) { + ujn = u[j+n] + } + if ujn != vn1 { + var rhat Word + qhat, rhat = divWW(ujn, u[j+n-1], vn1, rec) + + // x1 | x2 = q̂v_{n-2} + vn2 := v[n-2] + x1, x2 := mulWW(qhat, vn2) + // test if q̂v_{n-2} > br̂ + u_{j+n-2} + ujn2 := u[j+n-2] + for greaterThan(x1, x2, rhat, ujn2) { + qhat-- + prevRhat := rhat + rhat += vn1 + // v[n-1] >= 0, so this tests for overflow. + if rhat < prevRhat { + break + } + x1, x2 = mulWW(qhat, vn2) + } + } + + // D4. + // Compute the remainder u - (q̂*v) << (_W*j). + // The subtraction may overflow if q̂ estimate was off by one. + qhatv[n] = mulAddVWW(qhatv[0:n], v, qhat, 0) + qhl := len(qhatv) + if j+qhl > len(u) && qhatv[n] == 0 { + qhl-- + } + c := subVV(u[j:j+qhl], u[j:], qhatv) + if c != 0 { + c := addVV(u[j:j+n], u[j:], v) + // If n == qhl, the carry from subVV and the carry from addVV + // cancel out and don't affect u[j+n]. + if n < qhl { + u[j+n] += c + } + qhat-- + } + + if j == m && m == len(q) && qhat == 0 { + continue + } + q[j] = qhat + } + + putNat(qhatvp) +} + +// greaterThan reports whether (x1<<_W + x2) > (y1<<_W + y2) +func greaterThan(x1, x2, y1, y2 Word) bool { + return x1 > y1 || x1 == y1 && x2 > y2 +} + +const divRecursiveThreshold = 100 + +// divRecursive performs word-by-word division of u by v. +// The quotient is written in pre-allocated z. +// The remainder overwrites input u. +// +// Precondition: +// - len(z) >= len(u)-len(v) +// +// See Burnikel, Ziegler, "Fast Recursive Division", Algorithm 1 and 2. +func (z nat) divRecursive(u, v nat) { + // Recursion depth is less than 2 log2(len(v)) + // Allocate a slice of temporaries to be reused across recursion. + recDepth := 2 * bits.Len(uint(len(v))) + // large enough to perform Karatsuba on operands as large as v + tmp := getNat(3 * len(v)) + temps := make([]*nat, recDepth) + z.clear() + z.divRecursiveStep(u, v, 0, tmp, temps) + for _, n := range temps { + if n != nil { + putNat(n) + } + } + putNat(tmp) +} + +// divRecursiveStep computes the division of u by v. +// - z must be large enough to hold the quotient +// - the quotient will overwrite z +// - the remainder will overwrite u +func (z nat) divRecursiveStep(u, v nat, depth int, tmp *nat, temps []*nat) { + u = u.norm() + v = v.norm() + + if len(u) == 0 { + z.clear() + return + } + n := len(v) + if n < divRecursiveThreshold { + z.divBasic(u, v) + return + } + m := len(u) - n + if m < 0 { + return + } + + // Produce the quotient by blocks of B words. + // Division by v (length n) is done using a length n/2 division + // and a length n/2 multiplication for each block. The final + // complexity is driven by multiplication complexity. + B := n / 2 + + // Allocate a nat for qhat below. + if temps[depth] == nil { + temps[depth] = getNat(n) + } else { + *temps[depth] = temps[depth].make(B + 1) + } + + j := m + for j > B { + // Divide u[j-B:j+n] by vIn. Keep remainder in u + // for next block. + // + // The following property will be used (Lemma 2): + // if u = u1 << s + u0 + // v = v1 << s + v0 + // then floor(u1/v1) >= floor(u/v) + // + // Moreover, the difference is at most 2 if len(v1) >= len(u/v) + // We choose s = B-1 since len(v)-s >= B+1 >= len(u/v) + s := (B - 1) + // Except for the first step, the top bits are always + // a division remainder, so the quotient length is <= n. + uu := u[j-B:] + + qhat := *temps[depth] + qhat.clear() + qhat.divRecursiveStep(uu[s:B+n], v[s:], depth+1, tmp, temps) + qhat = qhat.norm() + // Adjust the quotient: + // u = u_h << s + u_l + // v = v_h << s + v_l + // u_h = q̂ v_h + rh + // u = q̂ (v - v_l) + rh << s + u_l + // After the above step, u contains a remainder: + // u = rh << s + u_l + // and we need to subtract q̂ v_l + // + // But it may be a bit too large, in which case q̂ needs to be smaller. + qhatv := tmp.make(3 * n) + qhatv.clear() + qhatv = qhatv.mul(qhat, v[:s]) + for i := 0; i < 2; i++ { + e := qhatv.cmp(uu.norm()) + if e <= 0 { + break + } + subVW(qhat, qhat, 1) + c := subVV(qhatv[:s], qhatv[:s], v[:s]) + if len(qhatv) > s { + subVW(qhatv[s:], qhatv[s:], c) + } + addAt(uu[s:], v[s:], 0) + } + if qhatv.cmp(uu.norm()) > 0 { + panic("impossible") + } + c := subVV(uu[:len(qhatv)], uu[:len(qhatv)], qhatv) + if c > 0 { + subVW(uu[len(qhatv):], uu[len(qhatv):], c) + } + addAt(z, qhat, j-B) + j -= B + } + + // Now u < (v< 0 { + subVW(qhat, qhat, 1) + c := subVV(qhatv[:s], qhatv[:s], v[:s]) + if len(qhatv) > s { + subVW(qhatv[s:], qhatv[s:], c) + } + addAt(u[s:], v[s:], 0) + } + } + if qhatv.cmp(u.norm()) > 0 { + panic("impossible") + } + c := subVV(u[0:len(qhatv)], u[0:len(qhatv)], qhatv) + if c > 0 { + c = subVW(u[len(qhatv):], u[len(qhatv):], c) + } + if c > 0 { + panic("impossible") + } + + // Done! + addAt(z, qhat.norm(), 0) +} From fd54ae8b0c7ed3ef9869112586069f7cac82cf1e Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Mon, 24 May 2021 20:36:42 -0700 Subject: [PATCH 161/940] [dev.typeparams] cmd/compile: adding union support in types1 Add union support in types1, and allow exporting of unions, and importing unions back into types1 and types2. Added new test mincheck.go/mincheck.dir that tests that type lists (type sets) are correctly exported/imported, so that types2 gives correct errors that an instantiation doesn't fit the type list in the type param constraint. Change-Id: I8041c6c79289c870a95ed5a1b10e4c1c16985b12 Reviewed-on: https://go-review.googlesource.com/c/go/+/322609 Trust: Dan Scales Trust: Robert Griesemer Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/importer/iimport.go | 14 +++++++ src/cmd/compile/internal/noder/types.go | 19 +++++++-- src/cmd/compile/internal/typecheck/iexport.go | 13 +++++++ src/cmd/compile/internal/typecheck/iimport.go | 13 +++++++ src/cmd/compile/internal/types/kind_string.go | 23 +++++------ src/cmd/compile/internal/types/size.go | 14 ++++++- src/cmd/compile/internal/types/type.go | 39 +++++++++++++++++++ src/cmd/compile/internal/types2/type.go | 13 ------- test/fixedbugs/bug195.go | 2 +- test/fixedbugs/issue11614.go | 2 +- test/typeparam/mincheck.dir/a.go | 16 ++++++++ test/typeparam/mincheck.dir/main.go | 38 ++++++++++++++++++ test/typeparam/mincheck.go | 7 ++++ 13 files changed, 182 insertions(+), 31 deletions(-) create mode 100644 test/typeparam/mincheck.dir/a.go create mode 100644 test/typeparam/mincheck.dir/main.go create mode 100644 test/typeparam/mincheck.go diff --git a/src/cmd/compile/internal/importer/iimport.go b/src/cmd/compile/internal/importer/iimport.go index 37e5113435c..fd48bfc1796 100644 --- a/src/cmd/compile/internal/importer/iimport.go +++ b/src/cmd/compile/internal/importer/iimport.go @@ -68,6 +68,7 @@ const ( interfaceType typeParamType instType + unionType ) const io_SeekCurrent = 1 // io.SeekCurrent (not defined in Go 1.4) @@ -660,6 +661,19 @@ func (r *importReader) doType(base *types2.Named) types2.Type { // we must always use the methods of the base (orig) type. t := types2.Instantiate(pos, baseType, targs) return t + + case unionType: + if r.p.exportVersion < iexportVersionGenerics { + errorf("unexpected instantiation type") + } + nt := int(r.uint64()) + terms := make([]types2.Type, nt) + tildes := make([]bool, nt) + for i := range terms { + terms[i] = r.typ() + tildes[i] = r.bool() + } + return types2.NewUnion(terms, tildes) } } diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go index 16d664f5380..c6e97d4206b 100644 --- a/src/cmd/compile/internal/noder/types.go +++ b/src/cmd/compile/internal/noder/types.go @@ -187,6 +187,9 @@ func (g *irgen) typ0(typ types2.Type) *types.Type { for i := range embeddeds { // TODO(mdempsky): Get embedding position. e := typ.EmbeddedType(i) + + // With Go 1.18, an embedded element can be any type, not + // just an interface. if t := types2.AsInterface(e); t != nil { if t.IsComparable() { // Ignore predefined type 'comparable', since it @@ -194,11 +197,9 @@ func (g *irgen) typ0(typ types2.Type) *types.Type { // relevant methods. continue } - embeddeds[j] = types.NewField(src.NoXPos, nil, g.typ1(e)) - j++ } - // Ignore embedded non-interface types - they correspond - // to type lists which we currently don't handle here. + embeddeds[j] = types.NewField(src.NoXPos, nil, g.typ1(e)) + j++ } embeddeds = embeddeds[:j] @@ -234,6 +235,16 @@ func (g *irgen) typ0(typ types2.Type) *types.Type { tp.SetBound(bound) return tp + case *types2.Union: + nt := typ.NumTerms() + tlist := make([]*types.Type, nt) + tildes := make([]bool, nt) + for i := range tlist { + term, _ := typ.Term(i) + tlist[i] = g.typ1(term) + } + return types.NewUnion(tlist, tildes) + case *types2.Tuple: // Tuples are used for the type of a function call (i.e. the // return value of the function). diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index 292bb2c409a..ea8e751852c 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -256,6 +256,7 @@ const ( interfaceType typeParamType instType + unionType ) const ( @@ -943,6 +944,18 @@ func (w *exportWriter) doTyp(t *types.Type) { w.signature(f.Type) } + case types.TUNION: + // TODO(danscales): possibly put out the tilde bools in more + // compact form. + w.startType(unionType) + nt := t.NumTerms() + w.uint64(uint64(nt)) + for i := 0; i < nt; i++ { + t, b := t.Term(i) + w.typ(t) + w.bool(b) + } + default: base.Fatalf("unexpected type: %v", t) } diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index d5b549483d8..3fb675f8244 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -790,6 +790,19 @@ func (r *importReader) typ1() *types.Type { baseType := r.typ() t := Instantiate(pos, baseType, targs) return t + + case unionType: + if r.p.exportVersion < iexportVersionGenerics { + base.Fatalf("unexpected instantiation type") + } + nt := int(r.uint64()) + terms := make([]*types.Type, nt) + tildes := make([]bool, nt) + for i := range terms { + terms[i] = r.typ() + tildes[i] = r.bool() + } + return types.NewUnion(terms, tildes) } } diff --git a/src/cmd/compile/internal/types/kind_string.go b/src/cmd/compile/internal/types/kind_string.go index ae24a58b921..3e6a8bc064e 100644 --- a/src/cmd/compile/internal/types/kind_string.go +++ b/src/cmd/compile/internal/types/kind_string.go @@ -38,20 +38,21 @@ func _() { _ = x[TSTRING-27] _ = x[TUNSAFEPTR-28] _ = x[TTYPEPARAM-29] - _ = x[TIDEAL-30] - _ = x[TNIL-31] - _ = x[TBLANK-32] - _ = x[TFUNCARGS-33] - _ = x[TCHANARGS-34] - _ = x[TSSA-35] - _ = x[TTUPLE-36] - _ = x[TRESULTS-37] - _ = x[NTYPE-38] + _ = x[TUNION-30] + _ = x[TIDEAL-31] + _ = x[TNIL-32] + _ = x[TBLANK-33] + _ = x[TFUNCARGS-34] + _ = x[TCHANARGS-35] + _ = x[TSSA-36] + _ = x[TTUPLE-37] + _ = x[TRESULTS-38] + _ = x[NTYPE-39] } -const _Kind_name = "xxxINT8UINT8INT16UINT16INT32UINT32INT64UINT64INTUINTUINTPTRCOMPLEX64COMPLEX128FLOAT32FLOAT64BOOLPTRFUNCSLICEARRAYSTRUCTCHANMAPINTERFORWANYSTRINGUNSAFEPTRTYPEPARAMIDEALNILBLANKFUNCARGSCHANARGSSSATUPLERESULTSNTYPE" +const _Kind_name = "xxxINT8UINT8INT16UINT16INT32UINT32INT64UINT64INTUINTUINTPTRCOMPLEX64COMPLEX128FLOAT32FLOAT64BOOLPTRFUNCSLICEARRAYSTRUCTCHANMAPINTERFORWANYSTRINGUNSAFEPTRTYPEPARAMUNIONIDEALNILBLANKFUNCARGSCHANARGSSSATUPLERESULTSNTYPE" -var _Kind_index = [...]uint8{0, 3, 7, 12, 17, 23, 28, 34, 39, 45, 48, 52, 59, 68, 78, 85, 92, 96, 99, 103, 108, 113, 119, 123, 126, 131, 135, 138, 144, 153, 162, 167, 170, 175, 183, 191, 194, 199, 206, 211} +var _Kind_index = [...]uint8{0, 3, 7, 12, 17, 23, 28, 34, 39, 45, 48, 52, 59, 68, 78, 85, 92, 96, 99, 103, 108, 113, 119, 123, 126, 131, 135, 138, 144, 153, 162, 167, 172, 175, 180, 188, 196, 199, 204, 211, 216} func (i Kind) String() string { if i >= Kind(len(_Kind_index)-1) { diff --git a/src/cmd/compile/internal/types/size.go b/src/cmd/compile/internal/types/size.go index f0e695ab964..7059eff398c 100644 --- a/src/cmd/compile/internal/types/size.go +++ b/src/cmd/compile/internal/types/size.go @@ -104,8 +104,14 @@ func expandiface(t *Type) { continue } + if m.Type.IsUnion() { + continue + } + + // Once we go to 1.18, then embedded types can be anything, but + // for now, just interfaces and unions. if !m.Type.IsInterface() { - base.ErrorfAt(m.Pos, "interface contains embedded non-interface %v", m.Type) + base.ErrorfAt(m.Pos, "interface contains embedded non-interface, non-union %v", m.Type) m.SetBroke(true) t.SetBroke(true) // Add to fields so that error messages @@ -405,6 +411,12 @@ func CalcSize(t *Type) { t.Align = uint8(PtrSize) expandiface(t) + case TUNION: + // Always part of an interface for now, so size/align don't matter. + // Pretend a union is represented like an interface. + w = 2 * int64(PtrSize) + t.Align = uint8(PtrSize) + case TCHAN: // implemented as pointer w = int64(PtrSize) diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index 3b0a9706f65..e7831121bff 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -73,6 +73,7 @@ const ( TSTRING TUNSAFEPTR TTYPEPARAM + TUNION // pseudo-types for literals TIDEAL // untyped numeric constants @@ -392,6 +393,12 @@ type Typeparam struct { bound *Type } +// Union contains Type fields specific to union types. +type Union struct { + terms []*Type + tildes []bool // whether terms[i] is of form ~T +} + // Ptr contains Type fields specific to pointer types. type Ptr struct { Elem *Type // element type @@ -574,6 +581,8 @@ func New(et Kind) *Type { t.Extra = new(Results) case TTYPEPARAM: t.Extra = new(Typeparam) + case TUNION: + t.Extra = new(Union) } return t } @@ -1453,6 +1462,10 @@ func (t *Type) IsInterface() bool { return t.kind == TINTER } +func (t *Type) IsUnion() bool { + return t.kind == TUNION +} + // IsEmptyInterface reports whether t is an empty interface type. func (t *Type) IsEmptyInterface() bool { return t.IsInterface() && t.AllMethods().Len() == 0 @@ -1811,6 +1824,32 @@ func (t *Type) Bound() *Type { return t.Extra.(*Typeparam).bound } +// NewUnion returns a new union with the specified set of terms (types). If +// tildes[i] is true, then terms[i] represents ~T, rather than just T. +func NewUnion(terms []*Type, tildes []bool) *Type { + t := New(TUNION) + if len(terms) != len(tildes) { + base.Fatalf("Mismatched terms and tildes for NewUnion") + } + t.Extra.(*Union).terms = terms + t.Extra.(*Union).tildes = tildes + return t +} + +// NumTerms returns the number of terms in a union type. +func (t *Type) NumTerms() int { + t.wantEtype(TUNION) + return len(t.Extra.(*Union).terms) +} + +// Term returns ith term of a union type as (term, tilde). If tilde is true, term +// represents ~T, rather than just T. +func (t *Type) Term(i int) (*Type, bool) { + t.wantEtype(TUNION) + u := t.Extra.(*Union) + return u.terms[i], u.tildes[i] +} + const BOGUS_FUNARG_OFFSET = -1000000000 func unzeroFieldOffsets(f []*Field) { diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index 79a8f3cd7f4..2a93ca03885 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -368,9 +368,6 @@ func NewInterface(methods []*Func, embeddeds []*Named) *Interface { } // NewInterfaceType returns a new (incomplete) interface for the given methods and embedded types. -// Each embedded type must have an underlying type of interface type (this property is not -// verified for defined types, which may be in the process of being set up and which don't -// have a valid underlying type yet). // NewInterfaceType takes ownership of the provided methods and may modify their types by setting // missing receivers. To compute the method set of the interface, Complete must be called. func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface { @@ -386,16 +383,6 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface { } } - // All embedded types should be interfaces; however, defined types - // may not yet be fully resolved. Only verify that non-defined types - // are interfaces. This matches the behavior of the code before the - // fix for #25301 (issue #25596). - for _, t := range embeddeds { - if _, ok := t.(*Named); !ok && !IsInterface(t) { - panic("embedded type is not an interface") - } - } - // sort for API stability sortMethods(methods) sortTypes(embeddeds) diff --git a/test/fixedbugs/bug195.go b/test/fixedbugs/bug195.go index 94f61fff7f1..6d8578d6cb0 100644 --- a/test/fixedbugs/bug195.go +++ b/test/fixedbugs/bug195.go @@ -1,4 +1,4 @@ -// errorcheck +// errorcheck -lang=go1.17 // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/test/fixedbugs/issue11614.go b/test/fixedbugs/issue11614.go index de15f9827ff..6ea463b7fe9 100644 --- a/test/fixedbugs/issue11614.go +++ b/test/fixedbugs/issue11614.go @@ -1,4 +1,4 @@ -// errorcheck +// errorcheck -lang=go1.17 // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/test/typeparam/mincheck.dir/a.go b/test/typeparam/mincheck.dir/a.go new file mode 100644 index 00000000000..f1844bba9da --- /dev/null +++ b/test/typeparam/mincheck.dir/a.go @@ -0,0 +1,16 @@ +// Copyright 2021 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 a + +type Ordered interface { + type int, int64, float64 +} + +func Min[T Ordered](x, y T) T { + if x < y { + return x + } + return y +} diff --git a/test/typeparam/mincheck.dir/main.go b/test/typeparam/mincheck.dir/main.go new file mode 100644 index 00000000000..72d8effcc50 --- /dev/null +++ b/test/typeparam/mincheck.dir/main.go @@ -0,0 +1,38 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "a" + "fmt" +) + +func main() { + const want = 2 + if got := a.Min[int](2, 3); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + if got := a.Min(2, 3); got != want { + panic(fmt.Sprintf("want %d, got %d", want, got)) + } + + if got := a.Min[float64](3.5, 2.0); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + if got := a.Min(3.5, 2.0); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + const want2 = "ay" + if got := a.Min[string]("bb", "ay"); got != want2 { // ERROR "string does not satisfy interface{int|int64|float64}" + panic(fmt.Sprintf("got %d, want %d", got, want2)) + } + + if got := a.Min("bb", "ay"); got != want2 { // ERROR "string does not satisfy interface{int|int64|float64}" + panic(fmt.Sprintf("got %d, want %d", got, want2)) + } +} diff --git a/test/typeparam/mincheck.go b/test/typeparam/mincheck.go new file mode 100644 index 00000000000..32cf4b830d2 --- /dev/null +++ b/test/typeparam/mincheck.go @@ -0,0 +1,7 @@ +// errorcheckdir -G=3 + +// Copyright 2021 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 ignored From bfd7798a6c756b22d7376db527339b41bf7f7327 Mon Sep 17 00:00:00 2001 From: tyltr Date: Wed, 26 May 2021 15:41:27 +0000 Subject: [PATCH 162/940] runtime,cmd/link/internal/ld: fix typos Change-Id: I558590cef7e2311aadbdcb4088033e350d3aae32 GitHub-Last-Rev: 513944a6238e0e32e2a2c266b70f7d50c9db508d GitHub-Pull-Request: golang/go#46389 Reviewed-on: https://go-review.googlesource.com/c/go/+/322809 Reviewed-by: Cherry Mui Reviewed-by: Ian Lance Taylor --- src/cmd/link/internal/ld/data.go | 2 +- src/runtime/malloc.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 223df63d9df..70fbb9dc4e2 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -1550,7 +1550,7 @@ func (ctxt *Link) dodata(symGroupType []sym.SymKind) { if ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal { // These symbols must have the same alignment as their section. - // Otherwize, ld might change the layout of Go sections. + // Otherwise, ld might change the layout of Go sections. ldr.SetSymAlign(ldr.Lookup("runtime.data", 0), state.dataMaxAlign[sym.SDATA]) ldr.SetSymAlign(ldr.Lookup("runtime.bss", 0), state.dataMaxAlign[sym.SBSS]) } diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 81e52258830..2759bbdaf90 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -296,7 +296,7 @@ const ( // high addresses if viewed as unsigned). // // On aix/ppc64, this offset allows to keep the heapAddrBits to - // 48. Otherwize, it would be 60 in order to handle mmap addresses + // 48. Otherwise, it would be 60 in order to handle mmap addresses // (in range 0x0a00000000000000 - 0x0afffffffffffff). But in this // case, the memory reserved in (s *pageAlloc).init for chunks // is causing important slowdowns. From 39da9ae5130afa58f8b9e4ea609a57d516bd78db Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 6 May 2021 22:28:37 -0400 Subject: [PATCH 163/940] go/types: ensure that Named.check is nilled out once it is expanded To support lazy expansion of defined types, *Named holds on to a *Checker field, which can pin the *Checker in memory. This can have meaningful memory implications for applications that keep type information around. Ensure that the Checker field is nilled out for any Named types that are instantiated during the type checking pass, by deferring a clean up to 'later' boundaries. In testing this almost exactly offset the ~6% memory footprint increase I observed with 1.17. Fixes #45580 Change-Id: I8aa5bb777573a924afe36e79fa65f8729336bceb Reviewed-on: https://go-review.googlesource.com/c/go/+/318849 Trust: Robert Findley Trust: Robert Griesemer Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/decl.go | 53 ++++++++++++++++++++++++++++++---------- src/go/types/sanitize.go | 3 +++ src/go/types/type.go | 17 ++++++++++++- 3 files changed, 59 insertions(+), 14 deletions(-) diff --git a/src/go/types/decl.go b/src/go/types/decl.go index 5f38a346cee..9211febc6da 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -577,15 +577,37 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) { // n0.check != nil, the cycle is reported. func (n0 *Named) under() Type { u := n0.underlying - if u == nil { - return Typ[Invalid] + + if u == Typ[Invalid] { + return u } // If the underlying type of a defined type is not a defined - // type, then that is the desired underlying type. + // (incl. instance) type, then that is the desired underlying + // type. + switch u.(type) { + case nil: + return Typ[Invalid] + default: + // common case + return u + case *Named, *instance: + // handled below + } + + if n0.check == nil { + panic("internal error: Named.check == nil but type is incomplete") + } + + // Invariant: after this point n0 as well as any named types in its + // underlying chain should be set up when this function exits. + check := n0.check + + // If we can't expand u at this point, it is invalid. n := asNamed(u) if n == nil { - return u // common case + n0.underlying = Typ[Invalid] + return n0.underlying } // Otherwise, follow the forward chain. @@ -597,7 +619,16 @@ func (n0 *Named) under() Type { u = Typ[Invalid] break } - n1 := asNamed(u) + var n1 *Named + switch u1 := u.(type) { + case *Named: + n1 = u1 + case *instance: + n1, _ = u1.expand().(*Named) + if n1 == nil { + u = Typ[Invalid] + } + } if n1 == nil { break // end of chain } @@ -608,11 +639,7 @@ func (n0 *Named) under() Type { if i, ok := seen[n]; ok { // cycle - // TODO(rFindley) revert this to a method on Checker. Having a possibly - // nil Checker on Named and TypeParam is too subtle. - if n0.check != nil { - n0.check.cycleError(path[i:]) - } + check.cycleError(path[i:]) u = Typ[Invalid] break } @@ -622,8 +649,8 @@ func (n0 *Named) under() Type { // We should never have to update the underlying type of an imported type; // those underlying types should have been resolved during the import. // Also, doing so would lead to a race condition (was issue #31749). - // Do this check always, not just in debug more (it's cheap). - if n0.check != nil && n.obj.pkg != n0.check.pkg { + // Do this check always, not just in debug mode (it's cheap). + if n.obj.pkg != check.pkg { panic("internal error: imported type with unresolved underlying type") } n.underlying = u @@ -665,7 +692,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) { } else { // defined type declaration - named := &Named{check: check, obj: obj} + named := check.newNamed(obj, nil, nil) def.setUnderlying(named) obj.typ = named // make sure recursive type declarations terminate diff --git a/src/go/types/sanitize.go b/src/go/types/sanitize.go index 5970ab38c71..727ec173eac 100644 --- a/src/go/types/sanitize.go +++ b/src/go/types/sanitize.go @@ -135,6 +135,9 @@ func (s sanitizer) typ(typ Type) Type { } case *Named: + if debug && t.check != nil { + panic("internal error: Named.check != nil") + } if orig := s.typ(t.orig); orig != t.orig { t.orig = orig } diff --git a/src/go/types/type.go b/src/go/types/type.go index 3303cfc0774..3fdb2365a03 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -644,7 +644,7 @@ func (c *Chan) Elem() Type { return c.elem } // A Named represents a named (defined) type. type Named struct { - check *Checker // for Named.under implementation + check *Checker // for Named.under implementation; nilled once under has been called info typeInfo // for cycle detection obj *TypeName // corresponding declared object orig Type // type (on RHS of declaration) this *Named type is derived of (for cycle reporting) @@ -673,6 +673,21 @@ func (check *Checker) newNamed(obj *TypeName, underlying Type, methods []*Func) if obj.typ == nil { obj.typ = typ } + // Ensure that typ is always expanded, at which point the check field can be + // nilled out. + // + // Note that currently we cannot nil out check inside typ.under(), because + // it's possible that typ is expanded multiple times. + // + // TODO(rFindley): clean this up so that under is the only function mutating + // named types. + check.later(func() { + switch typ.under().(type) { + case *Named, *instance: + panic("internal error: unexpanded underlying type") + } + typ.check = nil + }) return typ } From 55aefbb268d7d33ebf300ed5b1e38e55c10c8070 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 19 May 2021 16:34:58 -0400 Subject: [PATCH 164/940] doc/go1.17: mention enabling frame pointer on all ARM64 Updates #44513. Change-Id: I43e95de0423779b3311d96c56f7c8c1cc5be27b6 Reviewed-on: https://go-review.googlesource.com/c/go/+/321311 Trust: Cherry Mui Reviewed-by: Jeremy Faller --- doc/go1.17.html | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/go1.17.html b/doc/go1.17.html index bdde26bd108..5448b2af975 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -68,6 +68,14 @@ Do not send CLs removing the interior tags from such phrases. OpenBSD.

+

ARM64

+ +

+ Go programs now maintain stack frame pointers on the 64-bit ARM + architecture on all operating systems. Previously it maintained + stack frame pointers only on Linux, macOS, and iOS. +

+

TODO: complete the Ports section

From a92460fd2f5537bbd91a713ced00731d429563ac Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 26 May 2021 12:18:32 -0400 Subject: [PATCH 165/940] doc/go1.17: add release notes for runtime/metrics package Updates #44513. Change-Id: I571a791e9c76371be3b3f1a323f1ea8ff485cf0f Reviewed-on: https://go-review.googlesource.com/c/go/+/322857 Trust: Cherry Mui Reviewed-by: Jeremy Faller Reviewed-by: Michael Knyszek --- doc/go1.17.html | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/go1.17.html b/doc/go1.17.html index 5448b2af975..da50935a612 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -496,6 +496,16 @@ Do not send CLs removing the interior tags from such phrases.
+
runtime/metrics
+
+

+ New metrics were added that track total bytes and objects allocated and freed. + A new metric tracking the distribution of goroutine scheduling latencies was + also added. +

+
+
+
strconv

From 95748d1b741d2c612cf90d9b6f4f8bdb81800e23 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 18 May 2021 01:20:13 -0700 Subject: [PATCH 166/940] [dev.typeparams] cmd/compile: avoid some redundant type construction This CL updates noder and typecheck to avoid a couple of instances of redundant evaluation of type expressions: 1. When noding struct fields or parameter tuples, check for syntax.Type reuse between adjacent fields and then reuse the corresponding ir.Node type expression. It would perhaps be even better to avoid re-noding the type expression too, but noder's days are numbered anyway, so I'd rather be minimally invasive here. 2. When importing an empty interface, reuse the same cached empty interface instance that is used for empty interfaces that appear in source. This matches types2's behavior, which uses a single types2.Interface instance for all empty interfaces. These changes are motivated by making it possible to migrate from typecheck to types2 while passing toolstash -cmp. Updates #46208. Change-Id: Ia6458894494464d863181db356f3284630c90ffe Reviewed-on: https://go-review.googlesource.com/c/go/+/320789 Run-TryBot: Matthew Dempsky Trust: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/noder/noder.go | 6 ++++++ src/cmd/compile/internal/typecheck/iimport.go | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go index 4c7c9fc322f..06c3b00601f 100644 --- a/src/cmd/compile/internal/noder/noder.go +++ b/src/cmd/compile/internal/noder/noder.go @@ -625,6 +625,9 @@ func (p *noder) params(params []*syntax.Field, dddOk bool) []*ir.Field { for i, param := range params { p.setlineno(param) nodes = append(nodes, p.param(param, dddOk, i+1 == len(params))) + if i > 0 && params[i].Type == params[i-1].Type { + nodes[i].Ntype = nodes[i-1].Ntype + } } return nodes } @@ -917,6 +920,9 @@ func (p *noder) structType(expr *syntax.StructType) ir.Node { } else { n = ir.NewField(p.pos(field), p.name(field.Name), p.typeExpr(field.Type), nil) } + if i > 0 && expr.FieldList[i].Type == expr.FieldList[i-1].Type { + n.Ntype = l[i-1].Ntype + } if i < len(expr.TagList) && expr.TagList[i] != nil { n.Note = constant.StringVal(p.basicLit(expr.TagList[i])) } diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 3fb675f8244..16b3e7ceba4 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -745,6 +745,10 @@ func (r *importReader) typ1() *types.Type { methods[i] = types.NewField(pos, sym, typ) } + if len(embeddeds)+len(methods) == 0 { + return types.Types[types.TINTER] + } + t := types.NewInterface(r.currPkg, append(embeddeds, methods...)) // Ensure we expand the interface in the frontend (#25055). From b7f7d1cd7b3d965ec25d365b3e5057ef3278c729 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Mon, 24 May 2021 14:15:48 -0700 Subject: [PATCH 167/940] [dev.typeparams] cmd/compile: get type aliases working with generic types Generic types can the source type of a type alias, so modify g.typ0() to be able to deal with base generic types. Added test aliasimp.go that tests aliasing of local generic types and imported generic types. Change-Id: I1c398193819d47a36b014cc1f9bb55107e9a565b Reviewed-on: https://go-review.googlesource.com/c/go/+/322194 Trust: Dan Scales Trust: Robert Griesemer Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/noder/types.go | 45 ++++++++++++------------- test/typeparam/aliasimp.dir/a.go | 9 +++++ test/typeparam/aliasimp.dir/main.go | 38 +++++++++++++++++++++ test/typeparam/aliasimp.go | 7 ++++ 4 files changed, 76 insertions(+), 23 deletions(-) create mode 100644 test/typeparam/aliasimp.dir/a.go create mode 100644 test/typeparam/aliasimp.dir/main.go create mode 100644 test/typeparam/aliasimp.go diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go index c6e97d4206b..ae10e03a247 100644 --- a/src/cmd/compile/internal/noder/types.go +++ b/src/cmd/compile/internal/noder/types.go @@ -91,50 +91,49 @@ func (g *irgen) typ0(typ types2.Type) *types.Type { case *types2.Basic: return g.basic(typ) case *types2.Named: - if typ.TParams() != nil { + // If tparams is set, but targs is not, typ is a base generic + // type. typ is appearing as part of the source type of an alias, + // since that is the only use of a generic type that doesn't + // involve instantiation. We just translate the named type in the + // normal way below using g.obj(). + if typ.TParams() != nil && typ.TArgs() != nil { // typ is an instantiation of a defined (named) generic type. // This instantiation should also be a defined (named) type. // types2 gives us the substituted type in t.Underlying() // The substituted type may or may not still have type // params. We might, for example, be substituting one type // param for another type param. - - if typ.TArgs() == nil { - base.Fatalf("In typ0, Targs should be set if TParams is set") - } - - // When converted to types.Type, typ must have a name, - // based on the names of the type arguments. We need a - // name to deal with recursive generic types (and it also - // looks better when printing types). + // + // When converted to types.Type, typ has a unique name, + // based on the names of the type arguments. instName := instTypeName2(typ.Obj().Name(), typ.TArgs()) s := g.pkg(typ.Obj().Pkg()).Lookup(instName) if s.Def != nil { - // We have already encountered this instantiation, - // so use the type we previously created, since there + // We have already encountered this instantiation. + // Use the type we previously created, since there // must be exactly one instance of a defined type. return s.Def.Type() } // Create a forwarding type first and put it in the g.typs - // map, in order to deal with recursive generic types. - // Fully set up the extra ntyp information (Def, RParams, - // which may set HasTParam) before translating the - // underlying type itself, so we handle recursion - // correctly, including via method signatures. + // map, in order to deal with recursive generic types + // (including via method signatures).. Set up the extra + // ntyp information (Def, RParams, which may set + // HasTParam) before translating the underlying type + // itself, so we handle recursion correctly. ntyp := typecheck.NewIncompleteNamedType(g.pos(typ.Obj().Pos()), s) g.typs[typ] = ntyp // If ntyp still has type params, then we must be // referencing something like 'value[T2]', as when - // specifying the generic receiver of a method, - // where value was defined as "type value[T any] - // ...". Save the type args, which will now be the - // new type of the current type. + // specifying the generic receiver of a method, where + // value was defined as "type value[T any] ...". Save the + // type args, which will now be the new typeparams of the + // current type. // // If ntyp does not have type params, we are saving the - // concrete types used to instantiate this type. We'll use - // these when instantiating the methods of the + // non-generic types used to instantiate this type. We'll + // use these when instantiating the methods of the // instantiated type. rparams := make([]*types.Type, len(typ.TArgs())) for i, targ := range typ.TArgs() { diff --git a/test/typeparam/aliasimp.dir/a.go b/test/typeparam/aliasimp.dir/a.go new file mode 100644 index 00000000000..3fac4aac987 --- /dev/null +++ b/test/typeparam/aliasimp.dir/a.go @@ -0,0 +1,9 @@ +// Copyright 2020 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 a + +type Rimp[T any] struct { + F T +} diff --git a/test/typeparam/aliasimp.dir/main.go b/test/typeparam/aliasimp.dir/main.go new file mode 100644 index 00000000000..6638fa94545 --- /dev/null +++ b/test/typeparam/aliasimp.dir/main.go @@ -0,0 +1,38 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "a" + +type R[T any] struct { + F T +} + +type S = R + +type Sint = R[int] + +type Simp = a.Rimp + +type SimpString Simp[string] + +func main() { + var s S[int] + if s.F != 0 { + panic(s.F) + } + var s2 Sint + if s2.F != 0 { + panic(s2.F) + } + var s3 Simp[string] + if s3.F != "" { + panic(s3.F) + } + var s4 SimpString + if s4.F != "" { + panic(s4.F) + } +} diff --git a/test/typeparam/aliasimp.go b/test/typeparam/aliasimp.go new file mode 100644 index 00000000000..76930e5e4f6 --- /dev/null +++ b/test/typeparam/aliasimp.go @@ -0,0 +1,7 @@ +// rundir -G=3 + +// Copyright 2021 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 ignored From 4ed6317e735af24093b96077d1e813cc8b7dee6a Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Sun, 16 May 2021 14:48:05 -0700 Subject: [PATCH 168/940] [dev.typeparams] cmd/compile: always generate (*T).M wrappers for instantiated methods Always generate (*T).M wrappers for instantiated methods, even when the instantiated method is being generated for another package (its source package) Added new function t.IsInstantiated() to check for fully-instantiated types (generic type instantiated with concrete types, hence concrete themselves). This function helps hide the representation of instantiated types outside of the types package. Added new export/import test setsimp.go that needs this change. Change-Id: Ifb700db8c9494e1684c93735edb20f4709be5f7f Reviewed-on: https://go-review.googlesource.com/c/go/+/322193 Trust: Dan Scales Trust: Robert Griesemer Reviewed-by: Robert Griesemer --- .../compile/internal/reflectdata/reflect.go | 8 +- src/cmd/compile/internal/types/type.go | 7 + test/typeparam/setsimp.dir/a.go | 128 ++++++++++++++ test/typeparam/setsimp.dir/main.go | 156 ++++++++++++++++++ test/typeparam/setsimp.go | 7 + 5 files changed, 303 insertions(+), 3 deletions(-) create mode 100644 test/typeparam/setsimp.dir/a.go create mode 100644 test/typeparam/setsimp.dir/main.go create mode 100644 test/typeparam/setsimp.go diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index 3576a23db9f..d452d4f1942 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -956,7 +956,7 @@ func writeType(t *types.Type) *obj.LSym { // in the local package, even if they may be marked as part of // another package (the package of their base generic type). if tbase.Sym() != nil && tbase.Sym().Pkg != types.LocalPkg && - len(tbase.RParams()) == 0 { + !tbase.IsInstantiated() { if i := typecheck.BaseTypeIndex(t); i >= 0 { lsym.Pkg = tbase.Sym().Pkg.Prefix lsym.SymIdx = int32(i) @@ -1777,9 +1777,11 @@ func methodWrapper(rcvr *types.Type, method *types.Field) *obj.LSym { return lsym } - // Only generate (*T).M wrappers for T.M in T's own package. + // Only generate (*T).M wrappers for T.M in T's own package, except for + // instantiated methods. if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type && - rcvr.Elem().Sym() != nil && rcvr.Elem().Sym().Pkg != types.LocalPkg { + rcvr.Elem().Sym() != nil && rcvr.Elem().Sym().Pkg != types.LocalPkg && + !rcvr.Elem().IsInstantiated() { return lsym } diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index e7831121bff..08855f518ca 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -279,6 +279,13 @@ func (t *Type) SetRParams(rparams []*Type) { } } +// IsInstantiated reports whether t is a fully instantiated generic type; i.e. an +// instantiated generic type where all type arguments are non-generic or fully +// instantiated generic types. +func (t *Type) IsInstantiated() bool { + return len(t.RParams()) > 0 && !t.HasTParam() +} + // NoPkg is a nil *Pkg value for clarity. // It's intended for use when constructing types that aren't exported // and thus don't need to be associated with any package. diff --git a/test/typeparam/setsimp.dir/a.go b/test/typeparam/setsimp.dir/a.go new file mode 100644 index 00000000000..92449ce9562 --- /dev/null +++ b/test/typeparam/setsimp.dir/a.go @@ -0,0 +1,128 @@ +// Copyright 2021 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 a + +// SliceEqual reports whether two slices are equal: the same length and all +// elements equal. All floating point NaNs are considered equal. +func SliceEqual[Elem comparable](s1, s2 []Elem) bool { + if len(s1) != len(s2) { + return false + } + for i, v1 := range s1 { + v2 := s2[i] + if v1 != v2 { + isNaN := func(f Elem) bool { return f != f } + if !isNaN(v1) || !isNaN(v2) { + return false + } + } + } + return true +} + +// A Set is a set of elements of some type. +type Set[Elem comparable] struct { + m map[Elem]struct{} +} + +// Make makes a new set. +func Make[Elem comparable]() Set[Elem] { + return Set[Elem]{m: make(map[Elem]struct{})} +} + +// Add adds an element to a set. +func (s Set[Elem]) Add(v Elem) { + s.m[v] = struct{}{} +} + +// Delete removes an element from a set. If the element is not present +// in the set, this does nothing. +func (s Set[Elem]) Delete(v Elem) { + delete(s.m, v) +} + +// Contains reports whether v is in the set. +func (s Set[Elem]) Contains(v Elem) bool { + _, ok := s.m[v] + return ok +} + +// Len returns the number of elements in the set. +func (s Set[Elem]) Len() int { + return len(s.m) +} + +// Values returns the values in the set. +// The values will be in an indeterminate order. +func (s Set[Elem]) Values() []Elem { + r := make([]Elem, 0, len(s.m)) + for v := range s.m { + r = append(r, v) + } + return r +} + +// Equal reports whether two sets contain the same elements. +func Equal[Elem comparable](s1, s2 Set[Elem]) bool { + if len(s1.m) != len(s2.m) { + return false + } + for v1 := range s1.m { + if !s2.Contains(v1) { + return false + } + } + return true +} + +// Copy returns a copy of s. +func (s Set[Elem]) Copy() Set[Elem] { + r := Set[Elem]{m: make(map[Elem]struct{}, len(s.m))} + for v := range s.m { + r.m[v] = struct{}{} + } + return r +} + +// AddSet adds all the elements of s2 to s. +func (s Set[Elem]) AddSet(s2 Set[Elem]) { + for v := range s2.m { + s.m[v] = struct{}{} + } +} + +// SubSet removes all elements in s2 from s. +// Values in s2 that are not in s are ignored. +func (s Set[Elem]) SubSet(s2 Set[Elem]) { + for v := range s2.m { + delete(s.m, v) + } +} + +// Intersect removes all elements from s that are not present in s2. +// Values in s2 that are not in s are ignored. +func (s Set[Elem]) Intersect(s2 Set[Elem]) { + for v := range s.m { + if !s2.Contains(v) { + delete(s.m, v) + } + } +} + +// Iterate calls f on every element in the set. +func (s Set[Elem]) Iterate(f func(Elem)) { + for v := range s.m { + f(v) + } +} + +// Filter deletes any elements from s for which f returns false. +func (s Set[Elem]) Filter(f func(Elem) bool) { + for v := range s.m { + if !f(v) { + delete(s.m, v) + } + } +} diff --git a/test/typeparam/setsimp.dir/main.go b/test/typeparam/setsimp.dir/main.go new file mode 100644 index 00000000000..8fd16571439 --- /dev/null +++ b/test/typeparam/setsimp.dir/main.go @@ -0,0 +1,156 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "a" + "fmt" + "sort" +) + +func TestSet() { + s1 := a.Make[int]() + if got := s1.Len(); got != 0 { + panic(fmt.Sprintf("Len of empty set = %d, want 0", got)) + } + s1.Add(1) + s1.Add(1) + s1.Add(1) + if got := s1.Len(); got != 1 { + panic(fmt.Sprintf("(%v).Len() == %d, want 1", s1, got)) + } + s1.Add(2) + s1.Add(3) + s1.Add(4) + if got := s1.Len(); got != 4 { + panic(fmt.Sprintf("(%v).Len() == %d, want 4", s1, got)) + } + if !s1.Contains(1) { + panic(fmt.Sprintf("(%v).Contains(1) == false, want true", s1)) + } + if s1.Contains(5) { + panic(fmt.Sprintf("(%v).Contains(5) == true, want false", s1)) + } + vals := s1.Values() + sort.Ints(vals) + w1 := []int{1, 2, 3, 4} + if !a.SliceEqual(vals, w1) { + panic(fmt.Sprintf("(%v).Values() == %v, want %v", s1, vals, w1)) + } +} + +func TestEqual() { + s1 := a.Make[string]() + s2 := a.Make[string]() + if !a.Equal(s1, s2) { + panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", s1, s2)) + } + s1.Add("hello") + s1.Add("world") + if got := s1.Len(); got != 2 { + panic(fmt.Sprintf("(%v).Len() == %d, want 2", s1, got)) + } + if a.Equal(s1, s2) { + panic(fmt.Sprintf("a.Equal(%v, %v) = true, want false", s1, s2)) + } +} + +func TestCopy() { + s1 := a.Make[float64]() + s1.Add(0) + s2 := s1.Copy() + if !a.Equal(s1, s2) { + panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", s1, s2)) + } + s1.Add(1) + if a.Equal(s1, s2) { + panic(fmt.Sprintf("a.Equal(%v, %v) = true, want false", s1, s2)) + } +} + +func TestAddSet() { + s1 := a.Make[int]() + s1.Add(1) + s1.Add(2) + s2 := a.Make[int]() + s2.Add(2) + s2.Add(3) + s1.AddSet(s2) + if got := s1.Len(); got != 3 { + panic(fmt.Sprintf("(%v).Len() == %d, want 3", s1, got)) + } + s2.Add(1) + if !a.Equal(s1, s2) { + panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", s1, s2)) + } +} + +func TestSubSet() { + s1 := a.Make[int]() + s1.Add(1) + s1.Add(2) + s2 := a.Make[int]() + s2.Add(2) + s2.Add(3) + s1.SubSet(s2) + if got := s1.Len(); got != 1 { + panic(fmt.Sprintf("(%v).Len() == %d, want 1", s1, got)) + } + if vals, want := s1.Values(), []int{1}; !a.SliceEqual(vals, want) { + panic(fmt.Sprintf("after SubSet got %v, want %v", vals, want)) + } +} + +func TestIntersect() { + s1 := a.Make[int]() + s1.Add(1) + s1.Add(2) + s2 := a.Make[int]() + s2.Add(2) + s2.Add(3) + s1.Intersect(s2) + if got := s1.Len(); got != 1 { + panic(fmt.Sprintf("(%v).Len() == %d, want 1", s1, got)) + } + if vals, want := s1.Values(), []int{2}; !a.SliceEqual(vals, want) { + panic(fmt.Sprintf("after Intersect got %v, want %v", vals, want)) + } +} + +func TestIterate() { + s1 := a.Make[int]() + s1.Add(1) + s1.Add(2) + s1.Add(3) + s1.Add(4) + tot := 0 + s1.Iterate(func(i int) { tot += i }) + if tot != 10 { + panic(fmt.Sprintf("total of %v == %d, want 10", s1, tot)) + } +} + +func TestFilter() { + s1 := a.Make[int]() + s1.Add(1) + s1.Add(2) + s1.Add(3) + s1.Filter(func(v int) bool { return v%2 == 0 }) + if vals, want := s1.Values(), []int{2}; !a.SliceEqual(vals, want) { + panic(fmt.Sprintf("after Filter got %v, want %v", vals, want)) + } + +} + +func main() { + TestSet() + TestEqual() + TestCopy() + TestAddSet() + TestSubSet() + TestIntersect() + TestIterate() + TestFilter() +} diff --git a/test/typeparam/setsimp.go b/test/typeparam/setsimp.go new file mode 100644 index 00000000000..76930e5e4f6 --- /dev/null +++ b/test/typeparam/setsimp.go @@ -0,0 +1,7 @@ +// rundir -G=3 + +// Copyright 2021 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 ignored From 02beecb3974e9010d2deefaf09266286b0c6f408 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Wed, 26 May 2021 13:43:15 -0700 Subject: [PATCH 169/940] mime: document use of the Shared MIME-Info Database For #44513. Fixes #46013. Change-Id: I382603208aa94b66d5220cf0f418b8528a4e4148 Reviewed-on: https://go-review.googlesource.com/c/go/+/322892 Trust: Damien Neil Run-TryBot: Damien Neil TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- doc/go1.17.html | 4 +++- src/mime/type.go | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index da50935a612..771e2a6c8d9 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -408,7 +408,9 @@ Do not send CLs removing the interior tags from such phrases.

mime

- TODO: https://golang.org/cl/305230: support reading shared mime-info database on unix systems + On Unix systems, the table of MIME types is now read from the local system's + Shared MIME-info Database + when available.

diff --git a/src/mime/type.go b/src/mime/type.go index 9bbbf216a1d..26424339af8 100644 --- a/src/mime/type.go +++ b/src/mime/type.go @@ -96,9 +96,11 @@ func initMime() { // Extensions are looked up first case-sensitively, then case-insensitively. // // The built-in table is small but on unix it is augmented by the local -// system's mime.types file(s) if available under one or more of these -// names: +// system's MIME-info database or mime.types file(s) if available under one or +// more of these names: // +// /usr/local/share/mime/globs2 +// /usr/share/mime/globs2 // /etc/mime.types // /etc/apache2/mime.types // /etc/apache/mime.types From 0fbecece98977f6d0578cef1e8f3ae00a54c8ac4 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Wed, 26 May 2021 11:12:43 -0700 Subject: [PATCH 170/940] doc/go1.17: document syscall changes Fixes #46023 Change-Id: Ia63829d03afb0936862b16f0971175cbaa1095bc Reviewed-on: https://go-review.googlesource.com/c/go/+/322890 Trust: Damien Neil Run-TryBot: Damien Neil TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- doc/go1.17.html | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 771e2a6c8d9..194d3a0cd84 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -550,11 +550,16 @@ Do not send CLs removing the interior tags from such phrases.
syscall

- TODO: https://golang.org/cl/295371: do not overflow key memory in GetQueuedCompletionStatus +

+ The GetQueuedCompletionStatus and + PostQueuedCompletionStatus + functions are now deprecated. These functions have incorrect signatures and are superseded by + equivalents in the golang.org/x/sys/windows package.

- TODO: https://golang.org/cl/313653: restore signal mask after setting foreground process group + On Unix-like systems, the process group of a child process is now set with signals blocked. + This avoids sending a SIGTTOU to the child when the parent is in a background process group.

From 1d5298d46a695219ab4622ae5aa59898459fd0f5 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Wed, 26 May 2021 11:28:01 -0700 Subject: [PATCH 171/940] doc/go1.17: document net/... changes For #44513. Fixes #46014. Fixes #46015. Fixes #46016. Fixes #46017. Change-Id: I356483d68d07159281dfe2ea1e49430ddf200973 Reviewed-on: https://go-review.googlesource.com/c/go/+/322891 Trust: Damien Neil Run-TryBot: Damien Neil Reviewed-by: Ian Lance Taylor --- doc/go1.17.html | 23 +++++++++++++++++------ src/os/pipe_test.go | 2 +- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 194d3a0cd84..8313c2bc575 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -418,15 +418,20 @@ Do not send CLs removing the interior tags from such phrases.
net

- TODO: https://golang.org/cl/272668: add IP.IsPrivate + The new method IP.IsPrivate reports whether an address is + a private IPv4 address according to RFC 1918 + or a local IPv6 address according RFC 4193.

- TODO: https://golang.org/cl/301709: make go resolver aware of network parameter + The Go DNS resolver now only sends one DNS query when resolving an address for an IPv4-only or IPv6-only network, + rather than querying for both address families.

- TODO: https://golang.org/cl/307030: make ErrClosed and ParseError implement net.Error + The ErrClosed sentinel error and + ParseError error type now implement + the net.Error interface.

@@ -441,7 +446,9 @@ Do not send CLs removing the interior tags from such phrases.

- TODO: https://golang.org/cl/235437: add to deadlines only when positive + Setting the Server + ReadTimeout or WriteTimeout fields to a negative value now indicates no timeout + rather than an immediate timeout.

@@ -454,7 +461,10 @@ Do not send CLs removing the interior tags from such phrases.

net/http/httptest

- TODO: https://golang.org/cl/308950: panic on non-3 digit (XXX) status code in Recorder.WriteHeader + ResponseRecorder.WriteHeader> + now panics when the provided code is not a valid three-digit HTTP status code. + This matches the behavior of ResponseWriter> + implementations in the net/http package.

@@ -462,7 +472,8 @@ Do not send CLs removing the interior tags from such phrases.
net/url

- TODO: https://golang.org/cl/314850: add Values.Has + The new method Values.Has + reports whether a query parameter is set.

diff --git a/src/os/pipe_test.go b/src/os/pipe_test.go index b6636185029..b3d5380b8da 100644 --- a/src/os/pipe_test.go +++ b/src/os/pipe_test.go @@ -462,7 +462,7 @@ func TestFdReadRace(t *testing.T) { // Give the other goroutine a chance to enter the Read. // It doesn't matter if this occasionally fails, the test // will still pass, it just won't test anything. - time.Sleep(10 * time.Millisecond) + //time.Sleep(10 * time.Millisecond) r.Fd() // The bug was that Fd would hang until Read timed out. From a62c08734f8e2fc5333036e3a069a55288d1f674 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Wed, 26 May 2021 15:44:46 -0700 Subject: [PATCH 172/940] src/os: revert accidentally submitted change Change-Id: Ib34984a6bd0abc76266e8aac96f9f8ad8ae21d17 Reviewed-on: https://go-review.googlesource.com/c/go/+/322894 Trust: Damien Neil Run-TryBot: Damien Neil Run-TryBot: Ian Lance Taylor Reviewed-by: Ian Lance Taylor --- src/os/pipe_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/os/pipe_test.go b/src/os/pipe_test.go index b3d5380b8da..b6636185029 100644 --- a/src/os/pipe_test.go +++ b/src/os/pipe_test.go @@ -462,7 +462,7 @@ func TestFdReadRace(t *testing.T) { // Give the other goroutine a chance to enter the Read. // It doesn't matter if this occasionally fails, the test // will still pass, it just won't test anything. - //time.Sleep(10 * time.Millisecond) + time.Sleep(10 * time.Millisecond) r.Fd() // The bug was that Fd would hang until Read timed out. From cf23daeda3792eb2ba07c30823d5a0c8667f5083 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 25 May 2021 19:49:08 -0400 Subject: [PATCH 173/940] [dev.typeparams] cmd/compile: do not schedule in-register args late, even for block control In the scheduler we have the logic that if a Value is used as the block's control, we schedule it at the end, except for Phis and Args. Even the comment says so, the code doesn't exclude in-register Args (OpArgXXXReg). Change to check for score instead, which includes OpArgXXXRegs. It also includes GetClosurePtr, which must be scheduled early. We just happen to never use it as block control. Found when working on ARM64 register ABI. In theory this could apply to AMD64 as well. But on AMD64 we never use in-register Value as block control, as conditional branch is always based on FLAGS, never based on registers, so it doesn't actually cause any problem. Change-Id: I167a550309772639574f7468caf91bd805eb74c6 Reviewed-on: https://go-review.googlesource.com/c/go/+/322849 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Than McIntosh Reviewed-by: David Chase --- src/cmd/compile/internal/ssa/schedule.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/ssa/schedule.go b/src/cmd/compile/internal/ssa/schedule.go index 4e3e5e75e35..c5130b2ee50 100644 --- a/src/cmd/compile/internal/ssa/schedule.go +++ b/src/cmd/compile/internal/ssa/schedule.go @@ -220,7 +220,7 @@ func schedule(f *Func) { // unless they are phi values (which must be first). // OpArg also goes first -- if it is stack it register allocates // to a LoadReg, if it is register it is from the beginning anyway. - if c.Op == OpPhi || c.Op == OpArg { + if score[c.ID] == ScorePhi || score[c.ID] == ScoreArg { continue } score[c.ID] = ScoreControl From 4bb927f82e7d4661d287ec5e975ba6cbdee2ae90 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 25 May 2021 11:53:04 -0400 Subject: [PATCH 174/940] [dev.typeparams] cmd/compile: define ARM64 parameter registers Define the registers. They are not really enabled for now. Otherwise the compiler will start using them for go:registerparams functions and it is not fully working. Some test will fail. Now we can compile a simple Add function with registerparams (with registers enabled). Change-Id: Ifdfac931052c0196096a1dd8b0687b5fdedb14d5 Reviewed-on: https://go-review.googlesource.com/c/go/+/322850 Trust: Cherry Mui Reviewed-by: David Chase Reviewed-by: Than McIntosh --- src/cmd/compile/internal/arm64/ssa.go | 3 +++ src/cmd/compile/internal/ssa/config.go | 4 ++++ src/cmd/compile/internal/ssa/gen/ARM64Ops.go | 2 ++ src/cmd/compile/internal/ssa/opGen.go | 4 ++-- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/arm64/ssa.go b/src/cmd/compile/internal/arm64/ssa.go index 0c997bc4b3e..ca76b18497e 100644 --- a/src/cmd/compile/internal/arm64/ssa.go +++ b/src/cmd/compile/internal/arm64/ssa.go @@ -161,6 +161,9 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.From.Type = obj.TYPE_REG p.From.Reg = v.Args[0].Reg() ssagen.AddrAuto(&p.To, v) + case ssa.OpArgIntReg, ssa.OpArgFloatReg: + // TODO: generate morestack spill code + ssagen.CheckArgReg(v) case ssa.OpARM64ADD, ssa.OpARM64SUB, ssa.OpARM64AND, diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index a8393a19995..07d8b6e532b 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -228,6 +228,10 @@ func NewConfig(arch string, types Types, ctxt *obj.Link, optimize bool) *Config c.registers = registersARM64[:] c.gpRegMask = gpRegMaskARM64 c.fpRegMask = fpRegMaskARM64 + // XXX commented out for now. Uncomment it will enable register args for + // go:registerparams functions, which isn't fully working, so tests fail. + //c.intParamRegs = paramIntRegARM64 + //c.floatParamRegs = paramFloatRegARM64 c.FPReg = framepointerRegARM64 c.LinkReg = linkRegARM64 c.hasGReg = true diff --git a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go index 18a5666b40f..a91ece1c9f9 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go @@ -765,6 +765,8 @@ func init() { ops: ops, blocks: blocks, regnames: regNamesARM64, + ParamIntRegNames: "R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15", + ParamFloatRegNames: "F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15", gpregmask: gp, fpregmask: fp, framepointerreg: -1, // not used diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 1c37fbe0db4..cf31dfacf60 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -36400,8 +36400,8 @@ var registersARM64 = [...]Register{ {62, arm64.REG_F31, -1, "F31"}, {63, 0, -1, "SB"}, } -var paramIntRegARM64 = []int8(nil) -var paramFloatRegARM64 = []int8(nil) +var paramIntRegARM64 = []int8{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} +var paramFloatRegARM64 = []int8{31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46} var gpRegMaskARM64 = regMask(670826495) var fpRegMaskARM64 = regMask(9223372034707292160) var specialRegMaskARM64 = regMask(0) From 3075ffc93e962792ddf43b2a528ef19b1577ffb7 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 26 May 2021 15:17:27 -0700 Subject: [PATCH 175/940] os: deflake TestFdReadRace The test would hang if the call to Fd set the pipe to be non-blocking before the Read entered the first read system call. Avoid that problem by writing data to the pipe to wake up the read. For #24481 Fixes #44818 Change-Id: I0b798874c7b81e7308a38ebbf657efc4392ffacd Reviewed-on: https://go-review.googlesource.com/c/go/+/322893 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Damien Neil --- src/os/pipe_test.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/os/pipe_test.go b/src/os/pipe_test.go index b6636185029..41a1e9c78aa 100644 --- a/src/os/pipe_test.go +++ b/src/os/pipe_test.go @@ -442,12 +442,14 @@ func TestFdReadRace(t *testing.T) { defer r.Close() defer w.Close() - c := make(chan bool) + const count = 10 + + c := make(chan bool, 1) var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() - var buf [10]byte + var buf [count]byte r.SetReadDeadline(time.Now().Add(time.Minute)) c <- true if _, err := r.Read(buf[:]); os.IsTimeout(err) { @@ -466,8 +468,9 @@ func TestFdReadRace(t *testing.T) { r.Fd() // The bug was that Fd would hang until Read timed out. - // If the bug is fixed, then closing r here will cause - // the Read to exit before the timeout expires. + // If the bug is fixed, then writing to w and closing r here + // will cause the Read to exit before the timeout expires. + w.Write(make([]byte, count)) r.Close() }() From a4b2a04bc50d568579f437f324d56471bf31ec6c Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 25 May 2021 18:08:36 -0400 Subject: [PATCH 176/940] [dev.typeparams] cmd/internal/obj/arm64: use ABI-compatible registers in function prologue Avoid using R1, R2, etc. in function prologue, which may carry live argument values. Change-Id: I80322b3f7e8fda7aaff622aaa99bc76d02e09727 Reviewed-on: https://go-review.googlesource.com/c/go/+/322852 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Than McIntosh Reviewed-by: David Chase --- src/cmd/internal/obj/arm64/obj7.go | 80 +++++++++++++++--------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go index e41fb3bb753..13966f7b867 100644 --- a/src/cmd/internal/obj/arm64/obj7.go +++ b/src/cmd/internal/obj/arm64/obj7.go @@ -52,7 +52,7 @@ var complements = []obj.As{ } func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog { - // MOV g_stackguard(g), R1 + // MOV g_stackguard(g), RT1 p = obj.Appendp(p, c.newprog) p.As = AMOVD @@ -63,7 +63,7 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog { p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1 } p.To.Type = obj.TYPE_REG - p.To.Reg = REG_R1 + p.To.Reg = REGRT1 // Mark the stack bound check and morestack call async nonpreemptible. // If we get preempted here, when resumed the preemption request is @@ -74,25 +74,25 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog { q := (*obj.Prog)(nil) if framesize <= objabi.StackSmall { // small stack: SP < stackguard - // MOV SP, R2 - // CMP stackguard, R2 + // MOV SP, RT2 + // CMP stackguard, RT2 p = obj.Appendp(p, c.newprog) p.As = AMOVD p.From.Type = obj.TYPE_REG p.From.Reg = REGSP p.To.Type = obj.TYPE_REG - p.To.Reg = REG_R2 + p.To.Reg = REGRT2 p = obj.Appendp(p, c.newprog) p.As = ACMP p.From.Type = obj.TYPE_REG - p.From.Reg = REG_R1 - p.Reg = REG_R2 + p.From.Reg = REGRT1 + p.Reg = REGRT2 } else if framesize <= objabi.StackBig { // large stack: SP-framesize < stackguard-StackSmall - // SUB $(framesize-StackSmall), SP, R2 - // CMP stackguard, R2 + // SUB $(framesize-StackSmall), SP, RT2 + // CMP stackguard, RT2 p = obj.Appendp(p, c.newprog) p.As = ASUB @@ -100,13 +100,13 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog { p.From.Offset = int64(framesize) - objabi.StackSmall p.Reg = REGSP p.To.Type = obj.TYPE_REG - p.To.Reg = REG_R2 + p.To.Reg = REGRT2 p = obj.Appendp(p, c.newprog) p.As = ACMP p.From.Type = obj.TYPE_REG - p.From.Reg = REG_R1 - p.Reg = REG_R2 + p.From.Reg = REGRT1 + p.Reg = REGRT2 } else { // Such a large stack we need to protect against underflow. // The runtime guarantees SP > objabi.StackBig, but @@ -115,10 +115,10 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog { // stack guard to incorrectly succeed. We explicitly // guard against underflow. // - // SUBS $(framesize-StackSmall), SP, R2 + // SUBS $(framesize-StackSmall), SP, RT2 // // On underflow, jump to morestack // BLO label_of_call_to_morestack - // CMP stackguard, R2 + // CMP stackguard, RT2 p = obj.Appendp(p, c.newprog) p.As = ASUBS @@ -126,7 +126,7 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog { p.From.Offset = int64(framesize) - objabi.StackSmall p.Reg = REGSP p.To.Type = obj.TYPE_REG - p.To.Reg = REG_R2 + p.To.Reg = REGRT2 p = obj.Appendp(p, c.newprog) q = p @@ -136,8 +136,8 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog { p = obj.Appendp(p, c.newprog) p.As = ACMP p.From.Type = obj.TYPE_REG - p.From.Reg = REG_R1 - p.Reg = REG_R2 + p.From.Reg = REGRT1 + p.Reg = REGRT2 } // BLS do-morestack @@ -631,38 +631,38 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { if c.cursym.Func().Text.From.Sym.Wrapper() { // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame // - // MOV g_panic(g), R1 + // MOV g_panic(g), RT1 // CBNZ checkargp // end: // NOP // ... function body ... // checkargp: - // MOV panic_argp(R1), R2 - // ADD $(autosize+8), RSP, R3 - // CMP R2, R3 + // MOV panic_argp(RT1), RT2 + // ADD $(autosize+8), RSP, R20 + // CMP RT2, R20 // BNE end - // ADD $8, RSP, R4 - // MOVD R4, panic_argp(R1) + // ADD $8, RSP, R20 + // MOVD R20, panic_argp(RT1) // B end // // The NOP is needed to give the jumps somewhere to land. // It is a liblink NOP, not an ARM64 NOP: it encodes to 0 instruction bytes. q = q1 - // MOV g_panic(g), R1 + // MOV g_panic(g), RT1 q = obj.Appendp(q, c.newprog) q.As = AMOVD q.From.Type = obj.TYPE_MEM q.From.Reg = REGG q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic q.To.Type = obj.TYPE_REG - q.To.Reg = REG_R1 + q.To.Reg = REGRT1 - // CBNZ R1, checkargp + // CBNZ RT1, checkargp cbnz := obj.Appendp(q, c.newprog) cbnz.As = ACBNZ cbnz.From.Type = obj.TYPE_REG - cbnz.From.Reg = REG_R1 + cbnz.From.Reg = REGRT1 cbnz.To.Type = obj.TYPE_BRANCH // Empty branch target at the top of the function body @@ -674,33 +674,33 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { for last = end; last.Link != nil; last = last.Link { } - // MOV panic_argp(R1), R2 + // MOV panic_argp(RT1), RT2 mov := obj.Appendp(last, c.newprog) mov.As = AMOVD mov.From.Type = obj.TYPE_MEM - mov.From.Reg = REG_R1 + mov.From.Reg = REGRT1 mov.From.Offset = 0 // Panic.argp mov.To.Type = obj.TYPE_REG - mov.To.Reg = REG_R2 + mov.To.Reg = REGRT2 // CBNZ branches to the MOV above cbnz.To.SetTarget(mov) - // ADD $(autosize+8), SP, R3 + // ADD $(autosize+8), SP, R20 q = obj.Appendp(mov, c.newprog) q.As = AADD q.From.Type = obj.TYPE_CONST q.From.Offset = int64(c.autosize) + 8 q.Reg = REGSP q.To.Type = obj.TYPE_REG - q.To.Reg = REG_R3 + q.To.Reg = REG_R20 - // CMP R2, R3 + // CMP RT2, R20 q = obj.Appendp(q, c.newprog) q.As = ACMP q.From.Type = obj.TYPE_REG - q.From.Reg = REG_R2 - q.Reg = REG_R3 + q.From.Reg = REGRT2 + q.Reg = REG_R20 // BNE end q = obj.Appendp(q, c.newprog) @@ -708,22 +708,22 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { q.To.Type = obj.TYPE_BRANCH q.To.SetTarget(end) - // ADD $8, SP, R4 + // ADD $8, SP, R20 q = obj.Appendp(q, c.newprog) q.As = AADD q.From.Type = obj.TYPE_CONST q.From.Offset = 8 q.Reg = REGSP q.To.Type = obj.TYPE_REG - q.To.Reg = REG_R4 + q.To.Reg = REG_R20 - // MOV R4, panic_argp(R1) + // MOV R20, panic_argp(RT1) q = obj.Appendp(q, c.newprog) q.As = AMOVD q.From.Type = obj.TYPE_REG - q.From.Reg = REG_R4 + q.From.Reg = REG_R20 q.To.Type = obj.TYPE_MEM - q.To.Reg = REG_R1 + q.To.Reg = REGRT1 q.To.Offset = 0 // Panic.argp // B end From 4c68edd1feaad43e098dd7375d6c1cfc43243211 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 25 May 2021 18:40:28 -0400 Subject: [PATCH 177/940] [dev.typeparams] cmd/compile: add morestack arg spilling code on ARM64 Spill arg registers before calling morestack, and reload after. Change-Id: I09404def321b8f935d5e8836a46ccae8256d0d55 Reviewed-on: https://go-review.googlesource.com/c/go/+/322853 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: David Chase --- src/cmd/compile/internal/arm64/ssa.go | 11 ++++++++++- src/cmd/compile/internal/ssagen/ssa.go | 1 - src/cmd/internal/obj/arm64/obj7.go | 16 ++++++++++------ 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/cmd/compile/internal/arm64/ssa.go b/src/cmd/compile/internal/arm64/ssa.go index ca76b18497e..d82788218d9 100644 --- a/src/cmd/compile/internal/arm64/ssa.go +++ b/src/cmd/compile/internal/arm64/ssa.go @@ -162,7 +162,16 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.From.Reg = v.Args[0].Reg() ssagen.AddrAuto(&p.To, v) case ssa.OpArgIntReg, ssa.OpArgFloatReg: - // TODO: generate morestack spill code + // The assembler needs to wrap the entry safepoint/stack growth code with spill/unspill + // The loop only runs once. + for _, a := range v.Block.Func.RegArgs { + // Pass the spill/unspill information along to the assembler, offset by size of + // the saved LR slot. + addr := ssagen.SpillSlotAddr(a, arm64.REGSP, base.Ctxt.FixedFrameSize()) + s.FuncInfo().AddSpill( + obj.RegSpill{Reg: a.Reg, Addr: addr, Unspill: loadByType(a.Type), Spill: storeByType(a.Type)}) + } + v.Block.Func.RegArgs = nil ssagen.CheckArgReg(v) case ssa.OpARM64ADD, ssa.OpARM64SUB, diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 004e084f728..91b0c79cd3e 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -650,7 +650,6 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func { // it mimics the behavior of the former ABI (everything stored) and because it's not 100% // clear if naming conventions are respected in autogenerated code. // TODO figure out exactly what's unused, don't spill it. Make liveness fine-grained, also. - // TODO non-amd64 architectures have link registers etc that may require adjustment here. for _, p := range params.InParams() { typs, offs := p.RegisterTypesAndOffsets() for i, t := range typs { diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go index 13966f7b867..c94a0b67ee2 100644 --- a/src/cmd/internal/obj/arm64/obj7.go +++ b/src/cmd/internal/obj/arm64/obj7.go @@ -161,17 +161,20 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog { pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog) pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog) + if q != nil { + q.To.SetTarget(pcdata) + } + bls.To.SetTarget(pcdata) + + spill := c.cursym.Func().SpillRegisterArgs(pcdata, c.newprog) + // MOV LR, R3 - movlr := obj.Appendp(pcdata, c.newprog) + movlr := obj.Appendp(spill, c.newprog) movlr.As = AMOVD movlr.From.Type = obj.TYPE_REG movlr.From.Reg = REGLINK movlr.To.Type = obj.TYPE_REG movlr.To.Reg = REG_R3 - if q != nil { - q.To.SetTarget(movlr) - } - bls.To.SetTarget(movlr) debug := movlr if false { @@ -196,7 +199,8 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog { } call.To.Sym = c.ctxt.Lookup(morestack) - pcdata = c.ctxt.EndUnsafePoint(call, c.newprog, -1) + unspill := c.cursym.Func().UnspillRegisterArgs(call, c.newprog) + pcdata = c.ctxt.EndUnsafePoint(unspill, c.newprog, -1) // B start jmp := obj.Appendp(pcdata, c.newprog) From e99e9a6e0147592b12175a19a2a9dafe96a984f9 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 26 May 2021 13:54:31 -0700 Subject: [PATCH 178/940] [dev.typeparams] cmd/compile: simplify ~r/~b naming The compiler renames anonymous and blank result parameters to ~rN or ~bN, but the current semantics for computing N are rather annoying and difficult to reproduce cleanly. They also lead to difficult to read escape analysis results in tests. This CL changes N to always be calculated as the parameter's index within the function's result parameter tuple. E.g., if a function has a single result, it will now always be named "~r0". The normative change to this CL is fairly simple, but it requires updating a lot of test expectations. Change-Id: I58a3c94de00cb822cb94efe52d115531193c993c Reviewed-on: https://go-review.googlesource.com/c/go/+/323010 Trust: Matthew Dempsky Trust: Dan Scales Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Dan Scales --- .../compile/internal/logopt/logopt_test.go | 4 +- src/cmd/compile/internal/noder/object.go | 22 +++++----- src/cmd/compile/internal/typecheck/dcl.go | 9 ++-- test/escape2.go | 44 +++++++++---------- test/escape2n.go | 44 +++++++++---------- test/escape5.go | 8 ++-- test/escape_array.go | 16 +++---- test/escape_calls.go | 2 +- test/escape_closure.go | 8 ++-- test/escape_param.go | 10 ++--- test/escape_runtime_atomic.go | 4 +- test/escape_slice.go | 4 +- test/escape_struct_return.go | 4 +- test/escape_unsafe.go | 10 ++--- test/fixedbugs/issue12006.go | 6 +-- test/fixedbugs/issue12588.go | 6 +-- test/fixedbugs/issue42284.dir/a.go | 2 +- 17 files changed, 101 insertions(+), 102 deletions(-) diff --git a/src/cmd/compile/internal/logopt/logopt_test.go b/src/cmd/compile/internal/logopt/logopt_test.go index 71976174b03..41a11b0c701 100644 --- a/src/cmd/compile/internal/logopt/logopt_test.go +++ b/src/cmd/compile/internal/logopt/logopt_test.go @@ -209,7 +209,7 @@ func s15a8(x *[15]int64) [15]int64 { want(t, slogged, `{"range":{"start":{"line":11,"character":6},"end":{"line":11,"character":6}},"severity":3,"code":"isInBounds","source":"go compiler","message":""}`) want(t, slogged, `{"range":{"start":{"line":7,"character":6},"end":{"line":7,"character":6}},"severity":3,"code":"canInlineFunction","source":"go compiler","message":"cost: 35"}`) // escape analysis explanation - want(t, slogged, `{"range":{"start":{"line":7,"character":13},"end":{"line":7,"character":13}},"severity":3,"code":"leak","source":"go compiler","message":"parameter z leaks to ~r2 with derefs=0",`+ + want(t, slogged, `{"range":{"start":{"line":7,"character":13},"end":{"line":7,"character":13}},"severity":3,"code":"leak","source":"go compiler","message":"parameter z leaks to ~r0 with derefs=0",`+ `"relatedInformation":[`+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: y = z:"},`+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y := z (assign-pair)"},`+ @@ -220,7 +220,7 @@ func s15a8(x *[15]int64) [15]int64 { `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from \u0026y.b (address-of)"},`+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":9},"end":{"line":4,"character":9}}},"message":"inlineLoc"},`+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from ~R0 = \u0026y.b (assign-pair)"},`+ - `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: flow: ~r2 = ~R0:"},`+ + `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: flow: ~r0 = ~R0:"},`+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: from return (*int)(~R0) (return)"}]}`) }) } diff --git a/src/cmd/compile/internal/noder/object.go b/src/cmd/compile/internal/noder/object.go index a1a10e4eaaf..581a3652ec2 100644 --- a/src/cmd/compile/internal/noder/object.go +++ b/src/cmd/compile/internal/noder/object.go @@ -113,19 +113,21 @@ func (g *irgen) obj(obj types2.Object) *ir.Name { } case *types2.Var: - var sym *types.Sym - if class == ir.PPARAMOUT { + sym := g.sym(obj) + if class == ir.PPARAMOUT && (sym == nil || sym.IsBlank()) { // Backend needs names for result parameters, // even if they're anonymous or blank. - switch obj.Name() { - case "": - sym = typecheck.LookupNum("~r", len(ir.CurFunc.Dcl)) // 'r' for "result" - case "_": - sym = typecheck.LookupNum("~b", len(ir.CurFunc.Dcl)) // 'b' for "blank" + nresults := 0 + for _, n := range ir.CurFunc.Dcl { + if n.Class == ir.PPARAMOUT { + nresults++ + } + } + if sym == nil { + sym = typecheck.LookupNum("~r", nresults) // 'r' for "result" + } else { + sym = typecheck.LookupNum("~b", nresults) // 'b' for "blank" } - } - if sym == nil { - sym = g.sym(obj) } name = g.objCommon(pos, ir.ONAME, sym, class, g.typ(obj.Type())) diff --git a/src/cmd/compile/internal/typecheck/dcl.go b/src/cmd/compile/internal/typecheck/dcl.go index f3058d8811a..5f8b8b3d417 100644 --- a/src/cmd/compile/internal/typecheck/dcl.go +++ b/src/cmd/compile/internal/typecheck/dcl.go @@ -353,12 +353,10 @@ func funcargs(nt *ir.FuncType) { } // declare the out arguments. - gen := len(nt.Params) - for _, n := range nt.Results { + for i, n := range nt.Results { if n.Sym == nil { // Name so that escape analysis can track it. ~r stands for 'result'. - n.Sym = LookupNum("~r", gen) - gen++ + n.Sym = LookupNum("~r", i) } if n.Sym.IsBlank() { // Give it a name so we can assign to it during return. ~b stands for 'blank'. @@ -367,8 +365,7 @@ func funcargs(nt *ir.FuncType) { // func g() int // f is allowed to use a plain 'return' with no arguments, while g is not. // So the two cases must be distinguished. - n.Sym = LookupNum("~b", gen) - gen++ + n.Sym = LookupNum("~b", i) } funcarg(n, ir.PPARAMOUT) diff --git a/test/escape2.go b/test/escape2.go index b9b723d8666..04ab635aa52 100644 --- a/test/escape2.go +++ b/test/escape2.go @@ -59,7 +59,7 @@ func foo8(xx, yy *int) int { // ERROR "xx does not escape$" "yy does not escape$ return *xx } -func foo9(xx, yy *int) *int { // ERROR "leaking param: xx to result ~r2 level=0$" "leaking param: yy to result ~r2 level=0$" +func foo9(xx, yy *int) *int { // ERROR "leaking param: xx to result ~r0 level=0$" "leaking param: yy to result ~r0 level=0$" xx = yy return xx } @@ -343,11 +343,11 @@ func indaddr1(x int) *int { // ERROR "moved to heap: x$" return &x } -func indaddr2(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" +func indaddr2(x *int) *int { // ERROR "leaking param: x to result ~r0 level=0$" return *&x } -func indaddr3(x *int32) *int { // ERROR "leaking param: x to result ~r1 level=0$" +func indaddr3(x *int32) *int { // ERROR "leaking param: x to result ~r0 level=0$" return *(**int)(unsafe.Pointer(&x)) } @@ -374,11 +374,11 @@ func float64bitsptr(f float64) *uint64 { // ERROR "moved to heap: f$" return (*uint64)(unsafe.Pointer(&f)) } -func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f to result ~r1 level=0$" +func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f to result ~r0 level=0$" return (*uint64)(unsafe.Pointer(f)) } -func typesw(i interface{}) *int { // ERROR "leaking param: i to result ~r1 level=0$" +func typesw(i interface{}) *int { // ERROR "leaking param: i to result ~r0 level=0$" switch val := i.(type) { case *int: return val @@ -389,7 +389,7 @@ func typesw(i interface{}) *int { // ERROR "leaking param: i to result ~r1 level return nil } -func exprsw(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" +func exprsw(i *int) *int { // ERROR "leaking param: i to result ~r0 level=0$" switch j := i; *j + 110 { case 12: return j @@ -401,7 +401,7 @@ func exprsw(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" } // assigning to an array element is like assigning to the array -func foo60(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" +func foo60(i *int) *int { // ERROR "leaking param: i to result ~r0 level=0$" var a [12]*int a[0] = i return a[1] @@ -414,7 +414,7 @@ func foo60a(i *int) *int { // ERROR "i does not escape$" } // assigning to a struct field is like assigning to the struct -func foo61(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" +func foo61(i *int) *int { // ERROR "leaking param: i to result ~r0 level=0$" type S struct { a, b *int } @@ -611,11 +611,11 @@ func foo74c() { } } -func myprint(y *int, x ...interface{}) *int { // ERROR "leaking param: y to result ~r2 level=0$" "x does not escape$" +func myprint(y *int, x ...interface{}) *int { // ERROR "leaking param: y to result ~r0 level=0$" "x does not escape$" return y } -func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "leaking param: x to result ~r2 level=0$" "y does not escape$" +func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "leaking param: x to result ~r0 level=0$" "y does not escape$" return &x[0] } @@ -770,7 +770,7 @@ func foo91(x *int) map[*int]*int { // ERROR "leaking param: x$" return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int{...} escapes to heap$" } -func foo92(x *int) [2]*int { // ERROR "leaking param: x to result ~r1 level=0$" +func foo92(x *int) [2]*int { // ERROR "leaking param: x to result ~r0 level=0$" return [2]*int{x, nil} } @@ -783,7 +783,7 @@ func foo93(c chan *int) *int { // ERROR "c does not escape$" } // does not leak m -func foo94(m map[*int]*int, b bool) *int { // ERROR "leaking param: m to result ~r2 level=1" +func foo94(m map[*int]*int, b bool) *int { // ERROR "leaking param: m to result ~r0 level=1" for k, v := range m { if b { return k @@ -799,12 +799,12 @@ func foo95(m map[*int]*int, x *int) { // ERROR "m does not escape$" "leaking par } // does not leak m but does leak content -func foo96(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1" +func foo96(m []*int) *int { // ERROR "leaking param: m to result ~r0 level=1" return m[0] } // does leak m -func foo97(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$" +func foo97(m [1]*int) *int { // ERROR "leaking param: m to result ~r0 level=0$" return m[0] } @@ -814,12 +814,12 @@ func foo98(m map[int]*int) *int { // ERROR "m does not escape$" } // does leak m -func foo99(m *[1]*int) []*int { // ERROR "leaking param: m to result ~r1 level=0$" +func foo99(m *[1]*int) []*int { // ERROR "leaking param: m to result ~r0 level=0$" return m[:] } // does not leak m -func foo100(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1" +func foo100(m []*int) *int { // ERROR "leaking param: m to result ~r0 level=1" for _, v := range m { return v } @@ -827,7 +827,7 @@ func foo100(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1" } // does leak m -func foo101(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$" +func foo101(m [1]*int) *int { // ERROR "leaking param: m to result ~r0 level=0$" for _, v := range m { return v } @@ -890,27 +890,27 @@ func foo110(x *int) *int { // ERROR "leaking param: x$" return m[nil] } -func foo111(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0" +func foo111(x *int) *int { // ERROR "leaking param: x to result ~r0 level=0" m := []*int{x} // ERROR "\[\]\*int{...} does not escape$" return m[0] } -func foo112(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" +func foo112(x *int) *int { // ERROR "leaking param: x to result ~r0 level=0$" m := [1]*int{x} return m[0] } -func foo113(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" +func foo113(x *int) *int { // ERROR "leaking param: x to result ~r0 level=0$" m := Bar{ii: x} return m.ii } -func foo114(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" +func foo114(x *int) *int { // ERROR "leaking param: x to result ~r0 level=0$" m := &Bar{ii: x} // ERROR "&Bar{...} does not escape$" return m.ii } -func foo115(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" +func foo115(x *int) *int { // ERROR "leaking param: x to result ~r0 level=0$" return (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(x)) + 1)) } diff --git a/test/escape2n.go b/test/escape2n.go index 7c8208aa73c..01a25795f47 100644 --- a/test/escape2n.go +++ b/test/escape2n.go @@ -59,7 +59,7 @@ func foo8(xx, yy *int) int { // ERROR "xx does not escape$" "yy does not escape$ return *xx } -func foo9(xx, yy *int) *int { // ERROR "leaking param: xx to result ~r2 level=0$" "leaking param: yy to result ~r2 level=0$" +func foo9(xx, yy *int) *int { // ERROR "leaking param: xx to result ~r0 level=0$" "leaking param: yy to result ~r0 level=0$" xx = yy return xx } @@ -343,11 +343,11 @@ func indaddr1(x int) *int { // ERROR "moved to heap: x$" return &x } -func indaddr2(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" +func indaddr2(x *int) *int { // ERROR "leaking param: x to result ~r0 level=0$" return *&x } -func indaddr3(x *int32) *int { // ERROR "leaking param: x to result ~r1 level=0$" +func indaddr3(x *int32) *int { // ERROR "leaking param: x to result ~r0 level=0$" return *(**int)(unsafe.Pointer(&x)) } @@ -374,11 +374,11 @@ func float64bitsptr(f float64) *uint64 { // ERROR "moved to heap: f$" return (*uint64)(unsafe.Pointer(&f)) } -func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f to result ~r1 level=0$" +func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f to result ~r0 level=0$" return (*uint64)(unsafe.Pointer(f)) } -func typesw(i interface{}) *int { // ERROR "leaking param: i to result ~r1 level=0$" +func typesw(i interface{}) *int { // ERROR "leaking param: i to result ~r0 level=0$" switch val := i.(type) { case *int: return val @@ -389,7 +389,7 @@ func typesw(i interface{}) *int { // ERROR "leaking param: i to result ~r1 level return nil } -func exprsw(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" +func exprsw(i *int) *int { // ERROR "leaking param: i to result ~r0 level=0$" switch j := i; *j + 110 { case 12: return j @@ -401,7 +401,7 @@ func exprsw(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" } // assigning to an array element is like assigning to the array -func foo60(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" +func foo60(i *int) *int { // ERROR "leaking param: i to result ~r0 level=0$" var a [12]*int a[0] = i return a[1] @@ -414,7 +414,7 @@ func foo60a(i *int) *int { // ERROR "i does not escape$" } // assigning to a struct field is like assigning to the struct -func foo61(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" +func foo61(i *int) *int { // ERROR "leaking param: i to result ~r0 level=0$" type S struct { a, b *int } @@ -611,11 +611,11 @@ func foo74c() { } } -func myprint(y *int, x ...interface{}) *int { // ERROR "leaking param: y to result ~r2 level=0$" "x does not escape$" +func myprint(y *int, x ...interface{}) *int { // ERROR "leaking param: y to result ~r0 level=0$" "x does not escape$" return y } -func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "leaking param: x to result ~r2 level=0$" "y does not escape$" +func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "leaking param: x to result ~r0 level=0$" "y does not escape$" return &x[0] } @@ -770,7 +770,7 @@ func foo91(x *int) map[*int]*int { // ERROR "leaking param: x$" return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int{...} escapes to heap$" } -func foo92(x *int) [2]*int { // ERROR "leaking param: x to result ~r1 level=0$" +func foo92(x *int) [2]*int { // ERROR "leaking param: x to result ~r0 level=0$" return [2]*int{x, nil} } @@ -783,7 +783,7 @@ func foo93(c chan *int) *int { // ERROR "c does not escape$" } // does not leak m -func foo94(m map[*int]*int, b bool) *int { // ERROR "leaking param: m to result ~r2 level=1" +func foo94(m map[*int]*int, b bool) *int { // ERROR "leaking param: m to result ~r0 level=1" for k, v := range m { if b { return k @@ -799,12 +799,12 @@ func foo95(m map[*int]*int, x *int) { // ERROR "m does not escape$" "leaking par } // does not leak m but does leak content -func foo96(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1" +func foo96(m []*int) *int { // ERROR "leaking param: m to result ~r0 level=1" return m[0] } // does leak m -func foo97(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$" +func foo97(m [1]*int) *int { // ERROR "leaking param: m to result ~r0 level=0$" return m[0] } @@ -814,12 +814,12 @@ func foo98(m map[int]*int) *int { // ERROR "m does not escape$" } // does leak m -func foo99(m *[1]*int) []*int { // ERROR "leaking param: m to result ~r1 level=0$" +func foo99(m *[1]*int) []*int { // ERROR "leaking param: m to result ~r0 level=0$" return m[:] } // does not leak m -func foo100(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1" +func foo100(m []*int) *int { // ERROR "leaking param: m to result ~r0 level=1" for _, v := range m { return v } @@ -827,7 +827,7 @@ func foo100(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1" } // does leak m -func foo101(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$" +func foo101(m [1]*int) *int { // ERROR "leaking param: m to result ~r0 level=0$" for _, v := range m { return v } @@ -890,27 +890,27 @@ func foo110(x *int) *int { // ERROR "leaking param: x$" return m[nil] } -func foo111(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0" +func foo111(x *int) *int { // ERROR "leaking param: x to result ~r0 level=0" m := []*int{x} // ERROR "\[\]\*int{...} does not escape$" return m[0] } -func foo112(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" +func foo112(x *int) *int { // ERROR "leaking param: x to result ~r0 level=0$" m := [1]*int{x} return m[0] } -func foo113(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" +func foo113(x *int) *int { // ERROR "leaking param: x to result ~r0 level=0$" m := Bar{ii: x} return m.ii } -func foo114(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" +func foo114(x *int) *int { // ERROR "leaking param: x to result ~r0 level=0$" m := &Bar{ii: x} // ERROR "&Bar{...} does not escape$" return m.ii } -func foo115(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" +func foo115(x *int) *int { // ERROR "leaking param: x to result ~r0 level=0$" return (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(x)) + 1)) } diff --git a/test/escape5.go b/test/escape5.go index 82be2c38e79..73acfb46a94 100644 --- a/test/escape5.go +++ b/test/escape5.go @@ -22,19 +22,19 @@ func leaktoret(p *int) *int { // ERROR "leaking param: p to result" return p } -func leaktoret2(p *int) (*int, *int) { // ERROR "leaking param: p to result ~r1" "leaking param: p to result ~r2" +func leaktoret2(p *int) (*int, *int) { // ERROR "leaking param: p to result ~r0" "leaking param: p to result ~r1" return p, p } -func leaktoret22(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r2" "leaking param: q to result ~r3" +func leaktoret22(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r0" "leaking param: q to result ~r1" return p, q } -func leaktoret22b(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r3" "leaking param: q to result ~r2" +func leaktoret22b(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r1" "leaking param: q to result ~r0" return leaktoret22(q, p) } -func leaktoret22c(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r3" "leaking param: q to result ~r2" +func leaktoret22c(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r1" "leaking param: q to result ~r0" r, s := leaktoret22(q, p) return r, s } diff --git a/test/escape_array.go b/test/escape_array.go index 0d07fd861ff..83062c9436e 100644 --- a/test/escape_array.go +++ b/test/escape_array.go @@ -12,15 +12,15 @@ var Ssink *string type U [2]*string -func bar(a, b *string) U { // ERROR "leaking param: a to result ~r2 level=0$" "leaking param: b to result ~r2 level=0$" +func bar(a, b *string) U { // ERROR "leaking param: a to result ~r0 level=0$" "leaking param: b to result ~r0 level=0$" return U{a, b} } -func foo(x U) U { // ERROR "leaking param: x to result ~r1 level=0$" +func foo(x U) U { // ERROR "leaking param: x to result ~r0 level=0$" return U{x[1], x[0]} } -func bff(a, b *string) U { // ERROR "leaking param: a to result ~r2 level=0$" "leaking param: b to result ~r2 level=0$" +func bff(a, b *string) U { // ERROR "leaking param: a to result ~r0 level=0$" "leaking param: b to result ~r0 level=0$" return foo(foo(bar(a, b))) } @@ -41,27 +41,27 @@ func tbff2() *string { return u[1] } -func car(x U) *string { // ERROR "leaking param: x to result ~r1 level=0$" +func car(x U) *string { // ERROR "leaking param: x to result ~r0 level=0$" return x[0] } // BAD: need fine-grained analysis to track x[0] and x[1] differently. -func fun(x U, y *string) *string { // ERROR "leaking param: x to result ~r2 level=0$" "leaking param: y to result ~r2 level=0$" +func fun(x U, y *string) *string { // ERROR "leaking param: x to result ~r0 level=0$" "leaking param: y to result ~r0 level=0$" x[0] = y return x[1] } -func fup(x *U, y *string) *string { // ERROR "leaking param: x to result ~r2 level=1$" "leaking param: y$" +func fup(x *U, y *string) *string { // ERROR "leaking param: x to result ~r0 level=1$" "leaking param: y$" x[0] = y // leaking y to heap is intended return x[1] } -func fum(x *U, y **string) *string { // ERROR "leaking param: x to result ~r2 level=1$" "leaking param content: y$" +func fum(x *U, y **string) *string { // ERROR "leaking param: x to result ~r0 level=1$" "leaking param content: y$" x[0] = *y return x[1] } -func fuo(x *U, y *U) *string { // ERROR "leaking param: x to result ~r2 level=1$" "leaking param content: y$" +func fuo(x *U, y *U) *string { // ERROR "leaking param: x to result ~r0 level=1$" "leaking param content: y$" x[0] = y[0] return x[1] } diff --git a/test/escape_calls.go b/test/escape_calls.go index 9e1db5426ed..aa7c7f516cf 100644 --- a/test/escape_calls.go +++ b/test/escape_calls.go @@ -11,7 +11,7 @@ package foo -func f(buf []byte) []byte { // ERROR "leaking param: buf to result ~r1 level=0$" +func f(buf []byte) []byte { // ERROR "leaking param: buf to result ~r0 level=0$" return buf } diff --git a/test/escape_closure.go b/test/escape_closure.go index 9152319fe04..bd6c025476e 100644 --- a/test/escape_closure.go +++ b/test/escape_closure.go @@ -44,7 +44,7 @@ func ClosureCallArgs3() { func ClosureCallArgs4() { x := 0 - _ = func(p *int) *int { // ERROR "leaking param: p to result ~r1" "func literal does not escape" + _ = func(p *int) *int { // ERROR "leaking param: p to result ~r0" "func literal does not escape" return p }(&x) } @@ -111,7 +111,7 @@ func ClosureCallArgs11() { func ClosureCallArgs12() { x := 0 - defer func(p *int) *int { // ERROR "leaking param: p to result ~r1" "func literal does not escape" + defer func(p *int) *int { // ERROR "leaking param: p to result ~r0" "func literal does not escape" return p }(&x) } @@ -126,7 +126,7 @@ func ClosureCallArgs13() { func ClosureCallArgs14() { x := 0 p := &x - _ = func(p **int) *int { // ERROR "leaking param: p to result ~r1 level=1" "func literal does not escape" + _ = func(p **int) *int { // ERROR "leaking param: p to result ~r0 level=1" "func literal does not escape" return *p }(&p) } @@ -145,7 +145,7 @@ func ClosureLeak1(s string) string { // ERROR "s does not escape" } // See #14409 -- returning part of captured var leaks it. -func ClosureLeak1a(a ...string) string { // ERROR "leaking param: a to result ~r1 level=1$" +func ClosureLeak1a(a ...string) string { // ERROR "leaking param: a to result ~r0 level=1$" return func() string { // ERROR "func literal does not escape" return a[0] }() diff --git a/test/escape_param.go b/test/escape_param.go index dc93f689cf9..b630bae88fc 100644 --- a/test/escape_param.go +++ b/test/escape_param.go @@ -16,7 +16,7 @@ func zero() int { return 0 } var sink interface{} // in -> out -func param0(p *int) *int { // ERROR "leaking param: p to result ~r1" +func param0(p *int) *int { // ERROR "leaking param: p to result ~r0" return p } @@ -31,7 +31,7 @@ func caller0b() { } // in, in -> out, out -func param1(p1, p2 *int) (*int, *int) { // ERROR "leaking param: p1 to result ~r2" "leaking param: p2 to result ~r3" +func param1(p1, p2 *int) (*int, *int) { // ERROR "leaking param: p1 to result ~r0" "leaking param: p2 to result ~r1" return p1, p2 } @@ -222,7 +222,7 @@ func caller8() { } // *in -> out -func param9(p ***int) **int { // ERROR "leaking param: p to result ~r1 level=1" +func param9(p ***int) **int { // ERROR "leaking param: p to result ~r0 level=1" return *p } @@ -241,7 +241,7 @@ func caller9b() { } // **in -> out -func param10(p ***int) *int { // ERROR "leaking param: p to result ~r1 level=2" +func param10(p ***int) *int { // ERROR "leaking param: p to result ~r0 level=2" return **p } @@ -436,6 +436,6 @@ func param14a(x [4]*int) interface{} { // ERROR "leaking param: x$" // Convert to a direct interface, does not need an allocation. // So x only leaks to result. -func param14b(x *int) interface{} { // ERROR "leaking param: x to result ~r1 level=0" +func param14b(x *int) interface{} { // ERROR "leaking param: x to result ~r0 level=0" return x } diff --git a/test/escape_runtime_atomic.go b/test/escape_runtime_atomic.go index 62e8fede278..30d1d0c0c1d 100644 --- a/test/escape_runtime_atomic.go +++ b/test/escape_runtime_atomic.go @@ -13,8 +13,8 @@ import ( "unsafe" ) -// BAD: should always be "leaking param: addr to result ~r1 level=1$". -func Loadp(addr unsafe.Pointer) unsafe.Pointer { // ERROR "leaking param: addr( to result ~r1 level=1)?$" +// BAD: should always be "leaking param: addr to result ~r0 level=1$". +func Loadp(addr unsafe.Pointer) unsafe.Pointer { // ERROR "leaking param: addr( to result ~r0 level=1)?$" return atomic.Loadp(addr) } diff --git a/test/escape_slice.go b/test/escape_slice.go index d60414736c3..055b60be417 100644 --- a/test/escape_slice.go +++ b/test/escape_slice.go @@ -101,7 +101,7 @@ func slice11() { _ = s } -func slice12(x []int) *[1]int { // ERROR "leaking param: x to result ~r1 level=0$" +func slice12(x []int) *[1]int { // ERROR "leaking param: x to result ~r0 level=0$" return (*[1]int)(x) } @@ -110,7 +110,7 @@ func envForDir(dir string) []string { // ERROR "dir does not escape" return mergeEnvLists([]string{"PWD=" + dir}, env) // ERROR ".PWD=. \+ dir escapes to heap" "\[\]string{...} does not escape" } -func mergeEnvLists(in, out []string) []string { // ERROR "leaking param content: in" "leaking param content: out" "leaking param: out to result ~r2 level=0" +func mergeEnvLists(in, out []string) []string { // ERROR "leaking param content: in" "leaking param content: out" "leaking param: out to result ~r0 level=0" NextVar: for _, inkv := range in { k := strings.SplitAfterN(inkv, "=", 2)[0] diff --git a/test/escape_struct_return.go b/test/escape_struct_return.go index 222ef8bc22a..a42ae1e8c9b 100644 --- a/test/escape_struct_return.go +++ b/test/escape_struct_return.go @@ -15,11 +15,11 @@ type U struct { _spp **string } -func A(sp *string, spp **string) U { // ERROR "leaking param: sp to result ~r2 level=0$" "leaking param: spp to result ~r2 level=0$" +func A(sp *string, spp **string) U { // ERROR "leaking param: sp to result ~r0 level=0$" "leaking param: spp to result ~r0 level=0$" return U{sp, spp} } -func B(spp **string) U { // ERROR "leaking param: spp to result ~r1 level=0$" +func B(spp **string) U { // ERROR "leaking param: spp to result ~r0 level=0$" return U{*spp, spp} } diff --git a/test/escape_unsafe.go b/test/escape_unsafe.go index b34beacccb5..cec6674a142 100644 --- a/test/escape_unsafe.go +++ b/test/escape_unsafe.go @@ -15,7 +15,7 @@ import ( // (1) Conversion of a *T1 to Pointer to *T2. -func convert(p *float64) *uint64 { // ERROR "leaking param: p to result ~r1 level=0$" +func convert(p *float64) *uint64 { // ERROR "leaking param: p to result ~r0 level=0$" return (*uint64)(unsafe.Pointer(p)) } @@ -39,12 +39,12 @@ func arithMask() unsafe.Pointer { // (5) Conversion of the result of reflect.Value.Pointer or // reflect.Value.UnsafeAddr from uintptr to Pointer. -// BAD: should be "leaking param: p to result ~r1 level=0$" +// BAD: should be "leaking param: p to result ~r0 level=0$" func valuePointer(p *int) unsafe.Pointer { // ERROR "leaking param: p$" return unsafe.Pointer(reflect.ValueOf(p).Pointer()) } -// BAD: should be "leaking param: p to result ~r1 level=0$" +// BAD: should be "leaking param: p to result ~r0 level=0$" func valueUnsafeAddr(p *int) unsafe.Pointer { // ERROR "leaking param: p$" return unsafe.Pointer(reflect.ValueOf(p).Elem().UnsafeAddr()) } @@ -52,11 +52,11 @@ func valueUnsafeAddr(p *int) unsafe.Pointer { // ERROR "leaking param: p$" // (6) Conversion of a reflect.SliceHeader or reflect.StringHeader // Data field to or from Pointer. -func fromSliceData(s []int) unsafe.Pointer { // ERROR "leaking param: s to result ~r1 level=0$" +func fromSliceData(s []int) unsafe.Pointer { // ERROR "leaking param: s to result ~r0 level=0$" return unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&s)).Data) } -func fromStringData(s string) unsafe.Pointer { // ERROR "leaking param: s to result ~r1 level=0$" +func fromStringData(s string) unsafe.Pointer { // ERROR "leaking param: s to result ~r0 level=0$" return unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&s)).Data) } diff --git a/test/fixedbugs/issue12006.go b/test/fixedbugs/issue12006.go index 0a2ef8dad04..e878bc48e24 100644 --- a/test/fixedbugs/issue12006.go +++ b/test/fixedbugs/issue12006.go @@ -87,7 +87,7 @@ func TFooI() { FooI(a, b, c) // ERROR "a escapes to heap" "b escapes to heap" "... argument does not escape" } -func FooJ(args ...interface{}) *int32 { // ERROR "leaking param: args to result ~r1 level=1" +func FooJ(args ...interface{}) *int32 { // ERROR "leaking param: args to result ~r0 level=1" for i := 0; i < len(args); i++ { switch x := args[i].(type) { case nil: @@ -123,7 +123,7 @@ type fakeSlice struct { a *[4]interface{} } -func FooK(args fakeSlice) *int32 { // ERROR "leaking param: args to result ~r1 level=1" +func FooK(args fakeSlice) *int32 { // ERROR "leaking param: args to result ~r0 level=1" for i := 0; i < args.l; i++ { switch x := (*args.a)[i].(type) { case nil: @@ -148,7 +148,7 @@ func TFooK2() { isink = FooK(fs) } -func FooL(args []interface{}) *int32 { // ERROR "leaking param: args to result ~r1 level=1" +func FooL(args []interface{}) *int32 { // ERROR "leaking param: args to result ~r0 level=1" for i := 0; i < len(args); i++ { switch x := args[i].(type) { case nil: diff --git a/test/fixedbugs/issue12588.go b/test/fixedbugs/issue12588.go index 950ef36e206..dc8111198c4 100644 --- a/test/fixedbugs/issue12588.go +++ b/test/fixedbugs/issue12588.go @@ -35,7 +35,7 @@ func g(a *A) int { // ERROR "a does not escape" return 0 } -func h(a *B) *uint64 { // ERROR "leaking param: a to result ~r1 level=1" +func h(a *B) *uint64 { // ERROR "leaking param: a to result ~r0 level=1" for i, x := range &a.b { if i == 0 { return x @@ -44,7 +44,7 @@ func h(a *B) *uint64 { // ERROR "leaking param: a to result ~r1 level=1" return nil } -func h2(a *B) *uint64 { // ERROR "leaking param: a to result ~r1 level=1" +func h2(a *B) *uint64 { // ERROR "leaking param: a to result ~r0 level=1" p := &a.b for i, x := range p { if i == 0 { @@ -55,7 +55,7 @@ func h2(a *B) *uint64 { // ERROR "leaking param: a to result ~r1 level=1" } // Seems like below should be level=1, not 0. -func k(a B) *uint64 { // ERROR "leaking param: a to result ~r1 level=0" +func k(a B) *uint64 { // ERROR "leaking param: a to result ~r0 level=0" for i, x := range &a.b { if i == 0 { return x diff --git a/test/fixedbugs/issue42284.dir/a.go b/test/fixedbugs/issue42284.dir/a.go index ffe9310be35..f7fd80bd207 100644 --- a/test/fixedbugs/issue42284.dir/a.go +++ b/test/fixedbugs/issue42284.dir/a.go @@ -13,7 +13,7 @@ func E() I { // ERROR "can inline E" return T(0) // ERROR "T\(0\) escapes to heap" } -func F(i I) I { // ERROR "can inline F" "leaking param: i to result ~r1 level=0" +func F(i I) I { // ERROR "can inline F" "leaking param: i to result ~r0 level=0" i = nil return i } From 6da1661371410c46af84c578d644052894226314 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 25 May 2021 20:14:33 -0700 Subject: [PATCH 179/940] [dev.typeparams] cmd/compile: simplify inlining variadic calls We already have and use FixVariadicCall to normalize non-dotted calls to variadic functions elsewhere in the compiler to simplify rewriting of function calls. This CL updates inl.go to use it too. A couple tests need to be updated to (correctly) expect diagnostics about "... argument" instead of a slice literal. This is because inl.go previously failed to set Implicit on the slice literal node. Change-Id: I76bd79b95ae1f16e3b26ff7e9e1c468f538fd1f0 Reviewed-on: https://go-review.googlesource.com/c/go/+/323009 Trust: Matthew Dempsky Trust: Dan Scales Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/inline/inl.go | 51 ++-------------------- src/cmd/compile/internal/typecheck/func.go | 13 +++--- src/cmd/compile/internal/walk/convert.go | 2 +- test/fixedbugs/issue30898.go | 2 +- test/inline_variadic.go | 2 +- 5 files changed, 14 insertions(+), 56 deletions(-) diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go index 263e0b310b2..00f8447f059 100644 --- a/src/cmd/compile/internal/inline/inl.go +++ b/src/cmd/compile/internal/inline/inl.go @@ -793,6 +793,9 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b defer func() { inlMap[fn] = false }() + + typecheck.FixVariadicCall(n) + if base.Debug.TypecheckInl == 0 { typecheck.ImportedBody(fn) } @@ -914,51 +917,17 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b } as.Rhs.Append(n.Args...) - // For non-dotted calls to variadic functions, we assign the - // variadic parameter's temp name separately. - var vas *ir.AssignStmt - if recv := fn.Type().Recv(); recv != nil { as.Lhs.Append(inlParam(recv, as, inlvars)) } for _, param := range fn.Type().Params().Fields().Slice() { - // For ordinary parameters or variadic parameters in - // dotted calls, just add the variable to the - // assignment list, and we're done. - if !param.IsDDD() || n.IsDDD { - as.Lhs.Append(inlParam(param, as, inlvars)) - continue - } - - // Otherwise, we need to collect the remaining values - // to pass as a slice. - - x := len(as.Lhs) - for len(as.Lhs) < len(as.Rhs) { - as.Lhs.Append(argvar(param.Type, len(as.Lhs))) - } - varargs := as.Lhs[x:] - - vas = ir.NewAssignStmt(base.Pos, nil, nil) - vas.X = inlParam(param, vas, inlvars) - if len(varargs) == 0 { - vas.Y = typecheck.NodNil() - vas.Y.SetType(param.Type) - } else { - lit := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(param.Type), nil) - lit.List = varargs - vas.Y = lit - } + as.Lhs.Append(inlParam(param, as, inlvars)) } if len(as.Rhs) != 0 { ninit.Append(typecheck.Stmt(as)) } - if vas != nil { - ninit.Append(typecheck.Stmt(vas)) - } - if !delayretvars { // Zero the return parameters. for _, n := range retvars { @@ -1078,18 +1047,6 @@ func retvar(t *types.Field, i int) *ir.Name { return n } -// Synthesize a variable to store the inlined function's arguments -// when they come from a multiple return call. -func argvar(t *types.Type, i int) ir.Node { - n := typecheck.NewName(typecheck.LookupNum("~arg", i)) - n.SetType(t.Elem()) - n.Class = ir.PAUTO - n.SetUsed(true) - n.Curfn = ir.CurFunc // the calling function, not the called one - ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n) - return n -} - // The inlsubst type implements the actual inlining of a single // function call. type inlsubst struct { diff --git a/src/cmd/compile/internal/typecheck/func.go b/src/cmd/compile/internal/typecheck/func.go index f381e1dbdc4..760b8868ab7 100644 --- a/src/cmd/compile/internal/typecheck/func.go +++ b/src/cmd/compile/internal/typecheck/func.go @@ -8,6 +8,7 @@ import ( "cmd/compile/internal/base" "cmd/compile/internal/ir" "cmd/compile/internal/types" + "cmd/internal/src" "fmt" "go/constant" @@ -15,21 +16,21 @@ import ( ) // package all the arguments that match a ... T parameter into a []T. -func MakeDotArgs(typ *types.Type, args []ir.Node) ir.Node { +func MakeDotArgs(pos src.XPos, typ *types.Type, args []ir.Node) ir.Node { var n ir.Node if len(args) == 0 { - n = NodNil() + n = ir.NewNilExpr(pos) n.SetType(typ) } else { - lit := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ), nil) - lit.List.Append(args...) + args = append([]ir.Node(nil), args...) + lit := ir.NewCompLitExpr(pos, ir.OCOMPLIT, ir.TypeNode(typ), args) lit.SetImplicit(true) n = lit } n = Expr(n) if n.Type() == nil { - base.Fatalf("mkdotargslice: typecheck failed") + base.FatalfAt(pos, "mkdotargslice: typecheck failed") } return n } @@ -47,7 +48,7 @@ func FixVariadicCall(call *ir.CallExpr) { args := call.Args extra := args[vi:] - slice := MakeDotArgs(vt, extra) + slice := MakeDotArgs(call.Pos(), vt, extra) for i := range extra { extra[i] = nil // allow GC } diff --git a/src/cmd/compile/internal/walk/convert.go b/src/cmd/compile/internal/walk/convert.go index 26e17a126f2..5297332f6b0 100644 --- a/src/cmd/compile/internal/walk/convert.go +++ b/src/cmd/compile/internal/walk/convert.go @@ -499,7 +499,7 @@ func walkCheckPtrArithmetic(n *ir.ConvExpr, init *ir.Nodes) ir.Node { cheap := cheapExpr(n, init) - slice := typecheck.MakeDotArgs(types.NewSlice(types.Types[types.TUNSAFEPTR]), originals) + slice := typecheck.MakeDotArgs(base.Pos, types.NewSlice(types.Types[types.TUNSAFEPTR]), originals) slice.SetEsc(ir.EscNone) init.Append(mkcall("checkptrArithmetic", nil, init, typecheck.ConvNop(cheap, types.Types[types.TUNSAFEPTR]), slice)) diff --git a/test/fixedbugs/issue30898.go b/test/fixedbugs/issue30898.go index b6376d3f9e7..c7f6f2d3712 100644 --- a/test/fixedbugs/issue30898.go +++ b/test/fixedbugs/issue30898.go @@ -15,5 +15,5 @@ func debugf(format string, args ...interface{}) { // ERROR "can inline debugf" " func bar() { // ERROR "can inline bar" value := 10 - debugf("value is %d", value) // ERROR "inlining call to debugf" "value does not escape" "\[\]interface {}{...} does not escape" + debugf("value is %d", value) // ERROR "inlining call to debugf" "value does not escape" "\.\.\. argument does not escape" } diff --git a/test/inline_variadic.go b/test/inline_variadic.go index 687048a1922..49483d77f79 100644 --- a/test/inline_variadic.go +++ b/test/inline_variadic.go @@ -14,6 +14,6 @@ func head(xs ...string) string { // ERROR "can inline head" "leaking param: xs t } func f() string { // ERROR "can inline f" - x := head("hello", "world") // ERROR "inlining call to head" "\[\]string{...} does not escape" + x := head("hello", "world") // ERROR "inlining call to head" "\.\.\. argument does not escape" return x } From 1ec056244e1a058ea3a21f0abd1165d710398416 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 24 May 2021 04:41:58 -0700 Subject: [PATCH 180/940] [dev.typeparams] cmd/compile: inlining tweaks for toolstash This CL makes to minor changes motivated by making it easier to make large-scale changes to the inliner while satisfying toolstash -cmp: 1. When creating inlining variables, make sure to preserve the AutoTemp flag. This is necessary so that temporary variables introduced by rewriting f(g()) calls during typecheck stay autotemp after inlining and are (correctly) omitted from DWARF debugging information. 2. When sorting variables for stack frame layout, use a stable sort. This ensures that layout is insensitive to whether deadcode elimination happens before or after inlining. Change-Id: I672e752a873c7e16749b9873fd6573607e074309 Reviewed-on: https://go-review.googlesource.com/c/go/+/323011 Trust: Matthew Dempsky Trust: Dan Scales Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/inline/inl.go | 1 + src/cmd/compile/internal/ssagen/pgen.go | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go index 00f8447f059..042e3f2332a 100644 --- a/src/cmd/compile/internal/inline/inl.go +++ b/src/cmd/compile/internal/inline/inl.go @@ -1029,6 +1029,7 @@ func inlvar(var_ *ir.Name) *ir.Name { n.SetType(var_.Type()) n.Class = ir.PAUTO n.SetUsed(true) + n.SetAutoTemp(var_.AutoTemp()) n.Curfn = ir.CurFunc // the calling function, not the called one n.SetAddrtaken(var_.Addrtaken()) diff --git a/src/cmd/compile/internal/ssagen/pgen.go b/src/cmd/compile/internal/ssagen/pgen.go index 62567535d76..93157bfa11b 100644 --- a/src/cmd/compile/internal/ssagen/pgen.go +++ b/src/cmd/compile/internal/ssagen/pgen.go @@ -114,7 +114,10 @@ func (s *ssafn) AllocFrame(f *ssa.Func) { } } - sort.Sort(byStackVar(fn.Dcl)) + // Use sort.Stable instead of sort.Sort so stack layout (and thus + // compiler output) is less sensitive to frontend changes that + // introduce or remove unused variables. + sort.Stable(byStackVar(fn.Dcl)) // Reassign stack offsets of the locals that are used. lastHasPtr := false From 6ff0ae2aa4fdb9c6c267efb30927e87563387c49 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Thu, 13 May 2021 13:45:55 -0400 Subject: [PATCH 181/940] crypto/elliptic: fix typo in p521Point type name Change-Id: I6cab3624c875d9a70441a560e84f91c9b2df17b9 Reviewed-on: https://go-review.googlesource.com/c/go/+/320070 Trust: Filippo Valsorda Trust: Katie Hockman Run-TryBot: Filippo Valsorda Run-TryBot: Katie Hockman TryBot-Result: Go Bot Reviewed-by: Katie Hockman --- src/crypto/elliptic/p521.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/crypto/elliptic/p521.go b/src/crypto/elliptic/p521.go index ce74e0539c9..3d355943ec7 100644 --- a/src/crypto/elliptic/p521.go +++ b/src/crypto/elliptic/p521.go @@ -52,7 +52,7 @@ func (curve p521Curve) IsOnCurve(x, y *big.Int) bool { return x3.Equal(y2) == 1 } -type p512Point struct { +type p521Point struct { x, y, z *fiat.P521Element } @@ -67,7 +67,7 @@ func fiatP521ToBigInt(x *fiat.P521Element) *big.Int { // affineFromJacobian brings a point in Jacobian coordinates back to affine // coordinates, with (0, 0) representing infinity by convention. It also goes // back to big.Int values to match the exposed API. -func (curve p521Curve) affineFromJacobian(p *p512Point) (x, y *big.Int) { +func (curve p521Curve) affineFromJacobian(p *p521Point) (x, y *big.Int) { if p.z.IsZero() == 1 { return new(big.Int), new(big.Int) } @@ -99,17 +99,17 @@ func bigIntToFiatP521(x *big.Int) *fiat.P521Element { // jacobianFromAffine converts (x, y) affine coordinates into (x, y, z) Jacobian // coordinates. It also converts from big.Int to fiat, which is necessarily a // messy and variable-time operation, which we can't avoid due to the exposed API. -func (curve p521Curve) jacobianFromAffine(x, y *big.Int) *p512Point { +func (curve p521Curve) jacobianFromAffine(x, y *big.Int) *p521Point { // (0, 0) is by convention the point at infinity, which can't be represented // in affine coordinates, but is (0, 0, 0) in Jacobian. if x.Sign() == 0 && y.Sign() == 0 { - return &p512Point{ + return &p521Point{ x: new(fiat.P521Element), y: new(fiat.P521Element), z: new(fiat.P521Element), } } - return &p512Point{ + return &p521Point{ x: bigIntToFiatP521(x), y: bigIntToFiatP521(y), z: new(fiat.P521Element).One(), @@ -123,7 +123,7 @@ func (curve p521Curve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { } // addJacobian sets q = p1 + p2, and returns q. The points may overlap. -func (q *p512Point) addJacobian(p1, p2 *p512Point) *p512Point { +func (q *p521Point) addJacobian(p1, p2 *p521Point) *p521Point { // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl z1IsZero := p1.z.IsZero() z2IsZero := p2.z.IsZero() @@ -189,7 +189,7 @@ func (curve p521Curve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { } // doubleJacobian sets q = p + p, and returns q. The points may overlap. -func (q *p512Point) doubleJacobian(p *p512Point) *p512Point { +func (q *p521Point) doubleJacobian(p *p521Point) *p521Point { // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b delta := new(fiat.P521Element).Square(p.z) gamma := new(fiat.P521Element).Square(p.y) @@ -230,11 +230,11 @@ func (q *p512Point) doubleJacobian(p *p512Point) *p512Point { func (curve p521Curve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) { B := curve.jacobianFromAffine(Bx, By) - p, t := &p512Point{ + p, t := &p521Point{ x: new(fiat.P521Element), y: new(fiat.P521Element), z: new(fiat.P521Element), - }, &p512Point{ + }, &p521Point{ x: new(fiat.P521Element), y: new(fiat.P521Element), z: new(fiat.P521Element), From 9bc52686da81b515cf3ad654dfb1a536fabceafa Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Tue, 25 May 2021 12:21:11 -0400 Subject: [PATCH 182/940] cmd/go,cmd/link: do not check for staleness in most tests Instead, check that stale packages in the standard library are not rebuilt when already present in the build cache, and are not installed implicitly when rebuilt. We retain the staleness checks for the runtime package in tests involving '-i', because those are guaranteed to fail anyway if the package is stale and the "stale" failure message is arguably clearer. They can be removed if/when we remove the '-i' flag, but the runtime package is less likely to become stale because it does not have cgo dependencies. Fixes #46347 Updates #33598 Updates #35459 Updates #41696 Change-Id: I7b0a808addd930f9f4911ff53ded62272af75a40 Reviewed-on: https://go-review.googlesource.com/c/go/+/322629 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Cherry Mui Reviewed-by: Jay Conrod --- ...build_package_not_stale_trailing_slash.txt | 13 ----- src/cmd/go/testdata/script/cgo_stale.txt | 39 ++++++++++++++ src/cmd/go/testdata/script/list_std_stale.txt | 31 ----------- .../go/testdata/script/list_std_vendor.txt | 32 ++++++++++++ .../testdata/script/test_race_install_cgo.txt | 2 - src/cmd/go/testdata/script/toolexec.txt | 6 +++ src/cmd/link/dwarf_test.go | 52 +++++++++++++------ 7 files changed, 112 insertions(+), 63 deletions(-) delete mode 100644 src/cmd/go/testdata/script/build_package_not_stale_trailing_slash.txt create mode 100644 src/cmd/go/testdata/script/cgo_stale.txt delete mode 100644 src/cmd/go/testdata/script/list_std_stale.txt create mode 100644 src/cmd/go/testdata/script/list_std_vendor.txt diff --git a/src/cmd/go/testdata/script/build_package_not_stale_trailing_slash.txt b/src/cmd/go/testdata/script/build_package_not_stale_trailing_slash.txt deleted file mode 100644 index 38a151ef1f6..00000000000 --- a/src/cmd/go/testdata/script/build_package_not_stale_trailing_slash.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Tests Issue #12690 - -[gccgo] skip 'gccgo does not have GOROOT' - -! stale runtime -! stale os -! stale io - -env GOROOT=$GOROOT'/' - -! stale runtime -! stale os -! stale io \ No newline at end of file diff --git a/src/cmd/go/testdata/script/cgo_stale.txt b/src/cmd/go/testdata/script/cgo_stale.txt new file mode 100644 index 00000000000..9e46855eadb --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_stale.txt @@ -0,0 +1,39 @@ +# golang.org/issue/46347: a stale runtime/cgo should only force a single rebuild + +[!cgo] skip +[short] skip + + +# If we set a unique CGO_CFLAGS, the installed copy of runtime/cgo +# should be reported as stale. + +env CGO_CFLAGS=-DTestScript_cgo_stale=true +stale runtime/cgo + + +# If we then build a package that uses cgo, runtime/cgo should be rebuilt and +# cached with the new flag, but not installed to GOROOT (and thus still stale). + +env GOCACHE=$WORK/cache # Use a fresh cache to avoid interference between runs. + +go build -x . +stderr '[/\\]cgo'$GOEXE'["]? .* -importpath runtime/cgo' +stale runtime/cgo + + +# After runtime/cgo has been rebuilt and cached, it should not be rebuilt again +# even though it is still reported as stale. + +go build -x . +! stderr '[/\\]cgo'$GOEXE'["]? .* -importpath runtime/cgo' +stale runtime/cgo + + +-- go.mod -- +module example.com/m + +go 1.17 +-- m.go -- +package m + +import "C" diff --git a/src/cmd/go/testdata/script/list_std_stale.txt b/src/cmd/go/testdata/script/list_std_stale.txt deleted file mode 100644 index e5c1f334fd4..00000000000 --- a/src/cmd/go/testdata/script/list_std_stale.txt +++ /dev/null @@ -1,31 +0,0 @@ -# https://golang.org/issue/44725: packages in std should not be reported as stale, -# regardless of whether they are listed from within or outside GOROOT/src. - -# Control case: net should not be stale at the start of the test, -# and should depend on vendor/golang.org/… instead of golang.org/…. - -! stale net - -go list -deps net -stdout '^vendor/golang.org/x/net' -! stdout '^golang.org/x/net' - -# Net should also not be stale when viewed from within GOROOT/src, -# and should still report the same package dependencies. - -cd $GOROOT/src -! stale net - -go list -deps net -stdout '^vendor/golang.org/x/net' -! stdout '^golang.org/x/net' - - -# However, 'go mod' and 'go get' subcommands should report the original module -# dependencies, not the vendored packages. - -[!net] stop - -env GOPROXY= -go mod why -m golang.org/x/net -stdout '^# golang.org/x/net\nnet\ngolang.org/x/net' diff --git a/src/cmd/go/testdata/script/list_std_vendor.txt b/src/cmd/go/testdata/script/list_std_vendor.txt new file mode 100644 index 00000000000..8f27cc1e8d8 --- /dev/null +++ b/src/cmd/go/testdata/script/list_std_vendor.txt @@ -0,0 +1,32 @@ +# https://golang.org/issue/44725: packages in std should have the same +# dependencies regardless of whether they are listed from within or outside +# GOROOT/src. + +# Control case: net, viewed from outside the 'std' module, +# should depend on vendor/golang.org/… instead of golang.org/…. + +go list -deps net +stdout '^vendor/golang.org/x/net' +! stdout '^golang.org/x/net' +cp stdout $WORK/net-deps.txt + + +# It should still report the same package dependencies when viewed from +# within GOROOT/src. + +cd $GOROOT/src + +go list -deps net +stdout '^vendor/golang.org/x/net' +! stdout '^golang.org/x/net' +cmp stdout $WORK/net-deps.txt + + +# However, 'go mod' and 'go get' subcommands should report the original module +# dependencies, not the vendored packages. + +[!net] stop + +env GOPROXY= +go mod why -m golang.org/x/net +stdout '^# golang.org/x/net\nnet\ngolang.org/x/net' diff --git a/src/cmd/go/testdata/script/test_race_install_cgo.txt b/src/cmd/go/testdata/script/test_race_install_cgo.txt index 3f4eb90e3f6..e1fe4f2acea 100644 --- a/src/cmd/go/testdata/script/test_race_install_cgo.txt +++ b/src/cmd/go/testdata/script/test_race_install_cgo.txt @@ -2,8 +2,6 @@ [!race] skip -[!darwin] ! stale cmd/cgo # The darwin builders are spuriously stale; see #33598. - env GOBIN=$WORK/bin go install m/mtime m/sametime diff --git a/src/cmd/go/testdata/script/toolexec.txt b/src/cmd/go/testdata/script/toolexec.txt index 4f26da6d26b..bb86467942b 100644 --- a/src/cmd/go/testdata/script/toolexec.txt +++ b/src/cmd/go/testdata/script/toolexec.txt @@ -3,6 +3,12 @@ # Build our simple toolexec program. go build ./cmd/mytool +# Use an ephemeral build cache so that our toolexec output is not cached +# for any stale standard-library dependencies. +# +# TODO(#27628): This should not be necessary. +env GOCACHE=$WORK/gocache + # Build the main package with our toolexec program. For each action, it will # print the tool's name and the TOOLEXEC_IMPORTPATH value. We expect to compile # each package once, and link the main package once. diff --git a/src/cmd/link/dwarf_test.go b/src/cmd/link/dwarf_test.go index 0419613cbe2..3ca59bd47f0 100644 --- a/src/cmd/link/dwarf_test.go +++ b/src/cmd/link/dwarf_test.go @@ -19,6 +19,36 @@ import ( "testing" ) +// TestMain allows this test binary to run as a -toolexec wrapper for the 'go' +// command. If LINK_TEST_TOOLEXEC is set, TestMain runs the binary as if it were +// cmd/link, and otherwise runs the requested tool as a subprocess. +// +// This allows the test to verify the behavior of the current contents of the +// cmd/link package even if the installed cmd/link binary is stale. +func TestMain(m *testing.M) { + if os.Getenv("LINK_TEST_TOOLEXEC") == "" { + // Not running as a -toolexec wrapper. Just run the tests. + os.Exit(m.Run()) + } + + if strings.TrimSuffix(filepath.Base(os.Args[1]), ".exe") == "link" { + // Running as a -toolexec linker, and the tool is cmd/link. + // Substitute this test binary for the linker. + os.Args = os.Args[1:] + main() + os.Exit(0) + } + + cmd := exec.Command(os.Args[1], os.Args[2:]...) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + os.Exit(1) + } + os.Exit(0) +} + func testDWARF(t *testing.T, buildmode string, expectDWARF bool, env ...string) { testenv.MustHaveCGO(t) testenv.MustHaveGoBuild(t) @@ -29,17 +59,6 @@ func testDWARF(t *testing.T, buildmode string, expectDWARF bool, env ...string) t.Parallel() - out, err := exec.Command(testenv.GoToolPath(t), "list", "-f", "{{.Stale}}", "cmd/link").CombinedOutput() - if err != nil { - t.Fatalf("go list: %v\n%s", err, out) - } - if string(out) != "false\n" { - if strings.HasPrefix(testenv.Builder(), "darwin-") { - t.Skipf("cmd/link is spuriously stale on Darwin builders - see #33598") - } - t.Fatalf("cmd/link is stale - run go install cmd/link") - } - for _, prog := range []string{"testprog", "testprogcgo"} { prog := prog expectDWARF := expectDWARF @@ -48,11 +67,11 @@ func testDWARF(t *testing.T, buildmode string, expectDWARF bool, env ...string) if extld == "" { extld = "gcc" } + var err error expectDWARF, err = cmddwarf.IsDWARFEnabledOnAIXLd(extld) if err != nil { t.Fatal(err) } - } t.Run(prog, func(t *testing.T) { @@ -62,15 +81,14 @@ func testDWARF(t *testing.T, buildmode string, expectDWARF bool, env ...string) exe := filepath.Join(tmpDir, prog+".exe") dir := "../../runtime/testdata/" + prog - cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe) + cmd := exec.Command(testenv.GoToolPath(t), "build", "-toolexec", os.Args[0], "-o", exe) if buildmode != "" { cmd.Args = append(cmd.Args, "-buildmode", buildmode) } cmd.Args = append(cmd.Args, dir) - if env != nil { - cmd.Env = append(os.Environ(), env...) - cmd.Env = append(cmd.Env, "CGO_CFLAGS=") // ensure CGO_CFLAGS does not contain any flags. Issue #35459 - } + cmd.Env = append(os.Environ(), env...) + cmd.Env = append(cmd.Env, "CGO_CFLAGS=") // ensure CGO_CFLAGS does not contain any flags. Issue #35459 + cmd.Env = append(cmd.Env, "LINK_TEST_TOOLEXEC=1") out, err := cmd.CombinedOutput() if err != nil { t.Fatalf("go build -o %v %v: %v\n%s", exe, dir, err, out) From 950fa11c4cb01a145bb07eeb167d90a1846061b3 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Fri, 21 May 2021 14:02:30 -0400 Subject: [PATCH 183/940] net/http/httputil: always remove hop-by-hop headers Previously, we'd fail to remove the Connection header from a request like this: Connection: Connection: x-header Fixes #46313 Fixes CVE-2021-33197 Change-Id: Ie3009e926ceecfa86dfa6bcc6fe14ff01086be7d Reviewed-on: https://go-review.googlesource.com/c/go/+/321929 Run-TryBot: Filippo Valsorda Reviewed-by: Katie Hockman Trust: Katie Hockman Trust: Filippo Valsorda TryBot-Result: Go Bot --- src/net/http/httputil/reverseproxy.go | 22 ++++---- src/net/http/httputil/reverseproxy_test.go | 63 +++++++++++++++++++++- 2 files changed, 70 insertions(+), 15 deletions(-) diff --git a/src/net/http/httputil/reverseproxy.go b/src/net/http/httputil/reverseproxy.go index 1432ee26d37..5d39955d62d 100644 --- a/src/net/http/httputil/reverseproxy.go +++ b/src/net/http/httputil/reverseproxy.go @@ -253,22 +253,18 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { // important is "Connection" because we want a persistent // connection, regardless of what the client sent to us. for _, h := range hopHeaders { - hv := outreq.Header.Get(h) - if hv == "" { - continue - } - if h == "Te" && hv == "trailers" { - // Issue 21096: tell backend applications that - // care about trailer support that we support - // trailers. (We do, but we don't go out of - // our way to advertise that unless the - // incoming client request thought it was - // worth mentioning) - continue - } outreq.Header.Del(h) } + // Issue 21096: tell backend applications that care about trailer support + // that we support trailers. (We do, but we don't go out of our way to + // advertise that unless the incoming client request thought it was worth + // mentioning.) Note that we look at req.Header, not outreq.Header, since + // the latter has passed through removeConnectionHeaders. + if httpguts.HeaderValuesContainsToken(req.Header["Te"], "trailers") { + outreq.Header.Set("Te", "trailers") + } + // After stripping all the hop-by-hop connection headers above, add back any // necessary for protocol upgrades, such as for websockets. if reqUpType != "" { diff --git a/src/net/http/httputil/reverseproxy_test.go b/src/net/http/httputil/reverseproxy_test.go index 22720caf930..1898ed8b8af 100644 --- a/src/net/http/httputil/reverseproxy_test.go +++ b/src/net/http/httputil/reverseproxy_test.go @@ -91,8 +91,9 @@ func TestReverseProxy(t *testing.T) { getReq, _ := http.NewRequest("GET", frontend.URL, nil) getReq.Host = "some-name" - getReq.Header.Set("Connection", "close") - getReq.Header.Set("Te", "trailers") + getReq.Header.Set("Connection", "close, TE") + getReq.Header.Add("Te", "foo") + getReq.Header.Add("Te", "bar, trailers") getReq.Header.Set("Proxy-Connection", "should be deleted") getReq.Header.Set("Upgrade", "foo") getReq.Close = true @@ -236,6 +237,64 @@ func TestReverseProxyStripHeadersPresentInConnection(t *testing.T) { } } +func TestReverseProxyStripEmptyConnection(t *testing.T) { + // See Issue 46313. + const backendResponse = "I am the backend" + + // someConnHeader is some arbitrary header to be declared as a hop-by-hop header + // in the Request's Connection header. + const someConnHeader = "X-Some-Conn-Header" + + backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if c := r.Header.Values("Connection"); len(c) != 0 { + t.Errorf("handler got header %q = %v; want empty", "Connection", c) + } + if c := r.Header.Get(someConnHeader); c != "" { + t.Errorf("handler got header %q = %q; want empty", someConnHeader, c) + } + w.Header().Add("Connection", "") + w.Header().Add("Connection", someConnHeader) + w.Header().Set(someConnHeader, "should be deleted") + io.WriteString(w, backendResponse) + })) + defer backend.Close() + backendURL, err := url.Parse(backend.URL) + if err != nil { + t.Fatal(err) + } + proxyHandler := NewSingleHostReverseProxy(backendURL) + frontend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + proxyHandler.ServeHTTP(w, r) + if c := r.Header.Get(someConnHeader); c != "should be deleted" { + t.Errorf("handler modified header %q = %q; want %q", someConnHeader, c, "should be deleted") + } + })) + defer frontend.Close() + + getReq, _ := http.NewRequest("GET", frontend.URL, nil) + getReq.Header.Add("Connection", "") + getReq.Header.Add("Connection", someConnHeader) + getReq.Header.Set(someConnHeader, "should be deleted") + res, err := frontend.Client().Do(getReq) + if err != nil { + t.Fatalf("Get: %v", err) + } + defer res.Body.Close() + bodyBytes, err := io.ReadAll(res.Body) + if err != nil { + t.Fatalf("reading body: %v", err) + } + if got, want := string(bodyBytes), backendResponse; got != want { + t.Errorf("got body %q; want %q", got, want) + } + if c := res.Header.Get("Connection"); c != "" { + t.Errorf("handler got header %q = %q; want empty", "Connection", c) + } + if c := res.Header.Get(someConnHeader); c != "" { + t.Errorf("handler got header %q = %q; want empty", someConnHeader, c) + } +} + func TestXForwardedFor(t *testing.T) { const prevForwardedFor = "client ip" const backendResponse = "I am the backend" From fca7b8f3e690ec0562dd6ed609a8c7e6bef744c8 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Thu, 27 May 2021 15:14:18 +0000 Subject: [PATCH 184/940] Revert "net: verify results from Lookup* are valid domain names" This reverts commit c89f1224a544cde464fcb86e78ebb0cc97eedba2. Reason for revert: reverting so we can apply follow-up fixes and do a single cherry pick. Change-Id: I16c6283a0bcab056216f330fb98fa3b5f2b0780c Reviewed-on: https://go-review.googlesource.com/c/go/+/323129 Reviewed-by: Katie Hockman Reviewed-by: Filippo Valsorda Trust: Katie Hockman Run-TryBot: Katie Hockman TryBot-Result: Go Bot --- src/net/dnsclient_unix_test.go | 121 --------------------------------- src/net/lookup.go | 98 +++----------------------- 2 files changed, 8 insertions(+), 211 deletions(-) diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go index 69a9b972f08..ec690a1c0cf 100644 --- a/src/net/dnsclient_unix_test.go +++ b/src/net/dnsclient_unix_test.go @@ -1799,124 +1799,3 @@ func TestPTRandNonPTR(t *testing.T) { t.Errorf("names = %q; want %q", names, want) } } - -func TestCVE202133195(t *testing.T) { - fake := fakeDNSServer{ - rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) { - r := dnsmessage.Message{ - Header: dnsmessage.Header{ - ID: q.Header.ID, - Response: true, - RCode: dnsmessage.RCodeSuccess, - RecursionAvailable: true, - }, - Questions: q.Questions, - } - switch q.Questions[0].Type { - case dnsmessage.TypeCNAME: - r.Answers = []dnsmessage.Resource{} - case dnsmessage.TypeA: // CNAME lookup uses a A/AAAA as a proxy - r.Answers = append(r.Answers, - dnsmessage.Resource{ - Header: dnsmessage.ResourceHeader{ - Name: dnsmessage.MustNewName(".golang.org."), - Type: dnsmessage.TypeA, - Class: dnsmessage.ClassINET, - Length: 4, - }, - Body: &dnsmessage.AResource{ - A: TestAddr, - }, - }, - ) - case dnsmessage.TypeSRV: - n := q.Questions[0].Name - if n.String() == "_hdr._tcp.golang.org." { - n = dnsmessage.MustNewName(".golang.org.") - } - r.Answers = append(r.Answers, - dnsmessage.Resource{ - Header: dnsmessage.ResourceHeader{ - Name: n, - Type: dnsmessage.TypeSRV, - Class: dnsmessage.ClassINET, - Length: 4, - }, - Body: &dnsmessage.SRVResource{ - Target: dnsmessage.MustNewName(".golang.org."), - }, - }, - ) - case dnsmessage.TypeMX: - r.Answers = append(r.Answers, - dnsmessage.Resource{ - Header: dnsmessage.ResourceHeader{ - Name: dnsmessage.MustNewName(".golang.org."), - Type: dnsmessage.TypeMX, - Class: dnsmessage.ClassINET, - Length: 4, - }, - Body: &dnsmessage.MXResource{ - MX: dnsmessage.MustNewName(".golang.org."), - }, - }, - ) - case dnsmessage.TypeNS: - r.Answers = append(r.Answers, - dnsmessage.Resource{ - Header: dnsmessage.ResourceHeader{ - Name: dnsmessage.MustNewName(".golang.org."), - Type: dnsmessage.TypeNS, - Class: dnsmessage.ClassINET, - Length: 4, - }, - Body: &dnsmessage.NSResource{ - NS: dnsmessage.MustNewName(".golang.org."), - }, - }, - ) - case dnsmessage.TypePTR: - r.Answers = append(r.Answers, - dnsmessage.Resource{ - Header: dnsmessage.ResourceHeader{ - Name: dnsmessage.MustNewName(".golang.org."), - Type: dnsmessage.TypePTR, - Class: dnsmessage.ClassINET, - Length: 4, - }, - Body: &dnsmessage.PTRResource{ - PTR: dnsmessage.MustNewName(".golang.org."), - }, - }, - ) - } - return r, nil - }, - } - r := Resolver{PreferGo: true, Dial: fake.DialContext} - - _, err := r.LookupCNAME(context.Background(), "golang.org") - if expected := "lookup golang.org: CNAME target is invalid"; err.Error() != expected { - t.Errorf("LookupCNAME returned unexpected error, got %q, want %q", err.Error(), expected) - } - _, _, err = r.LookupSRV(context.Background(), "target", "tcp", "golang.org") - if expected := "lookup golang.org: SRV target is invalid"; err.Error() != expected { - t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected) - } - _, _, err = r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org") - if expected := "lookup golang.org: SRV header name is invalid"; err.Error() != expected { - t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected) - } - _, err = r.LookupMX(context.Background(), "golang.org") - if expected := "lookup golang.org: MX target is invalid"; err.Error() != expected { - t.Errorf("LookupMX returned unexpected error, got %q, want %q", err.Error(), expected) - } - _, err = r.LookupNS(context.Background(), "golang.org") - if expected := "lookup golang.org: NS target is invalid"; err.Error() != expected { - t.Errorf("LookupNS returned unexpected error, got %q, want %q", err.Error(), expected) - } - _, err = r.LookupAddr(context.Background(), "1.2.3.4") - if expected := "lookup 1.2.3.4: PTR target is invalid"; err.Error() != expected { - t.Errorf("LookupAddr returned unexpected error, got %q, want %q", err.Error(), expected) - } -} diff --git a/src/net/lookup.go b/src/net/lookup.go index 39d33796d5b..03599503bd1 100644 --- a/src/net/lookup.go +++ b/src/net/lookup.go @@ -396,9 +396,6 @@ func (r *Resolver) LookupPort(ctx context.Context, network, service string) (por // contain DNS "CNAME" records, as long as host resolves to // address records. // -// The returned canonical name is validated to be a properly -// formatted presentation-format domain name. -// // LookupCNAME uses context.Background internally; to specify the context, use // Resolver.LookupCNAME. func LookupCNAME(host string) (cname string, err error) { @@ -415,18 +412,8 @@ func LookupCNAME(host string) (cname string, err error) { // LookupCNAME does not return an error if host does not // contain DNS "CNAME" records, as long as host resolves to // address records. -// -// The returned canonical name is validated to be a properly -// formatted presentation-format domain name. -func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error) { - cname, err := r.lookupCNAME(ctx, host) - if err != nil { - return "", err - } - if !isDomainName(cname) { - return "", &DNSError{Err: "CNAME target is invalid", Name: host} - } - return cname, nil +func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, err error) { + return r.lookupCNAME(ctx, host) } // LookupSRV tries to resolve an SRV query of the given service, @@ -438,9 +425,6 @@ func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error) // That is, it looks up _service._proto.name. To accommodate services // publishing SRV records under non-standard names, if both service // and proto are empty strings, LookupSRV looks up name directly. -// -// The returned service names are validated to be properly -// formatted presentation-format domain names. func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { return DefaultResolver.lookupSRV(context.Background(), service, proto, name) } @@ -454,33 +438,12 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err // That is, it looks up _service._proto.name. To accommodate services // publishing SRV records under non-standard names, if both service // and proto are empty strings, LookupSRV looks up name directly. -// -// The returned service names are validated to be properly -// formatted presentation-format domain names. -func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) { - cname, addrs, err := r.lookupSRV(ctx, service, proto, name) - if err != nil { - return "", nil, err - } - if cname != "" && !isDomainName(cname) { - return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name} - } - for _, addr := range addrs { - if addr == nil { - continue - } - if !isDomainName(addr.Target) { - return "", nil, &DNSError{Err: "SRV target is invalid", Name: name} - } - } - return cname, addrs, nil +func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) { + return r.lookupSRV(ctx, service, proto, name) } // LookupMX returns the DNS MX records for the given domain name sorted by preference. // -// The returned mail server names are validated to be properly -// formatted presentation-format domain names. -// // LookupMX uses context.Background internally; to specify the context, use // Resolver.LookupMX. func LookupMX(name string) ([]*MX, error) { @@ -488,30 +451,12 @@ func LookupMX(name string) ([]*MX, error) { } // LookupMX returns the DNS MX records for the given domain name sorted by preference. -// -// The returned mail server names are validated to be properly -// formatted presentation-format domain names. func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) { - records, err := r.lookupMX(ctx, name) - if err != nil { - return nil, err - } - for _, mx := range records { - if mx == nil { - continue - } - if !isDomainName(mx.Host) { - return nil, &DNSError{Err: "MX target is invalid", Name: name} - } - } - return records, nil + return r.lookupMX(ctx, name) } // LookupNS returns the DNS NS records for the given domain name. // -// The returned name server names are validated to be properly -// formatted presentation-format domain names. -// // LookupNS uses context.Background internally; to specify the context, use // Resolver.LookupNS. func LookupNS(name string) ([]*NS, error) { @@ -519,23 +464,8 @@ func LookupNS(name string) ([]*NS, error) { } // LookupNS returns the DNS NS records for the given domain name. -// -// The returned name server names are validated to be properly -// formatted presentation-format domain names. func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) { - records, err := r.lookupNS(ctx, name) - if err != nil { - return nil, err - } - for _, ns := range records { - if ns == nil { - continue - } - if !isDomainName(ns.Host) { - return nil, &DNSError{Err: "NS target is invalid", Name: name} - } - } - return records, nil + return r.lookupNS(ctx, name) } // LookupTXT returns the DNS TXT records for the given domain name. @@ -565,18 +495,6 @@ func LookupAddr(addr string) (names []string, err error) { // LookupAddr performs a reverse lookup for the given address, returning a list // of names mapping to that address. -// -// The returned names are validated to be properly -// formatted presentation-format domain names. -func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) { - names, err := r.lookupAddr(ctx, addr) - if err != nil { - return nil, err - } - for _, name := range names { - if !isDomainName(name) { - return nil, &DNSError{Err: "PTR target is invalid", Name: addr} - } - } - return names, nil +func (r *Resolver) LookupAddr(ctx context.Context, addr string) (names []string, err error) { + return r.lookupAddr(ctx, addr) } From 06df0ee7fa8b6d7d095de77274f53fb81a43d622 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 25 May 2021 18:05:02 -0400 Subject: [PATCH 185/940] [dev.typeparams] cmd/compile: add arg/result register load/spill code on ARM64 Add code that loads results into registers (used in defer return code path) and spills argument registers (used for partially lived in-register args). Move some code from the amd64 package to a common place. Change-Id: I8d59b68693048fdba86e10769c4ac58de5fcfb64 Reviewed-on: https://go-review.googlesource.com/c/go/+/322851 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: David Chase Reviewed-by: Than McIntosh --- src/cmd/compile/internal/amd64/galign.go | 2 +- src/cmd/compile/internal/amd64/ssa.go | 23 +++++++++-------------- src/cmd/compile/internal/arm64/galign.go | 2 ++ src/cmd/compile/internal/arm64/ssa.go | 20 ++++++++++++++++++++ src/cmd/compile/internal/ssagen/arch.go | 8 ++++---- src/cmd/compile/internal/ssagen/ssa.go | 8 ++++++-- 6 files changed, 42 insertions(+), 21 deletions(-) diff --git a/src/cmd/compile/internal/amd64/galign.go b/src/cmd/compile/internal/amd64/galign.go index 2785aa03368..3b13e123a74 100644 --- a/src/cmd/compile/internal/amd64/galign.go +++ b/src/cmd/compile/internal/amd64/galign.go @@ -23,6 +23,6 @@ func Init(arch *ssagen.ArchInfo) { arch.SSAMarkMoves = ssaMarkMoves arch.SSAGenValue = ssaGenValue arch.SSAGenBlock = ssaGenBlock - arch.LoadRegResults = loadRegResults + arch.LoadRegResult = loadRegResult arch.SpillArgReg = spillArgReg } diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go index 7e2dc41928f..c27a5fe5b5a 100644 --- a/src/cmd/compile/internal/amd64/ssa.go +++ b/src/cmd/compile/internal/amd64/ssa.go @@ -1354,20 +1354,15 @@ func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) { } } -func loadRegResults(s *ssagen.State, f *ssa.Func) { - for _, o := range f.OwnAux.ABIInfo().OutParams() { - n := o.Name.(*ir.Name) - rts, offs := o.RegisterTypesAndOffsets() - for i := range o.Registers { - p := s.Prog(loadByType(rts[i])) - p.From.Type = obj.TYPE_MEM - p.From.Name = obj.NAME_AUTO - p.From.Sym = n.Linksym() - p.From.Offset = n.FrameOffset() + offs[i] - p.To.Type = obj.TYPE_REG - p.To.Reg = ssa.ObjRegForAbiReg(o.Registers[i], f.Config) - } - } +func loadRegResult(s *ssagen.State, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog { + p := s.Prog(loadByType(t)) + p.From.Type = obj.TYPE_MEM + p.From.Name = obj.NAME_AUTO + p.From.Sym = n.Linksym() + p.From.Offset = n.FrameOffset() + off + p.To.Type = obj.TYPE_REG + p.To.Reg = reg + return p } func spillArgReg(pp *objw.Progs, p *obj.Prog, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog { diff --git a/src/cmd/compile/internal/arm64/galign.go b/src/cmd/compile/internal/arm64/galign.go index d3db37e16f4..2a61b9dd997 100644 --- a/src/cmd/compile/internal/arm64/galign.go +++ b/src/cmd/compile/internal/arm64/galign.go @@ -23,4 +23,6 @@ func Init(arch *ssagen.ArchInfo) { arch.SSAMarkMoves = func(s *ssagen.State, b *ssa.Block) {} arch.SSAGenValue = ssaGenValue arch.SSAGenBlock = ssaGenBlock + arch.LoadRegResult = loadRegResult + arch.SpillArgReg = spillArgReg } diff --git a/src/cmd/compile/internal/arm64/ssa.go b/src/cmd/compile/internal/arm64/ssa.go index d82788218d9..74308a18f60 100644 --- a/src/cmd/compile/internal/arm64/ssa.go +++ b/src/cmd/compile/internal/arm64/ssa.go @@ -10,6 +10,7 @@ import ( "cmd/compile/internal/base" "cmd/compile/internal/ir" "cmd/compile/internal/logopt" + "cmd/compile/internal/objw" "cmd/compile/internal/ssa" "cmd/compile/internal/ssagen" "cmd/compile/internal/types" @@ -1278,3 +1279,22 @@ func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) { b.Fatalf("branch not implemented: %s", b.LongString()) } } + +func loadRegResult(s *ssagen.State, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog { + p := s.Prog(loadByType(t)) + p.From.Type = obj.TYPE_MEM + p.From.Name = obj.NAME_AUTO + p.From.Sym = n.Linksym() + p.From.Offset = n.FrameOffset() + off + p.To.Type = obj.TYPE_REG + p.To.Reg = reg + return p +} + +func spillArgReg(pp *objw.Progs, p *obj.Prog, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog { + p = pp.Append(p, storeByType(t), obj.TYPE_REG, reg, 0, obj.TYPE_MEM, 0, n.FrameOffset()+off) + p.To.Name = obj.NAME_PARAM + p.To.Sym = n.Linksym() + p.Pos = p.Pos.WithNotStmt() + return p +} diff --git a/src/cmd/compile/internal/ssagen/arch.go b/src/cmd/compile/internal/ssagen/arch.go index 7215f42c059..957fb3e84a9 100644 --- a/src/cmd/compile/internal/ssagen/arch.go +++ b/src/cmd/compile/internal/ssagen/arch.go @@ -42,10 +42,10 @@ type ArchInfo struct { // for all values in the block before SSAGenBlock. SSAGenBlock func(s *State, b, next *ssa.Block) - // LoadRegResults emits instructions that loads register-assigned results - // into registers. They are already in memory (PPARAMOUT nodes). - // Used in open-coded defer return path. - LoadRegResults func(s *State, f *ssa.Func) + // LoadRegResult emits instructions that loads register-assigned result + // at n+off (n is PPARAMOUT) to register reg. The result is already in + // memory. Used in open-coded defer return path. + LoadRegResult func(s *State, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog // SpillArgReg emits instructions that spill reg to n+off. SpillArgReg func(pp *objw.Progs, p *obj.Prog, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 91b0c79cd3e..f59220ab8e4 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -6930,8 +6930,12 @@ func genssa(f *ssa.Func, pp *objw.Progs) { // recovers a panic, it will return to caller with right results. // The results are already in memory, because they are not SSA'd // when the function has defers (see canSSAName). - if f.OwnAux.ABIInfo().OutRegistersUsed() != 0 { - Arch.LoadRegResults(&s, f) + for _, o := range f.OwnAux.ABIInfo().OutParams() { + n := o.Name.(*ir.Name) + rts, offs := o.RegisterTypesAndOffsets() + for i := range o.Registers { + Arch.LoadRegResult(&s, f, rts[i], ssa.ObjRegForAbiReg(o.Registers[i], f.Config), n, offs[i]) + } } pp.Prog(obj.ARET) From 963f33b03b88e2c010d6a9876c3f0cc8d1f36f2d Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 25 May 2021 19:19:08 -0400 Subject: [PATCH 186/940] [dev.typeparams] cmd/compile: enable register args on ARM64 Now it will be used for functions marked go:registerparams. test/abi tests are passing with it. Change-Id: I5af37ae6b79a1064832a42c7ef5f2cc0b5b6a342 Reviewed-on: https://go-review.googlesource.com/c/go/+/322854 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: David Chase Reviewed-by: Than McIntosh --- src/cmd/compile/internal/ssa/config.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index 07d8b6e532b..7d680304c9c 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -228,10 +228,8 @@ func NewConfig(arch string, types Types, ctxt *obj.Link, optimize bool) *Config c.registers = registersARM64[:] c.gpRegMask = gpRegMaskARM64 c.fpRegMask = fpRegMaskARM64 - // XXX commented out for now. Uncomment it will enable register args for - // go:registerparams functions, which isn't fully working, so tests fail. - //c.intParamRegs = paramIntRegARM64 - //c.floatParamRegs = paramFloatRegARM64 + c.intParamRegs = paramIntRegARM64 + c.floatParamRegs = paramFloatRegARM64 c.FPReg = framepointerRegARM64 c.LinkReg = linkRegARM64 c.hasGReg = true From 6b8c94b6c524710bc3290546176a0da2f7c8c9db Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 27 May 2021 12:35:01 -0400 Subject: [PATCH 187/940] go/types: guard against check==nil in newNamed When importing generic named types, it is possible for Checker.newNamed to be called during type instantiation when the Checker is nil. In this case we should be able to safely skip this delayed expansion. Updates #45580 Change-Id: I75422100464d57eba24642c93e06e8b47d904fc3 Reviewed-on: https://go-review.googlesource.com/c/go/+/322974 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/type.go | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/go/types/type.go b/src/go/types/type.go index 3fdb2365a03..2660ce4408c 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -661,11 +661,7 @@ func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named { if _, ok := underlying.(*Named); ok { panic("types.NewNamed: underlying type must not be *Named") } - typ := &Named{obj: obj, orig: underlying, underlying: underlying, methods: methods} - if obj.typ == nil { - obj.typ = typ - } - return typ + return (*Checker)(nil).newNamed(obj, underlying, methods) } func (check *Checker) newNamed(obj *TypeName, underlying Type, methods []*Func) *Named { @@ -681,13 +677,15 @@ func (check *Checker) newNamed(obj *TypeName, underlying Type, methods []*Func) // // TODO(rFindley): clean this up so that under is the only function mutating // named types. - check.later(func() { - switch typ.under().(type) { - case *Named, *instance: - panic("internal error: unexpanded underlying type") - } - typ.check = nil - }) + if check != nil { + check.later(func() { + switch typ.under().(type) { + case *Named, *instance: + panic("internal error: unexpanded underlying type") + } + typ.check = nil + }) + } return typ } From 8c99e5db431c28ef563fc4980b05b26f82172864 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 26 May 2021 21:42:09 -0700 Subject: [PATCH 188/940] [dev.typeparams] cmd/compile/internal/types2: ensure that Named.check is nilled out once it is expanded This is a port of - https://golang.org/cl/318849 - https://golang.org/cl/322974 For #45580. Change-Id: Ie0700ed6c8d472305d5ba7ff97da1ae063152aa3 Reviewed-on: https://go-review.googlesource.com/c/go/+/323030 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/decl.go | 51 ++++++++++++++++----- src/cmd/compile/internal/types2/sanitize.go | 3 ++ src/cmd/compile/internal/types2/type.go | 19 +++++++- 3 files changed, 60 insertions(+), 13 deletions(-) diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go index 1333e4c0eca..aa70f3880b8 100644 --- a/src/cmd/compile/internal/types2/decl.go +++ b/src/cmd/compile/internal/types2/decl.go @@ -523,15 +523,37 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init syntax.Expr) { // n0.check != nil, the cycle is reported. func (n0 *Named) under() Type { u := n0.underlying - if u == nil { - return Typ[Invalid] + + if u == Typ[Invalid] { + return u } // If the underlying type of a defined type is not a defined - // type, then that is the desired underlying type. + // (incl. instance) type, then that is the desired underlying + // type. + switch u.(type) { + case nil: + return Typ[Invalid] + default: + // common case + return u + case *Named, *instance: + // handled below + } + + if n0.check == nil { + panic("internal error: Named.check == nil but type is incomplete") + } + + // Invariant: after this point n0 as well as any named types in its + // underlying chain should be set up when this function exits. + check := n0.check + + // If we can't expand u at this point, it is invalid. n := asNamed(u) if n == nil { - return u // common case + n0.underlying = Typ[Invalid] + return n0.underlying } // Otherwise, follow the forward chain. @@ -543,7 +565,16 @@ func (n0 *Named) under() Type { u = Typ[Invalid] break } - n1 := asNamed(u) + var n1 *Named + switch u1 := u.(type) { + case *Named: + n1 = u1 + case *instance: + n1, _ = u1.expand().(*Named) + if n1 == nil { + u = Typ[Invalid] + } + } if n1 == nil { break // end of chain } @@ -554,11 +585,7 @@ func (n0 *Named) under() Type { if i, ok := seen[n]; ok { // cycle - // TODO(gri) revert this to a method on Checker. Having a possibly - // nil Checker on Named and TypeParam is too subtle. - if n0.check != nil { - n0.check.cycleError(path[i:]) - } + check.cycleError(path[i:]) u = Typ[Invalid] break } @@ -568,8 +595,8 @@ func (n0 *Named) under() Type { // We should never have to update the underlying type of an imported type; // those underlying types should have been resolved during the import. // Also, doing so would lead to a race condition (was issue #31749). - // Do this check always, not just in debug more (it's cheap). - if n0.check != nil && n.obj.pkg != n0.check.pkg { + // Do this check always, not just in debug mode (it's cheap). + if n.obj.pkg != check.pkg { panic("internal error: imported type with unresolved underlying type") } n.underlying = u diff --git a/src/cmd/compile/internal/types2/sanitize.go b/src/cmd/compile/internal/types2/sanitize.go index 9fad52e2242..c30febfda89 100644 --- a/src/cmd/compile/internal/types2/sanitize.go +++ b/src/cmd/compile/internal/types2/sanitize.go @@ -134,6 +134,9 @@ func (s sanitizer) typ(typ Type) Type { } case *Named: + if debug && t.check != nil { + panic("internal error: Named.check != nil") + } if orig := s.typ(t.fromRHS); orig != t.fromRHS { t.fromRHS = orig } diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index 2a93ca03885..3b2a5960e81 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -544,7 +544,7 @@ func (c *Chan) Elem() Type { return c.elem } // A Named represents a named (defined) type. type Named struct { - check *Checker // for Named.under implementation + check *Checker // for Named.under implementation; nilled once under has been called info typeInfo // for cycle detection obj *TypeName // corresponding declared object orig *Named // original, uninstantiated type @@ -574,6 +574,23 @@ func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tpar if obj.typ == nil { obj.typ = typ } + // Ensure that typ is always expanded, at which point the check field can be + // nilled out. + // + // Note that currently we cannot nil out check inside typ.under(), because + // it's possible that typ is expanded multiple times. + // + // TODO(gri): clean this up so that under is the only function mutating + // named types. + if check != nil { + check.later(func() { + switch typ.under().(type) { + case *Named, *instance: + panic("internal error: unexpanded underlying type") + } + typ.check = nil + }) + } return typ } From db66e9e15d16cfdb555140b26a5f009fd0d23d0e Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 27 May 2021 10:11:42 -0400 Subject: [PATCH 189/940] cmd/link: accept Windows line-ending in TestTrampolineCgo Apparently C printf emits "\r\n" on Windows. Accept that. Change-Id: If87ba41435e3147d3892cfc3fe3a105b066ff0aa Reviewed-on: https://go-review.googlesource.com/c/go/+/322973 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- src/cmd/link/link_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go index 8805ff1f02c..4d6bc76aca8 100644 --- a/src/cmd/link/link_test.go +++ b/src/cmd/link/link_test.go @@ -698,7 +698,7 @@ func TestTrampolineCgo(t *testing.T) { if err != nil { t.Errorf("executable failed to run: %v\n%s", err, out) } - if string(out) != "hello\n" { + if string(out) != "hello\n" && string(out) != "hello\r\n" { t.Errorf("unexpected output:\n%s", out) } @@ -717,7 +717,7 @@ func TestTrampolineCgo(t *testing.T) { if err != nil { t.Errorf("executable failed to run: %v\n%s", err, out) } - if string(out) != "hello\n" { + if string(out) != "hello\n" && string(out) != "hello\r\n" { t.Errorf("unexpected output:\n%s", out) } } From 56af34f875f55485b4ebc521fe0c695dafb9bc23 Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Tue, 25 May 2021 10:13:07 -0400 Subject: [PATCH 190/940] cmd/compile: place reg spills after OpArg{Int,Float}Reg ops Tweak the register allocator to maintain the invariant that OpArg{Int,Float}Reg values are placed together at the start of the entry block, before any other non-pseudo-op values. Without this change, when the register allocator adds spills we can wind up with an interleaving of OpArg*Reg and stores, which complicates debug location analysis. Updates #40724. Change-Id: Icf30dd814a9e25263ecbea2e48feb840a6e7f2bd Reviewed-on: https://go-review.googlesource.com/c/go/+/322630 Trust: Than McIntosh Run-TryBot: Than McIntosh TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/cmd/compile/internal/ssa/regalloc.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index c81d5574fe5..3b90b8769c2 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -1882,6 +1882,10 @@ func (s *regAllocState) placeSpills() { phiRegs[b.ID] = m } + mustBeFirst := func(op Op) bool { + return op.isLoweredGetClosurePtr() || op == OpPhi || op == OpArgIntReg || op == OpArgFloatReg + } + // Start maps block IDs to the list of spills // that go at the start of the block (but after any phis). start := map[ID][]*Value{} @@ -1971,7 +1975,7 @@ func (s *regAllocState) placeSpills() { // Put the spill in the best block we found. spill.Block = best spill.AddArg(bestArg) - if best == v.Block && v.Op != OpPhi { + if best == v.Block && !mustBeFirst(v.Op) { // Place immediately after v. after[v.ID] = append(after[v.ID], spill) } else { @@ -1983,15 +1987,15 @@ func (s *regAllocState) placeSpills() { // Insert spill instructions into the block schedules. var oldSched []*Value for _, b := range s.visitOrder { - nphi := 0 + nfirst := 0 for _, v := range b.Values { - if v.Op != OpPhi { + if !mustBeFirst(v.Op) { break } - nphi++ + nfirst++ } - oldSched = append(oldSched[:0], b.Values[nphi:]...) - b.Values = b.Values[:nphi] + oldSched = append(oldSched[:0], b.Values[nfirst:]...) + b.Values = b.Values[:nfirst] b.Values = append(b.Values, start[b.ID]...) for _, v := range oldSched { b.Values = append(b.Values, v) From 8bf5bf51738a198902e03bbec7e6ff220f4cb002 Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Mon, 10 May 2021 07:31:57 -0400 Subject: [PATCH 191/940] cmd/compile: improve debug locations for partially live in-params During DWARF debug location generation, as a preamble to the main data flow analysis, examine the function entry block to look for in-params arriving in registers that are partially or completely dead, and insert new OpArg{Int,Float}Reg values for the dead or partially-dead pieces. In addition, add entries to the f.NamedValues table for incoming live register-resident params that don't already have entries. This helps create better/saner DWARF location expressions for params. Example: func foo(s string, used int, notused int) int { return len(s) + used } When optimization is complete for this function, the parameter "notused" is completely dead, meaning that there is no entry for it in the f.NamedValues table (which then means we don't emit a DWARF variable location expression for it in the function enty block). In addition, since only the length field of "s" is used, there is no DWARF location expression for the other component of "s", leading to degraded DWARF. There are still problems/issues with DWARF location generation, but this does improve things with respect to being able to print the values of incoming parameters when stopped in the debugger at the entry point of a function (when optimization is enabled). Updates #40724. Change-Id: I5bb5253648942f9fd33b081fe1a5a36208e75785 Reviewed-on: https://go-review.googlesource.com/c/go/+/322631 Trust: Than McIntosh Run-TryBot: Than McIntosh TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/cmd/compile/internal/ssa/debug.go | 217 ++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) diff --git a/src/cmd/compile/internal/ssa/debug.go b/src/cmd/compile/internal/ssa/debug.go index a2c2a2d98e8..eaa94975ec2 100644 --- a/src/cmd/compile/internal/ssa/debug.go +++ b/src/cmd/compile/internal/ssa/debug.go @@ -7,10 +7,13 @@ package ssa import ( "cmd/compile/internal/abi" "cmd/compile/internal/ir" + "cmd/compile/internal/types" "cmd/internal/dwarf" "cmd/internal/obj" + "cmd/internal/src" "encoding/hex" "fmt" + "internal/buildcfg" "math/bits" "sort" "strings" @@ -335,6 +338,216 @@ func (s *debugState) stateString(state stateAtPC) string { return strings.Join(strs, "") } +// slotCanonicalizer is a table used to lookup and canonicalize +// LocalSlot's in a type insensitive way (e.g. taking into account the +// base name, offset, and width of the slot, but ignoring the slot +// type). +type slotCanonicalizer struct { + slmap map[slotKey]SlKeyIdx + slkeys []LocalSlot +} + +func newSlotCanonicalizer() *slotCanonicalizer { + return &slotCanonicalizer{ + slmap: make(map[slotKey]SlKeyIdx), + slkeys: []LocalSlot{LocalSlot{N: nil}}, + } +} + +type SlKeyIdx uint32 + +const noSlot = SlKeyIdx(0) + +// slotKey is a type-insensitive encapsulation of a LocalSlot; it +// is used to key a map within slotCanonicalizer. +type slotKey struct { + name *ir.Name + offset int64 + width int64 + splitOf SlKeyIdx // idx in slkeys slice in slotCanonicalizer + splitOffset int64 +} + +// lookup looks up a LocalSlot in the slot canonicalizer "sc", returning +// a canonical index for the slot, and adding it to the table if need +// be. Return value is the canonical slot index, and a boolean indicating +// whether the slot was found in the table already (TRUE => found). +func (sc *slotCanonicalizer) lookup(ls LocalSlot) (SlKeyIdx, bool) { + split := noSlot + if ls.SplitOf != nil { + split, _ = sc.lookup(*ls.SplitOf) + } + k := slotKey{ + name: ls.N, offset: ls.Off, width: ls.Type.Width, + splitOf: split, splitOffset: ls.SplitOffset, + } + if idx, ok := sc.slmap[k]; ok { + return idx, true + } + rv := SlKeyIdx(len(sc.slkeys)) + sc.slkeys = append(sc.slkeys, ls) + sc.slmap[k] = rv + return rv, false +} + +func (sc *slotCanonicalizer) canonSlot(idx SlKeyIdx) LocalSlot { + return sc.slkeys[idx] +} + +// PopulateABIInRegArgOps examines the entry block of the function +// and looks for incoming parameters that have missing or partial +// OpArg{Int,Float}Reg values, inserting additional values in +// cases where they are missing. Example: +// +// func foo(s string, used int, notused int) int { +// return len(s) + used +// } +// +// In the function above, the incoming parameter "used" is fully live, +// "notused" is not live, and "s" is partially live (only the length +// field of the string is used). At the point where debug value +// analysis runs, we might expect to see an entry block with: +// +// b1: +// v4 = ArgIntReg {s+8} [0] : BX +// v5 = ArgIntReg {used} [0] : CX +// +// While this is an accurate picture of the live incoming params, +// we also want to have debug locations for non-live params (or +// their non-live pieces), e.g. something like +// +// b1: +// v9 = ArgIntReg <*uint8> {s+0} [0] : AX +// v4 = ArgIntReg {s+8} [0] : BX +// v5 = ArgIntReg {used} [0] : CX +// v10 = ArgIntReg {unused} [0] : DI +// +// This function examines the live OpArg{Int,Float}Reg values and +// synthesizes new (dead) values for the non-live params or the +// non-live pieces of partially live params. +// +func PopulateABIInRegArgOps(f *Func) { + pri := f.ABISelf.ABIAnalyzeFuncType(f.Type.FuncType()) + + // When manufacturing new slots that correspond to splits of + // composite parameters, we want to avoid creating a new sub-slot + // that differs from some existing sub-slot only by type, since + // the debug location analysis will treat that slot as a separate + // entity. To achieve this, create a lookup table of existing + // slots that is type-insenstitive. + sc := newSlotCanonicalizer() + for _, sl := range f.Names { + sc.lookup(*sl) + } + + // Add slot -> value entry to f.NamedValues if not already present. + addToNV := func(v *Value, sl LocalSlot) { + values, ok := f.NamedValues[sl] + if !ok { + // Haven't seen this slot yet. + sla := f.localSlotAddr(sl) + f.Names = append(f.Names, sla) + } else { + for _, ev := range values { + if v == ev { + return + } + } + } + values = append(values, v) + f.NamedValues[sl] = values + } + + newValues := []*Value{} + + abiRegIndexToRegister := func(reg abi.RegIndex) int8 { + i := f.ABISelf.FloatIndexFor(reg) + if i >= 0 { // float PR + return f.Config.floatParamRegs[i] + } else { + return f.Config.intParamRegs[reg] + } + } + + // Helper to construct a new OpArg{Float,Int}Reg op value. + var pos src.XPos + if len(f.Entry.Values) != 0 { + pos = f.Entry.Values[0].Pos + } + synthesizeOpIntFloatArg := func(n *ir.Name, t *types.Type, reg abi.RegIndex, sl LocalSlot) *Value { + aux := &AuxNameOffset{n, sl.Off} + op, auxInt := ArgOpAndRegisterFor(reg, f.ABISelf) + v := f.newValueNoBlock(op, t, pos) + v.AuxInt = auxInt + v.Aux = aux + v.Args = nil + v.Block = f.Entry + newValues = append(newValues, v) + addToNV(v, sl) + f.setHome(v, &f.Config.registers[abiRegIndexToRegister(reg)]) + return v + } + + // Make a pass through the entry block looking for + // OpArg{Int,Float}Reg ops. Record the slots they use in a table + // ("sc"). We use a type-insensitive lookup for the slot table, + // since the type we get from the ABI analyzer won't always match + // what the compiler uses when creating OpArg{Int,Float}Reg ops. + for _, v := range f.Entry.Values { + if v.Op == OpArgIntReg || v.Op == OpArgFloatReg { + aux := v.Aux.(*AuxNameOffset) + sl := LocalSlot{N: aux.Name, Type: v.Type, Off: aux.Offset} + // install slot in lookup table + idx, _ := sc.lookup(sl) + // add to f.NamedValues if not already present + addToNV(v, sc.canonSlot(idx)) + } else if v.Op.IsCall() { + // if we hit a call, we've gone too far. + break + } + } + + // Now make a pass through the ABI in-params, looking for params + // or pieces of params that we didn't encounter in the loop above. + for _, inp := range pri.InParams() { + if !isNamedRegParam(inp) { + continue + } + n := inp.Name.(*ir.Name) + + // Param is spread across one or more registers. Walk through + // each piece to see whether we've seen an arg reg op for it. + types, offsets := inp.RegisterTypesAndOffsets() + for k, t := range types { + // Note: this recipe for creating a LocalSlot is designed + // to be compatible with the one used in expand_calls.go + // as opposed to decompose.go. The expand calls code just + // takes the base name and creates an offset into it, + // without using the SplitOf/SplitOffset fields. The code + // in decompose.go does the opposite -- it creates a + // LocalSlot object with "Off" set to zero, but with + // SplitOf pointing to a parent slot, and SplitOffset + // holding the offset into the parent object. + pieceSlot := LocalSlot{N: n, Type: t, Off: offsets[k]} + + // Look up this piece to see if we've seen a reg op + // for it. If not, create one. + _, found := sc.lookup(pieceSlot) + if !found { + // This slot doesn't appear in the map, meaning it + // corresponds to an in-param that is not live, or + // a portion of an in-param that is not live/used. + // Add a new dummy OpArg{Int,Float}Reg for it. + synthesizeOpIntFloatArg(n, t, inp.Registers[k], + pieceSlot) + } + } + } + + // Insert the new values into the head of the block. + f.Entry.Values = append(newValues, f.Entry.Values...) +} + // BuildFuncDebug returns debug information for f. // f must be fully processed, so that each Value is where it will be when // machine code is emitted. @@ -349,6 +562,10 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu state.stackOffset = stackOffset state.ctxt = ctxt + if buildcfg.Experiment.RegabiArgs { + PopulateABIInRegArgOps(f) + } + if state.loggingEnabled { state.logf("Generating location lists for function %q\n", f.Name) } From c2c1b53b39fd54b915b2a4bbae36d1c9793fac8a Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Thu, 27 May 2021 11:18:13 -0700 Subject: [PATCH 192/940] [dev.typeparams] cmd/compile: use old export format if not compiling with generics Write out export data with the old export format (iexportVersionPosCol) if not compiling with generics (-G=0, the default value). This helps ensure we don't break tests involving x/tools/go/gcexportdata (since we can't modify that tool yet to use the new format). Change-Id: I5f9bce44ed1e0696fc65fead6bab9e30de88461d Reviewed-on: https://go-review.googlesource.com/c/go/+/323189 Reviewed-by: Robert Griesemer Reviewed-by: Matthew Dempsky Trust: Robert Griesemer --- src/cmd/compile/internal/typecheck/iexport.go | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index ea8e751852c..9c242131769 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -306,7 +306,12 @@ func WriteExports(out *bufio.Writer) { // Assemble header. var hdr intWriter hdr.WriteByte('i') - hdr.uint64(iexportVersionCurrent) + if base.Flag.G > 0 { + hdr.uint64(iexportVersionCurrent) + } else { + // Use old export format if doing -G=0 (no generics) + hdr.uint64(iexportVersionPosCol) + } hdr.uint64(uint64(p.strings.Len())) hdr.uint64(dataLen) @@ -478,7 +483,9 @@ func (p *iexporter) doDecl(n *ir.Name) { // referenced via their type offset (via typOff) in all // other places in the signature and function that they // are used. - w.tparamList(n.Type().TParams().FieldSlice()) + if base.Flag.G > 0 { + w.tparamList(n.Type().TParams().FieldSlice()) + } w.signature(n.Type()) w.funcExt(n) @@ -511,8 +518,10 @@ func (p *iexporter) doDecl(n *ir.Name) { w.tag('T') w.pos(n.Pos()) - // Export any new typeparams needed for this type - w.typeList(n.Type().RParams()) + if base.Flag.G > 0 { + // Export any new typeparams needed for this type + w.typeList(n.Type().RParams()) + } underlying := n.Type().Underlying() if underlying == types.ErrorType.Underlying() { // For "type T error", use error as the @@ -826,6 +835,7 @@ func (w *exportWriter) startType(k itag) { func (w *exportWriter) doTyp(t *types.Type) { if t.Kind() == types.TTYPEPARAM { + assert(base.Flag.G > 0) // A typeparam has a name, but doesn't have an underlying type. // Just write out the details of the type param here. All other // uses of this typeparam type will be written out as its unique @@ -846,6 +856,7 @@ func (w *exportWriter) doTyp(t *types.Type) { s := t.Sym() if s != nil && t.OrigSym != nil { + assert(base.Flag.G > 0) // This is an instantiated type - could be a re-instantiation like // Value[T2] or a full instantiation like Value[int]. if strings.Index(s.Name, "[") < 0 { @@ -945,6 +956,7 @@ func (w *exportWriter) doTyp(t *types.Type) { } case types.TUNION: + assert(base.Flag.G > 0) // TODO(danscales): possibly put out the tilde bools in more // compact form. w.startType(unionType) From cdcd02842da7c004efd023881e3719105209c908 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Thu, 27 May 2021 10:40:06 -0700 Subject: [PATCH 193/940] net: verify results from Lookup* are valid domain names For the methods LookupCNAME, LookupSRV, LookupMX, LookupNS, and LookupAddr check that the returned domain names are in fact valid DNS names using the existing isDomainName function. Thanks to Philipp Jeitner and Haya Shulman from Fraunhofer SIT for reporting this issue. Fixes #46241 Fixes CVE-2021-33195 Change-Id: I47a4f58c031cb752f732e88bbdae7f819f0af4f3 Reviewed-on: https://go-review.googlesource.com/c/go/+/323131 Trust: Roland Shoemaker Run-TryBot: Roland Shoemaker TryBot-Result: Go Bot Reviewed-by: Filippo Valsorda Reviewed-by: Katie Hockman --- src/net/dnsclient_unix_test.go | 157 +++++++++++++++++++++++++++++++++ src/net/lookup.go | 111 ++++++++++++++++++++--- 2 files changed, 255 insertions(+), 13 deletions(-) diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go index ec690a1c0cf..a718e75a726 100644 --- a/src/net/dnsclient_unix_test.go +++ b/src/net/dnsclient_unix_test.go @@ -1799,3 +1799,160 @@ func TestPTRandNonPTR(t *testing.T) { t.Errorf("names = %q; want %q", names, want) } } + +func TestCVE202133195(t *testing.T) { + fake := fakeDNSServer{ + rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) { + r := dnsmessage.Message{ + Header: dnsmessage.Header{ + ID: q.Header.ID, + Response: true, + RCode: dnsmessage.RCodeSuccess, + RecursionAvailable: true, + }, + Questions: q.Questions, + } + switch q.Questions[0].Type { + case dnsmessage.TypeCNAME: + r.Answers = []dnsmessage.Resource{} + case dnsmessage.TypeA: // CNAME lookup uses a A/AAAA as a proxy + r.Answers = append(r.Answers, + dnsmessage.Resource{ + Header: dnsmessage.ResourceHeader{ + Name: dnsmessage.MustNewName(".golang.org."), + Type: dnsmessage.TypeA, + Class: dnsmessage.ClassINET, + Length: 4, + }, + Body: &dnsmessage.AResource{ + A: TestAddr, + }, + }, + ) + case dnsmessage.TypeSRV: + n := q.Questions[0].Name + if n.String() == "_hdr._tcp.golang.org." { + n = dnsmessage.MustNewName(".golang.org.") + } + r.Answers = append(r.Answers, + dnsmessage.Resource{ + Header: dnsmessage.ResourceHeader{ + Name: n, + Type: dnsmessage.TypeSRV, + Class: dnsmessage.ClassINET, + Length: 4, + }, + Body: &dnsmessage.SRVResource{ + Target: dnsmessage.MustNewName(".golang.org."), + }, + }, + ) + case dnsmessage.TypeMX: + r.Answers = append(r.Answers, + dnsmessage.Resource{ + Header: dnsmessage.ResourceHeader{ + Name: dnsmessage.MustNewName(".golang.org."), + Type: dnsmessage.TypeMX, + Class: dnsmessage.ClassINET, + Length: 4, + }, + Body: &dnsmessage.MXResource{ + MX: dnsmessage.MustNewName(".golang.org."), + }, + }, + ) + case dnsmessage.TypeNS: + r.Answers = append(r.Answers, + dnsmessage.Resource{ + Header: dnsmessage.ResourceHeader{ + Name: dnsmessage.MustNewName(".golang.org."), + Type: dnsmessage.TypeNS, + Class: dnsmessage.ClassINET, + Length: 4, + }, + Body: &dnsmessage.NSResource{ + NS: dnsmessage.MustNewName(".golang.org."), + }, + }, + ) + case dnsmessage.TypePTR: + r.Answers = append(r.Answers, + dnsmessage.Resource{ + Header: dnsmessage.ResourceHeader{ + Name: dnsmessage.MustNewName(".golang.org."), + Type: dnsmessage.TypePTR, + Class: dnsmessage.ClassINET, + Length: 4, + }, + Body: &dnsmessage.PTRResource{ + PTR: dnsmessage.MustNewName(".golang.org."), + }, + }, + ) + } + return r, nil + }, + } + + r := Resolver{PreferGo: true, Dial: fake.DialContext} + // Change the default resolver to match our manipulated resolver + originalDefault := DefaultResolver + DefaultResolver = &r + defer func() { + DefaultResolver = originalDefault + }() + + _, err := r.LookupCNAME(context.Background(), "golang.org") + if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected { + t.Errorf("Resolver.LookupCNAME returned unexpected error, got %q, want %q", err.Error(), expected) + } + _, err = LookupCNAME("golang.org") + if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected { + t.Errorf("LookupCNAME returned unexpected error, got %q, want %q", err.Error(), expected) + } + + _, _, err = r.LookupSRV(context.Background(), "target", "tcp", "golang.org") + if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected { + t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected) + } + _, _, err = LookupSRV("target", "tcp", "golang.org") + if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected { + t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected) + } + + _, _, err = r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org") + if expected := "lookup golang.org: SRV header name is invalid"; err == nil || err.Error() != expected { + t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected) + } + _, _, err = LookupSRV("hdr", "tcp", "golang.org") + if expected := "lookup golang.org: SRV header name is invalid"; err == nil || err.Error() != expected { + t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected) + } + + _, err = r.LookupMX(context.Background(), "golang.org") + if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected { + t.Errorf("Resolver.LookupMX returned unexpected error, got %q, want %q", err.Error(), expected) + } + _, err = LookupMX("golang.org") + if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected { + t.Errorf("LookupMX returned unexpected error, got %q, want %q", err.Error(), expected) + } + + _, err = r.LookupNS(context.Background(), "golang.org") + if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected { + t.Errorf("Resolver.LookupNS returned unexpected error, got %q, want %q", err.Error(), expected) + } + _, err = LookupNS("golang.org") + if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected { + t.Errorf("LookupNS returned unexpected error, got %q, want %q", err.Error(), expected) + } + + _, err = r.LookupAddr(context.Background(), "1.2.3.4") + if expected := "lookup 1.2.3.4: PTR target is invalid"; err == nil || err.Error() != expected { + t.Errorf("Resolver.LookupAddr returned unexpected error, got %q, want %q", err.Error(), expected) + } + _, err = LookupAddr("1.2.3.4") + if expected := "lookup 1.2.3.4: PTR target is invalid"; err == nil || err.Error() != expected { + t.Errorf("LookupAddr returned unexpected error, got %q, want %q", err.Error(), expected) + } +} diff --git a/src/net/lookup.go b/src/net/lookup.go index 03599503bd1..02a4cdcd1ee 100644 --- a/src/net/lookup.go +++ b/src/net/lookup.go @@ -396,10 +396,13 @@ func (r *Resolver) LookupPort(ctx context.Context, network, service string) (por // contain DNS "CNAME" records, as long as host resolves to // address records. // +// The returned canonical name is validated to be a properly +// formatted presentation-format domain name. +// // LookupCNAME uses context.Background internally; to specify the context, use // Resolver.LookupCNAME. func LookupCNAME(host string) (cname string, err error) { - return DefaultResolver.lookupCNAME(context.Background(), host) + return DefaultResolver.LookupCNAME(context.Background(), host) } // LookupCNAME returns the canonical name for the given host. @@ -412,8 +415,18 @@ func LookupCNAME(host string) (cname string, err error) { // LookupCNAME does not return an error if host does not // contain DNS "CNAME" records, as long as host resolves to // address records. -func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, err error) { - return r.lookupCNAME(ctx, host) +// +// The returned canonical name is validated to be a properly +// formatted presentation-format domain name. +func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error) { + cname, err := r.lookupCNAME(ctx, host) + if err != nil { + return "", err + } + if !isDomainName(cname) { + return "", &DNSError{Err: "CNAME target is invalid", Name: host} + } + return cname, nil } // LookupSRV tries to resolve an SRV query of the given service, @@ -425,8 +438,11 @@ func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, // That is, it looks up _service._proto.name. To accommodate services // publishing SRV records under non-standard names, if both service // and proto are empty strings, LookupSRV looks up name directly. +// +// The returned service names are validated to be properly +// formatted presentation-format domain names. func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { - return DefaultResolver.lookupSRV(context.Background(), service, proto, name) + return DefaultResolver.LookupSRV(context.Background(), service, proto, name) } // LookupSRV tries to resolve an SRV query of the given service, @@ -438,34 +454,88 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err // That is, it looks up _service._proto.name. To accommodate services // publishing SRV records under non-standard names, if both service // and proto are empty strings, LookupSRV looks up name directly. -func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) { - return r.lookupSRV(ctx, service, proto, name) +// +// The returned service names are validated to be properly +// formatted presentation-format domain names. +func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) { + cname, addrs, err := r.lookupSRV(ctx, service, proto, name) + if err != nil { + return "", nil, err + } + if cname != "" && !isDomainName(cname) { + return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name} + } + for _, addr := range addrs { + if addr == nil { + continue + } + if !isDomainName(addr.Target) { + return "", nil, &DNSError{Err: "SRV target is invalid", Name: name} + } + } + return cname, addrs, nil } // LookupMX returns the DNS MX records for the given domain name sorted by preference. // +// The returned mail server names are validated to be properly +// formatted presentation-format domain names. +// // LookupMX uses context.Background internally; to specify the context, use // Resolver.LookupMX. func LookupMX(name string) ([]*MX, error) { - return DefaultResolver.lookupMX(context.Background(), name) + return DefaultResolver.LookupMX(context.Background(), name) } // LookupMX returns the DNS MX records for the given domain name sorted by preference. +// +// The returned mail server names are validated to be properly +// formatted presentation-format domain names. func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) { - return r.lookupMX(ctx, name) + records, err := r.lookupMX(ctx, name) + if err != nil { + return nil, err + } + for _, mx := range records { + if mx == nil { + continue + } + if !isDomainName(mx.Host) { + return nil, &DNSError{Err: "MX target is invalid", Name: name} + } + } + return records, nil } // LookupNS returns the DNS NS records for the given domain name. // +// The returned name server names are validated to be properly +// formatted presentation-format domain names. +// // LookupNS uses context.Background internally; to specify the context, use // Resolver.LookupNS. func LookupNS(name string) ([]*NS, error) { - return DefaultResolver.lookupNS(context.Background(), name) + return DefaultResolver.LookupNS(context.Background(), name) } // LookupNS returns the DNS NS records for the given domain name. +// +// The returned name server names are validated to be properly +// formatted presentation-format domain names. func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) { - return r.lookupNS(ctx, name) + records, err := r.lookupNS(ctx, name) + if err != nil { + return nil, err + } + for _, ns := range records { + if ns == nil { + continue + } + if !isDomainName(ns.Host) { + return nil, &DNSError{Err: "NS target is invalid", Name: name} + } + } + return records, nil } // LookupTXT returns the DNS TXT records for the given domain name. @@ -484,17 +554,32 @@ func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) // LookupAddr performs a reverse lookup for the given address, returning a list // of names mapping to that address. // +// The returned names are validated to be properly formatted presentation-format +// domain names. +// // When using the host C library resolver, at most one result will be // returned. To bypass the host resolver, use a custom Resolver. // // LookupAddr uses context.Background internally; to specify the context, use // Resolver.LookupAddr. func LookupAddr(addr string) (names []string, err error) { - return DefaultResolver.lookupAddr(context.Background(), addr) + return DefaultResolver.LookupAddr(context.Background(), addr) } // LookupAddr performs a reverse lookup for the given address, returning a list // of names mapping to that address. -func (r *Resolver) LookupAddr(ctx context.Context, addr string) (names []string, err error) { - return r.lookupAddr(ctx, addr) +// +// The returned names are validated to be properly formatted presentation-format +// domain names. +func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) { + names, err := r.lookupAddr(ctx, addr) + if err != nil { + return nil, err + } + for _, name := range names { + if !isDomainName(name) { + return nil, &DNSError{Err: "PTR target is invalid", Name: addr} + } + } + return names, nil } From 0ece95a0feafe151cadf1346464952bb5c95fab3 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Mon, 24 May 2021 16:47:45 -0400 Subject: [PATCH 194/940] cmd/go: don't let 'go mod download' save sums for inconsistent requirements 'go mod download' calls modload.LoadModFile early to find the main module path in order to validate arguments. LoadModFile may write go.mod and go.sum to fix formatting and add a go directive. This calls keepSums, which, in eager mode, loaded the complete module graph in order to find out what sums are needed to load the complete module graph. If go.mod requires a lower version of a module than will be selected later, keepSums causes the sum for that version's go.mod to be retained, even though it isn't needed later after a consistent go.mod is written. This CL fixes keepSums not to load the graph if it hasn't already been loaded (whether eager or lazy), addressing comments from CL 318629. For #45332 Change-Id: I20d4404004e4ad335450fd0fd753e7bc0060f702 Reviewed-on: https://go-review.googlesource.com/c/go/+/322369 Trust: Jay Conrod Run-TryBot: Bryan C. Mills Reviewed-by: Bryan C. Mills TryBot-Result: Go Bot --- src/cmd/go/internal/modcmd/download.go | 16 ++++++++-------- src/cmd/go/internal/modload/init.go | 11 +++++------ src/cmd/go/testdata/script/mod_download.txt | 1 - 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/cmd/go/internal/modcmd/download.go b/src/cmd/go/internal/modcmd/download.go index 42b06dbc95c..0e5af852376 100644 --- a/src/cmd/go/internal/modcmd/download.go +++ b/src/cmd/go/internal/modcmd/download.go @@ -138,14 +138,14 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) { sem := make(chan token, runtime.GOMAXPROCS(0)) infos, infosErr := modload.ListModules(ctx, args, 0) if !haveExplicitArgs { - // 'go mod download' is sometimes run without arguments to pre-populate - // the module cache. It may fetch modules that aren't needed to build - // packages in the main mdoule. This is usually not intended, so don't save - // sums for downloaded modules (golang.org/issue/45332). - // TODO(golang.org/issue/45551): For now, save sums needed to load the - // build list (same as 1.15 behavior). In the future, report an error if - // go.mod or go.sum need to be updated after loading the build list. - modload.WriteGoMod(ctx) + // 'go mod download' is sometimes run without arguments to pre-populate the + // module cache. It may fetch modules that aren't needed to build packages + // in the main mdoule. This is usually not intended, so don't save sums for + // downloaded modules (golang.org/issue/45332). + // TODO(golang.org/issue/45551): For now, in ListModules, save sums needed + // to load the build list (same as 1.15 behavior). In the future, report an + // error if go.mod or go.sum need to be updated after loading the build + // list. modload.DisallowWriteGoMod() } diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go index 86c0db3fe4f..ea404b9f78f 100644 --- a/src/cmd/go/internal/modload/init.go +++ b/src/cmd/go/internal/modload/init.go @@ -1122,12 +1122,11 @@ func keepSums(ctx context.Context, ld *loader, rs *Requirements, which whichSums } } - if rs.depth == lazy && rs.graph.Load() == nil { - // The main module is lazy and we haven't needed to load the module graph so - // far. Don't incur the cost of loading it now — since we haven't loaded the - // graph, we probably don't have any checksums to contribute to the distant - // parts of the graph anyway. Instead, just request sums for the roots that - // we know about. + if rs.graph.Load() == nil { + // The module graph was not loaded, possibly because the main module is lazy + // or possibly because we haven't needed to load the graph yet. + // Save sums for the root modules (or their replacements), but don't + // incur the cost of loading the graph just to find and retain the sums. for _, m := range rs.rootModules { r := resolveReplacement(m) keep[modkey(r)] = true diff --git a/src/cmd/go/testdata/script/mod_download.txt b/src/cmd/go/testdata/script/mod_download.txt index ad640b45de1..c2b72b2a02c 100644 --- a/src/cmd/go/testdata/script/mod_download.txt +++ b/src/cmd/go/testdata/script/mod_download.txt @@ -167,5 +167,4 @@ require ( -- update/go.sum.update -- golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= -rsc.io/sampler v1.2.1/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= From ab2ef4aaa77dff91cd98ded88aeba0bf5b5b2e80 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Wed, 26 May 2021 18:06:26 -0700 Subject: [PATCH 195/940] doc/go1.17: document reflect changes For #44513. Fixes #46019. Change-Id: Ica84edd5703a4ccf343ff01e10483f8d51d1c79f Reviewed-on: https://go-review.googlesource.com/c/go/+/323069 Trust: Damien Neil Run-TryBot: Damien Neil TryBot-Result: Go Bot Reviewed-by: Dmitri Shuralyov Reviewed-by: Ian Lance Taylor --- doc/go1.17.html | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 8313c2bc575..d0a0c0f33f0 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -500,11 +500,13 @@ Do not send CLs removing the interior tags from such phrases.

- TODO: https://golang.org/cl/281233: add VisibleFields function + The new VisibleFields function + returns all the visible fields in a struct type, including fields inside anonymous struct members.

- TODO: https://golang.org/cl/284136: panic if ArrayOf is called with negative length + The ArrayOf function now panics when + called with a negative length.

From 193d5141318d65cea310d995258288bd000d734c Mon Sep 17 00:00:00 2001 From: Manlio Perillo Date: Thu, 27 May 2021 10:44:57 +0200 Subject: [PATCH 196/940] net/http: correct Client.Do doc about context cancelation The documentation of the Client.Do method and Get function incorrectly stated that, in case of context cancelation, the returned url.Error Timeout method returns true. Update the documentation to correctly match the implementation. See also CL 200798 that, due to an oversight, corrected only the documentation of the Client.Get method. Remove a TODO note added in CL 125575 (net/http: document that Client methods always return *url.Error), since it is no longer applicable after CL 200798 (net/http: fix and lock-in Client.Do docs on request cancelation). Fixes #46402 Change-Id: Ied2ee971ba22b61777762dbb19f16e08686634ca Reviewed-on: https://go-review.googlesource.com/c/go/+/323089 Reviewed-by: Damien Neil Trust: Michael Knyszek --- src/net/http/client.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/net/http/client.go b/src/net/http/client.go index 03c9155fbdd..e0cabc9d4cf 100644 --- a/src/net/http/client.go +++ b/src/net/http/client.go @@ -433,8 +433,7 @@ func basicAuth(username, password string) string { // An error is returned if there were too many redirects or if there // was an HTTP protocol error. A non-2xx response doesn't cause an // error. Any returned error will be of type *url.Error. The url.Error -// value's Timeout method will report true if request timed out or was -// canceled. +// value's Timeout method will report true if the request timed out. // // When err is nil, resp always contains a non-nil resp.Body. // Caller should close resp.Body when done reading from it. @@ -589,8 +588,7 @@ func urlErrorOp(method string) string { // standard library body types. // // Any returned error will be of type *url.Error. The url.Error -// value's Timeout method will report true if request timed out or was -// canceled. +// value's Timeout method will report true if the request timed out. func (c *Client) Do(req *Request) (*Response, error) { return c.do(req) } @@ -729,7 +727,6 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) { reqBodyClosed = true if !deadline.IsZero() && didTimeout() { err = &httpError{ - // TODO: early in cycle: s/Client.Timeout exceeded/timeout or context cancellation/ err: err.Error() + " (Client.Timeout exceeded while awaiting headers)", timeout: true, } From de5d1aca5e61e49e0704213961c68bcf14e288b8 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 26 May 2021 19:52:31 -0700 Subject: [PATCH 197/940] [dev.typeparams] cmd/compile: tweaks to match types2 This CL makes a handful of changes to either bring existing compiler output consistent with what types2 produces or to make it easier to reproduce with types2: 1. The position for embedded fields is corrected to the position of the syntax.Field, rather than the syntax.Type. 2. Methods and embedded types are sorted in export data the same way that types2 sorts them. 3. Don't write out position information for OLITERALs that don't have their own position (i.e., references to named constants). Change-Id: Ic3979215ae9ef280cfbba7b44c236e03fc12a2ef Reviewed-on: https://go-review.googlesource.com/c/go/+/323209 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer Reviewed-by: Dan Scales Trust: Matthew Dempsky --- src/cmd/compile/internal/noder/noder.go | 6 +++-- src/cmd/compile/internal/typecheck/iexport.go | 23 +++++++++++++++---- src/cmd/compile/internal/types/size.go | 7 +++++- src/cmd/compile/internal/types/sort.go | 15 ++++++++---- 4 files changed, 38 insertions(+), 13 deletions(-) diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go index 06c3b00601f..44385f34fd1 100644 --- a/src/cmd/compile/internal/noder/noder.go +++ b/src/cmd/compile/internal/noder/noder.go @@ -986,6 +986,8 @@ func (p *noder) packname(expr syntax.Expr) *types.Sym { } func (p *noder) embedded(typ syntax.Expr) *ir.Field { + pos := p.pos(syntax.StartPos(typ)) + op, isStar := typ.(*syntax.Operation) if isStar { if op.Op != syntax.Mul || op.Y != nil { @@ -995,11 +997,11 @@ func (p *noder) embedded(typ syntax.Expr) *ir.Field { } sym := p.packname(typ) - n := ir.NewField(p.pos(typ), typecheck.Lookup(sym.Name), importName(sym).(ir.Ntype), nil) + n := ir.NewField(pos, typecheck.Lookup(sym.Name), importName(sym).(ir.Ntype), nil) n.Embedded = true if isStar { - n.Ntype = ir.NewStarExpr(p.pos(op), n.Ntype) + n.Ntype = ir.NewStarExpr(pos, n.Ntype) } return n } diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index 9c242131769..e798ce51435 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -540,9 +540,12 @@ func (p *iexporter) doDecl(n *ir.Name) { break } - ms := t.Methods() - w.uint64(uint64(ms.Len())) - for _, m := range ms.Slice() { + // Sort methods, for consistency with types2. + methods := append([]*types.Field(nil), t.Methods().Slice()...) + sort.Sort(types.MethodsByName(methods)) + + w.uint64(uint64(len(methods))) + for _, m := range methods { w.pos(m.Pos) w.selector(m.Sym) w.param(m.Type.Recv()) @@ -550,7 +553,7 @@ func (p *iexporter) doDecl(n *ir.Name) { } w.typeExt(t) - for _, m := range ms.Slice() { + for _, m := range methods { w.methExt(m) } @@ -939,6 +942,12 @@ func (w *exportWriter) doTyp(t *types.Type) { } } + // Sort methods and embedded types, for consistency with types2. + // Note: embedded types may be anonymous, and types2 sorts them + // with sort.Stable too. + sort.Sort(types.MethodsByName(methods)) + sort.Stable(types.EmbeddedsByName(embeddeds)) + w.startType(interfaceType) w.setPkg(t.Pkg(), true) @@ -1590,7 +1599,11 @@ func (w *exportWriter) expr(n ir.Node) { case ir.OLITERAL: w.op(ir.OLITERAL) - w.pos(n.Pos()) + if ir.HasUniquePos(n) { + w.pos(n.Pos()) + } else { + w.pos(src.NoXPos) + } w.value(n.Type(), n.Val()) case ir.ONAME: diff --git a/src/cmd/compile/internal/types/size.go b/src/cmd/compile/internal/types/size.go index 7059eff398c..e6ca4556b94 100644 --- a/src/cmd/compile/internal/types/size.go +++ b/src/cmd/compile/internal/types/size.go @@ -126,10 +126,15 @@ func expandiface(t *Type) { // (including broken ones, if any) and add to t's // method set. for _, t1 := range m.Type.AllMethods().Slice() { - // Use m.Pos rather than t1.Pos to preserve embedding position. f := NewField(m.Pos, t1.Sym, t1.Type) addMethod(f, false) + + // Clear position after typechecking, for consistency with types2. + f.Pos = src.NoXPos } + + // Clear position after typechecking, for consistency with types2. + m.Pos = src.NoXPos } sort.Sort(MethodsByName(methods)) diff --git a/src/cmd/compile/internal/types/sort.go b/src/cmd/compile/internal/types/sort.go index dc59b064153..765c070cd94 100644 --- a/src/cmd/compile/internal/types/sort.go +++ b/src/cmd/compile/internal/types/sort.go @@ -4,11 +4,16 @@ package types -// MethodsByName sorts methods by symbol. +// MethodsByName sorts methods by name. type MethodsByName []*Field -func (x MethodsByName) Len() int { return len(x) } - -func (x MethodsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } - +func (x MethodsByName) Len() int { return len(x) } +func (x MethodsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } func (x MethodsByName) Less(i, j int) bool { return x[i].Sym.Less(x[j].Sym) } + +// EmbeddedsByName sorts embedded types by name. +type EmbeddedsByName []*Field + +func (x EmbeddedsByName) Len() int { return len(x) } +func (x EmbeddedsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } +func (x EmbeddedsByName) Less(i, j int) bool { return x[i].Type.Sym().Less(x[j].Type.Sym()) } From ea522bc546bb9f66285ea00744de8b258368b3ed Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 27 May 2021 02:50:17 -0700 Subject: [PATCH 198/940] [dev.typeparams] cmd/compile: add and use ir.RawOrigExpr This CL adds ir.RawOrigExpr, which can be used to represent arbitrary constant expressions without needing to build and carry around an entire IR representation of the original expression. It also allows distinguishing how the constant was originally written by the user (e.g., "0xff" vs "255"). This CL then also updates irgen to make use of this functionality for expressions that were constant folded by types2. Change-Id: I41e04e228e715ae2735c357b75633a2d08ee7021 Reviewed-on: https://go-review.googlesource.com/c/go/+/323210 Trust: Matthew Dempsky Trust: Robert Griesemer Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer Reviewed-by: Dan Scales --- src/cmd/compile/internal/ir/expr.go | 14 +++++++ src/cmd/compile/internal/ir/fmt.go | 5 +++ src/cmd/compile/internal/ir/node_gen.go | 16 +++++++ src/cmd/compile/internal/ir/val.go | 2 +- src/cmd/compile/internal/noder/expr.go | 51 ++++++++++++++++++++--- src/cmd/compile/internal/noder/helpers.go | 26 ++++++++++++ 6 files changed, 107 insertions(+), 7 deletions(-) diff --git a/src/cmd/compile/internal/ir/expr.go b/src/cmd/compile/internal/ir/expr.go index 9ea8b619653..519120ed6b8 100644 --- a/src/cmd/compile/internal/ir/expr.go +++ b/src/cmd/compile/internal/ir/expr.go @@ -448,6 +448,20 @@ func (n *ParenExpr) SetOTYPE(t *types.Type) { t.SetNod(n) } +// A RawOrigExpr represents an arbitrary Go expression as a string value. +// When printed in diagnostics, the string value is written out exactly as-is. +type RawOrigExpr struct { + miniExpr + Raw string +} + +func NewRawOrigExpr(pos src.XPos, op Op, raw string) *RawOrigExpr { + n := &RawOrigExpr{Raw: raw} + n.pos = pos + n.op = op + return n +} + // A ResultExpr represents a direct access to a result. type ResultExpr struct { miniExpr diff --git a/src/cmd/compile/internal/ir/fmt.go b/src/cmd/compile/internal/ir/fmt.go index 4ac5f3fea29..d9cc5f109f5 100644 --- a/src/cmd/compile/internal/ir/fmt.go +++ b/src/cmd/compile/internal/ir/fmt.go @@ -567,6 +567,11 @@ func exprFmt(n Node, s fmt.State, prec int) { return } + if n, ok := n.(*RawOrigExpr); ok { + fmt.Fprint(s, n.Raw) + return + } + switch n.Op() { case OPAREN: n := n.(*ParenExpr) diff --git a/src/cmd/compile/internal/ir/node_gen.go b/src/cmd/compile/internal/ir/node_gen.go index 22855d7163f..9a4858d0371 100644 --- a/src/cmd/compile/internal/ir/node_gen.go +++ b/src/cmd/compile/internal/ir/node_gen.go @@ -947,6 +947,22 @@ func (n *RangeStmt) editChildren(edit func(Node) Node) { } } +func (n *RawOrigExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) } +func (n *RawOrigExpr) copy() Node { + c := *n + c.init = copyNodes(c.init) + return &c +} +func (n *RawOrigExpr) doChildren(do func(Node) bool) bool { + if doNodes(n.init, do) { + return true + } + return false +} +func (n *RawOrigExpr) editChildren(edit func(Node) Node) { + editNodes(n.init, edit) +} + func (n *ResultExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) } func (n *ResultExpr) copy() Node { c := *n diff --git a/src/cmd/compile/internal/ir/val.go b/src/cmd/compile/internal/ir/val.go index af9f95b29d7..bfe7d2bb436 100644 --- a/src/cmd/compile/internal/ir/val.go +++ b/src/cmd/compile/internal/ir/val.go @@ -66,7 +66,7 @@ func Float64Val(v constant.Value) float64 { func AssertValidTypeForConst(t *types.Type, v constant.Value) { if !ValidTypeForConst(t, v) { - base.Fatalf("%v does not represent %v (%v)", t, v, v.Kind()) + base.Fatalf("%v (%v) does not represent %v (%v)", t, t.Kind(), v, v.Kind()) } } diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go index f96144f8d70..c901dc55345 100644 --- a/src/cmd/compile/internal/noder/expr.go +++ b/src/cmd/compile/internal/noder/expr.go @@ -5,6 +5,8 @@ package noder import ( + "fmt" + "cmd/compile/internal/base" "cmd/compile/internal/ir" "cmd/compile/internal/syntax" @@ -15,6 +17,8 @@ import ( ) func (g *irgen) expr(expr syntax.Expr) ir.Node { + expr = unparen(expr) // skip parens; unneeded after parse+typecheck + if expr == nil { return nil } @@ -67,7 +71,9 @@ func (g *irgen) expr(expr syntax.Expr) ir.Node { // Constant expression. if tv.Value != nil { - return Const(g.pos(expr), g.typ(typ), tv.Value) + typ := g.typ(typ) + value := FixValue(typ, tv.Value) + return OrigConst(g.pos(expr), typ, value, constExprOp(expr), syntax.String(expr)) } n := g.expr0(typ, expr) @@ -161,9 +167,6 @@ func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node { typed(g.typ(typ), n) return n - case *syntax.ParenExpr: - return g.expr(expr.X) // skip parens; unneeded after parse+typecheck - case *syntax.SelectorExpr: // Qualified identifier. if name, ok := expr.X.(*syntax.Name); ok { @@ -317,13 +320,17 @@ func getTargs(selinfo *types2.Selection) []types2.Type { } func (g *irgen) exprList(expr syntax.Expr) []ir.Node { + return g.exprs(unpackListExpr(expr)) +} + +func unpackListExpr(expr syntax.Expr) []syntax.Expr { switch expr := expr.(type) { case nil: return nil case *syntax.ListExpr: - return g.exprs(expr.ElemList) + return expr.ElemList default: - return []ir.Node{g.expr(expr)} + return []syntax.Expr{expr} } } @@ -402,3 +409,35 @@ func (g *irgen) typeExpr(typ syntax.Expr) *types.Type { } return n.Type() } + +// constExprOp returns an ir.Op that represents the outermost +// operation of the given constant expression. It's intended for use +// with ir.RawOrigExpr. +func constExprOp(expr syntax.Expr) ir.Op { + switch expr := expr.(type) { + default: + panic(fmt.Sprintf("%s: unexpected expression: %T", expr.Pos(), expr)) + + case *syntax.BasicLit: + return ir.OLITERAL + case *syntax.Name, *syntax.SelectorExpr: + return ir.ONAME + case *syntax.CallExpr: + return ir.OCALL + case *syntax.Operation: + if expr.Y == nil { + return unOps[expr.Op] + } + return binOps[expr.Op] + } +} + +func unparen(expr syntax.Expr) syntax.Expr { + for { + paren, ok := expr.(*syntax.ParenExpr) + if !ok { + return expr + } + expr = paren.X + } +} diff --git a/src/cmd/compile/internal/noder/helpers.go b/src/cmd/compile/internal/noder/helpers.go index 9da0e493007..ea30a3bfa99 100644 --- a/src/cmd/compile/internal/noder/helpers.go +++ b/src/cmd/compile/internal/noder/helpers.go @@ -43,6 +43,32 @@ func Const(pos src.XPos, typ *types.Type, val constant.Value) ir.Node { return typed(typ, ir.NewBasicLit(pos, val)) } +func OrigConst(pos src.XPos, typ *types.Type, val constant.Value, op ir.Op, raw string) ir.Node { + orig := ir.NewRawOrigExpr(pos, op, raw) + return ir.NewConstExpr(val, typed(typ, orig)) +} + +// FixValue returns val after converting and truncating it as +// appropriate for typ. +func FixValue(typ *types.Type, val constant.Value) constant.Value { + assert(typ.Kind() != types.TFORW) + switch { + case typ.IsInteger(): + val = constant.ToInt(val) + case typ.IsFloat(): + val = constant.ToFloat(val) + case typ.IsComplex(): + val = constant.ToComplex(val) + } + if !typ.IsUntyped() { + val = typecheck.DefaultLit(ir.NewBasicLit(src.NoXPos, val), typ).Val() + } + if typ.Kind() != types.TTYPEPARAM { + ir.AssertValidTypeForConst(typ, val) + } + return val +} + func Nil(pos src.XPos, typ *types.Type) ir.Node { return typed(typ, ir.NewNilExpr(pos)) } From 88583a2a6639c72f2cb0143b0135f50fa6b379c0 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 27 May 2021 02:42:15 -0700 Subject: [PATCH 199/940] [dev.typeparams] test: trim list of expected -G=3 failures 15 more tests are passing from recent changes. 83 still to go. Change-Id: I155b3e3db966d604ccec8bf3a7c182421f3d26c4 Reviewed-on: https://go-review.googlesource.com/c/go/+/323211 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- test/run.go | 59 ++++++++++++++++++++--------------------------------- 1 file changed, 22 insertions(+), 37 deletions(-) diff --git a/test/run.go b/test/run.go index ef243968092..cf1d3015989 100644 --- a/test/run.go +++ b/test/run.go @@ -2024,19 +2024,16 @@ func overlayDir(dstRoot, srcRoot string) error { // Temporary scaffolding until we pass all the tests at which point this map can be removed. var excludedFiles = map[string]bool{ "complit1.go": true, // types2 reports extra errors - "const2.go": true, // types2 not run after syntax errors "ddd1.go": true, // issue #42987 "directive.go": true, // misplaced compiler directive checks "float_lit3.go": true, // types2 reports extra errors "import1.go": true, // types2 reports extra errors - "import5.go": true, // issue #42988 "import6.go": true, // issue #43109 "initializerr.go": true, // types2 reports extra errors "linkname2.go": true, // error reported by noder (not running for types2 errorcheck test) "notinheap.go": true, // types2 doesn't report errors about conversions that are invalid due to //go:notinheap "printbig.go": true, // large untyped int passed to print (32-bit) "shift1.go": true, // issue #42989 - "shift2.go": true, // bad code generation; constant.Value of the wrong kind? "typecheck.go": true, // invalid function is not causing errors when called "writebarrier.go": true, // correct diagnostics, but different lines (probably irgen's fault) @@ -2048,18 +2045,15 @@ var excludedFiles = map[string]bool{ "fixedbugs/bug228.go": true, // types2 doesn't run when there are syntax errors "fixedbugs/bug231.go": true, // types2 bug? (same error reported twice) "fixedbugs/bug255.go": true, // types2 reports extra errors - "fixedbugs/bug351.go": true, // types2 reports extra errors "fixedbugs/bug374.go": true, // types2 reports extra errors "fixedbugs/bug385_32.go": true, // types2 doesn't produce missing error "type .* too large" (32-bit specific) "fixedbugs/bug388.go": true, // types2 not run due to syntax errors "fixedbugs/bug412.go": true, // types2 produces a follow-on error - "fixedbugs/bug420.go": true, // ICE in irgen "fixedbugs/issue10700.go": true, // types2 reports ok hint, but does not match regexp "fixedbugs/issue11590.go": true, // types2 doesn't report a follow-on error (pref: types2) "fixedbugs/issue11610.go": true, // types2 not run after syntax errors "fixedbugs/issue11614.go": true, // types2 reports an extra error - "fixedbugs/issue13415.go": true, // declared but not used conflict "fixedbugs/issue14520.go": true, // missing import path error by types2 "fixedbugs/issue16133.go": true, // types2 doesn't use package path for qualified identifiers when package name is ambiguous "fixedbugs/issue16428.go": true, // types2 reports two instead of one error @@ -2067,7 +2061,6 @@ var excludedFiles = map[string]bool{ "fixedbugs/issue17270.go": true, // ICE in irgen "fixedbugs/issue17645.go": true, // multiple errors on same line "fixedbugs/issue18331.go": true, // missing error about misuse of //go:noescape (irgen needs code from noder) - "fixedbugs/issue18393.go": true, // types2 not run after syntax errors "fixedbugs/issue18419.go": true, // types2 reports "fixedbugs/issue19012.go": true, // multiple errors on same line "fixedbugs/issue20174.go": true, // ICE due to width not calculated (probably irgen's fault) @@ -2082,15 +2075,12 @@ var excludedFiles = map[string]bool{ "fixedbugs/issue28268.go": true, // types2 reports follow-on errors "fixedbugs/issue31053.go": true, // types2 reports "unknown field" instead of "cannot refer to unexported field" "fixedbugs/issue33460.go": true, // types2 reports alternative positions in separate error - "fixedbugs/issue41575.go": true, // types2 reports alternative positions in separate error "fixedbugs/issue42058a.go": true, // types2 doesn't report "channel element type too large" "fixedbugs/issue42058b.go": true, // types2 doesn't report "channel element type too large" "fixedbugs/issue4232.go": true, // types2 reports (correct) extra errors - "fixedbugs/issue43479.go": true, // ICE in iexport due to Syms from the wrong package "fixedbugs/issue4452.go": true, // types2 reports (correct) extra errors "fixedbugs/issue4510.go": true, // types2 reports different (but ok) line numbers "fixedbugs/issue5609.go": true, // types2 needs a better error message - "fixedbugs/issue6889.go": true, // types2 can handle this without constant overflow "fixedbugs/issue7525b.go": true, // types2 reports init cycle error on different line - ok otherwise "fixedbugs/issue7525c.go": true, // types2 reports init cycle error on different line - ok otherwise "fixedbugs/issue7525d.go": true, // types2 reports init cycle error on different line - ok otherwise @@ -2105,31 +2095,26 @@ var excludedFiles = map[string]bool{ // - Some escape analysis diagnostics being printed without position information // - Some expressions printed differently (e.g., "int(100)" instead // of "100" or "&composite literal" instead of "&[4]int{...}"). - "closure3.go": true, - "escape2.go": true, - "escape2n.go": true, - "escape4.go": true, - "escape5.go": true, - "escape_array.go": true, - "escape_calls.go": true, - "escape_field.go": true, - "escape_iface.go": true, - "escape_indir.go": true, - "escape_level.go": true, - "escape_map.go": true, - "escape_param.go": true, - "escape_slice.go": true, - "escape_struct_param1.go": true, - "escape_struct_param2.go": true, - "fixedbugs/issue12006.go": true, - "fixedbugs/issue13799.go": true, - "fixedbugs/issue21709.go": true, - "fixedbugs/issue24651a.go": true, - "fixedbugs/issue24651b.go": true, - "fixedbugs/issue27557.go": true, - "fixedbugs/issue31573.go": true, - "fixedbugs/issue37837.go": true, - "fixedbugs/issue39292.go": true, - "fixedbugs/issue7921.go": true, - "inline.go": true, + "closure3.go": true, + "escape2.go": true, + "escape2n.go": true, + "escape4.go": true, + "escape_calls.go": true, + "escape_field.go": true, + "escape_iface.go": true, + "escape_indir.go": true, + "escape_level.go": true, + "escape_map.go": true, + "escape_param.go": true, + "escape_slice.go": true, + "escape_struct_param1.go": true, + "escape_struct_param2.go": true, + "fixedbugs/issue12006.go": true, + "fixedbugs/issue13799.go": true, + "fixedbugs/issue21709.go": true, + "fixedbugs/issue31573.go": true, + "fixedbugs/issue37837.go": true, + "fixedbugs/issue39292.go": true, + "fixedbugs/issue7921.go": true, + "inline.go": true, } From 417955d151359629ca11be968e3056e6636b828e Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 27 May 2021 02:47:04 -0700 Subject: [PATCH 200/940] [dev.typeparams] cmd/compile/internal/inline: refactor mkinlcall This CL refactors mkinlcall by extracting the core InlinedCallExpr construction code into a new "oldInline" function, and adds a new "NewInline" hook point that can be overriden with a new inliner implementation that only needs to worry about the details of constructing the InlinedCallExpr. It also moves the delayretvars optimization check into CanInline, so it's performed just once per inlinable function rather than once for each inlined call. Finally, it skips printing the function body about to be inlined (and updates the couple of regress tests that expected this output). We already report the inline body as it was saved, and this diagnostic is only applicable to the current inliner, which clones existing function body instances. In the unified IR inliner, we'll directly construct inline bodies from the serialized representation. Change-Id: Ibdbe617da83c07665dcbda402cc8d4d4431dde2f Reviewed-on: https://go-review.googlesource.com/c/go/+/323290 Trust: Matthew Dempsky Trust: Dan Scales Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/inline/inl.go | 187 ++++++++++-------- src/cmd/compile/internal/ir/func.go | 5 + src/cmd/compile/internal/typecheck/iexport.go | 1 + src/cmd/compile/internal/typecheck/iimport.go | 3 +- test/fixedbugs/issue24651a.go | 2 +- test/fixedbugs/issue24651b.go | 4 +- test/inline_big.go | 2 +- 7 files changed, 113 insertions(+), 91 deletions(-) diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go index 042e3f2332a..594f280f039 100644 --- a/src/cmd/compile/internal/inline/inl.go +++ b/src/cmd/compile/internal/inline/inl.go @@ -179,6 +179,8 @@ func CanInline(fn *ir.Func) { Cost: inlineMaxBudget - visitor.budget, Dcl: pruneUnusedAutos(n.Defn.(*ir.Func).Dcl, &visitor), Body: inlcopylist(fn.Body), + + CanDelayResults: canDelayResults(fn), } if base.Flag.LowerM > 1 { @@ -191,6 +193,38 @@ func CanInline(fn *ir.Func) { } } +// canDelayResults reports whether inlined calls to fn can delay +// declaring the result parameter until the "return" statement. +func canDelayResults(fn *ir.Func) bool { + // We can delay declaring+initializing result parameters if: + // (1) there's exactly one "return" statement in the inlined function; + // (2) it's not an empty return statement (#44355); and + // (3) the result parameters aren't named. + + nreturns := 0 + ir.VisitList(fn.Body, func(n ir.Node) { + if n, ok := n.(*ir.ReturnStmt); ok { + nreturns++ + if len(n.Results) == 0 { + nreturns++ // empty return statement (case 2) + } + } + }) + + if nreturns != 1 { + return false // not exactly one return statement (case 1) + } + + // temporaries for return values. + for _, param := range fn.Type().Results().FieldSlice() { + if sym := types.OrigSym(param.Sym); sym != nil && !sym.IsBlank() { + return false // found a named result parameter (case 3) + } + } + + return true +} + // Inline_Flood marks n's inline body for export and recursively ensures // all called functions are marked too. func Inline_Flood(n *ir.Name, exportsym func(*ir.Name)) { @@ -740,6 +774,11 @@ var inlgen int // when producing output for debugging the compiler itself. var SSADumpInline = func(*ir.Func) {} +// NewInline allows the inliner implementation to be overridden. +// If it returns nil, the legacy inliner will handle this call +// instead. +var NewInline = func(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExpr { return nil } + // If n is a call node (OCALLFUNC or OCALLMETH), and fn is an ONAME node for a // function with an inlinable body, return an OINLCALL node that can replace n. // The returned node's Ninit has the parameter assignments, the Nbody is the @@ -796,30 +835,64 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b typecheck.FixVariadicCall(n) - if base.Debug.TypecheckInl == 0 { - typecheck.ImportedBody(fn) + parent := base.Ctxt.PosTable.Pos(n.Pos()).Base().InliningIndex() + + sym := fn.Linksym() + inlIndex := base.Ctxt.InlTree.Add(parent, n.Pos(), sym) + + if base.Flag.GenDwarfInl > 0 { + if !sym.WasInlined() { + base.Ctxt.DwFixups.SetPrecursorFunc(sym, fn) + sym.Set(obj.AttrWasInlined, true) + } } - // We have a function node, and it has an inlineable body. - if base.Flag.LowerM > 1 { - fmt.Printf("%v: inlining call to %v %v { %v }\n", ir.Line(n), fn.Sym(), fn.Type(), ir.Nodes(fn.Inl.Body)) - } else if base.Flag.LowerM != 0 { + if base.Flag.LowerM != 0 { fmt.Printf("%v: inlining call to %v\n", ir.Line(n), fn) } if base.Flag.LowerM > 2 { fmt.Printf("%v: Before inlining: %+v\n", ir.Line(n), n) } + res := NewInline(n, fn, inlIndex) + if res == nil { + res = oldInline(n, fn, inlIndex) + } + + // transitive inlining + // might be nice to do this before exporting the body, + // but can't emit the body with inlining expanded. + // instead we emit the things that the body needs + // and each use must redo the inlining. + // luckily these are small. + ir.EditChildren(res, edit) + + if base.Flag.LowerM > 2 { + fmt.Printf("%v: After inlining %+v\n\n", ir.Line(res), res) + } + + return res +} + +// oldInline creates an InlinedCallExpr to replace the given call +// expression. fn is the callee function to be inlined. inlIndex is +// the inlining tree position index, for use with src.NewInliningBase +// when rewriting positions. +func oldInline(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExpr { + if base.Debug.TypecheckInl == 0 { + typecheck.ImportedBody(fn) + } + SSADumpInline(fn) - ninit := n.Init() + ninit := call.Init() // For normal function calls, the function callee expression // may contain side effects (e.g., added by addinit during // inlconv2expr or inlconv2list). Make sure to preserve these, // if necessary (#42703). - if n.Op() == ir.OCALLFUNC { - callee := n.X + if call.Op() == ir.OCALLFUNC { + callee := call.X for callee.Op() == ir.OCONVNOP { conv := callee.(*ir.ConvExpr) ninit.Append(ir.TakeInit(conv)...) @@ -857,25 +930,6 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b } // We can delay declaring+initializing result parameters if: - // (1) there's exactly one "return" statement in the inlined function; - // (2) it's not an empty return statement (#44355); and - // (3) the result parameters aren't named. - delayretvars := true - - nreturns := 0 - ir.VisitList(ir.Nodes(fn.Inl.Body), func(n ir.Node) { - if n, ok := n.(*ir.ReturnStmt); ok { - nreturns++ - if len(n.Results) == 0 { - delayretvars = false // empty return statement (case 2) - } - } - }) - - if nreturns != 1 { - delayretvars = false // not exactly one return statement (case 1) - } - // temporaries for return values. var retvars []ir.Node for i, t := range fn.Type().Results().Fields().Slice() { @@ -885,7 +939,6 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b m = inlvar(n) m = typecheck.Expr(m).(*ir.Name) inlvars[n] = m - delayretvars = false // found a named result parameter (case 3) } else { // anonymous return values, synthesize names for use in assignment that replaces return m = retvar(t, i) @@ -908,14 +961,14 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b // Assign arguments to the parameters' temp names. as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil) as.Def = true - if n.Op() == ir.OCALLMETH { - sel := n.X.(*ir.SelectorExpr) + if call.Op() == ir.OCALLMETH { + sel := call.X.(*ir.SelectorExpr) if sel.X == nil { - base.Fatalf("method call without receiver: %+v", n) + base.Fatalf("method call without receiver: %+v", call) } as.Rhs.Append(sel.X) } - as.Rhs.Append(n.Args...) + as.Rhs.Append(call.Args...) if recv := fn.Type().Recv(); recv != nil { as.Lhs.Append(inlParam(recv, as, inlvars)) @@ -928,7 +981,7 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b ninit.Append(typecheck.Stmt(as)) } - if !delayretvars { + if !fn.Inl.CanDelayResults { // Zero the return parameters. for _, n := range retvars { ninit.Append(ir.NewDecl(base.Pos, ir.ODCL, n.(*ir.Name))) @@ -941,40 +994,21 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b inlgen++ - parent := -1 - if b := base.Ctxt.PosTable.Pos(n.Pos()).Base(); b != nil { - parent = b.InliningIndex() - } - - sym := fn.Linksym() - newIndex := base.Ctxt.InlTree.Add(parent, n.Pos(), sym) - // Add an inline mark just before the inlined body. // This mark is inline in the code so that it's a reasonable spot // to put a breakpoint. Not sure if that's really necessary or not // (in which case it could go at the end of the function instead). // Note issue 28603. - inlMark := ir.NewInlineMarkStmt(base.Pos, types.BADWIDTH) - inlMark.SetPos(n.Pos().WithIsStmt()) - inlMark.Index = int64(newIndex) - ninit.Append(inlMark) - - if base.Flag.GenDwarfInl > 0 { - if !sym.WasInlined() { - base.Ctxt.DwFixups.SetPrecursorFunc(sym, fn) - sym.Set(obj.AttrWasInlined, true) - } - } + ninit.Append(ir.NewInlineMarkStmt(call.Pos().WithIsStmt(), int64(inlIndex))) subst := inlsubst{ - retlabel: retlabel, - retvars: retvars, - delayretvars: delayretvars, - inlvars: inlvars, - defnMarker: ir.NilExpr{}, - bases: make(map[*src.PosBase]*src.PosBase), - newInlIndex: newIndex, - fn: fn, + retlabel: retlabel, + retvars: retvars, + inlvars: inlvars, + defnMarker: ir.NilExpr{}, + bases: make(map[*src.PosBase]*src.PosBase), + newInlIndex: inlIndex, + fn: fn, } subst.edit = subst.node @@ -995,26 +1029,11 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b //dumplist("ninit post", ninit); - call := ir.NewInlinedCallExpr(base.Pos, nil, nil) - *call.PtrInit() = ninit - call.Body = body - call.ReturnVars = retvars - call.SetType(n.Type()) - call.SetTypecheck(1) - - // transitive inlining - // might be nice to do this before exporting the body, - // but can't emit the body with inlining expanded. - // instead we emit the things that the body needs - // and each use must redo the inlining. - // luckily these are small. - ir.EditChildren(call, edit) - - if base.Flag.LowerM > 2 { - fmt.Printf("%v: After inlining %+v\n\n", ir.Line(call), call) - } - - return call + res := ir.NewInlinedCallExpr(base.Pos, body, retvars) + res.SetInit(ninit) + res.SetType(call.Type()) + res.SetTypecheck(1) + return res } // Every time we expand a function we generate a new set of tmpnames, @@ -1057,10 +1076,6 @@ type inlsubst struct { // Temporary result variables. retvars []ir.Node - // Whether result variables should be initialized at the - // "return" statement. - delayretvars bool - inlvars map[*ir.Name]*ir.Name // defnMarker is used to mark a Node for reassignment. // inlsubst.clovar set this during creating new ONAME. @@ -1353,7 +1368,7 @@ func (subst *inlsubst) node(n ir.Node) ir.Node { } as.Rhs = subst.list(n.Results) - if subst.delayretvars { + if subst.fn.Inl.CanDelayResults { for _, n := range as.Lhs { as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, n.(*ir.Name))) n.Name().Defn = as diff --git a/src/cmd/compile/internal/ir/func.go b/src/cmd/compile/internal/ir/func.go index a4231a1bcb6..ca6c8eca8b7 100644 --- a/src/cmd/compile/internal/ir/func.go +++ b/src/cmd/compile/internal/ir/func.go @@ -166,6 +166,11 @@ type Inline struct { // another package is imported. Dcl []*Name Body []Node + + // CanDelayResults reports whether it's safe for the inliner to delay + // initializing the result parameters until immediately before the + // "return" statement. + CanDelayResults bool } // A Mark represents a scope boundary. diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index e798ce51435..f49718d4428 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -1313,6 +1313,7 @@ func (w *exportWriter) funcExt(n *ir.Name) { } if n.Func.Inl != nil { w.uint64(1 + uint64(n.Func.Inl.Cost)) + w.bool(n.Func.Inl.CanDelayResults) if n.Func.ExportInline() || n.Type().HasTParam() { w.p.doInline(n) } diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 16b3e7ceba4..cca14a0d919 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -927,7 +927,8 @@ func (r *importReader) funcExt(n *ir.Name) { // Inline body. if u := r.uint64(); u > 0 { n.Func.Inl = &ir.Inline{ - Cost: int32(u - 1), + Cost: int32(u - 1), + CanDelayResults: r.bool(), } n.Func.Endlineno = r.pos() } diff --git a/test/fixedbugs/issue24651a.go b/test/fixedbugs/issue24651a.go index 6c7bf309087..1bfe8ac1ce8 100644 --- a/test/fixedbugs/issue24651a.go +++ b/test/fixedbugs/issue24651a.go @@ -21,5 +21,5 @@ var x = 5 //go:noinline Provide a clean, constant reason for not inlining main func main() { // ERROR "cannot inline main: marked go:noinline$" println("Foo(", x, ")=", Foo(x)) - println("Bar(", x, ")=", Bar(x)) // ERROR "inlining call to Bar func\(int\) int { return x \* \(x \+ 1\) \* \(x \+ 2\) }$" + println("Bar(", x, ")=", Bar(x)) // ERROR "inlining call to Bar" } diff --git a/test/fixedbugs/issue24651b.go b/test/fixedbugs/issue24651b.go index aa88a6787b9..2af54fc4b53 100644 --- a/test/fixedbugs/issue24651b.go +++ b/test/fixedbugs/issue24651b.go @@ -19,6 +19,6 @@ var x = 5 //go:noinline Provide a clean, constant reason for not inlining main func main() { // ERROR "cannot inline main: marked go:noinline$" - println("Foo(", x, ")=", Foo(x)) // ERROR "inlining call to Foo func\(int\) int { return x \* \(x \+ 1\) \* \(x \+ 2\) }$" - println("Bar(", x, ")=", Bar(x)) // ERROR "inlining call to Bar func\(int\) int { return x \* \(x \+ 1\) \* \(x \+ 2\) }$" + println("Foo(", x, ")=", Foo(x)) // ERROR "inlining call to Foo" + println("Bar(", x, ")=", Bar(x)) // ERROR "inlining call to Bar" } diff --git a/test/inline_big.go b/test/inline_big.go index 68e1101d3b0..83672753f78 100644 --- a/test/inline_big.go +++ b/test/inline_big.go @@ -1023,7 +1023,7 @@ func f(a []int) int { // ERROR "cannot inline f:.*" "a does not escape" a[997] = 0 a[998] = 0 a[999] = 0 - x := small(a) // ERROR "inlining call to small .*" + x := small(a) // ERROR "inlining call to small" y := medium(a) // The crux of this test: medium is not inlined. return x + y } From 639acdc833bfd12b7edd43092d1b380d70cb2874 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 27 May 2021 16:12:12 -0700 Subject: [PATCH 201/940] doc/go1.17: clarify that compress/lzw Reader and Writer types are new For #26535 For #44513 For #46005 Change-Id: I70d3711ab6451a61b526abb3da8e91243f637656 Reviewed-on: https://go-review.googlesource.com/c/go/+/323273 Trust: Ian Lance Taylor Reviewed-by: Joe Tsai --- doc/go1.17.html | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index d0a0c0f33f0..b3485a0ca64 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -331,11 +331,16 @@ Do not send CLs removing the interior tags from such phrases.
compress/lzw

- The new - Reader.Reset - and - Writer.Reset - methods allow reuse of a Reader or Writer. + The NewReader + function is guaranteed to return a value of the new + type Reader, + and similarly NewWriter + is guaranteed to return a value of the new + type Writer. + These new types both implement a Reset method + (Reader.Reset, + Writer.Reset) + that allows reuse of the Reader or Writer.

From 22f5ece3b13b7e5f6dece399c96d1d665b3a05bc Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 27 May 2021 02:48:33 -0700 Subject: [PATCH 202/940] [dev.typeparams] cmd/compile/internal/noder: refactor irgen import handling Rather than re-parsing and re-resolving the import path string, use the PkgName object provided by types2 to determine what package path it refers to. Also, decompose importfile into smaller functions, so that we can directly pass the already-resolved package path to the importer. Finally, switch to simply using height as calculated by types2 rather than redoing the calculations. Change-Id: I3338f4e68387b2835b2e58d6df65d740d6a648cb Reviewed-on: https://go-review.googlesource.com/c/go/+/323309 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Dan Scales Trust: Dan Scales Trust: Matthew Dempsky --- src/cmd/compile/internal/noder/decl.go | 15 ++++++- src/cmd/compile/internal/noder/import.go | 50 +++++++++++++----------- src/cmd/compile/internal/noder/irgen.go | 3 +- 3 files changed, 42 insertions(+), 26 deletions(-) diff --git a/src/cmd/compile/internal/noder/decl.go b/src/cmd/compile/internal/noder/decl.go index 40cbe50affd..375eb418989 100644 --- a/src/cmd/compile/internal/noder/decl.go +++ b/src/cmd/compile/internal/noder/decl.go @@ -46,7 +46,12 @@ func (g *irgen) importDecl(p *noder, decl *syntax.ImportDecl) { g.pragmaFlags(decl.Pragma, 0) - ipkg := importfile(decl) + // Get the imported package's path, as resolved already by types2 + // and gcimporter. This is the same path as would be computed by + // parseImportPath. + path := pkgNameOf(g.info, decl).Imported().Path() + + ipkg := readImportFile(g.target, path) if ipkg == ir.Pkgs.Unsafe { p.importedUnsafe = true } @@ -55,6 +60,14 @@ func (g *irgen) importDecl(p *noder, decl *syntax.ImportDecl) { } } +// pkgNameOf returns the PkgName associated with the given ImportDecl. +func pkgNameOf(info *types2.Info, decl *syntax.ImportDecl) *types2.PkgName { + if name := decl.LocalPkgName; name != nil { + return info.Defs[name].(*types2.PkgName) + } + return info.Implicits[decl].(*types2.PkgName) +} + func (g *irgen) constDecl(out *ir.Nodes, decl *syntax.ConstDecl) { g.pragmaFlags(decl.Pragma, 0) diff --git a/src/cmd/compile/internal/noder/import.go b/src/cmd/compile/internal/noder/import.go index c4a57806ebf..24d911ba381 100644 --- a/src/cmd/compile/internal/noder/import.go +++ b/src/cmd/compile/internal/noder/import.go @@ -175,36 +175,44 @@ func resolveImportPath(path string) (string, error) { return path, nil } -// TODO(mdempsky): Return an error instead. func importfile(decl *syntax.ImportDecl) *types.Pkg { - if decl.Path.Kind != syntax.StringLit { - base.Errorf("import path must be a string") - return nil - } - - path, err := strconv.Unquote(decl.Path.Value) - if err != nil { - base.Errorf("import path must be a string") - return nil - } - - if err := checkImportPath(path, false); err != nil { - base.Errorf("%s", err.Error()) - return nil - } - - path, err = resolveImportPath(path) + path, err := parseImportPath(decl.Path) if err != nil { base.Errorf("%s", err) return nil } + pkg := readImportFile(typecheck.Target, path) + if pkg != ir.Pkgs.Unsafe && pkg.Height >= myheight { + myheight = pkg.Height + 1 + } + return pkg +} + +func parseImportPath(pathLit *syntax.BasicLit) (string, error) { + if pathLit.Kind != syntax.StringLit { + return "", errors.New("import path must be a string") + } + + path, err := strconv.Unquote(pathLit.Value) + if err != nil { + return "", errors.New("import path must be a string") + } + + if err := checkImportPath(path, false); err != nil { + return "", err + } + + return resolveImportPath(path) +} + +func readImportFile(target *ir.Package, path string) *types.Pkg { importpkg := types.NewPkg(path, "") if importpkg.Direct { return importpkg // already fully loaded } importpkg.Direct = true - typecheck.Target.Imports = append(typecheck.Target.Imports, importpkg) + target.Imports = append(target.Imports, importpkg) if path == "unsafe" { return importpkg // initialized with universe @@ -324,10 +332,6 @@ func importfile(decl *syntax.ImportDecl) *types.Pkg { base.Ctxt.AddImport(file[len(file)-len(path)-len(".a"):], fingerprint) } - if importpkg.Height >= myheight { - myheight = importpkg.Height + 1 - } - return importpkg } diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go index f02246111fc..abaaa8cbb04 100644 --- a/src/cmd/compile/internal/noder/irgen.go +++ b/src/cmd/compile/internal/noder/irgen.go @@ -98,6 +98,7 @@ type irgen struct { func (g *irgen) generate(noders []*noder) { types.LocalPkg.Name = g.self.Name() + types.LocalPkg.Height = g.self.Height() typecheck.TypecheckAllowed = true // Prevent size calculations until we set the underlying type @@ -132,8 +133,6 @@ Outer: } } } - assert(myheight == g.self.Height()) - types.LocalPkg.Height = myheight // 2. Process all package-block type declarations. As with imports, // we need to make sure all types are properly instantiated before From 3de3440fb9b2d7f8a14b33f96fcfcee8eb61ec55 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 27 May 2021 22:27:55 -0400 Subject: [PATCH 203/940] go/ast: remove FuncDecl.IsMethod for Go 1.17 The IsMethod method was added to FuncDecl in the process of working on support for type parameters, but is now only used in one place. It also didn't go through the proposal process. Remove it for 1.17. Also clean up a doc comment that mentioned type parameters. Fixes #46297 Change-Id: I432bdd626324f613baf059540b7c5436985b2b16 Reviewed-on: https://go-review.googlesource.com/c/go/+/323369 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/ast/ast.go | 6 +----- src/go/types/resolver.go | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/go/ast/ast.go b/src/go/ast/ast.go index c87529ec77d..337c87fd797 100644 --- a/src/go/ast/ast.go +++ b/src/go/ast/ast.go @@ -259,7 +259,7 @@ func (f *FieldList) End() token.Pos { return token.NoPos } -// NumFields returns the number of (type) parameters or struct fields represented by a FieldList. +// NumFields returns the number of parameters or struct fields represented by a FieldList. func (f *FieldList) NumFields() int { n := 0 if f != nil { @@ -973,10 +973,6 @@ type ( } ) -func (f *FuncDecl) IsMethod() bool { - return f.Recv.NumFields() != 0 -} - // Pos and End implementations for declaration nodes. func (d *BadDecl) Pos() token.Pos { return d.From } diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go index f67fc65cd18..114647a2fff 100644 --- a/src/go/types/resolver.go +++ b/src/go/types/resolver.go @@ -383,7 +383,7 @@ func (check *Checker) collectObjects() { info := &declInfo{file: fileScope, fdecl: d.decl} name := d.decl.Name.Name obj := NewFunc(d.decl.Name.Pos(), pkg, name, nil) - if !d.decl.IsMethod() { + if d.decl.Recv.NumFields() == 0 { // regular function if d.decl.Recv != nil { check.error(d.decl.Recv, _BadRecv, "method is missing receiver") From ccd9784edf556673a340f3a8d55d9a8c64b95f59 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 27 May 2021 16:16:37 -0700 Subject: [PATCH 204/940] doc/go1.17: document new debug/elf constant For #39677 For #44513 Change-Id: I8c4193fd4359b83e6739e7e30a3a42b5f21b0f1a Reviewed-on: https://go-review.googlesource.com/c/go/+/323275 Trust: Ian Lance Taylor Reviewed-by: Dmitri Shuralyov --- doc/go1.17.html | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/go1.17.html b/doc/go1.17.html index b3485a0ca64..4e847708e5c 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -373,6 +373,15 @@ Do not send CLs removing the interior tags from such phrases. +
debug/elf
+
+

+ The SHT_MIPS_ABIFLAGS + constant has been added. +

+
+
+
encoding/binary

From c295107708ad5fd26a78f9f1cb478f91aa7763e7 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 27 May 2021 16:24:49 -0700 Subject: [PATCH 205/940] doc/go1.17: mention new encoding/csv/Reader.FieldPos method For #44221 For #44513 Change-Id: I2d2d1c55255f4411c11fd51f0f3ae726cbf4d136 Reviewed-on: https://go-review.googlesource.com/c/go/+/323349 Trust: Ian Lance Taylor Reviewed-by: roger peppe --- doc/go1.17.html | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/go1.17.html b/doc/go1.17.html index 4e847708e5c..9480b1205c3 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -393,6 +393,18 @@ Do not send CLs removing the interior tags from such phrases.

+
encoding/csv
+
+

+ The new + Reader.FieldPos + method returns the line and column corresponding to the start of + a given field in the record most recently returned by + Read. +

+
+
+
flag

From 6f58088bd84daef583f30dcfdb7c2b9179bfff3a Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 27 May 2021 17:19:12 -0700 Subject: [PATCH 206/940] doc/go1.17: document new go/build/BuildContext.ToolTags field For #44513 Change-Id: Ib21af742e574fcaa7e38bb437d42dbeed9d01f0b Reviewed-on: https://go-review.googlesource.com/c/go/+/323350 Trust: Ian Lance Taylor Reviewed-by: Dmitri Shuralyov --- doc/go1.17.html | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/go1.17.html b/doc/go1.17.html index 9480b1205c3..65d8efdc1b2 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -413,6 +413,17 @@ Do not send CLs removing the interior tags from such phrases.

+
go/build
+
+

+ The new + Context.ToolTags + field holds the build tags appropriate to the current Go + toolchain configuration. +

+
+
+
io/fs

From bbda92359289ae5992bbd8da9ce37932e531adda Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 27 May 2021 17:30:08 -0700 Subject: [PATCH 207/940] doc/go1.17: mention new Windows SysProcAttr fields For #44011 For #44513 Change-Id: I512466f2e775e36098eb36ca7ef82333cd9e632a Reviewed-on: https://go-review.googlesource.com/c/go/+/323352 Trust: Ian Lance Taylor Reviewed-by: Dmitri Shuralyov --- doc/go1.17.html | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/go1.17.html b/doc/go1.17.html index 65d8efdc1b2..3e9587dbf7b 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -611,6 +611,15 @@ Do not send CLs removing the interior tags from such phrases. On Unix-like systems, the process group of a child process is now set with signals blocked. This avoids sending a SIGTTOU to the child when the parent is in a background process group.

+ +

+ The Windows version of + SysProcAttr + has two new fields. AdditionalInheritedHandles is + a list of additional handles to be inherited by the new child + process. ParentProcess permits specifying the + parent process of the new process. +

From 6624771c8346d69ef41526b1134c505bca399340 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 27 May 2021 17:33:01 -0700 Subject: [PATCH 208/940] doc/go1.17: mention testing.[TB].Setenv methods For #41260 For #44513 Change-Id: I47ac0c751dafeb05abfe66fdf77938774164915f Reviewed-on: https://go-review.googlesource.com/c/go/+/323353 Trust: Ian Lance Taylor Reviewed-by: roger peppe --- doc/go1.17.html | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/go1.17.html b/doc/go1.17.html index 3e9587dbf7b..9d775e169ae 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -628,6 +628,14 @@ Do not send CLs removing the interior tags from such phrases.

TODO: https://golang.org/cl/310033: add -shuffle=off|on|N to alter the execution order of tests and benchmarks

+ +

+ The new + T.Setenv + and B.Setenv + methods support setting an environment variable for the duration + of the test or benchmark. +

From 1419ca7cead4438c8c9f17d8901aeecd9c72f577 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 27 May 2021 17:25:43 -0700 Subject: [PATCH 209/940] doc/go1.17: mention new definitions of MSG_CMSG_CLOEXEC For #44513 Change-Id: I8c0070b116ee520a76726eb9d3dcbdd489a1fb1f Reviewed-on: https://go-review.googlesource.com/c/go/+/323351 Trust: Ian Lance Taylor Reviewed-by: Tobias Klauser Reviewed-by: Dmitri Shuralyov --- doc/go1.17.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/go1.17.html b/doc/go1.17.html index 9d775e169ae..3395c4e6700 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -619,6 +619,11 @@ Do not send CLs removing the interior tags from such phrases. a list of additional handles to be inherited by the new child process. ParentProcess permits specifying the parent process of the new process. + +

+ The constant MSG_CMSG_CLOEXEC is now defined on + DragonFly and all OpenBSD systems (it was already defined on + some OpenBSD systems and all FreeBSD, NetBSD, and Linux systems).

From f6cc392d1ddd53a003c413fba4c1fc244ce2d85e Mon Sep 17 00:00:00 2001 From: Ariel Mashraki Date: Mon, 19 Apr 2021 22:26:47 +0300 Subject: [PATCH 210/940] doc/go1.17: document text/template/parse.SkipFuncCheck Documents the newly added mode that skips type checking functions as per CL 301493. Fixes #46025 For #34652 For #44513 For #38627 Change-Id: I56c4f65924702a931944796e39f43cfeb66abc8a Reviewed-on: https://go-review.googlesource.com/c/go/+/311569 Reviewed-by: Ian Lance Taylor Reviewed-by: Emmanuel Odeke Trust: Michael Knyszek --- doc/go1.17.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 3395c4e6700..3805a4c14e0 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -647,7 +647,8 @@ Do not send CLs removing the interior tags from such phrases.
text/template/parse

- TODO: https://golang.org/cl/301493: add a mode to skip func-check on parsing + The new SkipFuncCheck Mode + value changes the template parser to not verify that functions are defined.

From 79bda650410c8617f0ae20dc552c6d5b8f8dcfc8 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 28 May 2021 17:32:15 -0700 Subject: [PATCH 211/940] doc/go1.17: mention time.Layout For #44513 Change-Id: Id4624e977654f7e8c489508a9dce98c9fab621a6 Reviewed-on: https://go-review.googlesource.com/c/go/+/323490 Trust: Ian Lance Taylor Reviewed-by: Rob Pike --- doc/go1.17.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/go1.17.html b/doc/go1.17.html index 3805a4c14e0..02a58f89844 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -673,6 +673,11 @@ Do not send CLs removing the interior tags from such phrases.

TODO: https://golang.org/cl/300996: support "," as separator for fractional seconds

+ +

+ The new constant Layout + defines the reference time. +

From 1607c2817241bd141af9331a3e6c3148e5cd5d8b Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 28 May 2021 11:58:05 -0400 Subject: [PATCH 212/940] go/types: unexport the GoVersion configuration option for Go 1.17 The GoVersion field was added to types.Config as part of the work on type parameters. Specifically, it was added to be consistent with cmd/compile/internal/types2, which requires such an option. This configuration option is useful, but is also non-trivial and did not go through the proposal process. Unexport it for Go 1.17; we can create a proposal to export it for Go 1.18. Fixes #46296 Change-Id: Id82d8a7096887dcfc404c4d6d8da9c761b316609 Reviewed-on: https://go-review.googlesource.com/c/go/+/323430 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/api.go | 4 ++-- src/go/types/check.go | 4 ++-- src/go/types/check_test.go | 2 +- src/go/types/stdlib_test.go | 3 ++- src/go/types/types_test.go | 6 ++++++ 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/go/types/api.go b/src/go/types/api.go index ed62a785d6c..8c0d9d22bf2 100644 --- a/src/go/types/api.go +++ b/src/go/types/api.go @@ -101,12 +101,12 @@ type ImporterFrom interface { // A Config specifies the configuration for type checking. // The zero value for Config is a ready-to-use default configuration. type Config struct { - // GoVersion describes the accepted Go language version. The string + // goVersion describes the accepted Go language version. The string // must follow the format "go%d.%d" (e.g. "go1.12") or it must be // empty; an empty string indicates the latest language version. // If the format is invalid, invoking the type checker will cause a // panic. - GoVersion string + goVersion string // If IgnoreFuncBodies is set, function bodies are not // type-checked. diff --git a/src/go/types/check.go b/src/go/types/check.go index 25ea4906be3..a923c3c6121 100644 --- a/src/go/types/check.go +++ b/src/go/types/check.go @@ -179,9 +179,9 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch info = new(Info) } - version, err := parseGoVersion(conf.GoVersion) + version, err := parseGoVersion(conf.goVersion) if err != nil { - panic(fmt.Sprintf("invalid Go version %q (%v)", conf.GoVersion, err)) + panic(fmt.Sprintf("invalid Go version %q (%v)", conf.goVersion, err)) } return &Checker{ diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go index c5dc93eade6..9c71277264b 100644 --- a/src/go/types/check_test.go +++ b/src/go/types/check_test.go @@ -240,7 +240,7 @@ func checkFiles(t *testing.T, sizes Sizes, goVersion string, filenames []string, // typecheck and collect typechecker errors var conf Config conf.Sizes = sizes - conf.GoVersion = goVersion + SetGoVersion(&conf, goVersion) // special case for importC.src if len(filenames) == 1 { diff --git a/src/go/types/stdlib_test.go b/src/go/types/stdlib_test.go index 3dea8dcf1ed..503d0a6f445 100644 --- a/src/go/types/stdlib_test.go +++ b/src/go/types/stdlib_test.go @@ -134,7 +134,8 @@ func testTestDir(t *testing.T, path string, ignore ...string) { // parse and type-check file file, err := parser.ParseFile(fset, filename, nil, 0) if err == nil { - conf := Config{GoVersion: goVersion, Importer: stdLibImporter} + conf := Config{Importer: stdLibImporter} + SetGoVersion(&conf, goVersion) _, err = conf.Check(filename, fset, []*ast.File{file}, nil) } diff --git a/src/go/types/types_test.go b/src/go/types/types_test.go index fd9462c4a27..25cd9966282 100644 --- a/src/go/types/types_test.go +++ b/src/go/types/types_test.go @@ -11,3 +11,9 @@ import "sync/atomic" // for tests where we may want to have a consistent // numbering for each individual test case. func ResetId() { atomic.StoreUint32(&lastId, 0) } + +// SetGoVersion sets the unexported goVersion field on config, so that tests +// which assert on behavior for older Go versions can set it. +func SetGoVersion(config *Config, goVersion string) { + config.goVersion = goVersion +} From 3b770f2ccb1fa6fecc22ea822a19447b10b70c5c Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Sat, 29 May 2021 22:14:12 -0400 Subject: [PATCH 213/940] go/types: don't declare 'comparable' when typeparams are disabled Fixes #46453 Change-Id: I92b9b1e43ec5182162b2eeeb667f1f548ea373a5 Reviewed-on: https://go-review.googlesource.com/c/go/+/323609 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/check_test.go | 8 ++++++++ src/go/types/universe.go | 5 ++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go index 9c71277264b..6c3b630a1b6 100644 --- a/src/go/types/check_test.go +++ b/src/go/types/check_test.go @@ -330,6 +330,14 @@ func TestIndexRepresentability(t *testing.T) { checkFiles(t, &StdSizes{4, 4}, "", []string{"index.go"}, [][]byte{[]byte(src)}, false) } +func TestIssue46453(t *testing.T) { + if typeparams.Enabled { + t.Skip("type params are enabled") + } + const src = "package p\ntype _ comparable // ERROR \"undeclared name: comparable\"" + checkFiles(t, nil, "", []string{"issue46453.go"}, [][]byte{[]byte(src)}, false) +} + func TestCheck(t *testing.T) { DefPredeclaredTestFuncs(); testDir(t, "check") } func TestExamples(t *testing.T) { testDir(t, "examples") } func TestFixedbugs(t *testing.T) { testDir(t, "fixedbugs") } diff --git a/src/go/types/universe.go b/src/go/types/universe.go index 7c211fa6f7e..d7feb2c609e 100644 --- a/src/go/types/universe.go +++ b/src/go/types/universe.go @@ -8,6 +8,7 @@ package types import ( "go/constant" + "go/internal/typeparams" "go/token" "strings" ) @@ -237,7 +238,9 @@ func init() { defPredeclaredConsts() defPredeclaredNil() defPredeclaredFuncs() - defPredeclaredComparable() + if typeparams.Enabled { + defPredeclaredComparable() + } universeIota = Universe.Lookup("iota").(*Const) universeByte = Universe.Lookup("byte").(*TypeName).typ.(*Basic) From f32f4f58d9cd9d15371ee6198c1b222bcf2b56d9 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Sun, 30 May 2021 18:13:36 -0700 Subject: [PATCH 214/940] [dev.typeparams] cmd/compile: simplify formatting of defined types The existing code for deciding how to format defined type names is incredibly convoluted and difficult to follow. In particular, I'm looking at changing how Vargen works, and I couldn't tell from the existing code whether my idea was viable. This CL overhauls the logic to be much simpler with fewer special cases, while overall behaving the same. A few notable intentional differences from how the current code works: 1. The old code replaced the 'S' verb for fmtTypeGo and fmtTypeDebug to 'v', whereas the new code leaves it alone. There's currently no code that actually uses 'S' with these modes anyway, so it doesn't seem important to maintain this special case. If future code wants 'v' formatting, it should just use 'v' instead of 'S'. 2. The old code included Vargen for fmtTypeIDName mode with the 'S' verb; but again, this functionality isn't actually used. I think it would make sense for fmtTypeIDName to include Vargen like fmtTypeID does (Vargen is logically part of the type's identity after all), but that breaks tests and toolstash -cmp. So for now, this is left as a TODO to investigate in the future. 3. The old code only added Vargen for fmtTypeID in 'v' mode when printing types from the local package. But because we don't currently support exporting function-scoped defined types anyway, this is again irrelevant. In fact, once we *do* support exporting function-scoped defined types, we'll need to include Vargen to generate the linker symbols correctly. Passes toolstash -cmp. Change-Id: I4e481276bc4dc8d5b17eebf597b612737f26be5b Reviewed-on: https://go-review.googlesource.com/c/go/+/323709 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/types/fmt.go | 35 +++++++++------------------ 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/src/cmd/compile/internal/types/fmt.go b/src/cmd/compile/internal/types/fmt.go index b538ea80542..cecd1b3cc1c 100644 --- a/src/cmd/compile/internal/types/fmt.go +++ b/src/cmd/compile/internal/types/fmt.go @@ -319,31 +319,20 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type // Unless the 'L' flag was specified, if the type has a name, just print that name. if verb != 'L' && t.Sym() != nil && t != Types[t.Kind()] { - switch mode { - case fmtTypeID, fmtTypeIDName: - if verb == 'S' { - if t.Vargen != 0 { - sconv2(b, t.Sym(), 'S', mode) - fmt.Fprintf(b, "·%d", t.Vargen) - return - } - sconv2(b, t.Sym(), 'S', mode) - return - } - - if mode == fmtTypeIDName { - sconv2(b, t.Sym(), 'v', fmtTypeIDName) - return - } - - if t.Sym().Pkg == LocalPkg && t.Vargen != 0 { - sconv2(b, t.Sym(), 'v', mode) - fmt.Fprintf(b, "·%d", t.Vargen) - return - } + // Default to 'v' if verb is invalid. + if verb != 'S' { + verb = 'v' } - sconv2(b, t.Sym(), 'v', mode) + sconv2(b, t.Sym(), verb, mode) + + // TODO(mdempsky): Investigate including Vargen in fmtTypeIDName + // output too. It seems like it should, but that mode is currently + // used in string representation used by reflection, which is + // user-visible and doesn't expect this. + if mode == fmtTypeID && t.Vargen != 0 { + fmt.Fprintf(b, "·%d", t.Vargen) + } return } From 0b80cf11366f28ef5d0d8bae9c46813e96ffd071 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Wed, 26 May 2021 15:29:39 -0400 Subject: [PATCH 215/940] cmd/go: make 'go get' save sums for incidentally updated modules When 'go get' updates a module, it may update another module in the build list that provides a package in 'all' that wasn't loaded as part of the 'go get' command. If 'go get' doesn't add a sum for that module, builds may fail later. With this change, 'go get' will fetch a sum for the content of an updated module if we had a sum for the version before the update. 'go get' won't load the complete package graph, so there are still cases where the build may be broken, like when an updated (but not loaded) package imports a package from a new module. Fixes #44129 Change-Id: I62eba3df4137a3e84e2ca8d549c36eec3670f08c Reviewed-on: https://go-review.googlesource.com/c/go/+/322832 Trust: Jay Conrod Trust: Bryan C. Mills Run-TryBot: Jay Conrod Reviewed-by: Bryan C. Mills TryBot-Result: Go Bot --- src/cmd/go/internal/modget/get.go | 54 +++++++- .../script/mod_get_update_unrelated_sum.txt | 120 ++++++++++++++++++ 2 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 src/cmd/go/testdata/script/mod_get_update_unrelated_sum.txt diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go index 563f1a988f0..8eee723f89b 100644 --- a/src/cmd/go/internal/modget/get.go +++ b/src/cmd/go/internal/modget/get.go @@ -38,6 +38,7 @@ import ( "cmd/go/internal/base" "cmd/go/internal/imports" "cmd/go/internal/load" + "cmd/go/internal/modfetch" "cmd/go/internal/modload" "cmd/go/internal/par" "cmd/go/internal/search" @@ -1466,6 +1467,8 @@ func (r *resolver) chooseArbitrarily(cs pathSet) (isPackage bool, m module.Versi // checkPackageProblems reloads packages for the given patterns and reports // missing and ambiguous package errors. It also reports retractions and // deprecations for resolved modules and modules needed to build named packages. +// It also adds a sum for each updated module in the build list if we had one +// before and didn't get one while loading packages. // // We skip missing-package errors earlier in the process, since we want to // resolve pathSets ourselves, but at that point, we don't have enough context @@ -1593,9 +1596,52 @@ func (r *resolver) checkPackageProblems(ctx context.Context, pkgPatterns []strin }) } + // Load sums for updated modules that had sums before. When we update a + // module, we may update another module in the build list that provides a + // package in 'all' that wasn't loaded as part of this 'go get' command. + // If we don't add a sum for that module, builds may fail later. + // Note that an incidentally updated package could still import packages + // from unknown modules or from modules in the build list that we didn't + // need previously. We can't handle that case without loading 'all'. + sumErrs := make([]error, len(r.buildList)) + for i := range r.buildList { + i := i + m := r.buildList[i] + mActual := m + if mRepl := modload.Replacement(m); mRepl.Path != "" { + mActual = mRepl + } + old := module.Version{Path: m.Path, Version: r.initialVersion[m.Path]} + if old.Version == "" { + continue + } + oldActual := old + if oldRepl := modload.Replacement(old); oldRepl.Path != "" { + oldActual = oldRepl + } + if mActual == oldActual || mActual.Version == "" || !modfetch.HaveSum(oldActual) { + continue + } + r.work.Add(func() { + if _, err := modfetch.DownloadZip(ctx, mActual); err != nil { + verb := "upgraded" + if semver.Compare(m.Version, old.Version) < 0 { + verb = "downgraded" + } + replaced := "" + if mActual != m { + replaced = fmt.Sprintf(" (replaced by %s)", mActual) + } + err = fmt.Errorf("%s %s %s => %s%s: error finding sum for %s: %v", verb, m.Path, old.Version, m.Version, replaced, mActual, err) + sumErrs[i] = err + } + }) + } + <-r.work.Idle() - // Report deprecations, then retractions. + // Report deprecations, then retractions, then errors fetching sums. + // Only errors fetching sums are hard errors. for _, mm := range deprecations { if mm.message != "" { fmt.Fprintf(os.Stderr, "go: module %s is deprecated: %s\n", mm.m.Path, mm.message) @@ -1615,6 +1661,12 @@ func (r *resolver) checkPackageProblems(ctx context.Context, pkgPatterns []strin if retractPath != "" { fmt.Fprintf(os.Stderr, "go: to switch to the latest unretracted version, run:\n\tgo get %s@latest\n", retractPath) } + for _, err := range sumErrs { + if err != nil { + base.Errorf("go: %v", err) + } + } + base.ExitIfErrors() } // reportChanges logs version changes to os.Stderr. diff --git a/src/cmd/go/testdata/script/mod_get_update_unrelated_sum.txt b/src/cmd/go/testdata/script/mod_get_update_unrelated_sum.txt new file mode 100644 index 00000000000..0093c0eda0c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_update_unrelated_sum.txt @@ -0,0 +1,120 @@ +# Check that 'go get' adds sums for updated modules if we had sums before, +# even if we didn't load packages from them. +# Verifies #44129. + +env fmt='{{.ImportPath}}: {{if .Error}}{{.Error.Err}}{{else}}ok{{end}}' + +# Control case: before upgrading, we have the sums we need. +# go list -deps -e -f $fmt . +# stdout '^rsc.io/quote: ok$' +# ! stdout rsc.io/sampler # not imported by quote in this version +cp go.mod.orig go.mod +cp go.sum.orig go.sum +go mod tidy +cmp go.mod.orig go.mod +cmp go.sum.orig go.sum + + +# Upgrade a module. This also upgrades rsc.io/quote, and though we didn't load +# a package from it, we had the sum for its old version, so we need the +# sum for the new version, too. +go get -d example.com/upgrade@v0.0.2 +grep '^rsc.io/quote v1.5.2 ' go.sum + +# The upgrade still breaks the build because the new version of quote imports +# rsc.io/sampler, and we don't have its zip sum. +go list -deps -e -f $fmt +stdout 'rsc.io/quote: ok' +stdout 'rsc.io/sampler: missing go.sum entry for module providing package rsc.io/sampler' +cp go.mod.orig go.mod +cp go.sum.orig go.sum + + +# Replace the old version with a directory before upgrading. +# We didn't need a sum for it before (even though we had one), so we won't +# fetch a new sum. +go mod edit -replace rsc.io/quote@v1.0.0=./dummy +go get -d example.com/upgrade@v0.0.2 +! grep '^rsc.io/quote v1.5.2 ' go.sum +cp go.mod.orig go.mod +cp go.sum.orig go.sum + + +# Replace the new version with a directory before upgrading. +# We can't get a sum for a directory. +go mod edit -replace rsc.io/quote@v1.5.2=./dummy +go get -d example.com/upgrade@v0.0.2 +! grep '^rsc.io/quote v1.5.2 ' go.sum +cp go.mod.orig go.mod +cp go.sum.orig go.sum + + +# Replace the new version with a different version. +# We should get a sum for that version. +go mod edit -replace rsc.io/quote@v1.5.2=rsc.io/quote@v1.5.1 +go get -d example.com/upgrade@v0.0.2 +! grep '^rsc.io/quote v1.5.2 ' go.sum +grep '^rsc.io/quote v1.5.1 ' go.sum +cp go.mod.orig go.mod +cp go.sum.orig go.sum + + +# Delete the new version's zip (but not mod) from the cache and go offline. +# 'go get' should fail when fetching the zip. +rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip +env GOPROXY=off +! go get -d example.com/upgrade@v0.0.2 +stderr '^go: upgraded rsc.io/quote v1.0.0 => v1.5.2: error finding sum for rsc.io/quote@v1.5.2: module lookup disabled by GOPROXY=off$' + +-- go.mod.orig -- +module m + +go 1.16 + +require ( + example.com/upgrade v0.0.1 + rsc.io/quote v1.0.0 +) + +replace ( + example.com/upgrade v0.0.1 => ./upgrade1 + example.com/upgrade v0.0.2 => ./upgrade2 +) +-- go.sum.orig -- +rsc.io/quote v1.0.0 h1:kQ3IZQzPTiDJxSZI98YaWgxFEhlNdYASHvh+MplbViw= +rsc.io/quote v1.0.0/go.mod h1:v83Ri/njykPcgJltBc/gEkJTmjTsNgtO1Y7vyIK1CQA= +-- go.sum.want -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.0.0 h1:kQ3IZQzPTiDJxSZI98YaWgxFEhlNdYASHvh+MplbViw= +rsc.io/quote v1.0.0/go.mod h1:v83Ri/njykPcgJltBc/gEkJTmjTsNgtO1Y7vyIK1CQA= +rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +-- use.go -- +package use + +import ( + _ "example.com/upgrade" + _ "rsc.io/quote" +) +-- upgrade1/go.mod -- +module example.com/upgrade + +go 1.16 +-- upgrade1/upgrade.go -- +package upgrade +-- upgrade2/go.mod -- +module example.com/upgrade + +go 1.16 + +require rsc.io/quote v1.5.2 // indirect +-- upgrade2/upgrade.go -- +package upgrade +-- dummy/go.mod -- +module rsc.io/quote + +go 1.16 +-- dummy/quote.go -- +package quote + From 2e59cc5fb4e81fbd2ee9f662caa707c1138bf5ae Mon Sep 17 00:00:00 2001 From: Vitaly Zdanevich Date: Sat, 29 May 2021 13:49:51 +0000 Subject: [PATCH 216/940] cmd/go: add [-src] to documentation Change-Id: I554b5021386575af6ff44571a95bb31b38a0547f GitHub-Last-Rev: 20aaec3aa0baee6112fc2e4d72e83f78b72a44ea GitHub-Pull-Request: golang/go#45956 Reviewed-on: https://go-review.googlesource.com/c/go/+/317109 Run-TryBot: Jay Conrod TryBot-Result: Go Bot Reviewed-by: Jay Conrod Trust: Bryan C. Mills --- src/cmd/go/alldocs.go | 2 +- src/cmd/go/internal/doc/doc.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index bad2b7f16ef..ab61017c4eb 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -293,7 +293,7 @@ // // Usage: // -// go doc [-u] [-c] [package|[package.]symbol[.methodOrField]] +// go doc [doc flags] [package|[package.]symbol[.methodOrField]] // // Doc prints the documentation comments associated with the item identified by its // arguments (a package, const, func, type, var, method, or struct field) diff --git a/src/cmd/go/internal/doc/doc.go b/src/cmd/go/internal/doc/doc.go index 67f76e22563..8580a5dc4d2 100644 --- a/src/cmd/go/internal/doc/doc.go +++ b/src/cmd/go/internal/doc/doc.go @@ -13,7 +13,7 @@ import ( var CmdDoc = &base.Command{ Run: runDoc, - UsageLine: "go doc [-u] [-c] [package|[package.]symbol[.methodOrField]]", + UsageLine: "go doc [doc flags] [package|[package.]symbol[.methodOrField]]", CustomFlags: true, Short: "show documentation for package or symbol", Long: ` From 2bec019fb5a7d379772c29be6e3487640d43e6fa Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 27 May 2021 10:13:00 -0400 Subject: [PATCH 217/940] doc/go1.17: add release notes for register ABI Also delete the TODO for the linker section. Updates #44513. Updates #40724. Change-Id: I4d62a907e8c3070831a052cdfe1e21648698df12 Reviewed-on: https://go-review.googlesource.com/c/go/+/323289 Trust: Cherry Mui Reviewed-by: Michael Knyszek Reviewed-by: Jeremy Faller --- doc/go1.17.html | 52 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 02a58f89844..ee498f76035 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -226,31 +226,57 @@ Do not send CLs removing the interior tags from such phrases.

Runtime

-

- TODO: https://golang.org/cl/304470: cmd/compile, runtime: add metadata for argument printing in traceback -

-

TODO: complete the Runtime section

Compiler

-

+

+ Go 1.17 implements a new way of passing function arguments and results using + registers instead of the stack. This work is enabled for Linux, MacOS, and + Windows on the 64-bit x86 architecture (the linux/amd64, + darwin/amd64, windows/amd64 ports). For a + representative set of Go packages and programs, benchmarking has shown + performance improvements of about 5%, and a typical reduction in binary size + of about 2%. +

+

+ This change does not affect the functionality of any safe Go code. It can affect + code outside the compatibility guidelines with + minimal impact. To maintain compatibility with existing assembly functions, + adapter functions converting between the new register-based calling convention + and the previous stack-based calling convention (also known as ABI wrappers) + are sometimes used. This is mostly invisible to users, except for assembly + functions that have their addresses taken in Go. Using reflect.ValueOf(fn).Pointer() + (or similar approaches such as via unsafe.Pointer) to get the address + of an assembly function will now return the address of the ABI wrapper. This is + mostly harmless, except for special-purpose assembly code (such as accessing + thread-local storage or requiring a special stack alignment). Assembly functions + called indirectly from Go via func values will now be made through + ABI wrappers, which may cause a very small performance overhead. Also, calling + Go functions from assembly may now go through ABI wrappers, with a very small + performance overhead. +

+ +

+ The format of stack traces from the runtime (printed when an uncaught panic + occurs, or when runtime.Stack is called) is improved. Previously, + the function arguments were printed as hexadecimal words based on the memory + layout. Now each argument in the source code is printed separately, separated + by commas. Aggregate-typed (struct, array, string, slice, interface, and complex) + arguments are delimited by curly braces. A caveat is that the value of an + argument that only lives in a register and is not stored to memory may be + inaccurate. Results (which were usually inaccurate) are no longer printed. +

+ +

Functions containing closures can now be inlined. One effect of this change is that a function with a closure may actually produce a distinct closure function for each place that the function is inlined. Hence, this change could reveal bugs where Go functions are compared (incorrectly) by pointer value. Go functions are by definition not comparable. - - TODO: complete the Compiler section, or delete if not needed -

- -

Linker

- -

- TODO: complete the Linker section, or delete if not needed

Core library

From 272552275f56345095b4ea7f404e5b317856cf07 Mon Sep 17 00:00:00 2001 From: OneOfOne Date: Fri, 21 May 2021 15:29:46 -0500 Subject: [PATCH 218/940] A+C: update name Change-Id: I1f88304858da5147bfd082c2fc2b7d24ed371cd8 Reviewed-on: https://go-review.googlesource.com/c/go/+/321955 Reviewed-by: Russ Cox Reviewed-by: Ian Lance Taylor --- AUTHORS | 2 +- CONTRIBUTORS | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 48ce71f4cc6..95d3158d204 100644 --- a/AUTHORS +++ b/AUTHORS @@ -41,7 +41,7 @@ Aeneas Rekkas (arekkas) Afanasev Stanislav Agis Anastasopoulos Agniva De Sarker -Ahmed Wahed +Ahmed W. Mones Ahmet Soormally Ahmy Yulrizka Aiden Scandella diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 6c7262adb1f..ee50a4c049a 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -67,7 +67,7 @@ Aeneas Rekkas (arekkas) Afanasev Stanislav Agis Anastasopoulos Agniva De Sarker -Ahmed Wahed +Ahmed W. Mones Ahmet Alp Balkan Ahmet Soormally Ahmy Yulrizka From 4b10e4c5473560539c6a6470e45391e8b9a9e786 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Tue, 1 Jun 2021 00:56:14 +0700 Subject: [PATCH 219/940] [dev.typeparams] cmd/compile: handle ONONAME in subster.node Fixes #46472 Change-Id: I27802978fa0c3bb32a29e452165a6fcac93473bb Reviewed-on: https://go-review.googlesource.com/c/go/+/323731 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/noder/stencil.go | 3 +++ test/typeparam/issue46472.go | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 test/typeparam/issue46472.go diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index e273a80b20f..36a6f2e6d02 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -350,6 +350,9 @@ func (subst *subster) node(n ir.Node) ir.Node { return v } return x + case ir.ONONAME: + // This handles the identifier in a type switch guard + fallthrough case ir.OLITERAL, ir.ONIL: if x.Sym() != nil { return x diff --git a/test/typeparam/issue46472.go b/test/typeparam/issue46472.go new file mode 100644 index 00000000000..bab48e7d2f5 --- /dev/null +++ b/test/typeparam/issue46472.go @@ -0,0 +1,20 @@ +// run -gcflags=-G=3 + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func foo[T any](d T) { + switch v := interface{}(d).(type) { + case string: + if v != "x" { + panic("unexpected v: "+v) + } + } + +} +func main() { + foo("x") +} From 2580e9a16049c12fbd0b058c4dc08cb7b0fdd08f Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 27 May 2021 02:47:25 -0700 Subject: [PATCH 220/940] [dev.typeparams] cmd/compile: refactor noder/irgen helpers This CL refactors the code for invoking the types2 checker and for validating //go:embed directives to be easier to reuse separately. No functional change. Change-Id: I706f4ea4a26b1f1d2f4064befcc0777a1067383d Reviewed-on: https://go-review.googlesource.com/c/go/+/323310 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Dan Scales Trust: Matthew Dempsky --- src/cmd/compile/internal/noder/irgen.go | 33 ++++++++++----- src/cmd/compile/internal/noder/noder.go | 49 +++++++++++----------- src/cmd/compile/internal/noder/types.go | 55 +++++++++++++------------ 3 files changed, 75 insertions(+), 62 deletions(-) diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go index abaaa8cbb04..d5ef0c0ef46 100644 --- a/src/cmd/compile/internal/noder/irgen.go +++ b/src/cmd/compile/internal/noder/irgen.go @@ -18,9 +18,9 @@ import ( "cmd/internal/src" ) -// check2 type checks a Go package using types2, and then generates IR -// using the results. -func check2(noders []*noder) { +// checkFiles configures and runs the types2 checker on the given +// parsed source files and then returns the result. +func checkFiles(noders []*noder, importer types2.Importer) (posMap, *types2.Package, *types2.Info) { if base.SyntaxErrors() != 0 { base.ErrorExit() } @@ -42,12 +42,10 @@ func check2(noders []*noder) { terr := err.(types2.Error) base.ErrorfAt(m.makeXPos(terr.Pos), "%s", terr.Msg) }, - Importer: &gcimports{ - packages: make(map[string]*types2.Package), - }, - Sizes: &gcSizes{}, + Importer: importer, + Sizes: &gcSizes{}, } - info := types2.Info{ + info := &types2.Info{ Types: make(map[syntax.Expr]types2.TypeAndValue), Defs: make(map[*syntax.Name]types2.Object), Uses: make(map[*syntax.Name]types2.Object), @@ -57,12 +55,25 @@ func check2(noders []*noder) { Inferred: make(map[syntax.Expr]types2.Inferred), // expand as needed } - pkg, err := conf.Check(base.Ctxt.Pkgpath, files, &info) - files = nil + + pkg, err := conf.Check(base.Ctxt.Pkgpath, files, info) base.ExitIfErrors() if err != nil { base.FatalfAt(src.NoXPos, "conf.Check error: %v", err) } + + return m, pkg, info +} + +// check2 type checks a Go package using types2, and then generates IR +// using the results. +func check2(noders []*noder) { + importer := &gcimports{ + packages: make(map[string]*types2.Package), + } + + m, pkg, info := checkFiles(noders, importer) + if base.Flag.G < 2 { os.Exit(0) } @@ -70,7 +81,7 @@ func check2(noders []*noder) { g := irgen{ target: typecheck.Target, self: pkg, - info: &info, + info: info, posMap: m, objs: make(map[types2.Object]*ir.Name), typs: make(map[types2.Type]*types.Type), diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go index 44385f34fd1..2fb852b1843 100644 --- a/src/cmd/compile/internal/noder/noder.go +++ b/src/cmd/compile/internal/noder/noder.go @@ -5,6 +5,7 @@ package noder import ( + "errors" "fmt" "go/constant" "go/token" @@ -1852,33 +1853,14 @@ func oldname(s *types.Sym) ir.Node { } func varEmbed(makeXPos func(syntax.Pos) src.XPos, name *ir.Name, decl *syntax.VarDecl, pragma *pragmas, haveEmbed bool) { - if pragma.Embeds == nil { - return - } - pragmaEmbeds := pragma.Embeds pragma.Embeds = nil - pos := makeXPos(pragmaEmbeds[0].Pos) + if len(pragmaEmbeds) == 0 { + return + } - if !haveEmbed { - base.ErrorfAt(pos, "go:embed only allowed in Go files that import \"embed\"") - return - } - if len(decl.NameList) > 1 { - base.ErrorfAt(pos, "go:embed cannot apply to multiple vars") - return - } - if decl.Values != nil { - base.ErrorfAt(pos, "go:embed cannot apply to var with initializer") - return - } - if decl.Type == nil { - // Should not happen, since Values == nil now. - base.ErrorfAt(pos, "go:embed cannot apply to var without type") - return - } - if typecheck.DeclContext != ir.PEXTERN { - base.ErrorfAt(pos, "go:embed cannot apply to var inside func") + if err := checkEmbed(decl, haveEmbed, typecheck.DeclContext != ir.PEXTERN); err != nil { + base.ErrorfAt(makeXPos(pragmaEmbeds[0].Pos), "%s", err) return } @@ -1889,3 +1871,22 @@ func varEmbed(makeXPos func(syntax.Pos) src.XPos, name *ir.Name, decl *syntax.Va typecheck.Target.Embeds = append(typecheck.Target.Embeds, name) name.Embed = &embeds } + +func checkEmbed(decl *syntax.VarDecl, haveEmbed, withinFunc bool) error { + switch { + case !haveEmbed: + return errors.New("go:embed only allowed in Go files that import \"embed\"") + case len(decl.NameList) > 1: + return errors.New("go:embed cannot apply to multiple vars") + case decl.Values != nil: + return errors.New("go:embed cannot apply to var with initializer") + case decl.Type == nil: + // Should not happen, since Values == nil now. + return errors.New("go:embed cannot apply to var without type") + case withinFunc: + return errors.New("go:embed cannot apply to var inside func") + + default: + return nil + } +} diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go index ae10e03a247..f34cf146bbd 100644 --- a/src/cmd/compile/internal/noder/types.go +++ b/src/cmd/compile/internal/noder/types.go @@ -390,38 +390,39 @@ func (g *irgen) selector(obj types2.Object) *types.Sym { // particular types is because go/types does *not* report it for // them. So in practice this limitation is probably moot. func (g *irgen) tpkg(typ types2.Type) *types.Pkg { - anyObj := func() types2.Object { - switch typ := typ.(type) { - case *types2.Signature: - if recv := typ.Recv(); recv != nil { - return recv - } - if params := typ.Params(); params.Len() > 0 { - return params.At(0) - } - if results := typ.Results(); results.Len() > 0 { - return results.At(0) - } - case *types2.Struct: - if typ.NumFields() > 0 { - return typ.Field(0) - } - case *types2.Interface: - if typ.NumExplicitMethods() > 0 { - return typ.ExplicitMethod(0) - } - case *types2.TypeParam: - return typ.Obj() - } - return nil - } - - if obj := anyObj(); obj != nil { + if obj := anyObj(typ); obj != nil { return g.pkg(obj.Pkg()) } return types.LocalPkg } +// anyObj returns some object accessible from typ, if any. +func anyObj(typ types2.Type) types2.Object { + switch typ := typ.(type) { + case *types2.Signature: + if recv := typ.Recv(); recv != nil { + return recv + } + if params := typ.Params(); params.Len() > 0 { + return params.At(0) + } + if results := typ.Results(); results.Len() > 0 { + return results.At(0) + } + case *types2.Struct: + if typ.NumFields() > 0 { + return typ.Field(0) + } + case *types2.Interface: + if typ.NumExplicitMethods() > 0 { + return typ.ExplicitMethod(0) + } + case *types2.TypeParam: + return typ.Obj() + } + return nil +} + func (g *irgen) basic(typ *types2.Basic) *types.Type { switch typ.Name() { case "byte": From 24e9707cbfa6b1ed6abdd4b11f9ddaf3aac5ad88 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 25 May 2021 16:31:41 -0700 Subject: [PATCH 221/940] cmd/link, cmd/cgo: support -flto in CFLAGS The linker now accepts unrecognized object files in external linking mode. These objects will simply be passed to the external linker. This permits using -flto which can generate pure byte code objects, whose symbol table the linker does not know how to read. The cgo tool now passes -fno-lto when generating objects whose symbols it needs to read. The cgo tool now emits matching types in different objects, so that the lto linker does not report a mismatch. This is based on https://golang.org/cl/293290 by Derek Parker. For #43505 Fixes #43830 Fixes #46295 Change-Id: I6787de213417466784ddef5af8899e453b4ae1ad Reviewed-on: https://go-review.googlesource.com/c/go/+/322614 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Michael Hudson-Doyle --- src/cmd/cgo/gcc.go | 2 + src/cmd/cgo/out.go | 16 ++++++-- src/cmd/dist/test.go | 29 ++++++++++---- .../testdata/script/cgo_lto2_issue43830.txt | 33 ++++++++++++++++ .../go/testdata/script/cgo_lto_issue43830.txt | 39 +++++++++++++++++++ src/cmd/link/internal/ld/ar.go | 4 ++ src/cmd/link/internal/ld/config.go | 6 ++- src/cmd/link/internal/ld/lib.go | 26 +++++++++++-- 8 files changed, 140 insertions(+), 15 deletions(-) create mode 100644 src/cmd/go/testdata/script/cgo_lto2_issue43830.txt create mode 100644 src/cmd/go/testdata/script/cgo_lto_issue43830.txt diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index ae61725bc75..a73e998877a 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -1638,6 +1638,8 @@ func (p *Package) gccCmd() []string { c = append(c, "-maix64") c = append(c, "-mcmodel=large") } + // disable LTO so we get an object whose symbols we can read + c = append(c, "-fno-lto") c = append(c, "-") //read input from standard input return c } diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 8c31d5b7941..94152f4278c 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -168,8 +168,18 @@ func (p *Package) writeDefs() { if *gccgo { fmt.Fprintf(fc, "extern byte *%s;\n", n.C) } else { - fmt.Fprintf(fm, "extern char %s[];\n", n.C) - fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C) + // Force a reference to all symbols so that + // the external linker will add DT_NEEDED + // entries as needed on ELF systems. + // Treat function variables differently + // to avoid type confict errors from LTO + // (Link Time Optimization). + if n.Kind == "fpvar" { + fmt.Fprintf(fm, "extern void %s();\n", n.C) + } else { + fmt.Fprintf(fm, "extern char %s[];\n", n.C) + fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C) + } fmt.Fprintf(fgo2, "//go:linkname __cgo_%s %s\n", n.C, n.C) fmt.Fprintf(fgo2, "//go:cgo_import_static %s\n", n.C) fmt.Fprintf(fgo2, "var __cgo_%s byte\n", n.C) @@ -1042,7 +1052,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { // This unpacks the argument struct above and calls the Go function. fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a *%s) {\n", cPrefix, exp.ExpName, gotype) - fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName) + fmt.Fprintf(fm, "void _cgoexp%s_%s(void* p){}\n", cPrefix, exp.ExpName) if gccResult != "void" { // Write results back to frame. diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 50bf80ba596..bc49c6d8040 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -722,14 +722,29 @@ func (t *tester) registerTests() { }, }) if t.hasCxx() { - t.tests = append(t.tests, distTest{ - name: "swig_callback", - heading: "../misc/swig/callback", - fn: func(dt *distTest) error { - t.addCmd(dt, "misc/swig/callback", t.goTest()) - return nil + t.tests = append(t.tests, + distTest{ + name: "swig_callback", + heading: "../misc/swig/callback", + fn: func(dt *distTest) error { + t.addCmd(dt, "misc/swig/callback", t.goTest()) + return nil + }, }, - }) + distTest{ + name: "swig_callback_lto", + heading: "../misc/swig/callback", + fn: func(dt *distTest) error { + cmd := t.addCmd(dt, "misc/swig/callback", t.goTest()) + cmd.Env = append(os.Environ(), + "CGO_CFLAGS=-flto", + "CGO_CXXFLAGS=-flto", + "CGO_LDFLAGS=-flto", + ) + return nil + }, + }, + ) } } } diff --git a/src/cmd/go/testdata/script/cgo_lto2_issue43830.txt b/src/cmd/go/testdata/script/cgo_lto2_issue43830.txt new file mode 100644 index 00000000000..e2483ba784d --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_lto2_issue43830.txt @@ -0,0 +1,33 @@ +# tests golang.org/issue/43830 + +[!cgo] skip 'skipping test without cgo' +[openbsd] env CC='clang' +[openbsd] [!exec:clang] skip 'skipping test without clang present' +[!openbsd] env CC='gcc' +[!openbsd] [!exec:gcc] skip 'skipping test without gcc present' + +env CGO_CFLAGS='-Wno-ignored-optimization-argument -flto -ffat-lto-objects' + +go build main.go + +-- main.go -- + +package main + +import "fmt" + +// #include "hello.h" +import "C" + +func main() { + hello := C.hello + fmt.Printf("%v\n", hello) +} + +-- hello.h -- + +#include + +void hello(void) { + printf("hello\n"); +} diff --git a/src/cmd/go/testdata/script/cgo_lto_issue43830.txt b/src/cmd/go/testdata/script/cgo_lto_issue43830.txt new file mode 100644 index 00000000000..06ab2f34c9d --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_lto_issue43830.txt @@ -0,0 +1,39 @@ +# tests golang.org/issue/43830 + +[!cgo] skip 'skipping test without cgo' +[openbsd] env CC='clang' +[openbsd] [!exec:clang] skip 'skipping test without clang present' +[!openbsd] env CC='gcc' +[!openbsd] [!exec:gcc] skip 'skipping test without gcc present' + +env CGO_CFLAGS='-Wno-ignored-optimization-argument -flto -ffat-lto-objects' + +go build main.go add.go + +-- main.go -- + +package main + +/* +int c_add(int a, int b) { + return myadd(a, b); +} +*/ +import "C" + +func main() { + println(C.c_add(1, 2)) +} + +-- add.go -- + +package main + +import "C" + +/* test */ + +//export myadd +func myadd(a C.int, b C.int) C.int { + return a + b +} diff --git a/src/cmd/link/internal/ld/ar.go b/src/cmd/link/internal/ld/ar.go index 22f53a4df2e..23915f90329 100644 --- a/src/cmd/link/internal/ld/ar.go +++ b/src/cmd/link/internal/ld/ar.go @@ -124,6 +124,10 @@ func hostArchive(ctxt *Link, name string) { libgcc := sym.Library{Pkg: "libgcc"} h := ldobj(ctxt, f, &libgcc, l, pname, name) + if h.ld == nil { + Errorf(nil, "%s unrecognized object file at offset %d", name, off) + continue + } f.MustSeek(h.off, 0) h.ld(ctxt, f, h.pkg, h.length, h.pn) } diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go index ae0d7520ebc..20f1d0b8c12 100644 --- a/src/cmd/link/internal/ld/config.go +++ b/src/cmd/link/internal/ld/config.go @@ -241,6 +241,10 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) { return true, "dynamically linking with a shared library" } + if unknownObjFormat { + return true, "some input objects have an unrecognized file format" + } + return false, "" } @@ -248,7 +252,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) { // // It is called after flags are processed and inputs are processed, // so the ctxt.LinkMode variable has an initial value from the -linkmode -// flag and the iscgo externalobj variables are set. +// flag and the iscgo, externalobj, and unknownObjFormat variables are set. func determineLinkMode(ctxt *Link) { extNeeded, extReason := mustLinkExternal(ctxt) via := "" diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index e8f001ba8ec..644faeb2fbc 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -343,10 +343,16 @@ var ( const pkgdef = "__.PKGDEF" var ( - // Set if we see an object compiled by the host compiler that is not - // from a package that is known to support internal linking mode. + // externalobj is set to true if we see an object compiled by + // the host compiler that is not from a package that is known + // to support internal linking mode. externalobj = false - theline string + + // unknownObjFormat is set to true if we see an object whose + // format we don't recognize. + unknownObjFormat = false + + theline string ) func Lflag(ctxt *Link, arg string) { @@ -1065,6 +1071,10 @@ func hostobjs(ctxt *Link) { } f.MustSeek(h.off, 0) + if h.ld == nil { + Errorf(nil, "%s: unrecognized object file format", h.pn) + continue + } h.ld(ctxt, f, h.pkg, h.length, h.pn) f.Close() } @@ -1855,6 +1865,14 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string, return ldhostobj(ldxcoff, ctxt.HeadType, f, pkg, length, pn, file) } + if c1 != 'g' || c2 != 'o' || c3 != ' ' || c4 != 'o' { + // An unrecognized object is just passed to the external linker. + // If we try to read symbols from this object, we will + // report an error at that time. + unknownObjFormat = true + return ldhostobj(nil, ctxt.HeadType, f, pkg, length, pn, file) + } + /* check the header */ line, err := f.ReadString('\n') if err != nil { @@ -1874,7 +1892,7 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string, return nil } - Errorf(nil, "%s: not an object file: @%d %02x%02x%02x%02x", pn, start, c1, c2, c3, c4) + Errorf(nil, "%s: not an object file: @%d %q", pn, start, line) return nil } From 567ee865f690cde59d5aeadc04bcc926d2316db8 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 1 Jun 2021 13:47:42 -0700 Subject: [PATCH 222/940] cmd/go: add declaration to cgo_lto_issue43830 test This permits the test to work in C99 mode. For #43830 Change-Id: Ide54bd62239cfe602e2664300f04e472df5daf43 Reviewed-on: https://go-review.googlesource.com/c/go/+/324009 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor Reviewed-by: Cherry Mui TryBot-Result: Go Bot --- src/cmd/go/testdata/script/cgo_lto_issue43830.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cmd/go/testdata/script/cgo_lto_issue43830.txt b/src/cmd/go/testdata/script/cgo_lto_issue43830.txt index 06ab2f34c9d..8bc7d8a540f 100644 --- a/src/cmd/go/testdata/script/cgo_lto_issue43830.txt +++ b/src/cmd/go/testdata/script/cgo_lto_issue43830.txt @@ -15,6 +15,7 @@ go build main.go add.go package main /* +extern int myadd(int, int); int c_add(int a, int b) { return myadd(a, b); } From 8e7abefdaaa3c00c35cfe04b787225926f70affe Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Fri, 28 May 2021 22:23:00 -0400 Subject: [PATCH 223/940] [dev.typeparams] cmd/compile: update ARM64 CALL* ops for register ABI Now they take variable number of args. Change-Id: I49c8bce9c3a403947eac03e397ae264a8f4fdd2c Reviewed-on: https://go-review.googlesource.com/c/go/+/323929 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: David Chase --- src/cmd/compile/internal/ssa/gen/ARM64Ops.go | 6 +++--- src/cmd/compile/internal/ssa/opGen.go | 6 +++--- src/cmd/compile/internal/ssa/rewriteARM64.go | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go index a91ece1c9f9..414c429db65 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go @@ -482,9 +482,9 @@ func init() { {name: "CSETM", argLength: 1, reg: readflags, asm: "CSETM", aux: "CCop"}, // auxint(flags) ? -1 : 0 // function calls - {name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem - {name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R26"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem - {name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem + {name: "CALLstatic", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). last arg=mem, auxint=argsize, returns mem + {name: "CALLclosure", argLength: -1, reg: regInfo{inputs: []regMask{gpsp, buildReg("R26"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, last arg=mem, auxint=argsize, returns mem + {name: "CALLinter", argLength: -1, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, last arg=mem, auxint=argsize, returns mem // pseudo-ops {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil. arg1=mem. diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index cf31dfacf60..df15c2edda4 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -20664,7 +20664,7 @@ var opcodeTable = [...]opInfo{ { name: "CALLstatic", auxType: auxCallOff, - argLen: 1, + argLen: -1, clobberFlags: true, call: true, reg: regInfo{ @@ -20674,7 +20674,7 @@ var opcodeTable = [...]opInfo{ { name: "CALLclosure", auxType: auxCallOff, - argLen: 3, + argLen: -1, clobberFlags: true, call: true, reg: regInfo{ @@ -20688,7 +20688,7 @@ var opcodeTable = [...]opInfo{ { name: "CALLinter", auxType: auxCallOff, - argLen: 2, + argLen: -1, clobberFlags: true, call: true, reg: regInfo{ diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go index 3cdc4d36cb5..debe5f2c2a6 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM64.go +++ b/src/cmd/compile/internal/ssa/rewriteARM64.go @@ -25997,7 +25997,7 @@ func rewriteValueARM64_OpSelectN(v *Value) bool { break } call := v_0 - if call.Op != OpARM64CALLstatic { + if call.Op != OpARM64CALLstatic || len(call.Args) != 1 { break } sym := auxToCall(call.Aux) From e4003463fff6a90d331c0a2da92774941693a4f7 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Fri, 28 May 2021 22:32:41 -0400 Subject: [PATCH 224/940] [dev.typeparams] cmd/compile: match register-ABI version of memmove call on ARM64 Update the rule to match register-ABI version of the call for inlining memmove. Change-Id: Ic6da810e4d7ac391ffb766fcdc943985f0739624 Reviewed-on: https://go-review.googlesource.com/c/go/+/323930 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: David Chase --- src/cmd/compile/internal/ssa/gen/ARM64.rules | 9 +++++++ src/cmd/compile/internal/ssa/rewriteARM64.go | 28 ++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules index 62699f290c2..530e48bcb25 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM64.rules +++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules @@ -2868,3 +2868,12 @@ && isInlinableMemmove(dst, src, sz, config) && clobber(s1, s2, s3, call) => (Move [sz] dst src mem) + +// Match post-lowering calls, register version. +(SelectN [0] call:(CALLstatic {sym} dst src (MOVDconst [sz]) mem)) + && sz >= 0 + && isSameCall(sym, "runtime.memmove") + && call.Uses == 1 + && isInlinableMemmove(dst, src, sz, config) + && clobber(call) + => (Move [sz] dst src mem) diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go index debe5f2c2a6..f7840c55039 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM64.go +++ b/src/cmd/compile/internal/ssa/rewriteARM64.go @@ -26031,6 +26031,34 @@ func rewriteValueARM64_OpSelectN(v *Value) bool { v.AddArg3(dst, src, mem) return true } + // match: (SelectN [0] call:(CALLstatic {sym} dst src (MOVDconst [sz]) mem)) + // cond: sz >= 0 && isSameCall(sym, "runtime.memmove") && call.Uses == 1 && isInlinableMemmove(dst, src, sz, config) && clobber(call) + // result: (Move [sz] dst src mem) + for { + if auxIntToInt64(v.AuxInt) != 0 { + break + } + call := v_0 + if call.Op != OpARM64CALLstatic || len(call.Args) != 4 { + break + } + sym := auxToCall(call.Aux) + mem := call.Args[3] + dst := call.Args[0] + src := call.Args[1] + call_2 := call.Args[2] + if call_2.Op != OpARM64MOVDconst { + break + } + sz := auxIntToInt64(call_2.AuxInt) + if !(sz >= 0 && isSameCall(sym, "runtime.memmove") && call.Uses == 1 && isInlinableMemmove(dst, src, sz, config) && clobber(call)) { + break + } + v.reset(OpMove) + v.AuxInt = int64ToAuxInt(sz) + v.AddArg3(dst, src, mem) + return true + } return false } func rewriteValueARM64_OpSlicemask(v *Value) bool { From 6633dc8b0982173064c587f0b5e98f0b16f2132a Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 27 May 2021 18:41:12 -0400 Subject: [PATCH 225/940] [dev.typeparams] reflect: call ABI0 spill/unspill functions on AMD64 CL 321950 changed runtime.spillArgs and unspillArgs to ABI0. References to those functions should have been updated to ABI0, but this one was missed. Change-Id: I99238e4a96c945a47bec0981a415037578c73de4 Reviewed-on: https://go-review.googlesource.com/c/go/+/323931 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek Reviewed-by: David Chase --- src/reflect/asm_amd64.s | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/reflect/asm_amd64.s b/src/reflect/asm_amd64.s index 7491c772acd..d21d498063b 100644 --- a/src/reflect/asm_amd64.s +++ b/src/reflect/asm_amd64.s @@ -59,7 +59,7 @@ TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$312 // NO_LOCAL_POINTERS is a lie. The stack map for the two locals in this // frame is specially handled in the runtime. See the comment above LOCAL_RETVALID. LEAQ LOCAL_REGARGS(SP), R12 - CALL runtime·spillArgs(SB) + CALL runtime·spillArgs(SB) MOVQ DX, 24(SP) // outside of moveMakeFuncArgPtrs's arg area MOVQ DX, 0(SP) MOVQ R12, 8(SP) @@ -75,5 +75,5 @@ TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$312 MOVQ AX, 24(SP) CALL ·callMethod(SB) LEAQ LOCAL_REGARGS(SP), R12 - CALL runtime·unspillArgs(SB) + CALL runtime·unspillArgs(SB) RET From c3639918d1c319e34bbb67b506394e8ee4d2fc6c Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 27 May 2021 18:22:49 -0400 Subject: [PATCH 226/940] [dev.typeparams] internal/abi: define ARM64 register ABI constants Change-Id: I9cdf0f2b6c1739f13a859a8e37351f8ecd77804a Reviewed-on: https://go-review.googlesource.com/c/go/+/323932 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/internal/abi/abi_arm64.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/internal/abi/abi_arm64.go diff --git a/src/internal/abi/abi_arm64.go b/src/internal/abi/abi_arm64.go new file mode 100644 index 00000000000..7544d7506ed --- /dev/null +++ b/src/internal/abi/abi_arm64.go @@ -0,0 +1,20 @@ +// Copyright 2021 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 goexperiment.regabireflect +// +build goexperiment.regabireflect + +package abi + +const ( + // See abi_generic.go. + + // R0 - R15. + IntArgRegs = 16 + + // F0 - F15. + FloatArgRegs = 16 + + EffectiveFloatRegSize = 8 +) From 58ad36b3592d3267ab9d9e0a91adecac08445028 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 27 May 2021 16:56:02 -0400 Subject: [PATCH 227/940] [dev.typeparams] internal/buildcfg: allow regabi GOEXPERIMENTs on ARM64 It is not working yet, but allow enabling the experiments so we can develop. Change-Id: I957eb05acb4d80b2858ff1f8c16bbfb24e0f6e56 Reviewed-on: https://go-review.googlesource.com/c/go/+/323933 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: David Chase --- src/internal/buildcfg/exp.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/internal/buildcfg/exp.go b/src/internal/buildcfg/exp.go index 11cd05f2ed0..196d6af4a60 100644 --- a/src/internal/buildcfg/exp.go +++ b/src/internal/buildcfg/exp.go @@ -98,8 +98,8 @@ func parseExperiments() goexperiment.Flags { } } - // regabi is only supported on amd64. - if GOARCH != "amd64" { + // regabi is only supported on amd64 and arm64. + if GOARCH != "amd64" && GOARCH != "arm64" { flags.RegabiWrappers = false flags.RegabiG = false flags.RegabiReflect = false From b1f48e8addb640b6cbfad56d790b7702ff9fd30d Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 1 Jun 2021 16:57:59 -0700 Subject: [PATCH 228/940] [dev.typeparams] cmd/compile: fix formatting Looks like CL 322850 didn't have the change to ARM64Ops.go properly gofmt'ed. Change-Id: I1a080bc13ea27b897fbb91f18ded754ce440994b Reviewed-on: https://go-review.googlesource.com/c/go/+/324109 Trust: Keith Randall Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/cmd/compile/internal/ssa/gen/ARM64Ops.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go index 414c429db65..5de0b5f0203 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go @@ -759,17 +759,17 @@ func init() { } archs = append(archs, arch{ - name: "ARM64", - pkg: "cmd/internal/obj/arm64", - genfile: "../../arm64/ssa.go", - ops: ops, - blocks: blocks, - regnames: regNamesARM64, + name: "ARM64", + pkg: "cmd/internal/obj/arm64", + genfile: "../../arm64/ssa.go", + ops: ops, + blocks: blocks, + regnames: regNamesARM64, ParamIntRegNames: "R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15", ParamFloatRegNames: "F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15", - gpregmask: gp, - fpregmask: fp, - framepointerreg: -1, // not used - linkreg: int8(num["R30"]), + gpregmask: gp, + fpregmask: fp, + framepointerreg: -1, // not used + linkreg: int8(num["R30"]), }) } From cae68700cc76d3118e470180a1cbeac616f3dfad Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 1 Jun 2021 17:00:22 -0700 Subject: [PATCH 229/940] runtime: fix formatting Fix up a gofmt complaint from CL 310591. Change-Id: I73534ef064a4cfc53539e5e65a8653e2cd684c64 Reviewed-on: https://go-review.googlesource.com/c/go/+/324090 Trust: Keith Randall Run-TryBot: Keith Randall Reviewed-by: Cherry Mui TryBot-Result: Go Bot --- src/runtime/internal/atomic/atomic_arm64.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/internal/atomic/atomic_arm64.go b/src/runtime/internal/atomic/atomic_arm64.go index 3c8736997f4..dbb1796ec09 100644 --- a/src/runtime/internal/atomic/atomic_arm64.go +++ b/src/runtime/internal/atomic/atomic_arm64.go @@ -8,8 +8,8 @@ package atomic import ( - "unsafe" "internal/cpu" + "unsafe" ) const ( From 84c0e5d47f46f2e1a7ce92341477d9801f0ef777 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 1 Jun 2021 14:58:36 -0700 Subject: [PATCH 230/940] cmd/link: move issue 43830 tests out of TestScript These tests pass or fail depending on the exact compiler version, which the TestScript tests don't support. Rewrite into Go. For #43830 For #46295 Change-Id: I91b61dfe329d518e461ee56f186f0e9b42858e77 Reviewed-on: https://go-review.googlesource.com/c/go/+/324049 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- .../testdata/script/cgo_lto2_issue43830.txt | 33 ----- .../go/testdata/script/cgo_lto_issue43830.txt | 40 ----- src/cmd/link/cgo_test.go | 138 ++++++++++++++++++ 3 files changed, 138 insertions(+), 73 deletions(-) delete mode 100644 src/cmd/go/testdata/script/cgo_lto2_issue43830.txt delete mode 100644 src/cmd/go/testdata/script/cgo_lto_issue43830.txt create mode 100644 src/cmd/link/cgo_test.go diff --git a/src/cmd/go/testdata/script/cgo_lto2_issue43830.txt b/src/cmd/go/testdata/script/cgo_lto2_issue43830.txt deleted file mode 100644 index e2483ba784d..00000000000 --- a/src/cmd/go/testdata/script/cgo_lto2_issue43830.txt +++ /dev/null @@ -1,33 +0,0 @@ -# tests golang.org/issue/43830 - -[!cgo] skip 'skipping test without cgo' -[openbsd] env CC='clang' -[openbsd] [!exec:clang] skip 'skipping test without clang present' -[!openbsd] env CC='gcc' -[!openbsd] [!exec:gcc] skip 'skipping test without gcc present' - -env CGO_CFLAGS='-Wno-ignored-optimization-argument -flto -ffat-lto-objects' - -go build main.go - --- main.go -- - -package main - -import "fmt" - -// #include "hello.h" -import "C" - -func main() { - hello := C.hello - fmt.Printf("%v\n", hello) -} - --- hello.h -- - -#include - -void hello(void) { - printf("hello\n"); -} diff --git a/src/cmd/go/testdata/script/cgo_lto_issue43830.txt b/src/cmd/go/testdata/script/cgo_lto_issue43830.txt deleted file mode 100644 index 8bc7d8a540f..00000000000 --- a/src/cmd/go/testdata/script/cgo_lto_issue43830.txt +++ /dev/null @@ -1,40 +0,0 @@ -# tests golang.org/issue/43830 - -[!cgo] skip 'skipping test without cgo' -[openbsd] env CC='clang' -[openbsd] [!exec:clang] skip 'skipping test without clang present' -[!openbsd] env CC='gcc' -[!openbsd] [!exec:gcc] skip 'skipping test without gcc present' - -env CGO_CFLAGS='-Wno-ignored-optimization-argument -flto -ffat-lto-objects' - -go build main.go add.go - --- main.go -- - -package main - -/* -extern int myadd(int, int); -int c_add(int a, int b) { - return myadd(a, b); -} -*/ -import "C" - -func main() { - println(C.c_add(1, 2)) -} - --- add.go -- - -package main - -import "C" - -/* test */ - -//export myadd -func myadd(a C.int, b C.int) C.int { - return a + b -} diff --git a/src/cmd/link/cgo_test.go b/src/cmd/link/cgo_test.go new file mode 100644 index 00000000000..09390daeb7e --- /dev/null +++ b/src/cmd/link/cgo_test.go @@ -0,0 +1,138 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "bytes" + "fmt" + "internal/testenv" + "os" + "os/exec" + "path/filepath" + "testing" +) + +// Issues 43830, 46295 +func TestCGOLTO(t *testing.T) { + testenv.MustHaveCGO(t) + testenv.MustHaveGoBuild(t) + + t.Parallel() + + for _, cc := range []string{"gcc", "clang"} { + for test := 0; test < 2; test++ { + t.Run(fmt.Sprintf("%s-%d", cc, test), func(t *testing.T) { + testCGOLTO(t, cc, test) + }) + } + } +} + +const test1_main = ` +package main + +/* +extern int myadd(int, int); +int c_add(int a, int b) { + return myadd(a, b); +} +*/ +import "C" + +func main() { + println(C.c_add(1, 2)) +} +` + +const test1_add = ` +package main + +import "C" + +/* test */ + +//export myadd +func myadd(a C.int, b C.int) C.int { + return a + b +} +` + +const test2_main = ` +package main + +import "fmt" + +/* +#include + +void hello(void) { + printf("hello\n"); +} +*/ +import "C" + +func main() { + hello := C.hello + fmt.Printf("%v\n", hello) +} +` + +func testCGOLTO(t *testing.T, cc string, test int) { + t.Parallel() + + if _, err := exec.LookPath(cc); err != nil { + t.Skipf("no %s compiler", cc) + } + + dir := t.TempDir() + + writeTempFile := func(name, contents string) { + if err := os.WriteFile(filepath.Join(dir, name), []byte(contents), 0644); err != nil { + t.Fatal(err) + } + } + + writeTempFile("go.mod", "module cgolto\n") + + switch test { + case 0: + writeTempFile("main.go", test1_main) + writeTempFile("add.go", test1_add) + case 1: + writeTempFile("main.go", test2_main) + default: + t.Fatalf("bad case %d", test) + } + + cmd := exec.Command(testenv.GoToolPath(t), "build") + cmd.Dir = dir + cmd.Env = append(os.Environ(), + "CC="+cc, + "CGO_CFLAGS=-flto", + ) + + t.Log("go build") + out, err := cmd.CombinedOutput() + t.Logf("%s", out) + + if err != nil { + t.Logf("go build failed: %v", err) + + // Error messages we've seen indicating that LTO is not supported. + var noLTO = []string{ + `unrecognized command line option "-flto"`, + "unable to pass LLVM bit-code files to linker", + "file not recognized: File format not recognized", + "LTO support has not been enabled", + } + for _, msg := range noLTO { + if bytes.Contains(out, []byte(msg)) { + t.Skipf("C compiler %v does not support LTO", cc) + } + } + + t.Error("failed") + } +} From d2b435117d3a1db612ad894125b8ab673a5a46ee Mon Sep 17 00:00:00 2001 From: Zachary Burkett Date: Sat, 29 May 2021 19:54:10 +0000 Subject: [PATCH 231/940] test: fix error check messages for 2 types2 tests Many compiler tests fail with -G=3 due to changes in error message format. This commit fixes two of these tests, to ensure I am on the right track in review. Updates #46447 Change-Id: I138956d536a1d48ca9198e6ddbfde13865bb5dd5 GitHub-Last-Rev: 0ed904b9fad5e6739fee02ab48c7bc66508d736b GitHub-Pull-Request: golang/go#46445 Reviewed-on: https://go-review.googlesource.com/c/go/+/323314 Reviewed-by: Matthew Dempsky Reviewed-by: Robert Griesemer Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot --- test/complit1.go | 14 +++++++------- test/ddd1.go | 10 +++++----- test/run.go | 2 -- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/test/complit1.go b/test/complit1.go index 7c2a4e2996d..8cbcd63ee0d 100644 --- a/test/complit1.go +++ b/test/complit1.go @@ -46,20 +46,20 @@ var ( _ = &T{0, 0, "", nil} // ok _ = &T{i: 0, f: 0, s: "", next: {}} // ERROR "missing type in composite literal|omit types within composite literal" _ = &T{0, 0, "", {}} // ERROR "missing type in composite literal|omit types within composite literal" - _ = TP{i: 0, f: 0, s: "", next: {}} // ERROR "invalid composite literal type TP|omit types within composite literal" + _ = TP{i: 0, f: 0, s: ""} // ERROR "invalid composite literal type TP" _ = &Ti{} // ERROR "invalid composite literal type Ti|expected.*type for composite literal" ) type M map[T]T var ( - _ = M{{i:1}: {i:2}} - _ = M{T{i:1}: {i:2}} - _ = M{{i:1}: T{i:2}} - _ = M{T{i:1}: T{i:2}} + _ = M{{i: 1}: {i: 2}} + _ = M{T{i: 1}: {i: 2}} + _ = M{{i: 1}: T{i: 2}} + _ = M{T{i: 1}: T{i: 2}} ) -type S struct { s [1]*M1 } +type S struct{ s [1]*M1 } type M1 map[S]int -var _ = M1{{s:[1]*M1{&M1{{}:1}}}:2} +var _ = M1{{s: [1]*M1{&M1{{}: 1}}}: 2} diff --git a/test/ddd1.go b/test/ddd1.go index ad49b347f49..f7381b7c946 100644 --- a/test/ddd1.go +++ b/test/ddd1.go @@ -17,8 +17,8 @@ var ( _ = sum(1, 2, 3) _ = sum() _ = sum(1.0, 2.0) - _ = sum(1.5) // ERROR "integer" - _ = sum("hello") // ERROR ".hello. .type untyped string. as type int|incompatible" + _ = sum(1.5) // ERROR "1\.5 .untyped float constant. as int|integer" + _ = sum("hello") // ERROR ".hello. (.untyped string constant. as int|.type untyped string. as type int)|incompatible" _ = sum([]int{1}) // ERROR "\[\]int{...}.*as type int|incompatible" ) @@ -27,9 +27,9 @@ func tuple() (int, int, int) { return 1, 2, 3 } var ( _ = sum(tuple()) - _ = sum(tuple()...) // ERROR "multiple-value" + _ = sum(tuple()...) // ERROR "\.{3} with 3-valued|multiple-value" _ = sum3(tuple()) - _ = sum3(tuple()...) // ERROR "multiple-value" ERROR "invalid use of .*[.][.][.]" + _ = sum3(tuple()...) // ERROR "\.{3} in call to non-variadic|multiple-value|invalid use of .*[.][.][.]" ) type T []T @@ -60,5 +60,5 @@ func bad(args ...int) { _ = [...]byte("foo") // ERROR "[.][.][.]" _ = [...][...]int{{1,2,3},{4,5,6}} // ERROR "[.][.][.]" - Foo(x...) // ERROR "invalid use of .*[.][.][.]" + Foo(x...) // ERROR "\.{3} in call to non-variadic|invalid use of .*[.][.][.]" } diff --git a/test/run.go b/test/run.go index cf1d3015989..ef1e9de1502 100644 --- a/test/run.go +++ b/test/run.go @@ -2023,8 +2023,6 @@ func overlayDir(dstRoot, srcRoot string) error { // List of files that the compiler cannot errorcheck with the new typechecker (compiler -G option). // Temporary scaffolding until we pass all the tests at which point this map can be removed. var excludedFiles = map[string]bool{ - "complit1.go": true, // types2 reports extra errors - "ddd1.go": true, // issue #42987 "directive.go": true, // misplaced compiler directive checks "float_lit3.go": true, // types2 reports extra errors "import1.go": true, // types2 reports extra errors From dc8f87b7493e173d65d3587389cc41468ba16dc0 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 1 Jun 2021 12:22:12 +0200 Subject: [PATCH 232/940] runtime/internal/sys: generate //go:build lines in gengoos.go For #41184 Change-Id: If7a1c3980f47bc28d0a13fe497eaba6178c65c91 Reviewed-on: https://go-review.googlesource.com/c/go/+/323750 Trust: Tobias Klauser Run-TryBot: Tobias Klauser TryBot-Result: Go Bot Reviewed-by: Russ Cox --- src/runtime/internal/sys/gengoos.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/runtime/internal/sys/gengoos.go b/src/runtime/internal/sys/gengoos.go index 51f64a6e5c6..ffe962f71df 100644 --- a/src/runtime/internal/sys/gengoos.go +++ b/src/runtime/internal/sys/gengoos.go @@ -48,18 +48,21 @@ func main() { if target == "nacl" { continue } - var buf bytes.Buffer - fmt.Fprintf(&buf, "// Code generated by gengoos.go using 'go generate'. DO NOT EDIT.\n\n") + var tags []string if target == "linux" { - fmt.Fprintf(&buf, "// +build !android\n") // must explicitly exclude android for linux + tags = append(tags, "!android") // must explicitly exclude android for linux } if target == "solaris" { - fmt.Fprintf(&buf, "// +build !illumos\n") // must explicitly exclude illumos for solaris + tags = append(tags, "!illumos") // must explicitly exclude illumos for solaris } if target == "darwin" { - fmt.Fprintf(&buf, "// +build !ios\n") // must explicitly exclude ios for darwin + tags = append(tags, "!ios") // must explicitly exclude ios for darwin } - fmt.Fprintf(&buf, "// +build %s\n\n", target) // must explicitly include target for bootstrapping purposes + tags = append(tags, target) // must explicitly include target for bootstrapping purposes + var buf bytes.Buffer + fmt.Fprintf(&buf, "// Code generated by gengoos.go using 'go generate'. DO NOT EDIT.\n\n") + fmt.Fprintf(&buf, "//go:build %s\n", strings.Join(tags, " && ")) + fmt.Fprintf(&buf, "// +build %s\n\n", strings.Join(tags, ",")) fmt.Fprintf(&buf, "package sys\n\n") fmt.Fprintf(&buf, "const GOOS = `%s`\n\n", target) for _, goos := range gooses { @@ -81,6 +84,7 @@ func main() { } var buf bytes.Buffer fmt.Fprintf(&buf, "// Code generated by gengoos.go using 'go generate'. DO NOT EDIT.\n\n") + fmt.Fprintf(&buf, "//go:build %s\n", target) fmt.Fprintf(&buf, "// +build %s\n\n", target) // must explicitly include target for bootstrapping purposes fmt.Fprintf(&buf, "package sys\n\n") fmt.Fprintf(&buf, "const GOARCH = `%s`\n\n", target) From d743e67e0695a8082f03fd90bb07e71cf9f34cf1 Mon Sep 17 00:00:00 2001 From: KimMachineGun Date: Sun, 23 May 2021 14:05:15 +0000 Subject: [PATCH 233/940] doc/go1.17: document flag changes for Go 1.17 For #44513 Fixes #46010 Change-Id: I1fe638e5db0b4f3b64dbfbd948154a7c7a80afc9 GitHub-Last-Rev: d5bd53b1df202329661ffb1818803f2ec1d3f57a GitHub-Pull-Request: golang/go#46150 Reviewed-on: https://go-review.googlesource.com/c/go/+/319273 Reviewed-by: Heschi Kreinick Trust: Robert Findley --- doc/go1.17.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index ee498f76035..6ddef3d47e0 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -434,7 +434,7 @@ Do not send CLs removing the interior tags from such phrases.
flag

- TODO: https://golang.org/cl/271788: panic if flag name begins with - or contains = + Flag declarations now panic if an invalid name is specified.

From 1c6a2ea2ea4b04416f7344ee5effe81816c7200b Mon Sep 17 00:00:00 2001 From: Uddeshya Singh Date: Fri, 7 May 2021 13:18:05 +0530 Subject: [PATCH 234/940] doc/go1.17: document time changes for Go1.17 Documents the newly implemented changes of - Time.IsDST() method - Addition of Time.UnixMilli, Time.UnixMicro and to-Time helpers UnixMicro, UnixMilli methods - Addition of comma "," support as separator for fraction seconds For #44513 Fixes #46026 Change-Id: Ib8d3449d3b061f013112d33362b50e68ad6ddffa Reviewed-on: https://go-review.googlesource.com/c/go/+/317913 Reviewed-by: Dmitri Shuralyov Reviewed-by: Ian Lance Taylor --- doc/go1.17.html | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 6ddef3d47e0..b287d41309f 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -689,15 +689,26 @@ Do not send CLs removing the interior tags from such phrases.

- TODO: https://golang.org/cl/264077: add Time.IsDST() to check if its Location is in Daylight Savings Time + The new Time.IsDST method can be used to check whether the time + is in Daylight Savings Time in its configured location.

- TODO: https://golang.org/cl/293349: add Time.Unix{Milli,Micro} and to-Time helpers UnixMicro, UnixMilli + The new Time.UnixMilli and + Time.UnixMicro methods return the number of milliseconds and + microseconds elapsed since January 1, 1970 UTC respectively.
+ The new UnixMilli and UnixMicro functions return local Time corresponding to given + Unix time.

- TODO: https://golang.org/cl/300996: support "," as separator for fractional seconds + The package now accepts comma "," as a separator for fractional seconds when parsing and formatting time. + The following time formats are now accepted: +

    +
  • 2006-01-02 14:06:03,999999999 -0700 MST
  • +
  • Mon Jan _2 14:06:03,120007 2006
  • +
  • Mon Jan 2 14:06:03,120007 2006
  • +

From ff9f5fb8591c6d3e4cd4881e75f49440a3a875c2 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 2 Jun 2021 07:43:57 -0700 Subject: [PATCH 235/940] cmd/link: recognize clang linker error in testCGOLTO Also recognize a case in which GCC does not run (from https://build.golang.org/log/7f6d8b35c905b9829f05906beccca44f208aa569). Fixes #46517 Change-Id: I4fe4164a5df92b2dec08fd767f65a4d5479f3f36 Reviewed-on: https://go-review.googlesource.com/c/go/+/324169 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills Reviewed-by: Tobias Klauser --- src/cmd/link/cgo_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cmd/link/cgo_test.go b/src/cmd/link/cgo_test.go index 09390daeb7e..26ab8024541 100644 --- a/src/cmd/link/cgo_test.go +++ b/src/cmd/link/cgo_test.go @@ -121,11 +121,14 @@ func testCGOLTO(t *testing.T, cc string, test int) { t.Logf("go build failed: %v", err) // Error messages we've seen indicating that LTO is not supported. + // These errors come from GCC or clang, not Go. var noLTO = []string{ `unrecognized command line option "-flto"`, "unable to pass LLVM bit-code files to linker", "file not recognized: File format not recognized", "LTO support has not been enabled", + "linker command failed with exit code", + "gcc: can't load library", } for _, msg := range noLTO { if bytes.Contains(out, []byte(msg)) { From 6e189afd3e7a3722c72b320ef604bf2910aee9e7 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 28 May 2021 17:28:12 -0700 Subject: [PATCH 236/940] doc/go1.17: mention SYS_WAIT6/WEXITED on NetBSD For #13987 For #16028 For #44513 Change-Id: I7a73446fcc80a01fa6de24eec1e5b993e543be37 Reviewed-on: https://go-review.googlesource.com/c/go/+/323489 Trust: Ian Lance Taylor Reviewed-by: Emmanuel Odeke --- doc/go1.17.html | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/go1.17.html b/doc/go1.17.html index b287d41309f..d80e68d4345 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -651,6 +651,14 @@ Do not send CLs removing the interior tags from such phrases. DragonFly and all OpenBSD systems (it was already defined on some OpenBSD systems and all FreeBSD, NetBSD, and Linux systems).

+ +

+ The constants SYS_WAIT6 and WEXITED + are now defined on NetBSD systems (SYS_WAIT6 was + already defined on DragonFly and FreeBSD systems; + WEXITED was already defined on Darwin, DragonFly, + FreeBSD, Linux, and Solaris systems). +

From dc2cb529a8c9e4b771163be1974ef39d76c3f548 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 27 May 2021 18:07:36 -0400 Subject: [PATCH 237/940] [dev.typeparams] runtime: mark assembly functions called directly from compiler ABIInternal For functions such as gcWriteBarrier and panicIndexXXX, the compiler generates ABIInternal calls directly. And they must not use wrappers because it follows a special calling convention or the caller's PC is used. Mark them as ABIInternal. Note that even though they are marked as ABIInternal, they don't actually use the internal ABI, i.e. regabiargs is not honored for now. Now all.bash passes with GOEXPERIMENT=regabiwrappers (at least on macOS). Change-Id: I87e41964e6dc4efae03e8eb636ae9fa1d99285bb Reviewed-on: https://go-review.googlesource.com/c/go/+/323934 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/cmd/internal/obj/arm64/obj7.go | 4 +- src/runtime/asm_arm64.s | 78 ++++++++++++++++-------------- src/runtime/duff_arm64.s | 4 +- src/runtime/mkduff.go | 4 +- src/runtime/race_arm64.s | 16 ++++-- 5 files changed, 60 insertions(+), 46 deletions(-) diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go index c94a0b67ee2..31b7c432451 100644 --- a/src/cmd/internal/obj/arm64/obj7.go +++ b/src/cmd/internal/obj/arm64/obj7.go @@ -325,9 +325,9 @@ func (c *ctxt7) rewriteToUseGot(p *obj.Prog) { // CALL REGTMP var sym *obj.LSym if p.As == obj.ADUFFZERO { - sym = c.ctxt.Lookup("runtime.duffzero") + sym = c.ctxt.LookupABI("runtime.duffzero", obj.ABIInternal) } else { - sym = c.ctxt.Lookup("runtime.duffcopy") + sym = c.ctxt.LookupABI("runtime.duffcopy", obj.ABIInternal) } offset := p.To.Offset p.As = AMOVD diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s index 2d495397a8d..ca04dddd5b9 100644 --- a/src/runtime/asm_arm64.s +++ b/src/runtime/asm_arm64.s @@ -103,7 +103,7 @@ nocgo: MOVD R0, (R0) // boom UNDEF -DATA runtime·mainPC+0(SB)/8,$runtime·main(SB) +DATA runtime·mainPC+0(SB)/8,$runtime·main(SB) GLOBL runtime·mainPC(SB),RODATA,$8 TEXT runtime·breakpoint(SB),NOSPLIT|NOFRAME,$0-0 @@ -1158,7 +1158,10 @@ TEXT ·checkASM(SB),NOSPLIT,$0-1 // It does not clobber any general-purpose registers, // but may clobber others (e.g., floating point registers) // The act of CALLing gcWriteBarrier will clobber R30 (LR). -TEXT runtime·gcWriteBarrier(SB),NOSPLIT,$200 +// +// Defined as ABIInternal since the compiler generates ABIInternal +// calls to it directly and it does not use the stack-based Go ABI. +TEXT runtime·gcWriteBarrier(SB),NOSPLIT,$200 // Save the registers clobbered by the fast path. MOVD R0, 184(RSP) MOVD R1, 192(RSP) @@ -1250,71 +1253,74 @@ flush: // in the caller's stack frame. These stubs write the args into that stack space and // then tail call to the corresponding runtime handler. // The tail call makes these stubs disappear in backtraces. -TEXT runtime·panicIndex(SB),NOSPLIT,$0-16 +// +// Defined as ABIInternal since the compiler generates ABIInternal +// calls to it directly and it does not use the stack-based Go ABI. +TEXT runtime·panicIndex(SB),NOSPLIT,$0-16 MOVD R0, x+0(FP) MOVD R1, y+8(FP) - JMP runtime·goPanicIndex(SB) -TEXT runtime·panicIndexU(SB),NOSPLIT,$0-16 + JMP runtime·goPanicIndex(SB) +TEXT runtime·panicIndexU(SB),NOSPLIT,$0-16 MOVD R0, x+0(FP) MOVD R1, y+8(FP) - JMP runtime·goPanicIndexU(SB) -TEXT runtime·panicSliceAlen(SB),NOSPLIT,$0-16 + JMP runtime·goPanicIndexU(SB) +TEXT runtime·panicSliceAlen(SB),NOSPLIT,$0-16 MOVD R1, x+0(FP) MOVD R2, y+8(FP) - JMP runtime·goPanicSliceAlen(SB) -TEXT runtime·panicSliceAlenU(SB),NOSPLIT,$0-16 + JMP runtime·goPanicSliceAlen(SB) +TEXT runtime·panicSliceAlenU(SB),NOSPLIT,$0-16 MOVD R1, x+0(FP) MOVD R2, y+8(FP) - JMP runtime·goPanicSliceAlenU(SB) -TEXT runtime·panicSliceAcap(SB),NOSPLIT,$0-16 + JMP runtime·goPanicSliceAlenU(SB) +TEXT runtime·panicSliceAcap(SB),NOSPLIT,$0-16 MOVD R1, x+0(FP) MOVD R2, y+8(FP) - JMP runtime·goPanicSliceAcap(SB) -TEXT runtime·panicSliceAcapU(SB),NOSPLIT,$0-16 + JMP runtime·goPanicSliceAcap(SB) +TEXT runtime·panicSliceAcapU(SB),NOSPLIT,$0-16 MOVD R1, x+0(FP) MOVD R2, y+8(FP) - JMP runtime·goPanicSliceAcapU(SB) -TEXT runtime·panicSliceB(SB),NOSPLIT,$0-16 + JMP runtime·goPanicSliceAcapU(SB) +TEXT runtime·panicSliceB(SB),NOSPLIT,$0-16 MOVD R0, x+0(FP) MOVD R1, y+8(FP) - JMP runtime·goPanicSliceB(SB) -TEXT runtime·panicSliceBU(SB),NOSPLIT,$0-16 + JMP runtime·goPanicSliceB(SB) +TEXT runtime·panicSliceBU(SB),NOSPLIT,$0-16 MOVD R0, x+0(FP) MOVD R1, y+8(FP) - JMP runtime·goPanicSliceBU(SB) -TEXT runtime·panicSlice3Alen(SB),NOSPLIT,$0-16 + JMP runtime·goPanicSliceBU(SB) +TEXT runtime·panicSlice3Alen(SB),NOSPLIT,$0-16 MOVD R2, x+0(FP) MOVD R3, y+8(FP) - JMP runtime·goPanicSlice3Alen(SB) -TEXT runtime·panicSlice3AlenU(SB),NOSPLIT,$0-16 + JMP runtime·goPanicSlice3Alen(SB) +TEXT runtime·panicSlice3AlenU(SB),NOSPLIT,$0-16 MOVD R2, x+0(FP) MOVD R3, y+8(FP) - JMP runtime·goPanicSlice3AlenU(SB) -TEXT runtime·panicSlice3Acap(SB),NOSPLIT,$0-16 + JMP runtime·goPanicSlice3AlenU(SB) +TEXT runtime·panicSlice3Acap(SB),NOSPLIT,$0-16 MOVD R2, x+0(FP) MOVD R3, y+8(FP) - JMP runtime·goPanicSlice3Acap(SB) -TEXT runtime·panicSlice3AcapU(SB),NOSPLIT,$0-16 + JMP runtime·goPanicSlice3Acap(SB) +TEXT runtime·panicSlice3AcapU(SB),NOSPLIT,$0-16 MOVD R2, x+0(FP) MOVD R3, y+8(FP) - JMP runtime·goPanicSlice3AcapU(SB) -TEXT runtime·panicSlice3B(SB),NOSPLIT,$0-16 + JMP runtime·goPanicSlice3AcapU(SB) +TEXT runtime·panicSlice3B(SB),NOSPLIT,$0-16 MOVD R1, x+0(FP) MOVD R2, y+8(FP) - JMP runtime·goPanicSlice3B(SB) -TEXT runtime·panicSlice3BU(SB),NOSPLIT,$0-16 + JMP runtime·goPanicSlice3B(SB) +TEXT runtime·panicSlice3BU(SB),NOSPLIT,$0-16 MOVD R1, x+0(FP) MOVD R2, y+8(FP) - JMP runtime·goPanicSlice3BU(SB) -TEXT runtime·panicSlice3C(SB),NOSPLIT,$0-16 + JMP runtime·goPanicSlice3BU(SB) +TEXT runtime·panicSlice3C(SB),NOSPLIT,$0-16 MOVD R0, x+0(FP) MOVD R1, y+8(FP) - JMP runtime·goPanicSlice3C(SB) -TEXT runtime·panicSlice3CU(SB),NOSPLIT,$0-16 + JMP runtime·goPanicSlice3C(SB) +TEXT runtime·panicSlice3CU(SB),NOSPLIT,$0-16 MOVD R0, x+0(FP) MOVD R1, y+8(FP) - JMP runtime·goPanicSlice3CU(SB) -TEXT runtime·panicSliceConvert(SB),NOSPLIT,$0-16 + JMP runtime·goPanicSlice3CU(SB) +TEXT runtime·panicSliceConvert(SB),NOSPLIT,$0-16 MOVD R2, x+0(FP) MOVD R3, y+8(FP) - JMP runtime·goPanicSliceConvert(SB) + JMP runtime·goPanicSliceConvert(SB) diff --git a/src/runtime/duff_arm64.s b/src/runtime/duff_arm64.s index 128b076af9d..33c4905078d 100644 --- a/src/runtime/duff_arm64.s +++ b/src/runtime/duff_arm64.s @@ -4,7 +4,7 @@ #include "textflag.h" -TEXT runtime·duffzero(SB), NOSPLIT|NOFRAME, $0-0 +TEXT runtime·duffzero(SB), NOSPLIT|NOFRAME, $0-0 STP.P (ZR, ZR), 16(R20) STP.P (ZR, ZR), 16(R20) STP.P (ZR, ZR), 16(R20) @@ -71,7 +71,7 @@ TEXT runtime·duffzero(SB), NOSPLIT|NOFRAME, $0-0 STP (ZR, ZR), (R20) RET -TEXT runtime·duffcopy(SB), NOSPLIT|NOFRAME, $0-0 +TEXT runtime·duffcopy(SB), NOSPLIT|NOFRAME, $0-0 LDP.P 16(R20), (R26, R27) STP.P (R26, R27), 16(R21) diff --git a/src/runtime/mkduff.go b/src/runtime/mkduff.go index da191cc594c..f0367450923 100644 --- a/src/runtime/mkduff.go +++ b/src/runtime/mkduff.go @@ -154,7 +154,7 @@ func zeroARM64(w io.Writer) { // ZR: always zero // R20: ptr to memory to be zeroed // On return, R20 points to the last zeroed dword. - fmt.Fprintln(w, "TEXT runtime·duffzero(SB), NOSPLIT|NOFRAME, $0-0") + fmt.Fprintln(w, "TEXT runtime·duffzero(SB), NOSPLIT|NOFRAME, $0-0") for i := 0; i < 63; i++ { fmt.Fprintln(w, "\tSTP.P\t(ZR, ZR), 16(R20)") } @@ -167,7 +167,7 @@ func copyARM64(w io.Writer) { // R21: ptr to destination memory // R26, R27 (aka REGTMP): scratch space // R20 and R21 are updated as a side effect - fmt.Fprintln(w, "TEXT runtime·duffcopy(SB), NOSPLIT|NOFRAME, $0-0") + fmt.Fprintln(w, "TEXT runtime·duffcopy(SB), NOSPLIT|NOFRAME, $0-0") for i := 0; i < 64; i++ { fmt.Fprintln(w, "\tLDP.P\t16(R20), (R26, R27)") diff --git a/src/runtime/race_arm64.s b/src/runtime/race_arm64.s index c6d5b91edc0..bfad08b9fbf 100644 --- a/src/runtime/race_arm64.s +++ b/src/runtime/race_arm64.s @@ -43,7 +43,9 @@ // func runtime·raceread(addr uintptr) // Called from instrumented code. -TEXT runtime·raceread(SB), NOSPLIT, $0-8 +// Defined as ABIInternal so as to avoid introducing a wrapper, +// which would make caller's PC ineffective. +TEXT runtime·raceread(SB), NOSPLIT, $0-8 MOVD addr+0(FP), R1 MOVD LR, R2 // void __tsan_read(ThreadState *thr, void *addr, void *pc); @@ -66,7 +68,9 @@ TEXT runtime·racereadpc(SB), NOSPLIT, $0-24 // func runtime·racewrite(addr uintptr) // Called from instrumented code. -TEXT runtime·racewrite(SB), NOSPLIT, $0-8 +// Defined as ABIInternal so as to avoid introducing a wrapper, +// which would make caller's PC ineffective. +TEXT runtime·racewrite(SB), NOSPLIT, $0-8 MOVD addr+0(FP), R1 MOVD LR, R2 // void __tsan_write(ThreadState *thr, void *addr, void *pc); @@ -89,7 +93,9 @@ TEXT runtime·racewritepc(SB), NOSPLIT, $0-24 // func runtime·racereadrange(addr, size uintptr) // Called from instrumented code. -TEXT runtime·racereadrange(SB), NOSPLIT, $0-16 +// Defined as ABIInternal so as to avoid introducing a wrapper, +// which would make caller's PC ineffective. +TEXT runtime·racereadrange(SB), NOSPLIT, $0-16 MOVD addr+0(FP), R1 MOVD size+8(FP), R2 MOVD LR, R3 @@ -114,7 +120,9 @@ TEXT runtime·racereadrangepc1(SB), NOSPLIT, $0-24 // func runtime·racewriterange(addr, size uintptr) // Called from instrumented code. -TEXT runtime·racewriterange(SB), NOSPLIT, $0-16 +// Defined as ABIInternal so as to avoid introducing a wrapper, +// which would make caller's PC ineffective. +TEXT runtime·racewriterange(SB), NOSPLIT, $0-16 MOVD addr+0(FP), R1 MOVD size+8(FP), R2 MOVD LR, R3 From 2e4b79949fbb6e0c7e68a1f0258c42ea791069e6 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 27 May 2021 19:02:27 -0400 Subject: [PATCH 238/940] [dev.typeparams] runtime: implement register ABI for reflectcall on ARM64 Implement register ABI version of reflectcall. Now runtime tests pass with GOEXPERIMENT=regabiwrappers,regabireflect on ARM64 (at least on macOS). Change-Id: I2812cd96bdc13f8dc91c867e3f571921c0cdfc8a Reviewed-on: https://go-review.googlesource.com/c/go/+/323935 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/runtime/asm_arm64.s | 94 ++++++++++++++++++++++++++++++++++++-- src/runtime/stubs_arm64.go | 7 +++ 2 files changed, 97 insertions(+), 4 deletions(-) diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s index ca04dddd5b9..3da2b8d3152 100644 --- a/src/runtime/asm_arm64.s +++ b/src/runtime/asm_arm64.s @@ -310,6 +310,86 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT|NOFRAME,$0-0 MOVW $0, R26 B runtime·morestack(SB) +#ifdef GOEXPERIMENT_regabireflect +// spillArgs stores return values from registers to a *internal/abi.RegArgs in R20. +TEXT ·spillArgs(SB),NOSPLIT,$0-0 + MOVD R0, (0*8)(R20) + MOVD R1, (1*8)(R20) + MOVD R2, (2*8)(R20) + MOVD R3, (3*8)(R20) + MOVD R4, (4*8)(R20) + MOVD R5, (5*8)(R20) + MOVD R6, (6*8)(R20) + MOVD R7, (7*8)(R20) + MOVD R8, (8*8)(R20) + MOVD R9, (9*8)(R20) + MOVD R10, (10*8)(R20) + MOVD R11, (11*8)(R20) + MOVD R12, (12*8)(R20) + MOVD R13, (13*8)(R20) + MOVD R14, (14*8)(R20) + MOVD R15, (15*8)(R20) + FMOVD F0, (16*8)(R20) + FMOVD F1, (17*8)(R20) + FMOVD F2, (18*8)(R20) + FMOVD F3, (19*8)(R20) + FMOVD F4, (20*8)(R20) + FMOVD F5, (21*8)(R20) + FMOVD F6, (22*8)(R20) + FMOVD F7, (23*8)(R20) + FMOVD F8, (24*8)(R20) + FMOVD F9, (25*8)(R20) + FMOVD F10, (26*8)(R20) + FMOVD F11, (27*8)(R20) + FMOVD F12, (28*8)(R20) + FMOVD F13, (29*8)(R20) + FMOVD F14, (30*8)(R20) + FMOVD F15, (31*8)(R20) + RET + +// unspillArgs loads args into registers from a *internal/abi.RegArgs in R20. +TEXT ·unspillArgs(SB),NOSPLIT,$0-0 + MOVD (0*8)(R20), R0 + MOVD (1*8)(R20), R1 + MOVD (2*8)(R20), R2 + MOVD (3*8)(R20), R3 + MOVD (4*8)(R20), R4 + MOVD (5*8)(R20), R5 + MOVD (6*8)(R20), R6 + MOVD (7*8)(R20), R7 + MOVD (8*8)(R20), R8 + MOVD (9*8)(R20), R9 + MOVD (10*8)(R20), R10 + MOVD (11*8)(R20), R11 + MOVD (12*8)(R20), R12 + MOVD (13*8)(R20), R13 + MOVD (14*8)(R20), R14 + MOVD (15*8)(R20), R15 + FMOVD (16*8)(R20), F0 + FMOVD (17*8)(R20), F1 + FMOVD (18*8)(R20), F2 + FMOVD (19*8)(R20), F3 + FMOVD (20*8)(R20), F4 + FMOVD (21*8)(R20), F5 + FMOVD (22*8)(R20), F6 + FMOVD (23*8)(R20), F7 + FMOVD (24*8)(R20), F8 + FMOVD (25*8)(R20), F9 + FMOVD (26*8)(R20), F10 + FMOVD (27*8)(R20), F11 + FMOVD (28*8)(R20), F12 + FMOVD (29*8)(R20), F13 + FMOVD (30*8)(R20), F14 + FMOVD (31*8)(R20), F15 + RET +#else +TEXT ·spillArgs(SB),NOSPLIT,$0-0 + RET + +TEXT ·unspillArgs(SB),NOSPLIT,$0-0 + RET +#endif + // reflectcall: call a function with the given argument list // func call(stackArgsType *_type, f *FuncVal, stackArgs *byte, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs). // we don't have variable-sized frames, so we use a small number @@ -381,12 +461,17 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-48; \ MOVBU.P R7, 1(R5); \ CMP R5, R6; \ BNE -3(PC); \ + /* set up argument registers */ \ + MOVD regArgs+40(FP), R20; \ + CALL ·unspillArgs(SB); \ /* call function */ \ MOVD f+8(FP), R26; \ - MOVD (R26), R0; \ - PCDATA $PCDATA_StackMapIndex, $0; \ - BL (R0); \ + MOVD (R26), R20; \ + PCDATA $PCDATA_StackMapIndex, $0; \ + BL (R20); \ /* copy return values back */ \ + MOVD regArgs+40(FP), R20; \ + CALL ·spillArgs(SB); \ MOVD stackArgsType+0(FP), R7; \ MOVD stackArgs+16(FP), R3; \ MOVWU stackArgsSize+24(FP), R4; \ @@ -403,11 +488,12 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-48; \ // to reflectcallmove. It does not follow the Go ABI; it expects its // arguments in registers. TEXT callRet<>(SB), NOSPLIT, $48-0 + NO_LOCAL_POINTERS MOVD R7, 8(RSP) MOVD R3, 16(RSP) MOVD R5, 24(RSP) MOVD R4, 32(RSP) - MOVD $0, 40(RSP) + MOVD R20, 40(RSP) BL runtime·reflectcallmove(SB) RET diff --git a/src/runtime/stubs_arm64.go b/src/runtime/stubs_arm64.go index f5e3bb48540..bd0533d1581 100644 --- a/src/runtime/stubs_arm64.go +++ b/src/runtime/stubs_arm64.go @@ -14,3 +14,10 @@ func save_g() func asmcgocall_no_g(fn, arg unsafe.Pointer) func emptyfunc() + +// Used by reflectcall and the reflect package. +// +// Spills/loads arguments in registers to/from an internal/abi.RegArgs +// respectively. Does not follow the Go ABI. +func spillArgs() +func unspillArgs() From 0c123cdf8ba88991e51fdb3523fdc7df03cf3118 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 27 May 2021 20:20:16 -0400 Subject: [PATCH 239/940] [dev.typeparams] reflect: implement register ABI for MakeFunc etc. on ARM64 Implement register ABI for reflect.MakeFunc and method Value Call on ARM64. Change-Id: I5487febb9ea764af5ccf5d7c94858ab0acec7cac Reviewed-on: https://go-review.googlesource.com/c/go/+/323936 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/reflect/asm_arm64.s | 61 ++++++++++++++++++++++++++++++++++------- src/runtime/stack.go | 6 ++-- 2 files changed, 54 insertions(+), 13 deletions(-) diff --git a/src/reflect/asm_arm64.s b/src/reflect/asm_arm64.s index 5fe88e27e40..5b9b3573fa2 100644 --- a/src/reflect/asm_arm64.s +++ b/src/reflect/asm_arm64.s @@ -5,34 +5,75 @@ #include "textflag.h" #include "funcdata.h" +// The frames of each of the two functions below contain two locals, at offsets +// that are known to the runtime. +// +// The first local is a bool called retValid with a whole pointer-word reserved +// for it on the stack. The purpose of this word is so that the runtime knows +// whether the stack-allocated return space contains valid values for stack +// scanning. +// +// The second local is an abi.RegArgs value whose offset is also known to the +// runtime, so that a stack map for it can be constructed, since it contains +// pointers visible to the GC. +#define LOCAL_RETVALID 40 +#define LOCAL_REGARGS 48 + +// The frame size of the functions below is +// 32 (args of callReflect) + 8 (bool + padding) + 392 (abi.RegArgs) = 432. + // makeFuncStub is the code half of the function returned by MakeFunc. // See the comment on the declaration of makeFuncStub in makefunc.go // for more details. // No arg size here, runtime pulls arg map out of the func value. -TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$40 +TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$432 NO_LOCAL_POINTERS + // NO_LOCAL_POINTERS is a lie. The stack map for the two locals in this + // frame is specially handled in the runtime. See the comment above LOCAL_RETVALID. + ADD $LOCAL_REGARGS, RSP, R20 + CALL runtime·spillArgs(SB) + MOVD R26, 32(RSP) // outside of moveMakeFuncArgPtrs's arg area + MOVD R26, 8(RSP) + MOVD R20, 16(RSP) + CALL ·moveMakeFuncArgPtrs(SB) + MOVD 32(RSP), R26 MOVD R26, 8(RSP) MOVD $argframe+0(FP), R3 MOVD R3, 16(RSP) - MOVB $0, 40(RSP) - ADD $40, RSP, R3 + MOVB $0, LOCAL_RETVALID(RSP) + ADD $LOCAL_RETVALID, RSP, R3 MOVD R3, 24(RSP) - MOVD $0, 32(RSP) - BL ·callReflect(SB) + ADD $LOCAL_REGARGS, RSP, R3 + MOVD R3, 32(RSP) + CALL ·callReflect(SB) + ADD $LOCAL_REGARGS, RSP, R20 + CALL runtime·unspillArgs(SB) RET // methodValueCall is the code half of the function returned by makeMethodValue. // See the comment on the declaration of methodValueCall in makefunc.go // for more details. // No arg size here; runtime pulls arg map out of the func value. -TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$40 +TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$432 NO_LOCAL_POINTERS + // NO_LOCAL_POINTERS is a lie. The stack map for the two locals in this + // frame is specially handled in the runtime. See the comment above LOCAL_RETVALID. + ADD $LOCAL_REGARGS, RSP, R20 + CALL runtime·spillArgs(SB) + MOVD R26, 32(RSP) // outside of moveMakeFuncArgPtrs's arg area + MOVD R26, 8(RSP) + MOVD R20, 16(RSP) + CALL ·moveMakeFuncArgPtrs(SB) + MOVD 32(RSP), R26 MOVD R26, 8(RSP) MOVD $argframe+0(FP), R3 MOVD R3, 16(RSP) - MOVB $0, 40(RSP) - ADD $40, RSP, R3 + MOVB $0, LOCAL_RETVALID(RSP) + ADD $LOCAL_RETVALID, RSP, R3 MOVD R3, 24(RSP) - MOVD $0, 32(RSP) - BL ·callMethod(SB) + ADD $LOCAL_REGARGS, RSP, R3 + MOVD R3, 32(RSP) + CALL ·callMethod(SB) + ADD $LOCAL_REGARGS, RSP, R20 + CALL runtime·unspillArgs(SB) RET diff --git a/src/runtime/stack.go b/src/runtime/stack.go index 622de45f25a..a1182b00bdc 100644 --- a/src/runtime/stack.go +++ b/src/runtime/stack.go @@ -1318,11 +1318,11 @@ func getStackMap(frame *stkframe, cache *pcvalueCache, debug bool) (locals, args } // stack objects. - if GOARCH == "amd64" && unsafe.Sizeof(abi.RegArgs{}) > 0 && frame.argmap != nil { + if (GOARCH == "amd64" || GOARCH == "arm64") && unsafe.Sizeof(abi.RegArgs{}) > 0 && frame.argmap != nil { // argmap is set when the function is reflect.makeFuncStub or reflect.methodValueCall. // We don't actually use argmap in this case, but we need to fake the stack object - // record for these frames which contain an internal/abi.RegArgs at a hard-coded offset - // on amd64. + // record for these frames which contain an internal/abi.RegArgs at a hard-coded offset. + // This offset matches the assembly code on amd64 and arm64. objs = methodValueCallFrameObjs } else { p := funcdata(f, _FUNCDATA_StackObjects) From aa9cfdf775692a9fa6cc4ea9768415d73323c0cc Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Fri, 28 May 2021 21:56:50 -0400 Subject: [PATCH 240/940] [dev.typeparams] runtime: update ABIInternal assembly with register ABI on ARM64 mcall calls a closure (using ABIInternal) with an argument. Update it to pass the argument in register. Panic functions tail-call Go panic functions using ABIInternal. Update them to pass the arguments in registers. Race functions are called using ABIInternal from compiler- instrumented code. Update them to receive the arguments in registers. Now all.bash passes with GOEXPERIMENT=regabi on ARM64 (at least on macOS). Change-Id: I648f6502c7eeb1422330c6c829181f12e08c7d0e Reviewed-on: https://go-review.googlesource.com/c/go/+/323937 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/runtime/asm_arm64.s | 75 +++++++++++++++++++++++++++++++++++++--- src/runtime/race_arm64.s | 18 ++++++++++ 2 files changed, 88 insertions(+), 5 deletions(-) diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s index 3da2b8d3152..170e4406fcb 100644 --- a/src/runtime/asm_arm64.s +++ b/src/runtime/asm_arm64.s @@ -152,7 +152,13 @@ TEXT gogo<>(SB), NOSPLIT|NOFRAME, $0 // Switch to m->g0's stack, call fn(g). // Fn must never return. It should gogo(&g->sched) // to keep running g. -TEXT runtime·mcall(SB), NOSPLIT|NOFRAME, $0-8 +TEXT runtime·mcall(SB), NOSPLIT|NOFRAME, $0-8 +#ifdef GOEXPERIMENT_regabiargs + MOVD R0, R26 // context +#else + MOVD fn+0(FP), R26 // context +#endif + // Save caller state in g->sched MOVD RSP, R0 MOVD R0, (g_sched+gobuf_sp)(g) @@ -168,14 +174,18 @@ TEXT runtime·mcall(SB), NOSPLIT|NOFRAME, $0-8 CMP g, R3 BNE 2(PC) B runtime·badmcall(SB) - MOVD fn+0(FP), R26 // context - MOVD 0(R26), R4 // code pointer + MOVD (g_sched+gobuf_sp)(g), R0 MOVD R0, RSP // sp = m->g0->sched.sp MOVD (g_sched+gobuf_bp)(g), R29 - MOVD R3, -8(RSP) - MOVD $0, -16(RSP) +#ifdef GOEXPERIMENT_regabiargs + MOVD R3, R0 // arg = g +#else + MOVD R3, -8(RSP) // arg = g +#endif + MOVD $0, -16(RSP) // dummy LR SUB $16, RSP + MOVD 0(R26), R4 // code pointer BL (R4) B runtime·badmcall2(SB) @@ -1351,20 +1361,40 @@ TEXT runtime·panicIndexU(SB),NOSPLIT,$0-16 MOVD R1, y+8(FP) JMP runtime·goPanicIndexU(SB) TEXT runtime·panicSliceAlen(SB),NOSPLIT,$0-16 +#ifdef GOEXPERIMENT_regabiargs + MOVD R1, R0 + MOVD R2, R1 +#else MOVD R1, x+0(FP) MOVD R2, y+8(FP) +#endif JMP runtime·goPanicSliceAlen(SB) TEXT runtime·panicSliceAlenU(SB),NOSPLIT,$0-16 +#ifdef GOEXPERIMENT_regabiargs + MOVD R1, R0 + MOVD R2, R1 +#else MOVD R1, x+0(FP) MOVD R2, y+8(FP) +#endif JMP runtime·goPanicSliceAlenU(SB) TEXT runtime·panicSliceAcap(SB),NOSPLIT,$0-16 +#ifdef GOEXPERIMENT_regabiargs + MOVD R1, R0 + MOVD R2, R1 +#else MOVD R1, x+0(FP) MOVD R2, y+8(FP) +#endif JMP runtime·goPanicSliceAcap(SB) TEXT runtime·panicSliceAcapU(SB),NOSPLIT,$0-16 +#ifdef GOEXPERIMENT_regabiargs + MOVD R1, R0 + MOVD R2, R1 +#else MOVD R1, x+0(FP) MOVD R2, y+8(FP) +#endif JMP runtime·goPanicSliceAcapU(SB) TEXT runtime·panicSliceB(SB),NOSPLIT,$0-16 MOVD R0, x+0(FP) @@ -1375,28 +1405,58 @@ TEXT runtime·panicSliceBU(SB),NOSPLIT,$0-16 MOVD R1, y+8(FP) JMP runtime·goPanicSliceBU(SB) TEXT runtime·panicSlice3Alen(SB),NOSPLIT,$0-16 +#ifdef GOEXPERIMENT_regabiargs + MOVD R2, R0 + MOVD R3, R1 +#else MOVD R2, x+0(FP) MOVD R3, y+8(FP) +#endif JMP runtime·goPanicSlice3Alen(SB) TEXT runtime·panicSlice3AlenU(SB),NOSPLIT,$0-16 +#ifdef GOEXPERIMENT_regabiargs + MOVD R2, R0 + MOVD R3, R1 +#else MOVD R2, x+0(FP) MOVD R3, y+8(FP) +#endif JMP runtime·goPanicSlice3AlenU(SB) TEXT runtime·panicSlice3Acap(SB),NOSPLIT,$0-16 +#ifdef GOEXPERIMENT_regabiargs + MOVD R2, R0 + MOVD R3, R1 +#else MOVD R2, x+0(FP) MOVD R3, y+8(FP) +#endif JMP runtime·goPanicSlice3Acap(SB) TEXT runtime·panicSlice3AcapU(SB),NOSPLIT,$0-16 +#ifdef GOEXPERIMENT_regabiargs + MOVD R2, R0 + MOVD R3, R1 +#else MOVD R2, x+0(FP) MOVD R3, y+8(FP) +#endif JMP runtime·goPanicSlice3AcapU(SB) TEXT runtime·panicSlice3B(SB),NOSPLIT,$0-16 +#ifdef GOEXPERIMENT_regabiargs + MOVD R1, R0 + MOVD R2, R1 +#else MOVD R1, x+0(FP) MOVD R2, y+8(FP) +#endif JMP runtime·goPanicSlice3B(SB) TEXT runtime·panicSlice3BU(SB),NOSPLIT,$0-16 +#ifdef GOEXPERIMENT_regabiargs + MOVD R1, R0 + MOVD R2, R1 +#else MOVD R1, x+0(FP) MOVD R2, y+8(FP) +#endif JMP runtime·goPanicSlice3BU(SB) TEXT runtime·panicSlice3C(SB),NOSPLIT,$0-16 MOVD R0, x+0(FP) @@ -1407,6 +1467,11 @@ TEXT runtime·panicSlice3CU(SB),NOSPLIT,$0-16 MOVD R1, y+8(FP) JMP runtime·goPanicSlice3CU(SB) TEXT runtime·panicSliceConvert(SB),NOSPLIT,$0-16 +#ifdef GOEXPERIMENT_regabiargs + MOVD R2, R0 + MOVD R3, R1 +#else MOVD R2, x+0(FP) MOVD R3, y+8(FP) +#endif JMP runtime·goPanicSliceConvert(SB) diff --git a/src/runtime/race_arm64.s b/src/runtime/race_arm64.s index bfad08b9fbf..2b2413b6b77 100644 --- a/src/runtime/race_arm64.s +++ b/src/runtime/race_arm64.s @@ -46,7 +46,11 @@ // Defined as ABIInternal so as to avoid introducing a wrapper, // which would make caller's PC ineffective. TEXT runtime·raceread(SB), NOSPLIT, $0-8 +#ifdef GOEXPERIMENT_regabiargs + MOVD R0, R1 // addr +#else MOVD addr+0(FP), R1 +#endif MOVD LR, R2 // void __tsan_read(ThreadState *thr, void *addr, void *pc); MOVD $__tsan_read(SB), R9 @@ -71,7 +75,11 @@ TEXT runtime·racereadpc(SB), NOSPLIT, $0-24 // Defined as ABIInternal so as to avoid introducing a wrapper, // which would make caller's PC ineffective. TEXT runtime·racewrite(SB), NOSPLIT, $0-8 +#ifdef GOEXPERIMENT_regabiargs + MOVD R0, R1 // addr +#else MOVD addr+0(FP), R1 +#endif MOVD LR, R2 // void __tsan_write(ThreadState *thr, void *addr, void *pc); MOVD $__tsan_write(SB), R9 @@ -96,8 +104,13 @@ TEXT runtime·racewritepc(SB), NOSPLIT, $0-24 // Defined as ABIInternal so as to avoid introducing a wrapper, // which would make caller's PC ineffective. TEXT runtime·racereadrange(SB), NOSPLIT, $0-16 +#ifdef GOEXPERIMENT_regabiargs + MOVD R1, R2 // size + MOVD R0, R1 // addr +#else MOVD addr+0(FP), R1 MOVD size+8(FP), R2 +#endif MOVD LR, R3 // void __tsan_read_range(ThreadState *thr, void *addr, uintptr size, void *pc); MOVD $__tsan_read_range(SB), R9 @@ -123,8 +136,13 @@ TEXT runtime·racereadrangepc1(SB), NOSPLIT, $0-24 // Defined as ABIInternal so as to avoid introducing a wrapper, // which would make caller's PC ineffective. TEXT runtime·racewriterange(SB), NOSPLIT, $0-16 +#ifdef GOEXPERIMENT_regabiargs + MOVD R1, R2 // size + MOVD R0, R1 // addr +#else MOVD addr+0(FP), R1 MOVD size+8(FP), R2 +#endif MOVD LR, R3 // void __tsan_write_range(ThreadState *thr, void *addr, uintptr size, void *pc); MOVD $__tsan_write_range(SB), R9 From e11d14225c032a7c2722798db3c309762fa99757 Mon Sep 17 00:00:00 2001 From: Jeremy Faller Date: Wed, 2 Jun 2021 11:20:40 -0400 Subject: [PATCH 241/940] doc/go1.17: remove runtime section Updates #44513 Change-Id: I359d56fc3eeece3005f092cca2cb485664affc23 Reviewed-on: https://go-review.googlesource.com/c/go/+/324209 Trust: Jeremy Faller Run-TryBot: Jeremy Faller TryBot-Result: Go Bot Reviewed-by: Dmitri Shuralyov Reviewed-by: Michael Knyszek --- doc/go1.17.html | 6 ------ 1 file changed, 6 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index d80e68d4345..27ef524286d 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -224,12 +224,6 @@ Do not send CLs removing the interior tags from such phrases. TODO: complete the Vet section

-

Runtime

- -

- TODO: complete the Runtime section -

-

Compiler

From 4f572d707661e3e84ff262d6c605eb6fa1f77abd Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 25 Feb 2021 08:21:52 -0800 Subject: [PATCH 242/940] io/fs: minor corrections to Sub docs Fixes #44376 Change-Id: I9cd21adb9d4d434c3d8b8eb8af3042b70c763ea1 Reviewed-on: https://go-review.googlesource.com/c/go/+/296389 Trust: Ian Lance Taylor Reviewed-by: Russ Cox --- src/io/fs/sub.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/io/fs/sub.go b/src/io/fs/sub.go index 7822e555eaa..ae20e030a93 100644 --- a/src/io/fs/sub.go +++ b/src/io/fs/sub.go @@ -19,10 +19,10 @@ type SubFS interface { // Sub returns an FS corresponding to the subtree rooted at fsys's dir. // -// If fs implements SubFS, Sub calls returns fsys.Sub(dir). -// Otherwise, if dir is ".", Sub returns fsys unchanged. +// If dir is ".", Sub returns fsys unchanged. +// Otherwise, if fs implements SubFS, Sub returns fsys.Sub(dir). // Otherwise, Sub returns a new FS implementation sub that, -// in effect, implements sub.Open(dir) as fsys.Open(path.Join(dir, name)). +// in effect, implements sub.Open(name) as fsys.Open(path.Join(dir, name)). // The implementation also translates calls to ReadDir, ReadFile, and Glob appropriately. // // Note that Sub(os.DirFS("/"), "prefix") is equivalent to os.DirFS("/prefix") From 7b876def6c4936cfae774d3007f8265876a9fbf7 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Fri, 16 Apr 2021 14:06:50 -0700 Subject: [PATCH 243/940] [dev.typeparams] cmd/compile: add dictionary argument to generic functions When converting from a generic function to a concrete implementation, add a dictionary argument to the generic function (both an actual argument at each callsite, and a formal argument of each implementation). The dictionary argument comes before all other arguments (including any receiver). The dictionary argument is checked for validity, but is otherwise unused. Subsequent CLs will start using the dictionary for, e.g., converting a value of generic type to interface{}. Import/export required adding support for LINKSYMOFFSET, which is used by the dictionary checking code. Change-Id: I16a7a8d23c7bd6a897e0da87c69f273be9103bd7 Reviewed-on: https://go-review.googlesource.com/c/go/+/323272 Trust: Keith Randall Trust: Dan Scales Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/noder/irgen.go | 2 + src/cmd/compile/internal/noder/stencil.go | 440 +++++++++++++++--- src/cmd/compile/internal/noder/transform.go | 74 ++- .../compile/internal/reflectdata/reflect.go | 151 +++++- src/cmd/compile/internal/typecheck/iexport.go | 10 +- src/cmd/compile/internal/typecheck/iimport.go | 7 + src/cmd/compile/internal/typecheck/subr.go | 13 +- src/cmd/compile/internal/types/type.go | 2 +- src/runtime/internal/atomic/atomic_arm64.go | 2 +- test/typeparam/dictionaryCapture.go | 100 ++++ 10 files changed, 688 insertions(+), 113 deletions(-) create mode 100644 test/typeparam/dictionaryCapture.go diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go index d5ef0c0ef46..3f362e9d2bc 100644 --- a/src/cmd/compile/internal/noder/irgen.go +++ b/src/cmd/compile/internal/noder/irgen.go @@ -105,6 +105,8 @@ type irgen struct { // Fully-instantiated generic types whose methods should be instantiated instTypeList []*types.Type + + dnum int // for generating unique dictionary variables } func (g *irgen) generate(noders []*noder) { diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 36a6f2e6d02..08c09c6fb13 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -10,9 +10,11 @@ package noder import ( "cmd/compile/internal/base" "cmd/compile/internal/ir" + "cmd/compile/internal/reflectdata" "cmd/compile/internal/typecheck" "cmd/compile/internal/types" "fmt" + "go/constant" "strings" ) @@ -70,72 +72,89 @@ func (g *irgen) stencil() { // instantiated function if it hasn't been created yet, and change // to calling that function directly. modified := false - foundFuncInst := false + closureRequired := false ir.Visit(decl, func(n ir.Node) { if n.Op() == ir.OFUNCINST { - // We found a function instantiation that is not - // immediately called. - foundFuncInst = true + // generic F, not immediately called + closureRequired = true } - if n.Op() != ir.OCALL || n.(*ir.CallExpr).X.Op() != ir.OFUNCINST { - return + if n.Op() == ir.OMETHEXPR && len(n.(*ir.SelectorExpr).X.Type().RParams()) > 0 { + // T.M, T a type which is generic, not immediately called + closureRequired = true } - // We have found a function call using a generic function - // instantiation. - call := n.(*ir.CallExpr) - inst := call.X.(*ir.InstExpr) - // Replace the OFUNCINST with a direct reference to the - // new stenciled function - st := g.getInstantiationForNode(inst) - call.X = st.Nname - if inst.X.Op() == ir.OCALLPART { - // When we create an instantiation of a method - // call, we make it a function. So, move the - // receiver to be the first arg of the function - // call. - withRecv := make([]ir.Node, len(call.Args)+1) - dot := inst.X.(*ir.SelectorExpr) - withRecv[0] = dot.X - copy(withRecv[1:], call.Args) - call.Args = withRecv + if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OFUNCINST { + // We have found a function call using a generic function + // instantiation. + call := n.(*ir.CallExpr) + inst := call.X.(*ir.InstExpr) + st := g.getInstantiationForNode(inst) + // Replace the OFUNCINST with a direct reference to the + // new stenciled function + call.X = st.Nname + if inst.X.Op() == ir.OCALLPART { + // When we create an instantiation of a method + // call, we make it a function. So, move the + // receiver to be the first arg of the function + // call. + call.Args.Prepend(inst.X.(*ir.SelectorExpr).X) + } + // Add dictionary to argument list. + dict := reflectdata.GetDictionaryForInstantiation(inst) + call.Args.Prepend(dict) + // Transform the Call now, which changes OCALL + // to OCALLFUNC and does typecheckaste/assignconvfn. + transformCall(call) + modified = true + } + if n.Op() == ir.OCALLMETH && n.(*ir.CallExpr).X.Op() == ir.ODOTMETH && len(deref(n.(*ir.CallExpr).X.Type().Recv().Type).RParams()) > 0 { + // Method call on a generic type, which was instantiated by stenciling. + // Method calls on explicitly instantiated types will have an OFUNCINST + // and are handled above. + call := n.(*ir.CallExpr) + meth := call.X.(*ir.SelectorExpr) + targs := deref(meth.Type().Recv().Type).RParams() + + t := meth.X.Type() + baseSym := deref(t).OrigSym + baseType := baseSym.Def.(*ir.Name).Type() + var gf *ir.Name + for _, m := range baseType.Methods().Slice() { + if meth.Sel == m.Sym { + gf = m.Nname.(*ir.Name) + break + } + } + + st := g.getInstantiation(gf, targs, true) + call.SetOp(ir.OCALL) + call.X = st.Nname + dict := reflectdata.GetDictionaryForMethod(gf, targs) + call.Args.Prepend(dict, meth.X) + // Transform the Call now, which changes OCALL + // to OCALLFUNC and does typecheckaste/assignconvfn. + transformCall(call) + modified = true } - // Transform the Call now, which changes OCALL - // to OCALLFUNC and does typecheckaste/assignconvfn. - transformCall(call) - modified = true }) - // If we found an OFUNCINST without a corresponding call in the - // above decl, then traverse the nodes of decl again (with + // If we found a reference to a generic instantiation that wasn't an + // immediate call, then traverse the nodes of decl again (with // EditChildren rather than Visit), where we actually change the - // OFUNCINST node to an ONAME for the instantiated function. + // reference to the instantiation to a closure that captures the + // dictionary, then does a direct call. // EditChildren is more expensive than Visit, so we only do this // in the infrequent case of an OFUNCINST without a corresponding // call. - if foundFuncInst { + if closureRequired { var edit func(ir.Node) ir.Node edit = func(x ir.Node) ir.Node { - if x.Op() == ir.OFUNCINST { - // inst.X is either a function name node - // or a selector expression for a method. - inst := x.(*ir.InstExpr) - st := g.getInstantiationForNode(inst) - modified = true - if inst.X.Op() == ir.ONAME { - return st.Nname - } - assert(inst.X.Op() == ir.OCALLPART) - - // Return a new selector expression referring - // to the newly stenciled function. - oldse := inst.X.(*ir.SelectorExpr) - newse := ir.NewSelectorExpr(oldse.Pos(), ir.OCALLPART, oldse.X, oldse.Sel) - newse.Selection = types.NewField(oldse.Pos(), st.Sym(), st.Type()) - newse.Selection.Nname = st - typed(inst.Type(), newse) - return newse - } ir.EditChildren(x, edit) + switch { + case x.Op() == ir.OFUNCINST: + return g.buildClosure(decl.(*ir.Func), x) + case x.Op() == ir.OMETHEXPR && len(deref(x.(*ir.SelectorExpr).X.Type()).RParams()) > 0: // TODO: test for ptr-to-method case + return g.buildClosure(decl.(*ir.Func), x) + } return x } edit(decl) @@ -153,6 +172,228 @@ func (g *irgen) stencil() { } +// buildClosure makes a closure to implement x, a OFUNCINST or OMETHEXPR +// of generic type. outer is the containing function. +func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { + pos := x.Pos() + var target *ir.Func // target instantiated function/method + var dictValue ir.Node // dictionary to use + var rcvrValue ir.Node // receiver, if a method value + typ := x.Type() // type of the closure + if x.Op() == ir.OFUNCINST { + inst := x.(*ir.InstExpr) + + // Type arguments we're instantiating with. + targs := typecheck.TypesOf(inst.Targs) + + // Find the generic function/method. + var gf *ir.Name + if inst.X.Op() == ir.ONAME { + // Instantiating a generic function call. + gf = inst.X.(*ir.Name) + } else if inst.X.Op() == ir.OCALLPART { + // Instantiating a method value x.M. + se := inst.X.(*ir.SelectorExpr) + rcvrValue = se.X + gf = se.Selection.Nname.(*ir.Name) + } else { + panic("unhandled") + } + + // target is the instantiated function we're trying to call. + // For functions, the target expects a dictionary as its first argument. + // For method values, the target expects a dictionary and the receiver + // as its first two arguments. + target = g.getInstantiation(gf, targs, rcvrValue != nil) + + // The value to use for the dictionary argument. + if rcvrValue == nil { + dictValue = reflectdata.GetDictionaryForFunc(gf, targs) + } else { + dictValue = reflectdata.GetDictionaryForMethod(gf, targs) + } + } else { // ir.OMETHEXPR + // Method expression T.M where T is a generic type. + // TODO: Is (*T).M right? + se := x.(*ir.SelectorExpr) + targs := se.X.Type().RParams() + if len(targs) == 0 { + if se.X.Type().IsPtr() { + targs = se.X.Type().Elem().RParams() + if len(targs) == 0 { + panic("bad") + } + } + } + t := se.X.Type() + baseSym := t.OrigSym + baseType := baseSym.Def.(*ir.Name).Type() + var gf *ir.Name + for _, m := range baseType.Methods().Slice() { + if se.Sel == m.Sym { + gf = m.Nname.(*ir.Name) + break + } + } + target = g.getInstantiation(gf, targs, true) + dictValue = reflectdata.GetDictionaryForMethod(gf, targs) + } + + // Build a closure to implement a function instantiation. + // + // func f[T any] (int, int) (int, int) { ...whatever... } + // + // Then any reference to f[int] not directly called gets rewritten to + // + // .dictN := ... dictionary to use ... + // func(a0, a1 int) (r0, r1 int) { + // return .inst.f[int](.dictN, a0, a1) + // } + // + // Similarly for method expressions, + // + // type g[T any] .... + // func (rcvr g[T]) f(a0, a1 int) (r0, r1 int) { ... } + // + // Any reference to g[int].f not directly called gets rewritten to + // + // .dictN := ... dictionary to use ... + // func(rcvr g[int], a0, a1 int) (r0, r1 int) { + // return .inst.g[int].f(.dictN, rcvr, a0, a1) + // } + // + // Also method values + // + // var x g[int] + // + // Any reference to x.f not directly called gets rewritten to + // + // .dictN := ... dictionary to use ... + // x2 := x + // func(a0, a1 int) (r0, r1 int) { + // return .inst.g[int].f(.dictN, x2, a0, a1) + // } + + // Make a new internal function. + fn := ir.NewFunc(pos) + fn.SetIsHiddenClosure(true) + + // This is the dictionary we want to use. + // Note: for now this is a compile-time constant, so we don't really need a closure + // to capture it (a wrapper function would work just as well). But eventually it + // will be a read of a subdictionary from the parent dictionary. + dictVar := ir.NewNameAt(pos, typecheck.LookupNum(".dict", g.dnum)) + g.dnum++ + dictVar.Class = ir.PAUTO + typed(types.Types[types.TUINTPTR], dictVar) + dictVar.Curfn = outer + dictAssign := ir.NewAssignStmt(pos, dictVar, dictValue) + dictAssign.SetTypecheck(1) + dictVar.Defn = dictAssign + outer.Dcl = append(outer.Dcl, dictVar) + + // assign the receiver to a temporary. + var rcvrVar *ir.Name + var rcvrAssign ir.Node + if rcvrValue != nil { + rcvrVar = ir.NewNameAt(pos, typecheck.LookupNum(".rcvr", g.dnum)) + g.dnum++ + rcvrVar.Class = ir.PAUTO + typed(rcvrValue.Type(), rcvrVar) + rcvrVar.Curfn = outer + rcvrAssign = ir.NewAssignStmt(pos, rcvrVar, rcvrValue) + rcvrAssign.SetTypecheck(1) + rcvrVar.Defn = rcvrAssign + outer.Dcl = append(outer.Dcl, rcvrVar) + } + + // Build formal argument and return lists. + var formalParams []*types.Field // arguments of closure + var formalResults []*types.Field // returns of closure + for i := 0; i < typ.NumParams(); i++ { + t := typ.Params().Field(i).Type + arg := ir.NewNameAt(pos, typecheck.LookupNum("a", i)) + arg.Class = ir.PPARAM + typed(t, arg) + arg.Curfn = fn + fn.Dcl = append(fn.Dcl, arg) + f := types.NewField(pos, arg.Sym(), t) + f.Nname = arg + formalParams = append(formalParams, f) + } + for i := 0; i < typ.NumResults(); i++ { + t := typ.Results().Field(i).Type + result := ir.NewNameAt(pos, typecheck.LookupNum("r", i)) // TODO: names not needed? + result.Class = ir.PPARAMOUT + typed(t, result) + result.Curfn = fn + fn.Dcl = append(fn.Dcl, result) + f := types.NewField(pos, result.Sym(), t) + f.Nname = result + formalResults = append(formalResults, f) + } + + // Build an internal function with the right signature. + closureType := types.NewSignature(x.Type().Pkg(), nil, nil, formalParams, formalResults) + sym := typecheck.ClosureName(outer) + sym.SetFunc(true) + fn.Nname = ir.NewNameAt(pos, sym) + fn.Nname.Func = fn + fn.Nname.Defn = fn + typed(closureType, fn.Nname) + fn.SetTypecheck(1) + + // Build body of closure. This involves just calling the wrapped function directly + // with the additional dictionary argument. + + // First, capture the dictionary variable for use in the closure. + dict2Var := ir.CaptureName(pos, fn, dictVar) + // Also capture the receiver variable. + var rcvr2Var *ir.Name + if rcvrValue != nil { + rcvr2Var = ir.CaptureName(pos, fn, rcvrVar) + } + + // Build arguments to call inside the closure. + var args []ir.Node + + // First the dictionary argument. + args = append(args, dict2Var) + // Then the receiver. + if rcvrValue != nil { + args = append(args, rcvr2Var) + } + // Then all the other arguments (including receiver for method expressions). + for i := 0; i < typ.NumParams(); i++ { + args = append(args, formalParams[i].Nname.(*ir.Name)) + } + + // Build call itself. + var innerCall ir.Node = ir.NewCallExpr(pos, ir.OCALL, target.Nname, args) + if len(formalResults) > 0 { + innerCall = ir.NewReturnStmt(pos, []ir.Node{innerCall}) + } + // Finish building body of closure. + ir.CurFunc = fn + // TODO: set types directly here instead of using typecheck.Stmt + typecheck.Stmt(innerCall) + ir.CurFunc = nil + fn.Body = []ir.Node{innerCall} + + // We're all done with the captured dictionary (and receiver, for method values). + ir.FinishCaptureNames(pos, outer, fn) + + // Make a closure referencing our new internal function. + c := ir.NewClosureExpr(pos, fn) + init := []ir.Node{dictAssign} + if rcvrValue != nil { + init = append(init, rcvrAssign) + } + c.SetInit(init) + typed(x.Type(), c) + return c +} + // instantiateMethods instantiates all the methods of all fully-instantiated // generic types that have been added to g.instTypeList. func (g *irgen) instantiateMethods() { @@ -167,14 +408,17 @@ func (g *irgen) instantiateMethods() { // not be set on imported instantiated types. baseSym := typ.OrigSym baseType := baseSym.Def.(*ir.Name).Type() - for j, m := range typ.Methods().Slice() { - name := m.Nname.(*ir.Name) + for j, _ := range typ.Methods().Slice() { baseNname := baseType.Methods().Slice()[j].Nname.(*ir.Name) - // Note: we are breaking an invariant here: - // m.Nname is now not equal m.Nname.Func.Nname. - // m.Nname has the type of a method, whereas m.Nname.Func.Nname has - // the type of a function, since it is an function instantiation. - name.Func = g.getInstantiation(baseNname, typ.RParams(), true) + // Eagerly generate the instantiations that implement these methods. + // We don't use the instantiations here, just generate them (and any + // further instantiations those generate, etc.). + // Note that we don't set the Func for any methods on instantiated + // types. Their signatures don't match so that would be confusing. + // Direct method calls go directly to the instantiations, implemented above. + // Indirect method calls use wrappers generated in reflectcall. Those wrappers + // will use these instantiations if they are needed (for interface tables or reflection). + _ = g.getInstantiation(baseNname, typ.RParams(), true) } } g.instTypeList = nil @@ -287,10 +531,7 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*type vars: make(map[*ir.Name]*ir.Name), } - newf.Dcl = make([]*ir.Name, len(gf.Dcl)) - for i, n := range gf.Dcl { - newf.Dcl[i] = subst.localvar(n) - } + newf.Dcl = make([]*ir.Name, 0, len(gf.Dcl)+1) // Replace the types in the function signature. // Ugly: also, we have to insert the Name nodes of the parameters/results into @@ -298,18 +539,40 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*type // because it came via conversion from the types2 type. oldt := nameNode.Type() // We also transform a generic method type to the corresponding - // instantiated function type where the receiver is the first parameter. + // instantiated function type where the dictionary is the first parameter. + dictionarySym := types.LocalPkg.Lookup(".dict") + dictionaryType := types.Types[types.TUINTPTR] + dictionaryName := ir.NewNameAt(gf.Pos(), dictionarySym) + typed(dictionaryType, dictionaryName) + dictionaryName.Class = ir.PPARAM + dictionaryName.Curfn = newf + newf.Dcl = append(newf.Dcl, dictionaryName) + for _, n := range gf.Dcl { + if n.Sym().Name == ".dict" { + panic("already has dictionary") + } + newf.Dcl = append(newf.Dcl, subst.localvar(n)) + } + dictionaryArg := types.NewField(gf.Pos(), dictionarySym, dictionaryType) + dictionaryArg.Nname = dictionaryName + var args []*types.Field + args = append(args, dictionaryArg) + args = append(args, oldt.Recvs().FieldSlice()...) + args = append(args, oldt.Params().FieldSlice()...) newt := types.NewSignature(oldt.Pkg(), nil, nil, - subst.fields(ir.PPARAM, append(oldt.Recvs().FieldSlice(), oldt.Params().FieldSlice()...), newf.Dcl), + subst.fields(ir.PPARAM, args, newf.Dcl), subst.fields(ir.PPARAMOUT, oldt.Results().FieldSlice(), newf.Dcl)) - newf.Nname.SetType(newt) + typed(newt, newf.Nname) ir.MarkFunc(newf.Nname) newf.SetTypecheck(1) - newf.Nname.SetTypecheck(1) // Make sure name/type of newf is set before substituting the body. newf.Body = subst.list(gf.Body) + + // Add code to check that the dictionary is correct. + newf.Body.Prepend(g.checkDictionary(dictionaryName, targs)...) + ir.CurFunc = savef return newf @@ -334,6 +597,44 @@ func (subst *subster) localvar(name *ir.Name) *ir.Name { return m } +// checkDictionary returns code that does runtime consistency checks +// between the dictionary and the types it should contain. +func (g *irgen) checkDictionary(name *ir.Name, targs []*types.Type) (code []ir.Node) { + if false { + return // checking turned off + } + // TODO: when moving to GCshape, this test will become harder. Call into + // runtime to check the expected shape is correct? + pos := name.Pos() + // Convert dictionary to *[N]uintptr + d := ir.NewConvExpr(pos, ir.OCONVNOP, types.Types[types.TUNSAFEPTR], name) + d.SetTypecheck(1) + d = ir.NewConvExpr(pos, ir.OCONVNOP, types.NewArray(types.Types[types.TUINTPTR], int64(len(targs))).PtrTo(), d) + d.SetTypecheck(1) + + // Check that each type entry in the dictionary is correct. + for i, t := range targs { + want := reflectdata.TypePtr(t) + typed(types.Types[types.TUINTPTR], want) + deref := ir.NewStarExpr(pos, d) + typed(d.Type().Elem(), deref) + idx := ir.NewConstExpr(constant.MakeUint64(uint64(i)), name) // TODO: what to set orig to? + typed(types.Types[types.TUINTPTR], idx) + got := ir.NewIndexExpr(pos, deref, idx) + typed(types.Types[types.TUINTPTR], got) + cond := ir.NewBinaryExpr(pos, ir.ONE, want, got) + typed(types.Types[types.TBOOL], cond) + panicArg := ir.NewNilExpr(pos) + typed(types.NewInterface(types.LocalPkg, nil), panicArg) + then := ir.NewUnaryExpr(pos, ir.OPANIC, panicArg) + then.SetTypecheck(1) + x := ir.NewIfStmt(pos, cond, []ir.Node{then}, nil) + x.SetTypecheck(1) + code = append(code, x) + } + return +} + // node is like DeepCopy(), but substitutes ONAME nodes based on subst.vars, and // also descends into closures. It substitutes type arguments for type parameters // in all the new nodes. @@ -837,13 +1138,14 @@ func (subst *subster) typ(t *types.Type) *types.Type { t2 := subst.typ(f.Type) oldsym := f.Nname.Sym() newsym := typecheck.MakeInstName(oldsym, subst.targs, true) + // TODO: use newsym? var nname *ir.Name if newsym.Def != nil { nname = newsym.Def.(*ir.Name) } else { - nname = ir.NewNameAt(f.Pos, newsym) + nname = ir.NewNameAt(f.Pos, oldsym) nname.SetType(t2) - newsym.Def = nname + oldsym.Def = nname } newfields[i] = types.NewField(f.Pos, f.Sym, t2) newfields[i].Nname = nname diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go index 2859089e69b..90d38fe5144 100644 --- a/src/cmd/compile/internal/noder/transform.go +++ b/src/cmd/compile/internal/noder/transform.go @@ -340,12 +340,12 @@ assignOK: } } -// Corresponds to typecheck.typecheckargs. +// Corresponds to, but slightly more general than, typecheck.typecheckargs. func transformArgs(n ir.InitNode) { var list []ir.Node switch n := n.(type) { default: - base.Fatalf("typecheckargs %+v", n.Op()) + base.Fatalf("transformArgs %+v", n.Op()) case *ir.CallExpr: list = n.Args if n.IsDDD { @@ -354,25 +354,31 @@ func transformArgs(n ir.InitNode) { case *ir.ReturnStmt: list = n.Results } - if len(list) != 1 { + + // Look to see if we have any multi-return functions as arguments. + extra := 0 + for _, arg := range list { + t := arg.Type() + if t.IsFuncArgStruct() { + num := t.Fields().Len() + if num <= 1 { + base.Fatalf("multi-return type with only %d parts", num) + } + extra += num - 1 + } + } + // If not, nothing to do. + if extra == 0 { return } - t := list[0].Type() - if t == nil || !t.IsFuncArgStruct() { - return - } - - // Rewrite f(g()) into t1, t2, ... = g(); f(t1, t2, ...). + // Rewrite f(..., g(), ...) into t1, ..., tN = g(); f(..., t1, ..., tN, ...). // Save n as n.Orig for fmt.go. if ir.Orig(n) == n { n.(ir.OrigNode).SetOrig(ir.SepCopy(n)) } - as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil) - as.Rhs.Append(list...) - // If we're outside of function context, then this call will // be executed during the generated init function. However, // init.go hasn't yet created it. Instead, associate the @@ -382,27 +388,42 @@ func transformArgs(n ir.InitNode) { if static { ir.CurFunc = typecheck.InitTodoFunc } - list = nil - for _, f := range t.FieldSlice() { - t := typecheck.Temp(f.Type) - as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, t)) - as.Lhs.Append(t) - list = append(list, t) + + // Expand multi-return function calls. + // The spec only allows a multi-return function as an argument + // if it is the only argument. This code must handle calls to + // stenciled generic functions which have extra arguments + // (like the dictionary) so it must handle a slightly more general + // cases, like f(n, g()) where g is multi-return. + newList := make([]ir.Node, 0, len(list)+extra) + for _, arg := range list { + t := arg.Type() + if t.IsFuncArgStruct() { + as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, []ir.Node{arg}) + for _, f := range t.FieldSlice() { + t := typecheck.Temp(f.Type) + as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, t)) + as.Lhs.Append(t) + newList = append(newList, t) + } + transformAssign(as, as.Lhs, as.Rhs) + as.SetTypecheck(1) + n.PtrInit().Append(as) + } else { + newList = append(newList, arg) + } } + if static { ir.CurFunc = nil } switch n := n.(type) { case *ir.CallExpr: - n.Args = list + n.Args = newList case *ir.ReturnStmt: - n.Results = list + n.Results = newList } - - transformAssign(as, as.Lhs, as.Rhs) - as.SetTypecheck(1) - n.PtrInit().Append(as) } // assignconvfn converts node n for assignment to type t. Corresponds to @@ -562,6 +583,11 @@ func transformDot(n *ir.SelectorExpr, isCall bool) ir.Node { if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && !isCall { n.SetOp(ir.OCALLPART) + if len(n.X.Type().RParams()) > 0 || n.X.Type().IsPtr() && len(n.X.Type().Elem().RParams()) > 0 { + // TODO: MethodValueWrapper needed for generics? + // Or did we successfully desugar all that at stencil time? + return n + } n.SetType(typecheck.MethodValueWrapper(n).Type()) } return n diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index d452d4f1942..604cec6096d 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -321,13 +321,6 @@ func methods(t *types.Type) []*typeSig { } typecheck.CalcMethods(mt) - // type stored in interface word - it := t - - if !types.IsDirectIface(it) { - it = types.NewPtr(t) - } - // make list of methods for t, // generating code if necessary. var ms []*typeSig @@ -355,8 +348,8 @@ func methods(t *types.Type) []*typeSig { sig := &typeSig{ name: f.Sym, - isym: methodWrapper(it, f), - tsym: methodWrapper(t, f), + isym: methodWrapper(t, f, true), + tsym: methodWrapper(t, f, false), type_: typecheck.NewMethodType(f.Type, t), mtype: typecheck.NewMethodType(f.Type, nil), } @@ -394,7 +387,7 @@ func imethods(t *types.Type) []*typeSig { // IfaceType.Method is not in the reflect data. // Generate the method body, so that compiled // code can refer to it. - methodWrapper(t, f) + methodWrapper(t, f, false) } return methods @@ -1765,7 +1758,28 @@ func CollectPTabs() { // // rcvr - U // method - M func (t T)(), a TFIELD type struct -func methodWrapper(rcvr *types.Type, method *types.Field) *obj.LSym { +// +// Also wraps methods on instantiated generic types for use in itab entries. +// For an instantiated generic type G[int], we generate wrappers like: +// G[int] pointer shaped: +// func (x G[int]) f(arg) { +// .inst.G[int].f(dictionary, x, arg) +// } +// G[int] not pointer shaped: +// func (x *G[int]) f(arg) { +// .inst.G[int].f(dictionary, *x, arg) +// } +// These wrappers are always fully stenciled. +func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSym { + orig := rcvr + if forItab && !types.IsDirectIface(rcvr) { + rcvr = rcvr.PtrTo() + } + generic := false + if !rcvr.IsInterface() && len(rcvr.RParams()) > 0 || rcvr.IsPtr() && len(rcvr.Elem().RParams()) > 0 { // TODO: right detection? + // TODO: check that we do the right thing when rcvr.IsInterface(). + generic = true + } newnam := ir.MethodSym(rcvr, method.Sym) lsym := newnam.Linksym() if newnam.Siggen() { @@ -1773,7 +1787,7 @@ func methodWrapper(rcvr *types.Type, method *types.Field) *obj.LSym { } newnam.SetSiggen(true) - if types.Identical(rcvr, method.Type.Recv().Type) { + if !generic && types.Identical(rcvr, method.Type.Recv().Type) { return lsym } @@ -1808,9 +1822,10 @@ func methodWrapper(rcvr *types.Type, method *types.Field) *obj.LSym { nthis := ir.AsNode(tfn.Type().Recv().Nname) methodrcvr := method.Type.Recv().Type + indirect := rcvr.IsPtr() && rcvr.Elem() == methodrcvr // generate nil pointer check for better error - if rcvr.IsPtr() && rcvr.Elem() == methodrcvr { + if indirect { // generating wrapper from *T to T. n := ir.NewIfStmt(base.Pos, nil, nil, nil) n.Cond = ir.NewBinaryExpr(base.Pos, ir.OEQ, nthis, typecheck.NodNil()) @@ -1832,7 +1847,7 @@ func methodWrapper(rcvr *types.Type, method *types.Field) *obj.LSym { // Disable tailcall for RegabiArgs for now. The IR does not connect the // arguments with the OTAILCALL node, and the arguments are not marshaled // correctly. - if !base.Flag.Cfg.Instrumenting && rcvr.IsPtr() && methodrcvr.IsPtr() && method.Embedded != 0 && !types.IsInterfaceMethod(method.Type) && !(base.Ctxt.Arch.Name == "ppc64le" && base.Ctxt.Flag_dynlink) && !buildcfg.Experiment.RegabiArgs { + if !base.Flag.Cfg.Instrumenting && rcvr.IsPtr() && methodrcvr.IsPtr() && method.Embedded != 0 && !types.IsInterfaceMethod(method.Type) && !(base.Ctxt.Arch.Name == "ppc64le" && base.Ctxt.Flag_dynlink) && !buildcfg.Experiment.RegabiArgs && !generic { // generate tail call: adjust pointer receiver and jump to embedded method. left := dot.X // skip final .M if !left.Type().IsPtr() { @@ -1843,8 +1858,44 @@ func methodWrapper(rcvr *types.Type, method *types.Field) *obj.LSym { fn.Body.Append(ir.NewTailCallStmt(base.Pos, method.Nname.(*ir.Name))) } else { fn.SetWrapper(true) // ignore frame for panic+recover matching - call := ir.NewCallExpr(base.Pos, ir.OCALL, dot, nil) - call.Args = ir.ParamNames(tfn.Type()) + var call *ir.CallExpr + if generic { + var args []ir.Node + var targs []*types.Type + if rcvr.IsPtr() { // TODO: correct condition? + targs = rcvr.Elem().RParams() + } else { + targs = rcvr.RParams() + } + if strings.HasPrefix(ir.MethodSym(orig, method.Sym).Name, ".inst.") { + fmt.Printf("%s\n", ir.MethodSym(orig, method.Sym).Name) + panic("multiple .inst.") + } + args = append(args, getDictionary(".inst."+ir.MethodSym(orig, method.Sym).Name, targs)) // TODO: remove .inst. + if indirect { + args = append(args, ir.NewStarExpr(base.Pos, nthis)) + } else { + args = append(args, nthis) + } + args = append(args, ir.ParamNames(tfn.Type())...) + + // TODO: Once we enter the gcshape world, we'll need a way to look up + // the stenciled implementation to use for this concrete type. Essentially, + // erase the concrete types and replace them with gc shape representatives. + sym := typecheck.MakeInstName(ir.MethodSym(methodrcvr, method.Sym), targs, true) + if sym.Def == nil { + // Currently we make sure that we have all the instantiations + // we need by generating them all in ../noder/stencil.go:instantiateMethods + // TODO: maybe there's a better, more incremental way to generate + // only the instantiations we need? + base.Fatalf("instantiation %s not found", sym.Name) + } + target := ir.AsNode(sym.Def) + call = ir.NewCallExpr(base.Pos, ir.OCALL, target, args) + } else { + call = ir.NewCallExpr(base.Pos, ir.OCALL, dot, nil) + call.Args = ir.ParamNames(tfn.Type()) + } call.IsDDD = tfn.Type().IsVariadic() if method.Type.NumResults() > 0 { ret := ir.NewReturnStmt(base.Pos, nil) @@ -1909,3 +1960,71 @@ func MarkUsedIfaceMethod(n *ir.CallExpr) { r.Add = InterfaceMethodOffset(ityp, midx) r.Type = objabi.R_USEIFACEMETHOD } + +// getDictionaryForInstantiation returns the dictionary that should be used for invoking +// the concrete instantiation described by inst. +func GetDictionaryForInstantiation(inst *ir.InstExpr) ir.Node { + targs := typecheck.TypesOf(inst.Targs) + if meth, ok := inst.X.(*ir.SelectorExpr); ok { + return GetDictionaryForMethod(meth.Selection.Nname.(*ir.Name), targs) + } + return GetDictionaryForFunc(inst.X.(*ir.Name), targs) +} + +func GetDictionaryForFunc(fn *ir.Name, targs []*types.Type) ir.Node { + return getDictionary(typecheck.MakeInstName(fn.Sym(), targs, false).Name, targs) +} +func GetDictionaryForMethod(meth *ir.Name, targs []*types.Type) ir.Node { + return getDictionary(typecheck.MakeInstName(meth.Sym(), targs, true).Name, targs) +} + +// getDictionary returns the dictionary for the given named generic function +// or method, with the given type arguments. +// TODO: pass a reference to the generic function instead? We might need +// that to look up protodictionaries. +func getDictionary(name string, targs []*types.Type) ir.Node { + if len(targs) == 0 { + base.Fatalf("%s should have type arguments", name) + } + + // The dictionary for this instantiation is named after the function + // and concrete types it is instantiated with. + // TODO: decouple this naming from the instantiation naming. The instantiation + // naming will be based on GC shapes, this naming must be fully stenciled. + if !strings.HasPrefix(name, ".inst.") { + base.Fatalf("%s should start in .inst.", name) + } + name = ".dict." + name[6:] + + // Get a symbol representing the dictionary. + sym := typecheck.Lookup(name) + + // Initialize the dictionary, if we haven't yet already. + if lsym := sym.Linksym(); len(lsym.P) == 0 { + off := 0 + // Emit an entry for each concrete type. + for _, t := range targs { + s := TypeLinksym(t) + off = objw.SymPtr(lsym, off, s, 0) + } + // TODO: subdictionaries + objw.Global(lsym, int32(off), obj.DUPOK|obj.RODATA) + } + + // Make a node referencing the dictionary symbol. + n := typecheck.NewName(sym) + n.SetType(types.Types[types.TUINTPTR]) // should probably be [...]uintptr, but doesn't really matter + n.SetTypecheck(1) + n.Class = ir.PEXTERN + sym.Def = n + + // Return the address of the dictionary. + np := typecheck.NodAddr(n) + // Note: treat dictionary pointers as uintptrs, so they aren't pointers + // with respect to GC. That saves on stack scanning work, write barriers, etc. + // We can get away with it because dictionaries are global variables. + // TODO: use a cast, or is typing directly ok? + np.SetType(types.Types[types.TUINTPTR]) + np.SetTypecheck(1) + return np +} diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index f49718d4428..d83f385fcbf 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -1904,6 +1904,14 @@ func (w *exportWriter) expr(n ir.Node) { w.op(ir.OEND) } + case ir.OLINKSYMOFFSET: + n := n.(*ir.LinksymOffsetExpr) + w.op(ir.OLINKSYMOFFSET) + w.pos(n.Pos()) + w.string(n.Linksym.Name) + w.uint64(uint64(n.Offset_)) + w.typ(n.Type()) + // unary expressions case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.ORECV: n := n.(*ir.UnaryExpr) @@ -2068,7 +2076,7 @@ func (w *exportWriter) localIdent(s *types.Sym) { } // TODO(mdempsky): Fix autotmp hack. - if i := strings.LastIndex(name, "."); i >= 0 && !strings.HasPrefix(name, ".autotmp_") { + if i := strings.LastIndex(name, "."); i >= 0 && !strings.HasPrefix(name, ".autotmp_") && !strings.HasPrefix(name, ".dict") { // TODO: just use autotmp names for dictionaries? base.Fatalf("unexpected dot in identifier: %v", name) } diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index cca14a0d919..4c31e47378a 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -1467,6 +1467,13 @@ func (r *importReader) node() ir.Node { n.Args.Append(r.exprList()...) return n + case ir.OLINKSYMOFFSET: + pos := r.pos() + name := r.string() + off := r.uint64() + typ := r.typ() + return ir.NewLinksymOffsetExpr(pos, Lookup(name).Linksym(), int64(off), typ) + // unary expressions case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.ORECV: n := ir.NewUnaryExpr(r.pos(), op, r.expr()) diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index 9eac802dab8..3e7799b35b2 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -901,6 +901,14 @@ func TypesOf(x []ir.Node) []*types.Type { // '(*genType[int,bool]).methodName' for methods func MakeInstName(fnsym *types.Sym, targs []*types.Type, hasBrackets bool) *types.Sym { b := bytes.NewBufferString("") + + // marker to distinguish generic instantiations from fully stenciled wrapper functions. + // Once we move to GC shape implementations, this prefix will not be necessary as the + // GC shape naming will distinguish them. + // e.g. f[8bytenonpointer] vs. f[int]. + // For now, we use .inst.f[int] vs. f[int]. + b.WriteString(".inst.") + name := fnsym.Name i := strings.Index(name, "[") assert(hasBrackets == (i >= 0)) @@ -924,10 +932,13 @@ func MakeInstName(fnsym *types.Sym, targs []*types.Type, hasBrackets bool) *type } b.WriteString("]") if i >= 0 { - i2 := strings.Index(name[i:], "]") + i2 := strings.LastIndex(name[i:], "]") assert(i2 >= 0) b.WriteString(name[i+i2+1:]) } + if strings.HasPrefix(b.String(), ".inst..inst.") { + panic(fmt.Sprintf("multiple .inst. prefix in %s", b.String())) + } return fnsym.Pkg.Lookup(b.String()) } diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index 08855f518ca..7a05230a78e 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -958,7 +958,7 @@ func (t *Type) FuncArgs() *Type { return t.Extra.(FuncArgs).T } -// IsFuncArgStruct reports whether t is a struct representing function parameters. +// IsFuncArgStruct reports whether t is a struct representing function parameters or results. func (t *Type) IsFuncArgStruct() bool { return t.kind == TSTRUCT && t.Extra.(*Struct).Funarg != FunargNone } diff --git a/src/runtime/internal/atomic/atomic_arm64.go b/src/runtime/internal/atomic/atomic_arm64.go index 3c8736997f4..dbb1796ec09 100644 --- a/src/runtime/internal/atomic/atomic_arm64.go +++ b/src/runtime/internal/atomic/atomic_arm64.go @@ -8,8 +8,8 @@ package atomic import ( - "unsafe" "internal/cpu" + "unsafe" ) const ( diff --git a/test/typeparam/dictionaryCapture.go b/test/typeparam/dictionaryCapture.go new file mode 100644 index 00000000000..9ce7c540ca4 --- /dev/null +++ b/test/typeparam/dictionaryCapture.go @@ -0,0 +1,100 @@ +// run -gcflags=-G=3 + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test situations where functions/methods are not +// immediately called and we need to capture the dictionary +// required for later invocation. + +// TODO: copy this test file, add -l to gcflags. + +package main + +func main() { + functions() + methodExpressions() + methodValues() + interfaceMethods() +} + +func g0[T any](x T) { +} +func g1[T any](x T) T { + return x +} +func g2[T any](x T) (T, T) { + return x, x +} + +func functions() { + f0 := g0[int] + f0(7) + f1 := g1[int] + is7(f1(7)) + f2 := g2[int] + is77(f2(7)) +} + +func is7(x int) { + if x != 7 { + println(x) + panic("assertion failed") + } +} +func is77(x, y int) { + if x != 7 || y != 7 { + println(x,y) + panic("assertion failed") + } +} + +type s[T any] struct { + a T +} + +func (x s[T]) g0() { +} +func (x s[T]) g1() T { + return x.a +} +func (x s[T]) g2() (T, T) { + return x.a, x.a +} + +func methodExpressions() { + x := s[int]{a:7} + f0 := s[int].g0 + f0(x) + f1 := s[int].g1 + is7(f1(x)) + f2 := s[int].g2 + is77(f2(x)) +} + +func methodValues() { + x := s[int]{a:7} + f0 := x.g0 + f0() + f1 := x.g1 + is7(f1()) + f2 := x.g2 + is77(f2()) +} + +var x interface{ + g0() + g1()int + g2()(int,int) +} = s[int]{a:7} +var y interface{} = s[int]{a:7} + +func interfaceMethods() { + x.g0() + is7(x.g1()) + is77(x.g2()) + y.(interface{g0()}).g0() + is7(y.(interface{g1()int}).g1()) + is77(y.(interface{g2()(int,int)}).g2()) +} From 589e32dbdf89484d620c635a966c736085cae5c4 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 25 May 2021 17:49:32 -0700 Subject: [PATCH 244/940] [dev.typeparams] cmd/compile/internal/types2: replace Sum type with Union type - We still mostly ignore the tilde information. - More consistent naming: A Union term is the pair (type, tilde). Rename Union.terms to Union.types; the Union.types and Union.tilde slices make up the Union terms. - Replace Sum.is with Union.underIs: underIs iterates through all union terms and calls its argument function with the underlying type of the term (and thus can ignore the tilde information). This also eliminates the need to call under in the argument function. - Added Union.is for situations where we need to consider the tilde information for each Union term. Change-Id: I70fcf1813e072651dc0f61d52d5555642ee762fd Reviewed-on: https://go-review.googlesource.com/c/go/+/323274 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/builtins.go | 16 ++- src/cmd/compile/internal/types2/expr.go | 4 +- src/cmd/compile/internal/types2/index.go | 18 +-- src/cmd/compile/internal/types2/infer.go | 5 +- src/cmd/compile/internal/types2/interface.go | 51 ++------ src/cmd/compile/internal/types2/operand.go | 19 ++- src/cmd/compile/internal/types2/predicates.go | 35 +++--- src/cmd/compile/internal/types2/sanitize.go | 5 +- .../compile/internal/types2/sizeof_test.go | 1 - src/cmd/compile/internal/types2/sizes.go | 4 +- src/cmd/compile/internal/types2/stmt.go | 6 +- src/cmd/compile/internal/types2/subst.go | 18 +-- src/cmd/compile/internal/types2/type.go | 72 +++--------- src/cmd/compile/internal/types2/typestring.go | 5 +- src/cmd/compile/internal/types2/unify.go | 7 +- src/cmd/compile/internal/types2/union.go | 111 +++++++++++++++--- 16 files changed, 187 insertions(+), 190 deletions(-) diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index 94fb506d801..1779e32c5c8 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -178,9 +178,9 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( mode = value } - case *Sum: - if t.is(func(t Type) bool { - switch t := under(t).(type) { + case *Union: + if t.underIs(func(t Type) bool { + switch t := t.(type) { case *Basic: if isString(t) && id == _Len { return true @@ -460,8 +460,8 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( m = 2 case *Map, *Chan: m = 1 - case *Sum: - return t.is(valid) + case *Union: + return t.underIs(valid) default: return false } @@ -749,10 +749,14 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { if tp := asTypeParam(x); tp != nil { // Test if t satisfies the requirements for the argument // type and collect possible result types at the same time. + // TODO(gri) This needs to consider the ~ information if we + // have a union type. var rtypes []Type + var tilde []bool if !tp.Bound().is(func(x Type) bool { if r := f(x); r != nil { rtypes = append(rtypes, r) + tilde = append(tilde, true) // for now - see TODO above return true } return false @@ -768,7 +772,7 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { // construct a suitable new type parameter tpar := NewTypeName(nopos, nil /* = Universe pkg */, "", nil) ptyp := check.NewTypeParam(tpar, 0, &emptyInterface) // assigns type to tpar as a side-effect - tsum := NewSum(rtypes) + tsum := newUnion(rtypes, tilde) ptyp.bound = &Interface{allMethods: markComplete, allTypes: tsum} return ptyp diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go index 23b79656bb5..b223387f18e 100644 --- a/src/cmd/compile/internal/types2/expr.go +++ b/src/cmd/compile/internal/types2/expr.go @@ -723,8 +723,8 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const default: return nil, nil, _InvalidUntypedConversion } - case *Sum: - ok := t.is(func(t Type) bool { + case *Union: + ok := t.underIs(func(t Type) bool { target, _, _ := check.implicitTypeAndValue(x, t) return target != nil }) diff --git a/src/cmd/compile/internal/types2/index.go b/src/cmd/compile/internal/types2/index.go index 33e79aac3eb..47e0853a3b0 100644 --- a/src/cmd/compile/internal/types2/index.go +++ b/src/cmd/compile/internal/types2/index.go @@ -91,15 +91,15 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo x.expr = e return - case *Sum: - // A sum type can be indexed if all of the sum's types + case *Union: + // A union type can be indexed if all of the union's terms // support indexing and have the same index and element - // type. Special rules apply for maps in the sum type. + // type. Special rules apply for maps in the union type. var tkey, telem Type // key is for map types only - nmaps := 0 // number of map types in sum type - if typ.is(func(t Type) bool { + nmaps := 0 // number of map types in union type + if typ.underIs(func(t Type) bool { var e Type - switch t := under(t).(type) { + switch t := t.(type) { case *Basic: if isString(t) { e = universeByte @@ -113,7 +113,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo case *Slice: e = t.elem case *Map: - // If there are multiple maps in the sum type, + // If there are multiple maps in the union type, // they must have identical key types. // TODO(gri) We may be able to relax this rule // but it becomes complicated very quickly. @@ -148,7 +148,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo // ok to continue even if indexing failed - map element type is known // If there are only maps, we are done. - if nmaps == len(typ.types) { + if nmaps == typ.NumTerms() { x.mode = mapindex x.typ = telem x.expr = e @@ -246,7 +246,7 @@ func (check *Checker) sliceExpr(x *operand, e *syntax.SliceExpr) { valid = true // x.typ doesn't change - case *Sum, *TypeParam: + case *Union, *TypeParam: check.error(x, "generic slice expressions not yet implemented") x.mode = invalid return diff --git a/src/cmd/compile/internal/types2/infer.go b/src/cmd/compile/internal/types2/infer.go index d8865784a5c..73ea8330d4a 100644 --- a/src/cmd/compile/internal/types2/infer.go +++ b/src/cmd/compile/internal/types2/infer.go @@ -307,7 +307,7 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { } } - case *Sum: + case *Union: return w.isParameterizedList(t.types) case *Signature: @@ -320,9 +320,6 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { // Thus, we only need to look at the input and result parameters. return w.isParameterized(t.params) || w.isParameterized(t.results) - case *Union: - unimplemented() - case *Interface: if t.allMethods != nil { // interface is complete - quick test diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go index d590066ad60..db34d0705fd 100644 --- a/src/cmd/compile/internal/types2/interface.go +++ b/src/cmd/compile/internal/types2/interface.go @@ -242,23 +242,26 @@ func completeInterface(check *Checker, pos syntax.Pos, ityp *Interface) { } types = t.allTypes case *Union: - types = NewSum(t.terms) - // TODO(gri) don't ignore tilde information + // TODO(gri) combine with default case once we have + // converted all tests to new notation and we + // can report an error when we don't have an + // interface before go1.18. + types = typ case *TypeParam: if check != nil && !check.allowVersion(check.pkg, 1, 18) { check.errorf(pos, "%s is a type parameter, not an interface", typ) continue } - types = t + types = typ default: - if t == Typ[Invalid] { + if typ == Typ[Invalid] { continue } if check != nil && !check.allowVersion(check.pkg, 1, 18) { check.errorf(pos, "%s is not an interface", typ) continue } - types = t + types = typ } allTypes = intersect(allTypes, types) } @@ -279,44 +282,6 @@ func completeInterface(check *Checker, pos syntax.Pos, ityp *Interface) { ityp.allTypes = allTypes } -// intersect computes the intersection of the types x and y. -// Note: An incomming nil type stands for the top type. A top -// type result is returned as nil. -func intersect(x, y Type) (r Type) { - defer func() { - if r == theTop { - r = nil - } - }() - - switch { - case x == theBottom || y == theBottom: - return theBottom - case x == nil || x == theTop: - return y - case y == nil || x == theTop: - return x - } - - xtypes := unpack(x) - ytypes := unpack(y) - // Compute the list rtypes which includes only - // types that are in both xtypes and ytypes. - // Quadratic algorithm, but good enough for now. - // TODO(gri) fix this - var rtypes []Type - for _, x := range xtypes { - if includes(ytypes, x) { - rtypes = append(rtypes, x) - } - } - - if rtypes == nil { - return theBottom - } - return NewSum(rtypes) -} - func sortTypes(list []Type) { sort.Stable(byUniqueTypeName(list)) } diff --git a/src/cmd/compile/internal/types2/operand.go b/src/cmd/compile/internal/types2/operand.go index 455d8b5dd1d..fdc6ec52aae 100644 --- a/src/cmd/compile/internal/types2/operand.go +++ b/src/cmd/compile/internal/types2/operand.go @@ -248,6 +248,12 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er V := x.typ + const debugAssignableTo = false + if debugAssignableTo && check != nil { + check.dump("V = %s", V) + check.dump("T = %s", T) + } + // x's type is identical to T if check.identical(V, T) { return true, 0 @@ -256,11 +262,20 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er Vu := optype(V) Tu := optype(T) + if debugAssignableTo && check != nil { + check.dump("Vu = %s", Vu) + check.dump("Tu = %s", Tu) + } + // x is an untyped value representable by a value of type T. if isUntyped(Vu) { - if t, ok := Tu.(*Sum); ok { - return t.is(func(t Type) bool { + if t, ok := Tu.(*Union); ok { + return t.is(func(t Type, tilde bool) bool { // TODO(gri) this could probably be more efficient + if tilde { + // TODO(gri) We need to check assignability + // for the underlying type of x. + } ok, _ := x.assignableTo(check, t, reason) return ok }), _IncompatibleAssign diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go index ab0a4572767..bcb3e221d00 100644 --- a/src/cmd/compile/internal/types2/predicates.go +++ b/src/cmd/compile/internal/types2/predicates.go @@ -28,8 +28,8 @@ func is(typ Type, what BasicInfo) bool { switch t := optype(typ).(type) { case *Basic: return t.info&what != 0 - case *Sum: - return t.is(func(typ Type) bool { return is(typ, what) }) + case *Union: + return t.underIs(func(t Type) bool { return is(t, what) }) } return false } @@ -124,11 +124,10 @@ func comparable(T Type, seen map[Type]bool) bool { return true case *Array: return comparable(t.elem, seen) - case *Sum: - pred := func(t Type) bool { + case *Union: + return t.underIs(func(t Type) bool { return comparable(t, seen) - } - return t.is(pred) + }) case *TypeParam: return t.Bound().IsComparable() } @@ -142,8 +141,8 @@ func hasNil(typ Type) bool { return t.kind == UnsafePointer case *Slice, *Pointer, *Signature, *Interface, *Map, *Chan: return true - case *Sum: - return t.is(hasNil) + case *Union: + return t.underIs(hasNil) } return false } @@ -261,21 +260,20 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { check.identical0(x.results, y.results, cmpTags, p) } - case *Sum: - // Two sum types are identical if they contain the same types. - // (Sum types always consist of at least two types. Also, the - // the set (list) of types in a sum type consists of unique - // types - each type appears exactly once. Thus, two sum types + case *Union: + // Two union types are identical if they contain the same terms. + // The set (list) of types in a union type consists of unique + // types - each type appears exactly once. Thus, two union types // must contain the same number of types to have chance of // being equal. - if y, ok := y.(*Sum); ok && len(x.types) == len(y.types) { + if y, ok := y.(*Union); ok && x.NumTerms() == y.NumTerms() { // Every type in x.types must be in y.types. // Quadratic algorithm, but probably good enough for now. // TODO(gri) we need a fast quick type ID/hash for all types. L: - for _, x := range x.types { - for _, y := range y.types { - if Identical(x, y) { + for i, xt := range x.types { + for j, yt := range y.types { + if Identical(xt, yt) && x.tilde[i] == y.tilde[j] { continue L // x is in y.types } } @@ -284,9 +282,6 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { return true } - case *Union: - unimplemented() - case *Interface: // Two interface types are identical if they have the same set of methods with // the same names and identical function types. Lower-case method names from diff --git a/src/cmd/compile/internal/types2/sanitize.go b/src/cmd/compile/internal/types2/sanitize.go index c30febfda89..ce26bab186e 100644 --- a/src/cmd/compile/internal/types2/sanitize.go +++ b/src/cmd/compile/internal/types2/sanitize.go @@ -106,11 +106,8 @@ func (s sanitizer) typ(typ Type) Type { s.tuple(t.params) s.tuple(t.results) - case *Sum: - s.typeList(t.types) - case *Union: - s.typeList(t.terms) + s.typeList(t.types) case *Interface: s.funcList(t.methods) diff --git a/src/cmd/compile/internal/types2/sizeof_test.go b/src/cmd/compile/internal/types2/sizeof_test.go index 552f3488cd8..d3c391161ed 100644 --- a/src/cmd/compile/internal/types2/sizeof_test.go +++ b/src/cmd/compile/internal/types2/sizeof_test.go @@ -27,7 +27,6 @@ func TestSizeof(t *testing.T) { {Pointer{}, 8, 16}, {Tuple{}, 12, 24}, {Signature{}, 44, 88}, - {Sum{}, 12, 24}, {Union{}, 24, 48}, {Interface{}, 52, 104}, {Map{}, 16, 32}, diff --git a/src/cmd/compile/internal/types2/sizes.go b/src/cmd/compile/internal/types2/sizes.go index c6b807cd065..cb789598e57 100644 --- a/src/cmd/compile/internal/types2/sizes.go +++ b/src/cmd/compile/internal/types2/sizes.go @@ -148,10 +148,8 @@ func (s *StdSizes) Sizeof(T Type) int64 { } offsets := s.Offsetsof(t.fields) return offsets[n-1] + s.Sizeof(t.fields[n-1].typ) - case *Sum: - panic("Sizeof unimplemented for type sum") case *Union: - unimplemented() + panic("Sizeof unimplemented for union") case *Interface: return s.WordSize * 2 } diff --git a/src/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go index c3e646c80c1..e9ffd4f5ca9 100644 --- a/src/cmd/compile/internal/types2/stmt.go +++ b/src/cmd/compile/internal/types2/stmt.go @@ -912,12 +912,12 @@ func rangeKeyVal(typ Type, wantKey, wantVal bool) (Type, Type, string) { msg = "receive from send-only channel" } return typ.elem, Typ[Invalid], msg - case *Sum: + case *Union: first := true var key, val Type var msg string - typ.is(func(t Type) bool { - k, v, m := rangeKeyVal(under(t), wantKey, wantVal) + typ.underIs(func(t Type) bool { + k, v, m := rangeKeyVal(t, wantKey, wantVal) if k == nil || m != "" { key, val, msg = k, v, m return false diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index a2b81ba0cc0..bfec61a0656 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -298,21 +298,13 @@ func (subst *subster) typ(typ Type) Type { } } - case *Sum: + case *Union: types, copied := subst.typeList(t.types) if copied { - // Don't do it manually, with a Sum literal: the new - // types list may not be unique and NewSum may remove - // duplicates. - return NewSum(types) - } - - case *Union: - terms, copied := subst.typeList(t.terms) - if copied { - // TODO(gri) Do we need to remove duplicates that may have - // crept in after substitution? It may not matter. - return newUnion(terms, t.tilde) + // TODO(gri) Remove duplicates that may have crept in after substitution + // (unlikely but possible). This matters for the Identical + // predicate on unions. + return newUnion(types, t.tilde) } case *Interface: diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index 3b2a5960e81..aab75811b8a 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -261,53 +261,6 @@ func (s *Signature) Results() *Tuple { return s.results } // Variadic reports whether the signature s is variadic. func (s *Signature) Variadic() bool { return s.variadic } -// A Sum represents a set of possible types. -// Sums are currently used to represent type lists of interfaces -// and thus the underlying types of type parameters; they are not -// first class types of Go. -type Sum struct { - types []Type // types are unique -} - -// NewSum returns a new Sum type consisting of the provided -// types if there are more than one. If there is exactly one -// type, it returns that type. If the list of types is empty -// the result is nil. -func NewSum(types []Type) Type { - if len(types) == 0 { - return nil - } - - // What should happen if types contains a sum type? - // Do we flatten the types list? For now we check - // and panic. This should not be possible for the - // current use case of type lists. - // TODO(gri) Come up with the rules for sum types. - for _, t := range types { - if _, ok := t.(*Sum); ok { - panic("sum type contains sum type - unimplemented") - } - } - - if len(types) == 1 { - return types[0] - } - return &Sum{types: types} -} - -// is reports whether all types in t satisfy pred. -func (s *Sum) is(pred func(Type) bool) bool { - if s == nil { - return false - } - for _, t := range s.types { - if !pred(t) { - return false - } - } - return true -} - // An Interface represents an interface type. type Interface struct { methods []*Func // ordered list of explicitly declared methods @@ -325,8 +278,8 @@ func unpack(typ Type) []Type { if typ == nil { return nil } - if sum := asSum(typ); sum != nil { - return sum.types + if u := asUnion(typ); u != nil { + return u.types } return []Type{typ} } @@ -716,9 +669,16 @@ func optype(typ Type) Type { // for a type parameter list of the form: // (type T interface { type T }). // See also issue #39680. - if u := t.Bound().allTypes; u != nil && u != typ { - // u != typ and u is a type parameter => under(u) != typ, so this is ok - return under(u) + if a := t.Bound().allTypes; a != nil { + // If we have a union with a single entry, ignore + // any tilde because under(~t) == under(t). + if u, _ := a.(*Union); u != nil && u.NumTerms() == 1 { + a = u.types[0] + } + if a != typ { + // a != typ and a is a type parameter => under(a) != typ, so this is ok + return under(a) + } } return theTop } @@ -800,7 +760,6 @@ func (t *Struct) Underlying() Type { return t } func (t *Pointer) Underlying() Type { return t } func (t *Tuple) Underlying() Type { return t } func (t *Signature) Underlying() Type { return t } -func (t *Sum) Underlying() Type { return t } func (t *Interface) Underlying() Type { return t } func (t *Map) Underlying() Type { return t } func (t *Chan) Underlying() Type { return t } @@ -818,7 +777,6 @@ func (t *Struct) String() string { return TypeString(t, nil) } func (t *Pointer) String() string { return TypeString(t, nil) } func (t *Tuple) String() string { return TypeString(t, nil) } func (t *Signature) String() string { return TypeString(t, nil) } -func (t *Sum) String() string { return TypeString(t, nil) } func (t *Interface) String() string { return TypeString(t, nil) } func (t *Map) String() string { return TypeString(t, nil) } func (t *Chan) String() string { return TypeString(t, nil) } @@ -833,7 +791,7 @@ func (t *top) String() string { return TypeString(t, nil) } // under must only be called when a type is known // to be fully set up. func under(t Type) Type { - // TODO(gri) is this correct for *Sum? + // TODO(gri) is this correct for *Union? if n := asNamed(t); n != nil { return n.under() } @@ -880,8 +838,8 @@ func asSignature(t Type) *Signature { return op } -func asSum(t Type) *Sum { - op, _ := optype(t).(*Sum) +func asUnion(t Type) *Union { + op, _ := optype(t).(*Union) return op } diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go index 55858b7b42a..466beb23988 100644 --- a/src/cmd/compile/internal/types2/typestring.go +++ b/src/cmd/compile/internal/types2/typestring.go @@ -157,11 +157,8 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { buf.WriteString("func") writeSignature(buf, t, qf, visited) - case *Sum: - writeTypeList(buf, t.types, qf, visited) - case *Union: - for i, e := range t.terms { + for i, e := range t.types { if i > 0 { buf.WriteString("|") } diff --git a/src/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go index f1630b75d0e..e5983dd40c6 100644 --- a/src/cmd/compile/internal/types2/unify.go +++ b/src/cmd/compile/internal/types2/unify.go @@ -352,12 +352,9 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool { u.nify(x.results, y.results, p) } - case *Sum: - // This should not happen with the current internal use of sum types. - panic("type inference across sum types not implemented") - case *Union: - unimplemented() + // This should not happen with the current internal use of union types. + panic("type inference across union types not implemented") case *Interface: // Two interface types are identical if they have the same set of methods with diff --git a/src/cmd/compile/internal/types2/union.go b/src/cmd/compile/internal/types2/union.go index 70dc3bc360b..a5ef721ee6b 100644 --- a/src/cmd/compile/internal/types2/union.go +++ b/src/cmd/compile/internal/types2/union.go @@ -10,16 +10,16 @@ import "cmd/compile/internal/syntax" // API // A Union represents a union of terms. -// A term is a type, possibly with a ~ (tilde) indication. +// A term is a type with a ~ (tilde) flag. type Union struct { - terms []Type // terms are unique + types []Type // types are unique tilde []bool // if tilde[i] is set, terms[i] is of the form ~T } -func NewUnion(terms []Type, tilde []bool) Type { return newUnion(terms, tilde) } +func NewUnion(types []Type, tilde []bool) Type { return newUnion(types, tilde) } -func (u *Union) NumTerms() int { return len(u.terms) } -func (u *Union) Term(i int) (Type, bool) { return u.terms[i], u.tilde[i] } +func (u *Union) NumTerms() int { return len(u.types) } +func (u *Union) Term(i int) (Type, bool) { return u.types[i], u.tilde[i] } func (u *Union) Underlying() Type { return u } func (u *Union) String() string { return TypeString(u, nil) } @@ -27,26 +27,52 @@ func (u *Union) String() string { return TypeString(u, nil) } // ---------------------------------------------------------------------------- // Implementation -func newUnion(terms []Type, tilde []bool) Type { - assert(len(terms) == len(tilde)) - if terms == nil { +func newUnion(types []Type, tilde []bool) Type { + assert(len(types) == len(tilde)) + if types == nil { return nil } t := new(Union) - t.terms = terms + t.types = types t.tilde = tilde return t } +// is reports whether f returned true for all terms (type, tilde) of u. +func (u *Union) is(f func(Type, bool) bool) bool { + if u == nil { + return false + } + for i, t := range u.types { + if !f(t, u.tilde[i]) { + return false + } + } + return true +} + +// is reports whether f returned true for the underlying types of all terms of u. +func (u *Union) underIs(f func(Type) bool) bool { + if u == nil { + return false + } + for _, t := range u.types { + if !f(under(t)) { + return false + } + } + return true +} + func parseUnion(check *Checker, tlist []syntax.Expr) Type { - var terms []Type + var types []Type var tilde []bool for _, x := range tlist { t, d := parseTilde(check, x) if len(tlist) == 1 && !d { return t // single type } - terms = append(terms, t) + types = append(types, t) tilde = append(tilde, d) } @@ -55,7 +81,7 @@ func parseUnion(check *Checker, tlist []syntax.Expr) Type { // for correctness of the code. // Note: This is a quadratic algorithm, but unions tend to be short. check.later(func() { - for i, t := range terms { + for i, t := range types { t := expand(t) if t == Typ[Invalid] { continue @@ -85,14 +111,14 @@ func parseUnion(check *Checker, tlist []syntax.Expr) Type { } // Complain about duplicate entries a|a, but also a|~a, and ~a|~a. - if includes(terms[:i], t) { + if includes(types[:i], t) { // TODO(gri) this currently doesn't print the ~ if present check.softErrorf(pos, "duplicate term %s in union element", t) } } }) - return newUnion(terms, tilde) + return newUnion(types, tilde) } func parseTilde(check *Checker, x syntax.Expr) (Type, bool) { @@ -103,3 +129,60 @@ func parseTilde(check *Checker, x syntax.Expr) (Type, bool) { } return check.anyType(x), tilde } + +// intersect computes the intersection of the types x and y. +// Note: An incomming nil type stands for the top type. A top +// type result is returned as nil. +func intersect(x, y Type) (r Type) { + defer func() { + if r == theTop { + r = nil + } + }() + + switch { + case x == theBottom || y == theBottom: + return theBottom + case x == nil || x == theTop: + return y + case y == nil || x == theTop: + return x + } + + // Compute the terms which are in both x and y. + xu, _ := x.(*Union) + yu, _ := y.(*Union) + switch { + case xu != nil && yu != nil: + // Quadratic algorithm, but good enough for now. + // TODO(gri) fix asymptotic performance + var types []Type + var tilde []bool + for _, y := range yu.types { + if includes(xu.types, y) { + types = append(types, y) + tilde = append(tilde, true) // TODO(gri) fix this + } + } + if types != nil { + return newUnion(types, tilde) + } + + case xu != nil: + if includes(xu.types, y) { + return y + } + + case yu != nil: + if includes(yu.types, x) { + return x + } + + default: // xu == nil && yu == nil + if Identical(x, y) { + return x + } + } + + return theBottom +} From 8c5c5a9e6983c00d63f3216976f102d79065a180 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 1 Jun 2021 22:48:20 -0700 Subject: [PATCH 245/940] [dev.typeparams] cmd/compile/internal/importer: review of support.go This CL removes the // UNREVIEWED disclaimer at the top of the file. This file is essentially a copy of its reviewed version at src/go/internal/gcimporter/support.go with adjustments to make it work for the compiler and types2. To see the changes made with respect to the original, compare patchset 1 against patchset 2. Change-Id: Icb8e7e7cac02751265c1020431018293826bad18 Reviewed-on: https://go-review.googlesource.com/c/go/+/324130 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/importer/support.go | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cmd/compile/internal/importer/support.go b/src/cmd/compile/internal/importer/support.go index 40b9c7c9583..3d1f77afcd0 100644 --- a/src/cmd/compile/internal/importer/support.go +++ b/src/cmd/compile/internal/importer/support.go @@ -1,4 +1,3 @@ -// UNREVIEWED // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. From cc52fdd1f3ec9ee24c0a0d6223ac934672c9569c Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 1 Jun 2021 23:05:25 -0700 Subject: [PATCH 246/940] [dev.typeparams] cmd/compile/internal/importer: review of exportdata.go This CL removes the // UNREVIEWED disclaimer at the top of the file. This file is essentially a copy of its reviewed version at src/go/internal/gcimporter/exportdata.go with adjustments to make it work for the compiler and types2. To see the changes made with respect to the original, compare patchset 1 against patchset 2. Change-Id: I276d898ef238afa37ec6b9605496407df36cf7d0 Reviewed-on: https://go-review.googlesource.com/c/go/+/324133 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/importer/exportdata.go | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cmd/compile/internal/importer/exportdata.go b/src/cmd/compile/internal/importer/exportdata.go index 3925a64314e..6a672be9c1b 100644 --- a/src/cmd/compile/internal/importer/exportdata.go +++ b/src/cmd/compile/internal/importer/exportdata.go @@ -1,4 +1,3 @@ -// UNREVIEWED // Copyright 2011 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. From 498a48327fae3b57e2696322f1ce2b681ccca668 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 1 Jun 2021 18:45:40 -0700 Subject: [PATCH 247/940] [dev.typeparams] cmd/compile: sort iface fields before expansion For toolstash -cmp compatibility with types2, we also need to sort fields (or at least the embedded types) *before* expanding them. This is relevant to what position information and parameter names are used for methods when embedded interfaces have overlapping methods. This came up in archive/zip, which has: type fileInfoDirEntry interface { fs.FileInfo fs.DirEntry } and both of these embedded interfaces in turn have an "IsDir() bool" method. Traditionally, cmd/compile would keep the method from fs.FileInfo.IsDir, but with types2 it will now keep fs.DirEntry.IsDir instead. This doesn't affect correctness at all, but it does end up in DWARF sometimes. Change-Id: Iac8d6321894be335466a76b5bf8a0c1b15a3581b Reviewed-on: https://go-review.googlesource.com/c/go/+/324330 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types/size.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/cmd/compile/internal/types/size.go b/src/cmd/compile/internal/types/size.go index e6ca4556b94..f5a74f83b39 100644 --- a/src/cmd/compile/internal/types/size.go +++ b/src/cmd/compile/internal/types/size.go @@ -90,6 +90,26 @@ func expandiface(t *Type) { methods = append(methods, m) } + { + methods := t.Methods().Slice() + sort.SliceStable(methods, func(i, j int) bool { + mi, mj := methods[i], methods[j] + + // Sort embedded types by type name (if any). + if mi.Sym == nil && mj.Sym == nil { + return mi.Type.Sym().Less(mj.Type.Sym()) + } + + // Sort methods before embedded types. + if mi.Sym == nil || mj.Sym == nil { + return mi.Sym != nil + } + + // Sort methods by symbol name. + return mi.Sym.Less(mj.Sym) + }) + } + for _, m := range t.Methods().Slice() { if m.Sym == nil { continue From dd7ba3ba2c860c40be6d70b63d4a678449cae80f Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Wed, 2 Jun 2021 09:20:22 -0700 Subject: [PATCH 248/940] net: don't rely on system hosts in TestCVE202133195 Also don't unnecessarily deref the error return. Fixes #46504 Change-Id: I22d14ac76776f8988fa0774bdcb5fcd801ce0185 Reviewed-on: https://go-review.googlesource.com/c/go/+/324190 Trust: David Chase Trust: Damien Neil Run-TryBot: David Chase TryBot-Result: Go Bot Reviewed-by: Damien Neil --- src/net/dnsclient_unix_test.go | 39 +++++++++++++++++----------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go index a718e75a726..a59be7fea0d 100644 --- a/src/net/dnsclient_unix_test.go +++ b/src/net/dnsclient_unix_test.go @@ -1898,61 +1898,62 @@ func TestCVE202133195(t *testing.T) { // Change the default resolver to match our manipulated resolver originalDefault := DefaultResolver DefaultResolver = &r - defer func() { - DefaultResolver = originalDefault - }() + defer func() { DefaultResolver = originalDefault }() + // Redirect host file lookups. + defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath) + testHookHostsPath = "testdata/hosts" _, err := r.LookupCNAME(context.Background(), "golang.org") if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected { - t.Errorf("Resolver.LookupCNAME returned unexpected error, got %q, want %q", err.Error(), expected) + t.Errorf("Resolver.LookupCNAME returned unexpected error, got %q, want %q", err, expected) } _, err = LookupCNAME("golang.org") if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected { - t.Errorf("LookupCNAME returned unexpected error, got %q, want %q", err.Error(), expected) + t.Errorf("LookupCNAME returned unexpected error, got %q, want %q", err, expected) } _, _, err = r.LookupSRV(context.Background(), "target", "tcp", "golang.org") if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected { - t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected) + t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err, expected) } _, _, err = LookupSRV("target", "tcp", "golang.org") if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected { - t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected) + t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected) } _, _, err = r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org") if expected := "lookup golang.org: SRV header name is invalid"; err == nil || err.Error() != expected { - t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected) + t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err, expected) } _, _, err = LookupSRV("hdr", "tcp", "golang.org") if expected := "lookup golang.org: SRV header name is invalid"; err == nil || err.Error() != expected { - t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected) + t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected) } _, err = r.LookupMX(context.Background(), "golang.org") if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected { - t.Errorf("Resolver.LookupMX returned unexpected error, got %q, want %q", err.Error(), expected) + t.Errorf("Resolver.LookupMX returned unexpected error, got %q, want %q", err, expected) } _, err = LookupMX("golang.org") if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected { - t.Errorf("LookupMX returned unexpected error, got %q, want %q", err.Error(), expected) + t.Errorf("LookupMX returned unexpected error, got %q, want %q", err, expected) } _, err = r.LookupNS(context.Background(), "golang.org") if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected { - t.Errorf("Resolver.LookupNS returned unexpected error, got %q, want %q", err.Error(), expected) + t.Errorf("Resolver.LookupNS returned unexpected error, got %q, want %q", err, expected) } _, err = LookupNS("golang.org") if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected { - t.Errorf("LookupNS returned unexpected error, got %q, want %q", err.Error(), expected) + t.Errorf("LookupNS returned unexpected error, got %q, want %q", err, expected) } - _, err = r.LookupAddr(context.Background(), "1.2.3.4") - if expected := "lookup 1.2.3.4: PTR target is invalid"; err == nil || err.Error() != expected { - t.Errorf("Resolver.LookupAddr returned unexpected error, got %q, want %q", err.Error(), expected) + _, err = r.LookupAddr(context.Background(), "192.0.2.42") + if expected := "lookup 192.0.2.42: PTR target is invalid"; err == nil || err.Error() != expected { + t.Errorf("Resolver.LookupAddr returned unexpected error, got %q, want %q", err, expected) } - _, err = LookupAddr("1.2.3.4") - if expected := "lookup 1.2.3.4: PTR target is invalid"; err == nil || err.Error() != expected { - t.Errorf("LookupAddr returned unexpected error, got %q, want %q", err.Error(), expected) + _, err = LookupAddr("192.0.2.42") + if expected := "lookup 192.0.2.42: PTR target is invalid"; err == nil || err.Error() != expected { + t.Errorf("LookupAddr returned unexpected error, got %q, want %q", err, expected) } } From c7b98115815a04d9efa664c163d39f5fea38b32c Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 1 Jun 2021 23:01:41 -0700 Subject: [PATCH 249/940] [dev.typeparams] cmd/compile/internal/importer: review of gcimporter.go This CL removes the // UNREVIEWED disclaimer at the top of the file. This file is essentially a copy of its reviewed version at src/go/internal/gcimporter/gcimporter.go with adjustments to make it work for the compiler and types2. To see the changes made with respect to the original, compare patchset 1 against patchset 2. Change-Id: I0fd635730fb6bdee8cef1b89154f4049a6581751 Reviewed-on: https://go-review.googlesource.com/c/go/+/324132 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/importer/gcimporter.go | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cmd/compile/internal/importer/gcimporter.go b/src/cmd/compile/internal/importer/gcimporter.go index feb18cf2c9a..6c5458fad18 100644 --- a/src/cmd/compile/internal/importer/gcimporter.go +++ b/src/cmd/compile/internal/importer/gcimporter.go @@ -1,4 +1,3 @@ -// UNREVIEWED // Copyright 2011 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. From 6b1cdeaef3099b32d244cef7bb5adc4d7b7628fc Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 1 Jun 2021 17:00:26 -0700 Subject: [PATCH 250/940] [dev.typeparams] cmd/link: include "go build" output in test logs If running "go build" outputs anything, write it to the test log even if the test succeeds. This makes it easier to diagnose errors within the compiler by adding print statements and finding them in the test log, even if the compiler exits successfully. Change-Id: Id04716c4e1dcd9220c35ea0040ea516c1dd5237c Reviewed-on: https://go-review.googlesource.com/c/go/+/324329 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/cmd/link/internal/ld/dwarf_test.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/cmd/link/internal/ld/dwarf_test.go b/src/cmd/link/internal/ld/dwarf_test.go index 2f59c2fe0aa..543dd5caac7 100644 --- a/src/cmd/link/internal/ld/dwarf_test.go +++ b/src/cmd/link/internal/ld/dwarf_test.go @@ -101,8 +101,11 @@ func gobuild(t *testing.T, dir string, testfile string, gcflags string) *builtFi } cmd := exec.Command(testenv.GoToolPath(t), "build", gcflags, "-o", dst, src) - if b, err := cmd.CombinedOutput(); err != nil { - t.Logf("build: %s\n", b) + b, err := cmd.CombinedOutput() + if len(b) != 0 { + t.Logf("## build output:\n%s", b) + } + if err != nil { t.Fatalf("build error: %v", err) } From 97cb0113a358a24931bc91c956da0cb023f2776c Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Wed, 2 Jun 2021 00:03:25 -0700 Subject: [PATCH 251/940] [dev.typeparams] cmd/compile: fix export/import of constants with typeparam type A constant will have a TYPEPARAM type if it appears in a place where it must match that typeparam type (e.g. in a binary operation with a variable of that typeparam type). If so, then we must write out its actual constant kind as well, so its constant val can be read in properly during import. Fixed some export/import tests which were casting some untyped constants to avoid this problem. Change-Id: I285ad8f1c8febbe526769c96e6b27acbd23050f0 Reviewed-on: https://go-review.googlesource.com/c/go/+/324189 Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/typecheck/iexport.go | 44 ++++++++++++++----- src/cmd/compile/internal/typecheck/iimport.go | 28 ++++++++++-- test/typeparam/fact.go | 6 +-- test/typeparam/factimp.dir/a.go | 6 +-- test/typeparam/listimp.dir/a.go | 3 +- 5 files changed, 65 insertions(+), 22 deletions(-) diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index d83f385fcbf..66c356ee7c8 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -1061,26 +1061,50 @@ func constTypeOf(typ *types.Type) constant.Kind { } func (w *exportWriter) value(typ *types.Type, v constant.Value) { - ir.AssertValidTypeForConst(typ, v) w.typ(typ) + var kind constant.Kind + var valType *types.Type - // Each type has only one admissible constant representation, - // so we could type switch directly on v.U here. However, - // switching on the type increases symmetry with import logic - // and provides a useful consistency check. + if typ.Kind() == types.TTYPEPARAM { + // A constant will have a TYPEPARAM type if it appears in a place + // where it must match that typeparam type (e.g. in a binary + // operation with a variable of that typeparam type). If so, then + // we must write out its actual constant kind as well, so its + // constant val can be read in properly during import. + kind = v.Kind() + w.int64(int64(kind)) - switch constTypeOf(typ) { + switch kind { + case constant.Int: + valType = types.Types[types.TINT64] + case constant.Float: + valType = types.Types[types.TFLOAT64] + case constant.Complex: + valType = types.Types[types.TCOMPLEX128] + } + } else { + ir.AssertValidTypeForConst(typ, v) + kind = constTypeOf(typ) + valType = typ + } + + // Each type has only one admissible constant representation, so we could + // type switch directly on v.Kind() here. However, switching on the type + // (in the non-typeparam case) increases symmetry with import logic and + // provides a useful consistency check. + + switch kind { case constant.Bool: w.bool(constant.BoolVal(v)) case constant.String: w.string(constant.StringVal(v)) case constant.Int: - w.mpint(v, typ) + w.mpint(v, valType) case constant.Float: - w.mpfloat(v, typ) + w.mpfloat(v, valType) case constant.Complex: - w.mpfloat(constant.Real(v), typ) - w.mpfloat(constant.Imag(v), typ) + w.mpfloat(constant.Real(v), valType) + w.mpfloat(constant.Imag(v), valType) } } diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 4c31e47378a..96107b657b6 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -400,19 +400,39 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name { } func (p *importReader) value(typ *types.Type) constant.Value { - switch constTypeOf(typ) { + var kind constant.Kind + var valType *types.Type + + if typ.Kind() == types.TTYPEPARAM { + // If a constant had a typeparam type, then we wrote out its + // actual constant kind as well. + kind = constant.Kind(p.int64()) + switch kind { + case constant.Int: + valType = types.Types[types.TINT64] + case constant.Float: + valType = types.Types[types.TFLOAT64] + case constant.Complex: + valType = types.Types[types.TCOMPLEX128] + } + } else { + kind = constTypeOf(typ) + valType = typ + } + + switch kind { case constant.Bool: return constant.MakeBool(p.bool()) case constant.String: return constant.MakeString(p.string()) case constant.Int: var i big.Int - p.mpint(&i, typ) + p.mpint(&i, valType) return constant.Make(&i) case constant.Float: - return p.float(typ) + return p.float(valType) case constant.Complex: - return makeComplex(p.float(typ), p.float(typ)) + return makeComplex(p.float(valType), p.float(valType)) } base.Fatalf("unexpected value type: %v", typ) diff --git a/test/typeparam/fact.go b/test/typeparam/fact.go index 16b2adf6fb7..ea86ae3e028 100644 --- a/test/typeparam/fact.go +++ b/test/typeparam/fact.go @@ -9,10 +9,10 @@ package main import "fmt" func fact[T interface { type int, int64, float64 }](n T) T { - if n == T(1) { - return T(1) + if n == 1 { + return 1 } - return n * fact(n - T(1)) + return n * fact(n - 1) } func main() { diff --git a/test/typeparam/factimp.dir/a.go b/test/typeparam/factimp.dir/a.go index e11575e66e5..35524743829 100644 --- a/test/typeparam/factimp.dir/a.go +++ b/test/typeparam/factimp.dir/a.go @@ -5,8 +5,8 @@ package a func Fact[T interface { type int, int64, float64 }](n T) T { - if n == T(1) { - return T(1) + if n == 1 { + return 1 } - return n * Fact(n - T(1)) + return n * Fact(n - 1) } diff --git a/test/typeparam/listimp.dir/a.go b/test/typeparam/listimp.dir/a.go index a4118a0e819..0a4634b7be4 100644 --- a/test/typeparam/listimp.dir/a.go +++ b/test/typeparam/listimp.dir/a.go @@ -42,11 +42,10 @@ type ListNum[T OrderedNum] struct { const Clip = 5 // clippedLargest returns the largest in the list of OrderNums, but a max of 5. -// TODO(danscales): fix export/import of an untype constant with typeparam type func (l *ListNum[T]) ClippedLargest() T { var max T for p := l; p != nil; p = p.Next { - if p.Val > max && p.Val < T(Clip) { + if p.Val > max && p.Val < Clip { max = p.Val } } From 848b58e47357965dc5a61fb0ae5535da717e2633 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 27 May 2021 19:03:16 -0700 Subject: [PATCH 252/940] [dev.typeparams] cmd/compile/internal/types2: clean up type set/union intersection - Eliminate the need for bottom type: This is now represented by an empty union (denoting the set of no types). - Clean up type set intersection and incorporate tilde information in intersection operation and satisfaction tests. - Minor cleanups along the way. - Note: The intersection algorithm does not always compute the largest possible intersection. To be addressed in a follow-up CL. Change-Id: I7fa19df5996da36a4d8f29300d30a0aa4d8a3e5c Reviewed-on: https://go-review.googlesource.com/c/go/+/323354 Trust: Robert Griesemer Run-TryBot: Robert Griesemer Reviewed-by: Robert Findley TryBot-Result: Go Bot --- src/cmd/compile/internal/types2/interface.go | 10 -- src/cmd/compile/internal/types2/predicates.go | 11 +- src/cmd/compile/internal/types2/sanitize.go | 2 +- .../compile/internal/types2/sizeof_test.go | 1 - src/cmd/compile/internal/types2/subst.go | 4 +- .../internal/types2/testdata/check/issues.go2 | 2 +- .../types2/testdata/examples/constraints.go2 | 14 +++ src/cmd/compile/internal/types2/type.go | 40 +++---- src/cmd/compile/internal/types2/typestring.go | 7 +- src/cmd/compile/internal/types2/union.go | 105 +++++++++++++----- 10 files changed, 118 insertions(+), 78 deletions(-) diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go index db34d0705fd..770b8ba5cc8 100644 --- a/src/cmd/compile/internal/types2/interface.go +++ b/src/cmd/compile/internal/types2/interface.go @@ -109,16 +109,6 @@ func flattenUnion(list []syntax.Expr, x syntax.Expr) []syntax.Expr { return append(list, x) } -// includes reports whether typ is in list -func includes(list []Type, typ Type) bool { - for _, e := range list { - if Identical(typ, e) { - return true - } - } - return false -} - func (check *Checker) completeInterface(pos syntax.Pos, ityp *Interface) { if ityp.allMethods != nil { return diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go index bcb3e221d00..74436836cd8 100644 --- a/src/cmd/compile/internal/types2/predicates.go +++ b/src/cmd/compile/internal/types2/predicates.go @@ -97,9 +97,9 @@ func comparable(T Type, seen map[Type]bool) bool { seen[T] = true // If T is a type parameter not constrained by any type - // list (i.e., it's underlying type is the top type), + // list (i.e., it's operational type is the top type), // T is comparable if it has the == method. Otherwise, - // the underlying type "wins". For instance + // the operational type "wins". For instance // // interface{ comparable; type []byte } // @@ -370,10 +370,9 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { // case *instance: // unreachable since types are expanded - case *bottom, *top: - // Either both types are theBottom, or both are theTop in which - // case the initial x == y check will have caught them. Otherwise - // they are not identical. + case *top: + // Either both types are theTop in which case the initial x == y check + // will have caught them. Otherwise they are not identical. case nil: // avoid a crash in case of nil type diff --git a/src/cmd/compile/internal/types2/sanitize.go b/src/cmd/compile/internal/types2/sanitize.go index ce26bab186e..03aef90fe13 100644 --- a/src/cmd/compile/internal/types2/sanitize.go +++ b/src/cmd/compile/internal/types2/sanitize.go @@ -77,7 +77,7 @@ func (s sanitizer) typ(typ Type) Type { s[typ] = typ switch t := typ.(type) { - case *Basic, *bottom, *top: + case *Basic, *top: // nothing to do case *Array: diff --git a/src/cmd/compile/internal/types2/sizeof_test.go b/src/cmd/compile/internal/types2/sizeof_test.go index d3c391161ed..daa039bf92a 100644 --- a/src/cmd/compile/internal/types2/sizeof_test.go +++ b/src/cmd/compile/internal/types2/sizeof_test.go @@ -34,7 +34,6 @@ func TestSizeof(t *testing.T) { {Named{}, 68, 136}, {TypeParam{}, 28, 48}, {instance{}, 52, 96}, - {bottom{}, 0, 0}, {top{}, 0, 0}, // Objects diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index bfec61a0656..617a03ddbc1 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -206,7 +206,7 @@ func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap // Otherwise, targ's type or underlying type must also be one of the interface types listed, if any. if !iface.isSatisfiedBy(targ) { - check.softErrorf(pos, "%s does not satisfy %s (%s not found in %s)", targ, tpar.bound, under(targ), iface.allTypes) + check.softErrorf(pos, "%s does not satisfy %s (%s not found in %s)", targ, tpar.bound, targ, iface.allTypes) return false } @@ -249,7 +249,7 @@ func (subst *subster) typ(typ Type) Type { // Call typOrNil if it's possible that typ is nil. panic("nil typ") - case *Basic, *bottom, *top: + case *Basic, *top: // nothing to do case *Array: diff --git a/src/cmd/compile/internal/types2/testdata/check/issues.go2 b/src/cmd/compile/internal/types2/testdata/check/issues.go2 index 1c73b5da921..f0a7b247489 100644 --- a/src/cmd/compile/internal/types2/testdata/check/issues.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/issues.go2 @@ -234,7 +234,7 @@ func _[T interface{ type func() }](f T) { type sliceOf[E any] interface{ type []E } -func append[T interface{}, S sliceOf[T], T2 interface{ type T }](s S, t ...T2) S +func append[T interface{}, S sliceOf[T], T2 interface{ T }](s S, t ...T2) S var f func() var cancelSlice []context.CancelFunc diff --git a/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 b/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 index e8b3912884c..f6291ccf7dd 100644 --- a/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 +++ b/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 @@ -23,3 +23,17 @@ type ( _ interface{~ /* ERROR cannot use interface */ interface{}} _ interface{int|interface /* ERROR cannot use interface */ {}} ) + +// Multiple embedded union elements are intersected. The order in which they +// appear in the interface doesn't matter since intersection is a symmetric +// operation. + +type myInt1 int +type myInt2 int + +func _[T interface{ myInt1|myInt2; ~int }]() T { return T(0) } +func _[T interface{ ~int; myInt1|myInt2 }]() T { return T(0) } + +// Here the intersections are empty - there's no type that's in the type set of T. +func _[T interface{ myInt1|myInt2; int }]() T { return T(0 /* ERROR cannot convert */ ) } +func _[T interface{ int; myInt1|myInt2 }]() T { return T(0 /* ERROR cannot convert */ ) } diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index aab75811b8a..990b9d374c6 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -376,7 +376,6 @@ func (t *Interface) Method(i int) *Func { t.Complete(); return t.allMethods[i] } // Empty reports whether t is the empty interface. func (t *Interface) Empty() bool { t.Complete() - // A non-nil allTypes may still have length 0 but represents the bottom type. return len(t.allMethods) == 0 && t.allTypes == nil } @@ -431,11 +430,15 @@ func (t *Interface) iterate(f func(*Interface) bool, seen map[*Interface]bool) b // "implements" predicate. func (t *Interface) isSatisfiedBy(typ Type) bool { t.Complete() - if t.allTypes == nil { - return true + switch t := t.allTypes.(type) { + case nil: + return true // no type restrictions + case *Union: + r, _ := t.intersect(typ, false) + return r != nil + default: + return Identical(t, typ) } - types := unpack(t.allTypes) - return includes(types, typ) || includes(types, under(typ)) } // Complete computes the interface's method set. It must be called by users of @@ -654,13 +657,11 @@ func (t *TypeParam) Bound() *Interface { return iface } -// optype returns a type's operational type. Except for -// type parameters, the operational type is the same -// as the underlying type (as returned by under). For -// Type parameters, the operational type is determined -// by the corresponding type bound's type list. The -// result may be the bottom or top type, but it is never -// the incoming type parameter. +// optype returns a type's operational type. Except for type parameters, +// the operational type is the same as the underlying type (as returned +// by under). For Type parameters, the operational type is determined +// by the corresponding type constraint. The result may be the top type, +// but it is never the incoming type parameter. func optype(typ Type) Type { if t := asTypeParam(typ); t != nil { // If the optype is typ, return the top type as we have @@ -733,20 +734,11 @@ var expandf func(Type) Type func init() { expandf = expand } -// bottom represents the bottom of the type lattice. -// It is the underlying type of a type parameter that -// cannot be satisfied by any type, usually because -// the intersection of type constraints left nothing). -type bottom struct{} - -// theBottom is the singleton bottom type. -var theBottom = &bottom{} - // top represents the top of the type lattice. // It is the underlying type of a type parameter that // can be satisfied by any type (ignoring methods), -// usually because the type constraint has no type -// list. +// because its type constraint contains no restrictions +// besides methods. type top struct{} // theTop is the singleton top type. @@ -766,7 +758,6 @@ func (t *Chan) Underlying() Type { return t } func (t *Named) Underlying() Type { return t.underlying } func (t *TypeParam) Underlying() Type { return t } func (t *instance) Underlying() Type { return t } -func (t *bottom) Underlying() Type { return t } func (t *top) Underlying() Type { return t } // Type-specific implementations of String. @@ -783,7 +774,6 @@ func (t *Chan) String() string { return TypeString(t, nil) } func (t *Named) String() string { return TypeString(t, nil) } func (t *TypeParam) String() string { return TypeString(t, nil) } func (t *instance) String() string { return TypeString(t, nil) } -func (t *bottom) String() string { return TypeString(t, nil) } func (t *top) String() string { return TypeString(t, nil) } // under returns the true expanded underlying type. diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go index 466beb23988..28583b62d9a 100644 --- a/src/cmd/compile/internal/types2/typestring.go +++ b/src/cmd/compile/internal/types2/typestring.go @@ -158,6 +158,10 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { writeSignature(buf, t, qf, visited) case *Union: + if t.IsEmpty() { + buf.WriteString("⊥") + break + } for i, e := range t.types { if i > 0 { buf.WriteString("|") @@ -294,9 +298,6 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { writeTypeList(buf, t.targs, qf, visited) buf.WriteByte(']') - case *bottom: - buf.WriteString("⊥") - case *top: buf.WriteString("⊤") diff --git a/src/cmd/compile/internal/types2/union.go b/src/cmd/compile/internal/types2/union.go index a5ef721ee6b..671e36111b1 100644 --- a/src/cmd/compile/internal/types2/union.go +++ b/src/cmd/compile/internal/types2/union.go @@ -16,8 +16,12 @@ type Union struct { tilde []bool // if tilde[i] is set, terms[i] is of the form ~T } -func NewUnion(types []Type, tilde []bool) Type { return newUnion(types, tilde) } +// NewUnion returns a new Union type with the given terms (types[i], tilde[i]). +// The lengths of both arguments must match. An empty union represents the set +// of no types. +func NewUnion(types []Type, tilde []bool) *Union { return newUnion(types, tilde) } +func (u *Union) IsEmpty() bool { return len(u.types) == 0 } func (u *Union) NumTerms() int { return len(u.types) } func (u *Union) Term(i int) (Type, bool) { return u.types[i], u.tilde[i] } @@ -27,10 +31,12 @@ func (u *Union) String() string { return TypeString(u, nil) } // ---------------------------------------------------------------------------- // Implementation -func newUnion(types []Type, tilde []bool) Type { +var emptyUnion = new(Union) + +func newUnion(types []Type, tilde []bool) *Union { assert(len(types) == len(tilde)) - if types == nil { - return nil + if len(types) == 0 { + return emptyUnion } t := new(Union) t.types = types @@ -40,7 +46,7 @@ func newUnion(types []Type, tilde []bool) Type { // is reports whether f returned true for all terms (type, tilde) of u. func (u *Union) is(f func(Type, bool) bool) bool { - if u == nil { + if u.IsEmpty() { return false } for i, t := range u.types { @@ -53,7 +59,7 @@ func (u *Union) is(f func(Type, bool) bool) bool { // is reports whether f returned true for the underlying types of all terms of u. func (u *Union) underIs(f func(Type) bool) bool { - if u == nil { + if u.IsEmpty() { return false } for _, t := range u.types { @@ -130,26 +136,24 @@ func parseTilde(check *Checker, x syntax.Expr) (Type, bool) { return check.anyType(x), tilde } -// intersect computes the intersection of the types x and y. -// Note: An incomming nil type stands for the top type. A top -// type result is returned as nil. +// intersect computes the intersection of the types x and y, +// A nil type stands for the set of all types; an empty union +// stands for the set of no types. func intersect(x, y Type) (r Type) { - defer func() { - if r == theTop { - r = nil - } - }() - + // If one of the types is nil (no restrictions) + // the result is the other type. switch { - case x == theBottom || y == theBottom: - return theBottom - case x == nil || x == theTop: + case x == nil: return y - case y == nil || x == theTop: + case y == nil: return x } // Compute the terms which are in both x and y. + // TODO(gri) This is not correct as it may not always compute + // the "largest" intersection. For instance, for + // x = myInt|~int, y = ~int + // we get the result myInt but we should get ~int. xu, _ := x.(*Union) yu, _ := y.(*Union) switch { @@ -158,23 +162,29 @@ func intersect(x, y Type) (r Type) { // TODO(gri) fix asymptotic performance var types []Type var tilde []bool - for _, y := range yu.types { - if includes(xu.types, y) { - types = append(types, y) - tilde = append(tilde, true) // TODO(gri) fix this + for j, y := range yu.types { + yt := yu.tilde[j] + if r, rt := xu.intersect(y, yt); r != nil { + // Terms x[i] and y[j] match: Select the one that + // is not a ~t because that is the intersection + // type. If both are ~t, they are identical: + // T ∩ T = T + // T ∩ ~t = T + // ~t ∩ T = T + // ~t ∩ ~t = ~t + types = append(types, r) + tilde = append(tilde, rt) } } - if types != nil { - return newUnion(types, tilde) - } + return newUnion(types, tilde) case xu != nil: - if includes(xu.types, y) { + if r, _ := xu.intersect(y, false); r != nil { return y } case yu != nil: - if includes(yu.types, x) { + if r, _ := yu.intersect(x, false); r != nil { return x } @@ -184,5 +194,42 @@ func intersect(x, y Type) (r Type) { } } - return theBottom + return emptyUnion +} + +// includes reports whether typ is in list. +func includes(list []Type, typ Type) bool { + for _, e := range list { + if Identical(typ, e) { + return true + } + } + return false +} + +// intersect computes the intersection of the union u and term (y, yt) +// and returns the intersection term, if any. Otherwise the result is +// (nil, false). +func (u *Union) intersect(y Type, yt bool) (Type, bool) { + under_y := under(y) + for i, x := range u.types { + xt := u.tilde[i] + // determine which types xx, yy to compare + xx := x + if yt { + xx = under(x) + } + yy := y + if xt { + yy = under_y + } + if Identical(xx, yy) { + // T ∩ T = T + // T ∩ ~t = T + // ~t ∩ T = T + // ~t ∩ ~t = ~t + return xx, xt && yt + } + } + return nil, false } From 3c1d502a19dcdaaf0f7ddf58ccad9953fe5d92d1 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 27 May 2021 22:09:58 -0700 Subject: [PATCH 253/940] [dev.typeparams] cmd/compile/internal/types2: eliminate need for unpack and asUnion functions Change-Id: Iaa75b091d52f44939330e5945305aea323ba58f4 Reviewed-on: https://go-review.googlesource.com/c/go/+/323355 Trust: Robert Griesemer Run-TryBot: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/builtins.go | 12 +++---- src/cmd/compile/internal/types2/infer.go | 15 +++++---- src/cmd/compile/internal/types2/subst.go | 11 ++++--- src/cmd/compile/internal/types2/type.go | 35 ++++++--------------- 4 files changed, 29 insertions(+), 44 deletions(-) diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index 1779e32c5c8..20c4ff62a16 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -749,14 +749,12 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { if tp := asTypeParam(x); tp != nil { // Test if t satisfies the requirements for the argument // type and collect possible result types at the same time. - // TODO(gri) This needs to consider the ~ information if we - // have a union type. var rtypes []Type - var tilde []bool - if !tp.Bound().is(func(x Type) bool { - if r := f(x); r != nil { + var tildes []bool + if !tp.Bound().is(func(typ Type, tilde bool) bool { + if r := f(typ); r != nil { rtypes = append(rtypes, r) - tilde = append(tilde, true) // for now - see TODO above + tildes = append(tildes, tilde) return true } return false @@ -772,7 +770,7 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { // construct a suitable new type parameter tpar := NewTypeName(nopos, nil /* = Universe pkg */, "", nil) ptyp := check.NewTypeParam(tpar, 0, &emptyInterface) // assigns type to tpar as a side-effect - tsum := newUnion(rtypes, tilde) + tsum := newUnion(rtypes, tildes) ptyp.bound = &Interface{allMethods: markComplete, allTypes: tsum} return ptyp diff --git a/src/cmd/compile/internal/types2/infer.go b/src/cmd/compile/internal/types2/infer.go index 73ea8330d4a..63cd63aacc6 100644 --- a/src/cmd/compile/internal/types2/infer.go +++ b/src/cmd/compile/internal/types2/infer.go @@ -328,7 +328,7 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { return true } } - return w.isParameterizedList(unpack(t.allTypes)) + return w.isParameterized(t.allTypes) } return t.iterate(func(t *Interface) bool { @@ -477,11 +477,14 @@ func (check *Checker) inferB(tparams []*TypeName, targs []Type, report bool) (ty func (check *Checker) structuralType(constraint Type) Type { if iface, _ := under(constraint).(*Interface); iface != nil { check.completeInterface(nopos, iface) - types := unpack(iface.allTypes) - if len(types) == 1 { - return types[0] + if u, _ := iface.allTypes.(*Union); u != nil { + if u.NumTerms() == 1 { + // TODO(gri) do we need to respect tilde? + return u.types[0] + } + return nil } - return nil + return iface.allTypes } - return constraint + return nil } diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index 617a03ddbc1..35ca197d64c 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -194,14 +194,15 @@ func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap check.softErrorf(pos, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ) return false } - for _, t := range unpack(targBound.allTypes) { - if !iface.isSatisfiedBy(t) { + return iface.is(func(typ Type, tilde bool) bool { + // TODO(gri) incorporate tilde information! + if !iface.isSatisfiedBy(typ) { // TODO(gri) match this error message with the one below (or vice versa) - check.softErrorf(pos, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, t, iface.allTypes) + check.softErrorf(pos, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, typ, iface.allTypes) return false } - } - return false + return true + }) } // Otherwise, targ's type or underlying type must also be one of the interface types listed, if any. diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index 990b9d374c6..92f35f1279c 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -272,29 +272,17 @@ type Interface struct { obj Object // type declaration defining this interface; or nil (for better error messages) } -// unpack unpacks a type into a list of types. -// TODO(gri) Try to eliminate the need for this function. -func unpack(typ Type) []Type { - if typ == nil { - return nil - } - if u := asUnion(typ); u != nil { - return u.types - } - return []Type{typ} -} - -// is reports whether interface t represents types that all satisfy pred. -func (t *Interface) is(pred func(Type) bool) bool { - if t.allTypes == nil { +// is reports whether interface t represents types that all satisfy f. +func (t *Interface) is(f func(Type, bool) bool) bool { + switch t := t.allTypes.(type) { + case nil, *top: + // TODO(gri) should settle on top or nil to represent this case return false // we must have at least one type! (was bug) + case *Union: + return t.is(func(typ Type, tilde bool) bool { return f(typ, tilde) }) + default: + return f(t, false) } - for _, t := range unpack(t.allTypes) { - if !pred(t) { - return false - } - } - return true } // emptyInterface represents the empty (completed) interface @@ -828,11 +816,6 @@ func asSignature(t Type) *Signature { return op } -func asUnion(t Type) *Union { - op, _ := optype(t).(*Union) - return op -} - func asInterface(t Type) *Interface { op, _ := optype(t).(*Interface) return op From d36b7d7bdd130dacfc6166d16dd879e2231baf62 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 1 Jun 2021 22:56:01 -0700 Subject: [PATCH 254/940] [dev.typeparams] cmd/compile/internal/importer: review of gcimporter_test.go This CL removes the // UNREVIEWED disclaimer at the top of the file. This file is essentially a copy of its reviewed version at src/go/internal/gcimporter/gcimporter_test.go with adjustments to make it work for the compiler and types2. To see the changes made with respect to the original, compare patchset 2 against patchset 3. Change-Id: Iaeb9a56a6a56f4c1d93e7bfedc5b1f1968fa6792 Reviewed-on: https://go-review.googlesource.com/c/go/+/324131 Trust: Robert Griesemer Run-TryBot: Robert Griesemer Reviewed-by: Robert Findley TryBot-Result: Go Bot --- .../internal/importer/gcimporter_test.go | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/cmd/compile/internal/importer/gcimporter_test.go b/src/cmd/compile/internal/importer/gcimporter_test.go index 7fb8fed59cf..44c5e06cd67 100644 --- a/src/cmd/compile/internal/importer/gcimporter_test.go +++ b/src/cmd/compile/internal/importer/gcimporter_test.go @@ -1,4 +1,3 @@ -// UNREVIEWED // Copyright 2011 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. @@ -10,7 +9,6 @@ import ( "cmd/compile/internal/types2" "fmt" "internal/testenv" - "io/ioutil" "os" "os/exec" "path/filepath" @@ -64,7 +62,7 @@ const maxTime = 30 * time.Second func testDir(t *testing.T, dir string, endTime time.Time) (nimports int) { dirname := filepath.Join(runtime.GOROOT(), "pkg", runtime.GOOS+"_"+runtime.GOARCH, dir) - list, err := ioutil.ReadDir(dirname) + list, err := os.ReadDir(dirname) if err != nil { t.Fatalf("testDir(%s): %s", dirname, err) } @@ -92,7 +90,7 @@ func testDir(t *testing.T, dir string, endTime time.Time) (nimports int) { } func mktmpdir(t *testing.T) string { - tmpdir, err := ioutil.TempDir("", "gcimporter_test") + tmpdir, err := os.MkdirTemp("", "gcimporter_test") if err != nil { t.Fatal("mktmpdir:", err) } @@ -142,7 +140,7 @@ func TestVersionHandling(t *testing.T) { } const dir = "./testdata/versions" - list, err := ioutil.ReadDir(dir) + list, err := os.ReadDir(dir) if err != nil { t.Fatal(err) } @@ -195,7 +193,7 @@ func TestVersionHandling(t *testing.T) { // create file with corrupted export data // 1) read file - data, err := ioutil.ReadFile(filepath.Join(dir, name)) + data, err := os.ReadFile(filepath.Join(dir, name)) if err != nil { t.Fatal(err) } @@ -212,7 +210,7 @@ func TestVersionHandling(t *testing.T) { // 4) write the file pkgpath += "_corrupted" filename := filepath.Join(corruptdir, pkgpath) + ".a" - ioutil.WriteFile(filename, data, 0666) + os.WriteFile(filename, data, 0666) // test that importing the corrupted file results in an error _, err = Import(make(map[string]*types2.Package), pkgpath, corruptdir, nil) @@ -261,8 +259,7 @@ var importedObjectTests = []struct { {"io.Reader", "type Reader interface{Read(p []byte) (n int, err error)}"}, {"io.ReadWriter", "type ReadWriter interface{Reader; Writer}"}, {"go/ast.Node", "type Node interface{End() go/token.Pos; Pos() go/token.Pos}"}, - // go/types.Type has grown much larger - excluded for now - // {"go/types.Type", "type Type interface{String() string; Underlying() Type}"}, + {"go/types.Type", "type Type interface{String() string; Underlying() Type}"}, } func TestImportedTypes(t *testing.T) { @@ -457,17 +454,17 @@ func TestIssue13898(t *testing.T) { t.Fatal("go/types not found") } - // look for go/types2.Object type + // look for go/types.Object type obj := lookupObj(t, goTypesPkg.Scope(), "Object") typ, ok := obj.Type().(*types2.Named) if !ok { - t.Fatalf("go/types2.Object type is %v; wanted named type", typ) + t.Fatalf("go/types.Object type is %v; wanted named type", typ) } - // lookup go/types2.Object.Pkg method + // lookup go/types.Object.Pkg method m, index, indirect := types2.LookupFieldOrMethod(typ, false, nil, "Pkg") if m == nil { - t.Fatalf("go/types2.Object.Pkg not found (index = %v, indirect = %v)", index, indirect) + t.Fatalf("go/types.Object.Pkg not found (index = %v, indirect = %v)", index, indirect) } // the method must belong to go/types From 9a99e728fecccb992a175f9d39c5c64d78d429fc Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 2 Jun 2021 15:36:11 -0700 Subject: [PATCH 255/940] [dev.typeparams] cmd/compile/internal/types2: convert testdata/examples tests to type set sytax Change-Id: Ida3837c9cbb970a2b49cd1598c6e6e9de8aa9690 Reviewed-on: https://go-review.googlesource.com/c/go/+/324529 Trust: Robert Griesemer Run-TryBot: Robert Griesemer Reviewed-by: Robert Findley TryBot-Result: Go Bot --- .../internal/types2/testdata/examples/functions.go2 | 2 +- .../internal/types2/testdata/examples/inference.go2 | 6 +++--- .../compile/internal/types2/testdata/examples/types.go2 | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/cmd/compile/internal/types2/testdata/examples/functions.go2 b/src/cmd/compile/internal/types2/testdata/examples/functions.go2 index 0c2a408f021..154d09f5287 100644 --- a/src/cmd/compile/internal/types2/testdata/examples/functions.go2 +++ b/src/cmd/compile/internal/types2/testdata/examples/functions.go2 @@ -98,7 +98,7 @@ func g2b[P, Q any](x P, y Q) { // Here's an example of a recursive function call with variadic // arguments and type inference inferring the type parameter of // the caller (i.e., itself). -func max[T interface{ type int }](x ...T) T { +func max[T interface{ ~int }](x ...T) T { var x0 T if len(x) > 0 { x0 = x[0] diff --git a/src/cmd/compile/internal/types2/testdata/examples/inference.go2 b/src/cmd/compile/internal/types2/testdata/examples/inference.go2 index b47ce758054..75d47d2c9b4 100644 --- a/src/cmd/compile/internal/types2/testdata/examples/inference.go2 +++ b/src/cmd/compile/internal/types2/testdata/examples/inference.go2 @@ -7,7 +7,7 @@ package p type Ordered interface { - type int, float64, string + ~int|~float64|~string } func min[T Ordered](x, y T) T @@ -54,7 +54,7 @@ func _() { mixed[int, string](1.1 /* ERROR cannot use 1.1 */ , "", false) } -func related1[Slice interface{type []Elem}, Elem any](s Slice, e Elem) +func related1[Slice interface{~[]Elem}, Elem any](s Slice, e Elem) func _() { // related1 can be called with explicit instantiation. @@ -78,7 +78,7 @@ func _() { related1(si, "foo" /* ERROR cannot use "foo" */ ) } -func related2[Elem any, Slice interface{type []Elem}](e Elem, s Slice) +func related2[Elem any, Slice interface{~[]Elem}](e Elem, s Slice) func _() { // related2 can be called with explicit instantiation. diff --git a/src/cmd/compile/internal/types2/testdata/examples/types.go2 b/src/cmd/compile/internal/types2/testdata/examples/types.go2 index a7825ed2d9b..66e7a7b90e1 100644 --- a/src/cmd/compile/internal/types2/testdata/examples/types.go2 +++ b/src/cmd/compile/internal/types2/testdata/examples/types.go2 @@ -159,7 +159,7 @@ type _ struct { // are type parameters. As with ordinary type definitions, the // types underlying properties are "inherited" but the methods // are not. -func _[T interface{ m(); type int }]() { +func _[T interface{ m(); ~int }]() { type L T var x L @@ -232,11 +232,11 @@ func _[A Adder[A], B Adder[B], C Adder[A]]() { // The type of variables (incl. parameters and return values) cannot // be an interface with type constraints or be/embed comparable. type I interface { - type int + ~int } var ( - _ interface /* ERROR contains type constraints */ {type int} + _ interface /* ERROR contains type constraints */ {~int} _ I /* ERROR contains type constraints */ ) @@ -267,7 +267,7 @@ func _() { // (If a type list contains just a single const type, we could // allow it, but such type lists don't make much sense in the // first place.) -func _[T interface { type int, float64 }]() { +func _[T interface{~int|~float64}]() { // not valid const _ = T /* ERROR not constant */ (0) const _ T /* ERROR invalid constant type T */ = 1 From c790964ae457f244e634184a810b226b27bf7e0b Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 2 Jun 2021 15:45:43 -0700 Subject: [PATCH 256/940] [dev.typeparams] cmd/compile/internal/types2: convert testdata/fixedbugs tests to type set sytax Change-Id: I2ad94c71bebb93e0e3f4eba9d5199a3b3e9fa63d Reviewed-on: https://go-review.googlesource.com/c/go/+/324530 Trust: Robert Griesemer Run-TryBot: Robert Griesemer Reviewed-by: Robert Findley --- .../compile/internal/types2/testdata/fixedbugs/issue39634.go2 | 4 ++-- .../compile/internal/types2/testdata/fixedbugs/issue39680.go2 | 4 ++-- .../compile/internal/types2/testdata/fixedbugs/issue39699.go2 | 2 +- .../compile/internal/types2/testdata/fixedbugs/issue39723.go2 | 2 +- .../compile/internal/types2/testdata/fixedbugs/issue39755.go2 | 4 ++-- .../compile/internal/types2/testdata/fixedbugs/issue41124.go2 | 4 ++-- .../compile/internal/types2/testdata/fixedbugs/issue42758.go2 | 2 +- .../compile/internal/types2/testdata/fixedbugs/issue45548.go2 | 2 +- .../compile/internal/types2/testdata/fixedbugs/issue45635.go2 | 2 +- .../compile/internal/types2/testdata/fixedbugs/issue45985.go2 | 2 +- 10 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2 index 92ea3054795..39ec5d7b307 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2 @@ -31,12 +31,12 @@ type x7[A any] struct{ foo7 } func main7() { var _ foo7 = x7[int]{} } // crash 8 -type foo8[A any] interface { type A } +type foo8[A any] interface { ~A } func bar8[A foo8[A]](a A) {} func main8() {} // crash 9 -type foo9[A any] interface { type foo9 /* ERROR cannot use interface */ [A] } +type foo9[A any] interface { ~/* ERROR cannot use interface */ foo9[A] } func _() { var _ = new(foo9 /* ERROR interface contains type constraints */ [int]) } // crash 12 diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39680.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39680.go2 index 9bc26f35461..01eadd2dbf9 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39680.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39680.go2 @@ -7,13 +7,13 @@ package p import "fmt" // Minimal test case. -func _[T interface{type T}](x T) T{ +func _[T interface{~T}](x T) T{ return x } // Test case from issue. type constr[T any] interface { - type T + ~T } func Print[T constr[T]](s []T) { diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39699.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39699.go2 index 75491e7e26f..72f83997c24 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39699.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39699.go2 @@ -8,7 +8,7 @@ type T0 interface{ } type T1 interface{ - type int + ~int } type T2 interface{ diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39723.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39723.go2 index 61bc6067892..367b3f1360f 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39723.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39723.go2 @@ -6,4 +6,4 @@ package p // A constraint must be an interface; it cannot // be a type parameter, for instance. -func _[A interface{ type int }, B A /* ERROR not an interface */ ]() +func _[A interface{ ~int }, B A /* ERROR not an interface */ ]() diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39755.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39755.go2 index b7ab68818e9..257b73a2fbe 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39755.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39755.go2 @@ -4,14 +4,14 @@ package p -func _[T interface{type map[string]int}](x T) { +func _[T interface{~map[string]int}](x T) { _ = x == nil } // simplified test case from issue type PathParamsConstraint interface { - type map[string]string, []struct{key, value string} + ~map[string]string | ~[]struct{key, value string} } type PathParams[T PathParamsConstraint] struct { diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue41124.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue41124.go2 index 61f766bcbd7..ab535049dd7 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue41124.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue41124.go2 @@ -7,7 +7,7 @@ package p // Test case from issue. type Nat interface { - type Zero, Succ + Zero|Succ } type Zero struct{} @@ -22,7 +22,7 @@ type I1 interface { } type I2 interface { - type int + ~int } type I3 interface { diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue42758.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue42758.go2 index 698cb8a16ba..bf0031f5d24 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue42758.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue42758.go2 @@ -17,7 +17,7 @@ func _[T any](x interface{}){ } type constraint interface { - type int + ~int } func _[T constraint](x interface{}){ diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45548.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45548.go2 index b1e42497e85..b8ba0ad4a70 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45548.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45548.go2 @@ -4,7 +4,7 @@ package p -func f[F interface{type *Q}, G interface{type *R}, Q, R any](q Q, r R) {} +func f[F interface{~*Q}, G interface{~*R}, Q, R any](q Q, r R) {} func _() { f[*float64, *int](1, 2) diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45635.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45635.go2 index 65662cdc766..e9b57ae8f10 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45635.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45635.go2 @@ -13,7 +13,7 @@ type N[T any] struct{} var _ N[] /* ERROR expecting type */ type I interface { - type map[int]int, []int + ~map[int]int | ~[]int } func _[T I](i, j int) { diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45985.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45985.go2 index 7678e348ef9..f25b9d2b266 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45985.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45985.go2 @@ -5,7 +5,7 @@ package issue45985 // TODO(gri): this error should be on app[int] below. -func app[S /* ERROR "type S = S does not match" */ interface{ type []T }, T any](s S, e T) S { +func app[S /* ERROR "type S = S does not match" */ interface{ ~[]T }, T any](s S, e T) S { return append(s, e) } From 8cdce85bdf80f6aa9bd3979d3ecab6565512b736 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 2 Jun 2021 16:12:25 -0700 Subject: [PATCH 257/940] [dev.typeparams] cmd/compile/internal/types2: convert testdata/check tests to type set sytax Change-Id: I0c2dda10ba7cb40330545fd10fbacb8c84f66a2d Reviewed-on: https://go-review.googlesource.com/c/go/+/324569 Trust: Robert Griesemer Reviewed-by: Robert Findley --- .../types2/testdata/check/builtins.go2 | 8 +- .../internal/types2/testdata/check/issues.go2 | 26 +++--- .../internal/types2/testdata/check/linalg.go2 | 16 ++-- .../types2/testdata/check/tinference.go2 | 20 ++--- .../types2/testdata/check/typeinst2.go2 | 29 +++---- .../types2/testdata/check/typeparams.go2 | 80 +++++++++---------- 6 files changed, 90 insertions(+), 89 deletions(-) diff --git a/src/cmd/compile/internal/types2/testdata/check/builtins.go2 b/src/cmd/compile/internal/types2/testdata/check/builtins.go2 index 3918d836b52..5bb67efec9d 100644 --- a/src/cmd/compile/internal/types2/testdata/check/builtins.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/builtins.go2 @@ -7,19 +7,19 @@ package builtins type Bmc interface { - type map[rune]string, chan int + ~map[rune]string | ~chan int } type Bms interface { - type map[string]int, []int + ~map[string]int | ~[]int } type Bcs interface { - type chan bool, []float64 + ~chan bool | ~[]float64 } type Bss interface { - type []int, []string + ~[]int | ~[]string } func _[T any] () { diff --git a/src/cmd/compile/internal/types2/testdata/check/issues.go2 b/src/cmd/compile/internal/types2/testdata/check/issues.go2 index f0a7b247489..59dd4ae465a 100644 --- a/src/cmd/compile/internal/types2/testdata/check/issues.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/issues.go2 @@ -57,7 +57,7 @@ func _() { // type with a type list constraint, all of the type argument's types in its // bound, but at least one (!), must be in the type list of the bound of the // corresponding parameterized type's type parameter. -type T1[P interface{type uint}] struct{} +type T1[P interface{~uint}] struct{} func _[P any]() { _ = T1[P /* ERROR P has no type constraints */ ]{} @@ -65,7 +65,7 @@ func _[P any]() { // This is the original (simplified) program causing the same issue. type Unsigned interface { - type uint + ~uint } type T2[U Unsigned] struct { @@ -156,7 +156,7 @@ type inf2[T any] struct{ inf2 /* ERROR illegal cycle */ [T] } // predicate disjunction in the implementation was wrong because if a type list // contains both an integer and a floating-point type, the type parameter is // neither an integer or a floating-point number. -func convert[T1, T2 interface{type int, uint, float32}](v T1) T2 { +func convert[T1, T2 interface{~int | ~uint | ~float32}](v T1) T2 { return T2(v) } @@ -168,12 +168,12 @@ func _() { // both numeric, or both strings. The implementation had the same problem // with this check as the conversion issue above (issue #39623). -func issue39623[T interface{type int, string}](x, y T) T { +func issue39623[T interface{~int | ~string}](x, y T) T { return x + y } // Simplified, from https://go2goplay.golang.org/p/efS6x6s-9NI: -func Sum[T interface{type int, string}](s []T) (sum T) { +func Sum[T interface{~int | ~string}](s []T) (sum T) { for _, v := range s { sum += v } @@ -182,19 +182,19 @@ func Sum[T interface{type int, string}](s []T) (sum T) { // Assignability of an unnamed pointer type to a type parameter that // has a matching underlying type. -func _[T interface{}, PT interface{type *T}] (x T) PT { +func _[T interface{}, PT interface{~*T}] (x T) PT { return &x } // Indexing of generic types containing type parameters in their type list: -func at[T interface{ type []E }, E interface{}](x T, i int) E { +func at[T interface{ ~[]E }, E interface{}](x T, i int) E { return x[i] } // A generic type inside a function acts like a named type. Its underlying // type is itself, its "operational type" is defined by the type list in // the tybe bound, if any. -func _[T interface{type int}](x T) { +func _[T interface{~int}](x T) { type myint int var _ int = int(x) var _ T = 42 @@ -203,24 +203,24 @@ func _[T interface{type int}](x T) { // Indexing a generic type with an array type bound checks length. // (Example by mdempsky@.) -func _[T interface { type [10]int }](x T) { +func _[T interface { ~[10]int }](x T) { _ = x[9] // ok _ = x[20 /* ERROR out of bounds */ ] } // Pointer indirection of a generic type. -func _[T interface{ type *int }](p T) int { +func _[T interface{ ~*int }](p T) int { return *p } // Channel sends and receives on generic types. -func _[T interface{ type chan int }](ch T) int { +func _[T interface{ ~chan int }](ch T) int { ch <- 0 return <- ch } // Calling of a generic variable. -func _[T interface{ type func() }](f T) { +func _[T interface{ ~func() }](f T) { f() go f() } @@ -232,7 +232,7 @@ func _[T interface{ type func() }](f T) { // type parameter that was substituted with a defined type. // Test case from an (originally) failing example. -type sliceOf[E any] interface{ type []E } +type sliceOf[E any] interface{ ~[]E } func append[T interface{}, S sliceOf[T], T2 interface{ T }](s S, t ...T2) S diff --git a/src/cmd/compile/internal/types2/testdata/check/linalg.go2 b/src/cmd/compile/internal/types2/testdata/check/linalg.go2 index 0d27603a583..efc090a1d1f 100644 --- a/src/cmd/compile/internal/types2/testdata/check/linalg.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/linalg.go2 @@ -9,10 +9,10 @@ import "math" // Numeric is type bound that matches any numeric type. // It would likely be in a constraints package in the standard library. type Numeric interface { - type int, int8, int16, int32, int64, - uint, uint8, uint16, uint32, uint64, uintptr, - float32, float64, - complex64, complex128 + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~complex64 | ~complex128 } func DotProduct[T Numeric](s1, s2 []T) T { @@ -42,14 +42,14 @@ func AbsDifference[T NumericAbs[T]](a, b T) T { // OrderedNumeric is a type bound that matches numeric types that support the < operator. type OrderedNumeric interface { - type int, int8, int16, int32, int64, - uint, uint8, uint16, uint32, uint64, uintptr, - float32, float64 + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 } // Complex is a type bound that matches the two complex types, which do not have a < operator. type Complex interface { - type complex64, complex128 + ~complex64 | ~complex128 } // OrderedAbs is a helper type that defines an Abs method for diff --git a/src/cmd/compile/internal/types2/testdata/check/tinference.go2 b/src/cmd/compile/internal/types2/testdata/check/tinference.go2 index a53fde0a2a9..2fdb39ca7a8 100644 --- a/src/cmd/compile/internal/types2/testdata/check/tinference.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/tinference.go2 @@ -8,28 +8,28 @@ import "strconv" type any interface{} -func f0[A any, B interface{type C}, C interface{type D}, D interface{type A}](A, B, C, D) +func f0[A any, B interface{~C}, C interface{~D}, D interface{~A}](A, B, C, D) func _() { f := f0[string] f("a", "b", "c", "d") f0("a", "b", "c", "d") } -func f1[A any, B interface{type A}](A, B) +func f1[A any, B interface{~A}](A, B) func _() { f := f1[int] f(int(0), int(0)) f1(int(0), int(0)) } -func f2[A any, B interface{type []A}](A, B) +func f2[A any, B interface{~[]A}](A, B) func _() { f := f2[byte] f(byte(0), []byte{}) f2(byte(0), []byte{}) } -func f3[A any, B interface{type C}, C interface{type *A}](A, B, C) +func f3[A any, B interface{~C}, C interface{~*A}](A, B, C) func _() { f := f3[int] var x int @@ -37,7 +37,7 @@ func _() { f3(x, &x, &x) } -func f4[A any, B interface{type []C}, C interface{type *A}](A, B, C) +func f4[A any, B interface{~[]C}, C interface{~*A}](A, B, C) func _() { f := f4[int] var x int @@ -45,14 +45,14 @@ func _() { f4(x, []*int{}, &x) } -func f5[A interface{type struct{b B; c C}}, B any, C interface{type *B}](x B) A +func f5[A interface{~struct{b B; c C}}, B any, C interface{~*B}](x B) A func _() { x := f5(1.2) var _ float64 = x.b var _ float64 = *x.c } -func f6[A any, B interface{type struct{f []A}}](B) A +func f6[A any, B interface{~struct{f []A}}](B) A func _() { x := f6(struct{f []string}{}) var _ string = x @@ -60,11 +60,11 @@ func _() { // TODO(gri) Need to flag invalid recursive constraints. At the // moment these cause infinite recursions and stack overflow. -// func f7[A interface{type B}, B interface{type A}]() +// func f7[A interface{type B}, B interface{~A}]() // More realistic examples -func Double[S interface{ type []E }, E interface{ type int, int8, int16, int32, int64 }](s S) S { +func Double[S interface{ ~[]E }, E interface{ ~int | ~int8 | ~int16 | ~int32 | ~int64 }](s S) S { r := make(S, len(s)) for i, v := range s { r[i] = v + v @@ -80,7 +80,7 @@ var _ = Double(MySlice{1}) type Setter[B any] interface { Set(string) - type *B + ~*B } func FromStrings[T interface{}, PT Setter[T]](s []string) []T { diff --git a/src/cmd/compile/internal/types2/testdata/check/typeinst2.go2 b/src/cmd/compile/internal/types2/testdata/check/typeinst2.go2 index 1096bb42eb7..37745dfcba7 100644 --- a/src/cmd/compile/internal/types2/testdata/check/typeinst2.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/typeinst2.go2 @@ -148,15 +148,15 @@ func _[T any](r R2[T, int], p *R2[string, T]) { p.pm() } -// An interface can (explicitly) declare at most one type list. +// It is ok to have multiple embedded unions. type _ interface { m0() - type int, string, bool - type /* ERROR multiple type lists */ float32, float64 + ~int | ~string | ~bool + ~float32 | ~float64 m1() m2() - type /* ERROR multiple type lists */ complex64, complex128 - type /* ERROR multiple type lists */ rune + ~complex64 | ~complex128 + ~rune } // Interface type lists may contain each type at most once. @@ -164,23 +164,24 @@ type _ interface { // for them to be all in a single list, and we report the error // as well.) type _ interface { - type int, int /* ERROR duplicate term int */ - type /* ERROR multiple type lists */ int /* ERROR duplicate term int */ + ~int|~int /* ERROR duplicate term int */ + ~int|int /* ERROR duplicate term int */ + int|int /* ERROR duplicate term int */ } type _ interface { - type struct{f int}, struct{g int}, struct /* ERROR duplicate term */ {f int} + ~struct{f int} | ~struct{g int} | ~struct /* ERROR duplicate term */ {f int} } // Interface type lists can contain any type, incl. *Named types. // Verify that we use the underlying type to compute the operational type. type MyInt int -func add1[T interface{type MyInt}](x T) T { +func add1[T interface{~MyInt}](x T) T { return x + 1 } type MyString string -func double[T interface{type MyInt, MyString}](x T) T { +func double[T interface{~MyInt | ~MyString}](x T) T { return x + x } @@ -189,15 +190,15 @@ func double[T interface{type MyInt, MyString}](x T) T { // type lists. type E0 interface { - type int, bool, string + ~int | ~bool | ~string } type E1 interface { - type int, float64, string + ~int | ~float64 | ~string } type E2 interface { - type float64 + ~float64 } type I0 interface { @@ -246,7 +247,7 @@ var _ = f12[float64] type I0_ interface { E0 - type int + ~int } func f0_[T I0_]() diff --git a/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 b/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 index badda01105b..4074ef17ea2 100644 --- a/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 @@ -52,22 +52,22 @@ func swapswap[A, B any](a A, b B) (A, B) { type F[A, B any] func(A, B) (B, A) -func min[T interface{ type int }](x, y T) T { +func min[T interface{ ~int }](x, y T) T { if x < y { return x } return y } -func _[T interface{type int, float32}](x, y T) bool { return x < y } +func _[T interface{~int | ~float32}](x, y T) bool { return x < y } func _[T any](x, y T) bool { return x /* ERROR cannot compare */ < y } -func _[T interface{type int, float32, bool}](x, y T) bool { return x /* ERROR cannot compare */ < y } +func _[T interface{~int | ~float32 | ~bool}](x, y T) bool { return x /* ERROR cannot compare */ < y } func _[T C1[T]](x, y T) bool { return x /* ERROR cannot compare */ < y } func _[T C2[T]](x, y T) bool { return x < y } type C1[T any] interface{} -type C2[T any] interface{ type int, float32 } +type C2[T any] interface{ ~int | ~float32 } func new[T any]() *T { var x T @@ -95,48 +95,48 @@ var _ = f3[int, rune, bool](1, struct{x rune}{}, nil) // indexing func _[T any] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } -func _[T interface{ type int }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } -func _[T interface{ type string }] (x T, i int) { _ = x[i] } -func _[T interface{ type []int }] (x T, i int) { _ = x[i] } -func _[T interface{ type [10]int, *[20]int, map[int]int }] (x T, i int) { _ = x[i] } -func _[T interface{ type string, []byte }] (x T, i int) { _ = x[i] } -func _[T interface{ type []int, [1]rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } -func _[T interface{ type string, []rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } +func _[T interface{ ~int }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } +func _[T interface{ ~string }] (x T, i int) { _ = x[i] } +func _[T interface{ ~[]int }] (x T, i int) { _ = x[i] } +func _[T interface{ ~[10]int | ~*[20]int | ~map[int]int }] (x T, i int) { _ = x[i] } +func _[T interface{ ~string | ~[]byte }] (x T, i int) { _ = x[i] } +func _[T interface{ ~[]int | ~[1]rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } +func _[T interface{ ~string | ~[]rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } // indexing with various combinations of map types in type lists (see issue #42616) -func _[T interface{ type []E, map[int]E }, E any](x T, i int) { _ = x[i] } -func _[T interface{ type []E }, E any](x T, i int) { _ = &x[i] } -func _[T interface{ type map[int]E }, E any](x T, i int) { _, _ = x[i] } // comma-ok permitted -func _[T interface{ type []E, map[int]E }, E any](x T, i int) { _ = &x /* ERROR cannot take address */ [i] } -func _[T interface{ type []E, map[int]E, map[uint]E }, E any](x T, i int) { _ = x /* ERROR cannot index */ [i] } // different map element types -func _[T interface{ type []E, map[string]E }, E any](x T, i int) { _ = x[i /* ERROR cannot use i */ ] } +func _[T interface{ ~[]E | ~map[int]E }, E any](x T, i int) { _ = x[i] } +func _[T interface{ ~[]E }, E any](x T, i int) { _ = &x[i] } +func _[T interface{ ~map[int]E }, E any](x T, i int) { _, _ = x[i] } // comma-ok permitted +func _[T interface{ ~[]E | ~map[int]E }, E any](x T, i int) { _ = &x /* ERROR cannot take address */ [i] } +func _[T interface{ ~[]E | ~map[int]E | ~map[uint]E }, E any](x T, i int) { _ = x /* ERROR cannot index */ [i] } // different map element types +func _[T interface{ ~[]E | ~map[string]E }, E any](x T, i int) { _ = x[i /* ERROR cannot use i */ ] } // slicing // TODO(gri) implement this -func _[T interface{ type string }] (x T, i, j, k int) { _ = x /* ERROR invalid operation */ [i:j:k] } +func _[T interface{ ~string }] (x T, i, j, k int) { _ = x /* ERROR invalid operation */ [i:j:k] } // len/cap built-ins func _[T any](x T) { _ = len(x /* ERROR invalid argument */ ) } -func _[T interface{ type int }](x T) { _ = len(x /* ERROR invalid argument */ ) } -func _[T interface{ type string, []byte, int }](x T) { _ = len(x /* ERROR invalid argument */ ) } -func _[T interface{ type string }](x T) { _ = len(x) } -func _[T interface{ type [10]int }](x T) { _ = len(x) } -func _[T interface{ type []byte }](x T) { _ = len(x) } -func _[T interface{ type map[int]int }](x T) { _ = len(x) } -func _[T interface{ type chan int }](x T) { _ = len(x) } -func _[T interface{ type string, []byte, chan int }](x T) { _ = len(x) } +func _[T interface{ ~int }](x T) { _ = len(x /* ERROR invalid argument */ ) } +func _[T interface{ ~string | ~[]byte | ~int }](x T) { _ = len(x /* ERROR invalid argument */ ) } +func _[T interface{ ~string }](x T) { _ = len(x) } +func _[T interface{ ~[10]int }](x T) { _ = len(x) } +func _[T interface{ ~[]byte }](x T) { _ = len(x) } +func _[T interface{ ~map[int]int }](x T) { _ = len(x) } +func _[T interface{ ~chan int }](x T) { _ = len(x) } +func _[T interface{ ~string | ~[]byte | ~chan int }](x T) { _ = len(x) } func _[T any](x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _[T interface{ type int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _[T interface{ type string, []byte, int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _[T interface{ type string }](x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _[T interface{ type [10]int }](x T) { _ = cap(x) } -func _[T interface{ type []byte }](x T) { _ = cap(x) } -func _[T interface{ type map[int]int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _[T interface{ type chan int }](x T) { _ = cap(x) } -func _[T interface{ type []byte, chan int }](x T) { _ = cap(x) } +func _[T interface{ ~int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } +func _[T interface{ ~string | ~[]byte | ~int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } +func _[T interface{ ~string }](x T) { _ = cap(x /* ERROR invalid argument */ ) } +func _[T interface{ ~[10]int }](x T) { _ = cap(x) } +func _[T interface{ ~[]byte }](x T) { _ = cap(x) } +func _[T interface{ ~map[int]int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } +func _[T interface{ ~chan int }](x T) { _ = cap(x) } +func _[T interface{ ~[]byte | ~chan int }](x T) { _ = cap(x) } // range iteration @@ -144,7 +144,7 @@ func _[T interface{}](x T) { for range x /* ERROR cannot range */ {} } -func _[T interface{ type string, []string }](x T) { +func _[T interface{ ~string | ~[]string }](x T) { for range x {} for i := range x { _ = i } for i, _ := range x { _ = i } @@ -156,23 +156,23 @@ func _[T interface{ type string, []string }](x T) { } -func _[T interface{ type string, []rune, map[int]rune }](x T) { +func _[T interface{ ~string | ~[]rune | ~map[int]rune }](x T) { for _, e := range x { _ = e } for i, e := range x { _ = i; _ = e } } -func _[T interface{ type string, []rune, map[string]rune }](x T) { +func _[T interface{ ~string | ~[]rune | ~map[string]rune }](x T) { for _, e := range x { _ = e } for i, e := range x /* ERROR must have the same key type */ { _ = e } } -func _[T interface{ type string, chan int }](x T) { +func _[T interface{ ~string | ~chan int }](x T) { for range x {} for i := range x { _ = i } for i, _ := range x { _ = i } // TODO(gri) should get an error here: channels only return one value } -func _[T interface{ type string, chan<-int }](x T) { +func _[T interface{ ~string | ~chan<-int }](x T) { for i := range x /* ERROR send-only channel */ { _ = i } } @@ -400,7 +400,7 @@ func _[T any](x T) { } } -func _[T interface{type int}](x T) { +func _[T interface{~int}](x T) { _ = x /* ERROR not an interface */ .(int) switch x /* ERROR not an interface */ .(type) { } From 10d6b36ca3f8d48a667742eee791dacbcfc888cd Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 2 Jun 2021 17:05:37 -0700 Subject: [PATCH 258/940] [dev.typeparams] cmd/compile/internal/types2: disallow ~T where T is a defined type or an interface Change-Id: I35f6f43db00d56847da48320308f2fcfff924738 Reviewed-on: https://go-review.googlesource.com/c/go/+/324570 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- .../internal/types2/testdata/check/typeinst2.go2 | 4 ++-- .../internal/types2/testdata/examples/constraints.go2 | 9 +++++++++ .../internal/types2/testdata/fixedbugs/issue39634.go2 | 4 ++-- src/cmd/compile/internal/types2/union.go | 11 ++++++----- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/cmd/compile/internal/types2/testdata/check/typeinst2.go2 b/src/cmd/compile/internal/types2/testdata/check/typeinst2.go2 index 37745dfcba7..14d8f0ea8ca 100644 --- a/src/cmd/compile/internal/types2/testdata/check/typeinst2.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/typeinst2.go2 @@ -176,12 +176,12 @@ type _ interface { // Interface type lists can contain any type, incl. *Named types. // Verify that we use the underlying type to compute the operational type. type MyInt int -func add1[T interface{~MyInt}](x T) T { +func add1[T interface{MyInt}](x T) T { return x + 1 } type MyString string -func double[T interface{~MyInt | ~MyString}](x T) T { +func double[T interface{MyInt|MyString}](x T) T { return x + x } diff --git a/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 b/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 index f6291ccf7dd..efefaa2a256 100644 --- a/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 +++ b/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 @@ -24,6 +24,15 @@ type ( _ interface{int|interface /* ERROR cannot use interface */ {}} ) +type ( + // Tilde is not permitted on defined types or interfaces. + foo int + bar interface{} + _ interface{foo} + _ interface{~ /* ERROR invalid use of ~ */ foo } + _ interface{~ /* ERROR invalid use of ~ */ bar } +) + // Multiple embedded union elements are intersected. The order in which they // appear in the interface doesn't matter since intersection is a symmetric // operation. diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2 index 39ec5d7b307..6d002f5d2fc 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2 @@ -36,8 +36,8 @@ func bar8[A foo8[A]](a A) {} func main8() {} // crash 9 -type foo9[A any] interface { ~/* ERROR cannot use interface */ foo9[A] } -func _() { var _ = new(foo9 /* ERROR interface contains type constraints */ [int]) } +type foo9[A any] interface { foo9 /* ERROR illegal cycle */ [A] } +func _() { var _ = new(foo9 /* ERROR illegal cycle */ [int]) } // crash 12 var u /* ERROR cycle */ , i [func /* ERROR used as value */ /* ERROR used as value */ (u, c /* ERROR undeclared */ /* ERROR undeclared */ ) {}(0, len /* ERROR must be called */ /* ERROR must be called */ )]c /* ERROR undeclared */ /* ERROR undeclared */ diff --git a/src/cmd/compile/internal/types2/union.go b/src/cmd/compile/internal/types2/union.go index 671e36111b1..30570b5e802 100644 --- a/src/cmd/compile/internal/types2/union.go +++ b/src/cmd/compile/internal/types2/union.go @@ -106,17 +106,18 @@ func parseUnion(check *Checker, tlist []syntax.Expr) Type { } u := under(t) - if tilde[i] { - // TODO(gri) enable this check once we have converted tests - // if !Identical(u, t) { - // check.errorf(x, "invalid use of ~ (underlying type of %s is %s)", t, u) - // } + if tilde[i] && !Identical(u, t) { + check.errorf(x, "invalid use of ~ (underlying type of %s is %s)", t, u) + continue // don't report another error for t } if _, ok := u.(*Interface); ok { + // A single type with a ~ is a single-term union. check.errorf(pos, "cannot use interface %s with ~ or inside a union (implementation restriction)", t) + continue // don't report another error for t } // Complain about duplicate entries a|a, but also a|~a, and ~a|~a. + // TODO(gri) We should also exclude myint|~int since myint is included in ~int. if includes(types[:i], t) { // TODO(gri) this currently doesn't print the ~ if present check.softErrorf(pos, "duplicate term %s in union element", t) From 95c618e99a3f733543fd36ef19e833d04acc8710 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 2 Jun 2021 17:50:47 -0700 Subject: [PATCH 259/940] [dev.typeparams] cmd/compile/internal/types2: add Config.AllowTypeLists to control type list handling Eventually the flag should not be set anymore, but we set it in the compiler until all tests have been converted. Also, convert some more types2 tests to use the type set notation. Change-Id: I616599a3473451ab75d67272016b2bd3de6835af Reviewed-on: https://go-review.googlesource.com/c/go/+/324571 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/noder/irgen.go | 1 + src/cmd/compile/internal/types2/api.go | 6 ++++++ src/cmd/compile/internal/types2/api_test.go | 16 ++++++++-------- src/cmd/compile/internal/types2/interface.go | 11 +++++++++-- .../types2/testdata/examples/constraints.go2 | 12 ++++++++++++ .../compile/internal/types2/typestring_test.go | 1 - 6 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go index 3f362e9d2bc..b70d82d7e67 100644 --- a/src/cmd/compile/internal/noder/irgen.go +++ b/src/cmd/compile/internal/noder/irgen.go @@ -38,6 +38,7 @@ func checkFiles(noders []*noder, importer types2.Importer) (posMap, *types2.Pack GoVersion: base.Flag.Lang, IgnoreLabels: true, // parser already checked via syntax.CheckBranches mode CompilerErrorMessages: true, // use error strings matching existing compiler errors + AllowTypeLists: true, // remove this line once all tests use type set syntax Error: func(err error) { terr := err.(types2.Error) base.ErrorfAt(m.makeXPos(terr.Pos), "%s", terr.Msg) diff --git a/src/cmd/compile/internal/types2/api.go b/src/cmd/compile/internal/types2/api.go index 2939dcc0bdf..433250f02c8 100644 --- a/src/cmd/compile/internal/types2/api.go +++ b/src/cmd/compile/internal/types2/api.go @@ -125,6 +125,12 @@ type Config struct { // TODO(gri) Consolidate error messages and remove this flag. CompilerErrorMessages bool + // If AllowTypeLists is set, the type list syntax is permitted + // in an interface in addition to the type set syntax. + // TODO(gri) Remove once type lists are no longer supported by + // the parser. + AllowTypeLists bool + // If go115UsesCgo is set, the type checker expects the // _cgo_gotypes.go file generated by running cmd/cgo to be // provided as a package source file. Qualified identifiers diff --git a/src/cmd/compile/internal/types2/api_test.go b/src/cmd/compile/internal/types2/api_test.go index d82d29cad87..49d710067a8 100644 --- a/src/cmd/compile/internal/types2/api_test.go +++ b/src/cmd/compile/internal/types2/api_test.go @@ -345,7 +345,7 @@ func TestTypesInfo(t *testing.T) { {genericPkg + `g0; type t[P any] int; var x struct{ f t[int] }; var _ = x.f`, `x.f`, `generic_g0.t[int]`}, // issue 45096 - {genericPkg + `issue45096; func _[T interface{ type int8, int16, int32 }](x T) { _ = x < 0 }`, `0`, `generic_issue45096.T₁`}, + {genericPkg + `issue45096; func _[T interface{ ~int8 | ~int16 | ~int32 }](x T) { _ = x < 0 }`, `0`, `generic_issue45096.T₁`}, } for _, test := range tests { @@ -454,38 +454,38 @@ func TestInferredInfo(t *testing.T) { // `func(float64)`, // }, - {genericPkg + `s1; func f[T any, P interface{type *T}](x T); func _(x string) { f(x) }`, + {genericPkg + `s1; func f[T any, P interface{~*T}](x T); func _(x string) { f(x) }`, `f`, []string{`string`, `*string`}, `func(x string)`, }, - {genericPkg + `s2; func f[T any, P interface{type *T}](x []T); func _(x []int) { f(x) }`, + {genericPkg + `s2; func f[T any, P interface{~*T}](x []T); func _(x []int) { f(x) }`, `f`, []string{`int`, `*int`}, `func(x []int)`, }, - {genericPkg + `s3; type C[T any] interface{type chan<- T}; func f[T any, P C[T]](x []T); func _(x []int) { f(x) }`, + {genericPkg + `s3; type C[T any] interface{~chan<- T}; func f[T any, P C[T]](x []T); func _(x []int) { f(x) }`, `f`, []string{`int`, `chan<- int`}, `func(x []int)`, }, - {genericPkg + `s4; type C[T any] interface{type chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T); func _(x []int) { f(x) }`, + {genericPkg + `s4; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T); func _(x []int) { f(x) }`, `f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func(x []int)`, }, - {genericPkg + `t1; func f[T any, P interface{type *T}]() T; func _() { _ = f[string] }`, + {genericPkg + `t1; func f[T any, P interface{~*T}]() T; func _() { _ = f[string] }`, `f`, []string{`string`, `*string`}, `func() string`, }, - {genericPkg + `t2; type C[T any] interface{type chan<- T}; func f[T any, P C[T]]() []T; func _() { _ = f[int] }`, + {genericPkg + `t2; type C[T any] interface{~chan<- T}; func f[T any, P C[T]]() []T; func _() { _ = f[int] }`, `f`, []string{`int`, `chan<- int`}, `func() []int`, }, - {genericPkg + `t3; type C[T any] interface{type chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T; func _() { _ = f[int] }`, + {genericPkg + `t3; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T; func _() { _ = f[int] }`, `f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func() []int`, diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go index 770b8ba5cc8..c79026f00dd 100644 --- a/src/cmd/compile/internal/types2/interface.go +++ b/src/cmd/compile/internal/types2/interface.go @@ -34,18 +34,25 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType continue // ignore } + // TODO(gri) Remove type list handling once the parser doesn't accept type lists anymore. if name == "type" { + // Report an error for the first type list per interface + // if we don't allow type lists, but continue. + if !check.conf.AllowTypeLists && tlist == nil { + check.softErrorf(f.Name, "use generalized embedding syntax instead of a type list") + } // For now, collect all type list entries as if it // were a single union, where each union element is // of the form ~T. - // TODO(gri) remove once we disallow type lists op := new(syntax.Operation) // We should also set the position (but there is no setter); // we don't care because this code will eventually go away. op.Op = syntax.Tilde op.X = f.Type tlist = append(tlist, op) - if tname != nil && tname != f.Name { + // Report an error if we have multiple type lists in an + // interface, but only if they are permitted in the first place. + if check.conf.AllowTypeLists && tname != nil && tname != f.Name { check.error(f.Name, "cannot have multiple type lists in an interface") } tname = f.Name diff --git a/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 b/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 index efefaa2a256..d9805fe6940 100644 --- a/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 +++ b/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 @@ -6,6 +6,18 @@ package p +type ( + // Type lists are processed as unions but an error is reported. + // TODO(gri) remove this once the parser doesn't accept type lists anymore. + _ interface{ + type /* ERROR use generalized embedding syntax instead of a type list */ int + } + _ interface{ + type /* ERROR use generalized embedding syntax instead of a type list */ int + type float32 + } +) + type ( // Arbitrary types may be embedded like interfaces. _ interface{int} diff --git a/src/cmd/compile/internal/types2/typestring_test.go b/src/cmd/compile/internal/types2/typestring_test.go index 8d0ca760bfc..88103b81b12 100644 --- a/src/cmd/compile/internal/types2/typestring_test.go +++ b/src/cmd/compile/internal/types2/typestring_test.go @@ -91,7 +91,6 @@ var independentTestTypes = []testEntry{ dup("interface{}"), dup("interface{m()}"), dup(`interface{String() string; m(int) float32}`), - {"interface{type int, float32, complex128}", "interface{~int|~float32|~complex128}"}, dup("interface{int|float32|complex128}"), dup("interface{int|~float32|~complex128}"), From 9c054f413751fdec62aa33df19ec1249426767ee Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 1 Jun 2021 19:16:33 -0400 Subject: [PATCH 260/940] [dev.typeparams] cmd/link: take function address in assembly in TestFuncAlign In TestFuncAlign we want to get the address of an assembly function. Take the address in assembly, so we get the actual function's address, not the wrapper's. Change-Id: Idc1fe2c8426562c70f8f7d6e489584ef059bc556 Reviewed-on: https://go-review.googlesource.com/c/go/+/324249 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- src/cmd/link/link_test.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go index 4d6bc76aca8..4a580991ef4 100644 --- a/src/cmd/link/link_test.go +++ b/src/cmd/link/link_test.go @@ -524,14 +524,13 @@ const testFuncAlignSrc = ` package main import ( "fmt" - "reflect" ) func alignPc() +var alignPcFnAddr uintptr func main() { - addr := reflect.ValueOf(alignPc).Pointer() - if (addr % 512) != 0 { - fmt.Printf("expected 512 bytes alignment, got %v\n", addr) + if alignPcFnAddr % 512 != 0 { + fmt.Printf("expected 512 bytes alignment, got %v\n", alignPcFnAddr) } else { fmt.Printf("PASS") } @@ -546,6 +545,9 @@ TEXT ·alignPc(SB),NOSPLIT, $0-0 PCALIGN $512 MOVD $3, R1 RET + +GLOBL ·alignPcFnAddr(SB),RODATA,$8 +DATA ·alignPcFnAddr(SB)/8,$·alignPc(SB) ` // TestFuncAlign verifies that the address of a function can be aligned From b5f37faf3b0fa4c8ae24461bf99cdc0f1f583fa3 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 1 Jun 2021 19:18:25 -0400 Subject: [PATCH 261/940] [dev.typeparams] cmd/internal/goobj: add duffzero/duffcopy to builtin list duffzero and duffcopy are commonly referenced functions. Add them to builtin list, so they are referenced by index, not by name. Also change gcWriteBarrier to ABIInternal, which is changed in CL 266638. Regenerate the file. Change-Id: If8550d9ed300ac2be930a7c58657a9cf1933ac1d Reviewed-on: https://go-review.googlesource.com/c/go/+/324250 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- src/cmd/internal/goobj/builtinlist.go | 7 ++++++- src/cmd/internal/goobj/mkbuiltin.go | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/cmd/internal/goobj/builtinlist.go b/src/cmd/internal/goobj/builtinlist.go index 9f248137daa..608c0d72223 100644 --- a/src/cmd/internal/goobj/builtinlist.go +++ b/src/cmd/internal/goobj/builtinlist.go @@ -33,6 +33,7 @@ var builtins = [...]struct { {"runtime.goPanicSlice3BU", 1}, {"runtime.goPanicSlice3C", 1}, {"runtime.goPanicSlice3CU", 1}, + {"runtime.goPanicSliceConvert", 1}, {"runtime.printbool", 1}, {"runtime.printfloat", 1}, {"runtime.printint", 1}, @@ -129,6 +130,8 @@ var builtins = [...]struct { {"runtime.makeslice64", 1}, {"runtime.makeslicecopy", 1}, {"runtime.growslice", 1}, + {"runtime.unsafeslice", 1}, + {"runtime.unsafeslice64", 1}, {"runtime.memmove", 1}, {"runtime.memclrNoHeapPointers", 1}, {"runtime.memclrHasPointers", 1}, @@ -203,7 +206,9 @@ var builtins = [...]struct { {"runtime.newproc", 1}, {"runtime.panicoverflow", 1}, {"runtime.sigpanic", 1}, - {"runtime.gcWriteBarrier", 0}, + {"runtime.gcWriteBarrier", 1}, + {"runtime.duffzero", 1}, + {"runtime.duffcopy", 1}, {"runtime.morestack", 0}, {"runtime.morestackc", 0}, {"runtime.morestack_noctxt", 0}, diff --git a/src/cmd/internal/goobj/mkbuiltin.go b/src/cmd/internal/goobj/mkbuiltin.go index 18b969586cc..c9995fcedef 100644 --- a/src/cmd/internal/goobj/mkbuiltin.go +++ b/src/cmd/internal/goobj/mkbuiltin.go @@ -151,7 +151,9 @@ var fextras = [...]extra{ {"sigpanic", 1}, // compiler backend inserted calls - {"gcWriteBarrier", 0}, // asm function, ABI0 + {"gcWriteBarrier", 1}, + {"duffzero", 1}, + {"duffcopy", 1}, // assembler backend inserted calls {"morestack", 0}, // asm function, ABI0 From 165d39a1d460880f2d28619a4609f272448b0d60 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 1 Jun 2021 19:29:24 -0400 Subject: [PATCH 262/940] [dev.typeparams] test: adjust codegen test for register ABI on ARM64 In codegen/arithmetic.go, previously there are MOVD's that match for loads of arguments. With register ABI there are no more such loads. Remove the MOVD matches. Change-Id: I920ee2629c8c04d454f13a0c08e283d3528d9a64 Reviewed-on: https://go-review.googlesource.com/c/go/+/324251 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- test/codegen/arithmetic.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/codegen/arithmetic.go b/test/codegen/arithmetic.go index a27a17f6e11..eb0f338036c 100644 --- a/test/codegen/arithmetic.go +++ b/test/codegen/arithmetic.go @@ -202,7 +202,7 @@ func ConstDivs(n1 uint, n2 int) (uint, int) { // amd64:"MOVQ\t[$]-1085102592571150095","IMULQ",-"IDIVQ" // 386:"MOVL\t[$]-252645135","IMULL",-"IDIVL" - // arm64:`MOVD`,`SMULH`,-`DIV` + // arm64:`SMULH`,-`DIV` // arm:`MOVW`,`MUL`,-`.*udiv` b := n2 / 17 // signed @@ -266,7 +266,7 @@ func ConstMods(n1 uint, n2 int) (uint, int) { // amd64:"MOVQ\t[$]-1085102592571150095","IMULQ",-"IDIVQ" // 386:"MOVL\t[$]-252645135","IMULL",-"IDIVL" - // arm64:`MOVD`,`SMULH`,-`DIV` + // arm64:`SMULH`,-`DIV` // arm:`MOVW`,`MUL`,-`.*udiv` b := n2 % 17 // signed From 5a008a92e84f05e79fbe9fd8ab283bcee95d54ee Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 2 Jun 2021 18:00:12 -0400 Subject: [PATCH 263/940] [dev.typeparams] internal/bytealg: call memeqbody directly in memequal_varlen on ARM64 Currently, memequal_varlen opens up a frame and call memequal, which then tail-calls memeqbody. This CL changes memequal_varlen tail-calls memeqbody directly. This makes it simpler to switch to the register ABI in the next CL. Change-Id: Ia1367c0abb7f4755fe736c404411793fb9e5c04f Reviewed-on: https://go-review.googlesource.com/c/go/+/324399 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/internal/bytealg/equal_arm64.s | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/internal/bytealg/equal_arm64.s b/src/internal/bytealg/equal_arm64.s index 01aa7b7b7aa..944edd87686 100644 --- a/src/internal/bytealg/equal_arm64.s +++ b/src/internal/bytealg/equal_arm64.s @@ -20,20 +20,15 @@ equal: RET // memequal_varlen(a, b unsafe.Pointer) bool -TEXT runtime·memequal_varlen(SB),NOSPLIT,$40-17 - MOVD a+0(FP), R3 - MOVD b+8(FP), R4 - CMP R3, R4 +TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-17 + MOVD a+0(FP), R0 + MOVD b+8(FP), R2 + CMP R0, R2 BEQ eq - MOVD 8(R26), R5 // compiler stores size at offset 8 in the closure - CBZ R5, eq - MOVD R3, 8(RSP) - MOVD R4, 16(RSP) - MOVD R5, 24(RSP) - BL runtime·memequal(SB) - MOVBU 32(RSP), R3 - MOVB R3, ret+16(FP) - RET + MOVD 8(R26), R1 // compiler stores size at offset 8 in the closure + CBZ R1, eq + MOVD $ret+16(FP), R8 + B memeqbody<>(SB) eq: MOVD $1, R3 MOVB R3, ret+16(FP) From 370ff5ff96cf02dfbbc33b70934219367fa700bb Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Wed, 2 Jun 2021 18:12:14 -0700 Subject: [PATCH 264/940] [dev.typeparams] test: update all the typeparam tests to use the new union/tilde syntax Did a mix of tilde and non-tilde usage. Tilde notation is not quite fully functional, so no tests are currently trying to distinguish (fail/not fail) based on tilde usage. Change-Id: Ib50cec2fc0684f9d9f3561c889fd44c7a7af458c Reviewed-on: https://go-review.googlesource.com/c/go/+/324572 Trust: Dan Scales Trust: Robert Griesemer Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- test/typeparam/absdiff.go | 16 ++++++++-------- test/typeparam/adder.go | 2 +- test/typeparam/double.go | 2 +- test/typeparam/fact.go | 2 +- test/typeparam/factimp.dir/a.go | 2 +- test/typeparam/list.go | 14 +++++++------- test/typeparam/listimp.dir/a.go | 14 +++++++------- test/typeparam/min.go | 2 +- test/typeparam/mincheck.dir/a.go | 2 +- test/typeparam/minimp.dir/a.go | 2 +- test/typeparam/ordered.go | 8 ++++---- test/typeparam/orderedmap.go | 8 ++++---- test/typeparam/sliceimp.dir/a.go | 8 ++++---- test/typeparam/sliceimp.dir/main.go | 4 ++-- test/typeparam/slices.go | 12 ++++++------ test/typeparam/smallest.go | 8 ++++---- test/typeparam/smoketest.go | 2 +- test/typeparam/sum.go | 2 +- 18 files changed, 55 insertions(+), 55 deletions(-) diff --git a/test/typeparam/absdiff.go b/test/typeparam/absdiff.go index 1381d7c92c9..ecaa907795d 100644 --- a/test/typeparam/absdiff.go +++ b/test/typeparam/absdiff.go @@ -12,10 +12,10 @@ import ( ) type Numeric interface { - type int, int8, int16, int32, int64, - uint, uint8, uint16, uint32, uint64, uintptr, - float32, float64, - complex64, complex128 + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~complex64 | ~complex128 } // numericAbs matches numeric types with an Abs method. @@ -33,14 +33,14 @@ func absDifference[T numericAbs[T]](a, b T) T { // orderedNumeric matches numeric types that support the < operator. type orderedNumeric interface { - type int, int8, int16, int32, int64, - uint, uint8, uint16, uint32, uint64, uintptr, - float32, float64 + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 } // Complex matches the two complex types, which do not have a < operator. type Complex interface { - type complex64, complex128 + ~complex64 | ~complex128 } // orderedAbs is a helper type that defines an Abs method for diff --git a/test/typeparam/adder.go b/test/typeparam/adder.go index eb564b5bd54..79319bd2369 100644 --- a/test/typeparam/adder.go +++ b/test/typeparam/adder.go @@ -11,7 +11,7 @@ import ( ) type AddType interface { - type int, int64, string + int | int64 | string } // Add can add numbers or strings diff --git a/test/typeparam/double.go b/test/typeparam/double.go index ce78ec97483..66526138145 100644 --- a/test/typeparam/double.go +++ b/test/typeparam/double.go @@ -12,7 +12,7 @@ import ( ) type Number interface { - type int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr, float32, float64 + ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64 } type MySlice []int diff --git a/test/typeparam/fact.go b/test/typeparam/fact.go index ea86ae3e028..baa7fbc68e5 100644 --- a/test/typeparam/fact.go +++ b/test/typeparam/fact.go @@ -8,7 +8,7 @@ package main import "fmt" -func fact[T interface { type int, int64, float64 }](n T) T { +func fact[T interface { ~int | ~int64 | ~float64 }](n T) T { if n == 1 { return 1 } diff --git a/test/typeparam/factimp.dir/a.go b/test/typeparam/factimp.dir/a.go index 35524743829..cb1ff2615b0 100644 --- a/test/typeparam/factimp.dir/a.go +++ b/test/typeparam/factimp.dir/a.go @@ -4,7 +4,7 @@ package a -func Fact[T interface { type int, int64, float64 }](n T) T { +func Fact[T interface { int | int64 | float64 }](n T) T { if n == 1 { return 1 } diff --git a/test/typeparam/list.go b/test/typeparam/list.go index 579078f02f7..c63c9bff79f 100644 --- a/test/typeparam/list.go +++ b/test/typeparam/list.go @@ -11,10 +11,10 @@ import ( ) type Ordered interface { - type int, int8, int16, int32, int64, - uint, uint8, uint16, uint32, uint64, uintptr, - float32, float64, - string + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string } // _List is a linked list of ordered values of type T. @@ -34,9 +34,9 @@ func (l *_List[T]) Largest() T { } type OrderedNum interface { - type int, int8, int16, int32, int64, - uint, uint8, uint16, uint32, uint64, uintptr, - float32, float64 + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 } // _ListNum is a linked _List of ordered numeric values of type T. diff --git a/test/typeparam/listimp.dir/a.go b/test/typeparam/listimp.dir/a.go index 0a4634b7be4..2b5b23cde33 100644 --- a/test/typeparam/listimp.dir/a.go +++ b/test/typeparam/listimp.dir/a.go @@ -5,10 +5,10 @@ package a type Ordered interface { - type int, int8, int16, int32, int64, - uint, uint8, uint16, uint32, uint64, uintptr, - float32, float64, - string + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string } // List is a linked list of ordered values of type T. @@ -28,9 +28,9 @@ func (l *List[T]) Largest() T { } type OrderedNum interface { - type int, int8, int16, int32, int64, - uint, uint8, uint16, uint32, uint64, uintptr, - float32, float64 + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 } // ListNum is a linked _List of ordered numeric values of type T. diff --git a/test/typeparam/min.go b/test/typeparam/min.go index 6e28c062a8a..d6c65d68b79 100644 --- a/test/typeparam/min.go +++ b/test/typeparam/min.go @@ -11,7 +11,7 @@ import ( ) type Ordered interface { - type int, int64, float64, string + ~int | ~int64 | ~float64 | ~string } func min[T Ordered](x, y T) T { diff --git a/test/typeparam/mincheck.dir/a.go b/test/typeparam/mincheck.dir/a.go index f1844bba9da..7d42492b741 100644 --- a/test/typeparam/mincheck.dir/a.go +++ b/test/typeparam/mincheck.dir/a.go @@ -5,7 +5,7 @@ package a type Ordered interface { - type int, int64, float64 + int | int64 | float64 } func Min[T Ordered](x, y T) T { diff --git a/test/typeparam/minimp.dir/a.go b/test/typeparam/minimp.dir/a.go index 16c1b035f48..6c3e0eba363 100644 --- a/test/typeparam/minimp.dir/a.go +++ b/test/typeparam/minimp.dir/a.go @@ -5,7 +5,7 @@ package a type Ordered interface { - type int, int64, float64, string + ~int | ~int64 | ~float64 | ~string } func Min[T Ordered](x, y T) T { diff --git a/test/typeparam/ordered.go b/test/typeparam/ordered.go index 448db68bb55..699505ec75b 100644 --- a/test/typeparam/ordered.go +++ b/test/typeparam/ordered.go @@ -13,10 +13,10 @@ import ( ) type Ordered interface { - type int, int8, int16, int32, int64, - uint, uint8, uint16, uint32, uint64, uintptr, - float32, float64, - string + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string } type orderedSlice[Elem Ordered] []Elem diff --git a/test/typeparam/orderedmap.go b/test/typeparam/orderedmap.go index db1b3742674..6a895bd3960 100644 --- a/test/typeparam/orderedmap.go +++ b/test/typeparam/orderedmap.go @@ -15,10 +15,10 @@ import ( ) type Ordered interface { - type int, int8, int16, int32, int64, - uint, uint8, uint16, uint32, uint64, uintptr, - float32, float64, - string + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string } // _Map is an ordered map. diff --git a/test/typeparam/sliceimp.dir/a.go b/test/typeparam/sliceimp.dir/a.go index 2b58d1c29e1..61b1b17a982 100644 --- a/test/typeparam/sliceimp.dir/a.go +++ b/test/typeparam/sliceimp.dir/a.go @@ -5,10 +5,10 @@ package a type Ordered interface { - type int, int8, int16, int32, int64, - uint, uint8, uint16, uint32, uint64, uintptr, - float32, float64, - string + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string } // Max returns the maximum of two values of some ordered type. diff --git a/test/typeparam/sliceimp.dir/main.go b/test/typeparam/sliceimp.dir/main.go index 0a8e756b26c..2d4d3b28318 100644 --- a/test/typeparam/sliceimp.dir/main.go +++ b/test/typeparam/sliceimp.dir/main.go @@ -12,8 +12,8 @@ import ( ) type Integer interface { - type int, int8, int16, int32, int64, - uint, uint8, uint16, uint32, uint64, uintptr + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr } func TestEqual() { diff --git a/test/typeparam/slices.go b/test/typeparam/slices.go index 149199eb649..50783a5439b 100644 --- a/test/typeparam/slices.go +++ b/test/typeparam/slices.go @@ -15,15 +15,15 @@ import ( ) type Ordered interface { - type int, int8, int16, int32, int64, - uint, uint8, uint16, uint32, uint64, uintptr, - float32, float64, - string + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string } type Integer interface { - type int, int8, int16, int32, int64, - uint, uint8, uint16, uint32, uint64, uintptr + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr } // Max returns the maximum of two values of some ordered type. diff --git a/test/typeparam/smallest.go b/test/typeparam/smallest.go index d8515360497..3fead6a0671 100644 --- a/test/typeparam/smallest.go +++ b/test/typeparam/smallest.go @@ -11,10 +11,10 @@ import ( ) type Ordered interface { - type int, int8, int16, int32, int64, - uint, uint8, uint16, uint32, uint64, uintptr, - float32, float64, - string + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string } func Smallest[T Ordered](s []T) T { diff --git a/test/typeparam/smoketest.go b/test/typeparam/smoketest.go index b7d6201b2c1..d92e02713d7 100644 --- a/test/typeparam/smoketest.go +++ b/test/typeparam/smoketest.go @@ -37,7 +37,7 @@ func (x T2[P1, P2, P3]) m() {} type _ interface { m1() m2() - type int, float32, string + int | float32 | string m3() } diff --git a/test/typeparam/sum.go b/test/typeparam/sum.go index c82d8e4c612..53e6face11a 100644 --- a/test/typeparam/sum.go +++ b/test/typeparam/sum.go @@ -10,7 +10,7 @@ import ( "fmt" ) -func Sum[T interface{ type int, float64 }](vec []T) T { +func Sum[T interface{ int | float64 }](vec []T) T { var sum T for _, elt := range vec { sum = sum + elt From 5a40fab19fd615aa879e8f499a63e31d98257886 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 2 Jun 2021 17:30:58 -0400 Subject: [PATCH 265/940] [dev.typeparams] runtime, internal/bytealg: port performance-critical functions to register ABI on ARM64 This CL ports a few performance-critical assembly functions to use register arguments directly. This is similar to CL 308931 and CL 310184. Change-Id: I6e30dfff17f76b8578ce8cfd51de21b66610fdb0 Reviewed-on: https://go-review.googlesource.com/c/go/+/324400 Trust: Cherry Mui Run-TryBot: Cherry Mui Reviewed-by: Than McIntosh Reviewed-by: Michael Knyszek TryBot-Result: Go Bot --- src/internal/bytealg/compare_arm64.s | 113 ++++++++++++-------- src/internal/bytealg/equal_arm64.s | 93 ++++++++++------- src/runtime/asm_arm64.s | 150 ++++++++++++++++++--------- src/runtime/memclr_arm64.s | 4 +- src/runtime/memmove_arm64.s | 4 +- 5 files changed, 233 insertions(+), 131 deletions(-) diff --git a/src/internal/bytealg/compare_arm64.s b/src/internal/bytealg/compare_arm64.s index 56d56f241eb..5a802072583 100644 --- a/src/internal/bytealg/compare_arm64.s +++ b/src/internal/bytealg/compare_arm64.s @@ -5,65 +5,88 @@ #include "go_asm.h" #include "textflag.h" -TEXT ·Compare(SB),NOSPLIT|NOFRAME,$0-56 - MOVD a_base+0(FP), R2 - MOVD a_len+8(FP), R0 - MOVD b_base+24(FP), R3 - MOVD b_len+32(FP), R1 +TEXT ·Compare(SB),NOSPLIT|NOFRAME,$0-56 +#ifdef GOEXPERIMENT_regabiargs + // R0 = a_base (want in R0) + // R1 = a_len (want in R1) + // R2 = a_cap (unused) + // R3 = b_base (want in R2) + // R4 = b_len (want in R3) + // R5 = b_cap (unused) + MOVD R3, R2 + MOVD R4, R3 +#else + MOVD a_base+0(FP), R0 + MOVD a_len+8(FP), R1 + MOVD b_base+24(FP), R2 + MOVD b_len+32(FP), R3 MOVD $ret+48(FP), R7 +#endif B cmpbody<>(SB) -TEXT runtime·cmpstring(SB),NOSPLIT|NOFRAME,$0-40 - MOVD a_base+0(FP), R2 - MOVD a_len+8(FP), R0 - MOVD b_base+16(FP), R3 - MOVD b_len+24(FP), R1 +TEXT runtime·cmpstring(SB),NOSPLIT|NOFRAME,$0-40 +#ifdef GOEXPERIMENT_regabiargs + // R0 = a_base + // R1 = a_len + // R2 = b_base + // R3 = b_len +#else + MOVD a_base+0(FP), R0 + MOVD a_len+8(FP), R1 + MOVD b_base+16(FP), R2 + MOVD b_len+24(FP), R3 MOVD $ret+32(FP), R7 +#endif B cmpbody<>(SB) // On entry: -// R0 is the length of a -// R1 is the length of b -// R2 points to the start of a -// R3 points to the start of b +// R0 points to the start of a +// R1 is the length of a +// R2 points to the start of b +// R3 is the length of b +#ifndef GOEXPERIMENT_regabiargs // R7 points to return value (-1/0/1 will be written here) +#endif // // On exit: +#ifdef GOEXPERIMENT_regabiargs +// R0 is the result +#endif // R4, R5, R6, R8, R9 and R10 are clobbered TEXT cmpbody<>(SB),NOSPLIT|NOFRAME,$0-0 - CMP R2, R3 + CMP R0, R2 BEQ samebytes // same starting pointers; compare lengths - CMP R0, R1 - CSEL LT, R1, R0, R6 // R6 is min(R0, R1) + CMP R1, R3 + CSEL LT, R3, R1, R6 // R6 is min(R1, R3) CBZ R6, samebytes BIC $0xf, R6, R10 CBZ R10, small // length < 16 - ADD R2, R10 // end of chunk16 + ADD R0, R10 // end of chunk16 // length >= 16 chunk16_loop: - LDP.P 16(R2), (R4, R8) - LDP.P 16(R3), (R5, R9) + LDP.P 16(R0), (R4, R8) + LDP.P 16(R2), (R5, R9) CMP R4, R5 BNE cmp CMP R8, R9 BNE cmpnext - CMP R10, R2 + CMP R10, R0 BNE chunk16_loop AND $0xf, R6, R6 CBZ R6, samebytes SUBS $8, R6 BLT tail // the length of tail > 8 bytes - MOVD.P 8(R2), R4 - MOVD.P 8(R3), R5 + MOVD.P 8(R0), R4 + MOVD.P 8(R2), R5 CMP R4, R5 BNE cmp SUB $8, R6 // compare last 8 bytes tail: - MOVD (R2)(R6), R4 - MOVD (R3)(R6), R5 + MOVD (R0)(R6), R4 + MOVD (R2)(R6), R5 CMP R4, R5 BEQ samebytes cmp: @@ -71,52 +94,56 @@ cmp: REV R5, R5 CMP R4, R5 ret: - MOVD $1, R4 - CNEG HI, R4, R4 - MOVD R4, (R7) + MOVD $1, R0 + CNEG HI, R0, R0 +#ifndef GOEXPERIMENT_regabiargs + MOVD R0, (R7) +#endif RET small: TBZ $3, R6, lt_8 - MOVD (R2), R4 - MOVD (R3), R5 + MOVD (R0), R4 + MOVD (R2), R5 CMP R4, R5 BNE cmp SUBS $8, R6 BEQ samebytes + ADD $8, R0 ADD $8, R2 - ADD $8, R3 SUB $8, R6 B tail lt_8: TBZ $2, R6, lt_4 - MOVWU (R2), R4 - MOVWU (R3), R5 + MOVWU (R0), R4 + MOVWU (R2), R5 CMPW R4, R5 BNE cmp SUBS $4, R6 BEQ samebytes + ADD $4, R0 ADD $4, R2 - ADD $4, R3 lt_4: TBZ $1, R6, lt_2 - MOVHU (R2), R4 - MOVHU (R3), R5 + MOVHU (R0), R4 + MOVHU (R2), R5 CMPW R4, R5 BNE cmp + ADD $2, R0 ADD $2, R2 - ADD $2, R3 lt_2: TBZ $0, R6, samebytes one: - MOVBU (R2), R4 - MOVBU (R3), R5 + MOVBU (R0), R4 + MOVBU (R2), R5 CMPW R4, R5 BNE ret samebytes: - CMP R1, R0 - CSET NE, R4 - CNEG LO, R4, R4 - MOVD R4, (R7) + CMP R3, R1 + CSET NE, R0 + CNEG LO, R0, R0 +#ifndef GOEXPERIMENT_regabiargs + MOVD R0, (R7) +#endif RET cmpnext: REV R8, R4 diff --git a/src/internal/bytealg/equal_arm64.s b/src/internal/bytealg/equal_arm64.s index 944edd87686..cf5cf54e597 100644 --- a/src/internal/bytealg/equal_arm64.s +++ b/src/internal/bytealg/equal_arm64.s @@ -6,53 +6,70 @@ #include "textflag.h" // memequal(a, b unsafe.Pointer, size uintptr) bool -TEXT runtime·memequal(SB),NOSPLIT|NOFRAME,$0-25 - MOVD size+16(FP), R1 +TEXT runtime·memequal(SB),NOSPLIT|NOFRAME,$0-25 +#ifndef GOEXPERIMENT_regabiargs + MOVD size+16(FP), R2 +#endif // short path to handle 0-byte case - CBZ R1, equal + CBZ R2, equal +#ifndef GOEXPERIMENT_regabiargs MOVD a+0(FP), R0 - MOVD b+8(FP), R2 + MOVD b+8(FP), R1 MOVD $ret+24(FP), R8 +#endif B memeqbody<>(SB) equal: MOVD $1, R0 +#ifndef GOEXPERIMENT_regabiargs MOVB R0, ret+24(FP) +#endif RET // memequal_varlen(a, b unsafe.Pointer) bool -TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-17 +TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-17 +#ifndef GOEXPERIMENT_regabiargs MOVD a+0(FP), R0 - MOVD b+8(FP), R2 - CMP R0, R2 + MOVD b+8(FP), R1 +#endif + CMP R0, R1 BEQ eq - MOVD 8(R26), R1 // compiler stores size at offset 8 in the closure - CBZ R1, eq + MOVD 8(R26), R2 // compiler stores size at offset 8 in the closure + CBZ R2, eq +#ifndef GOEXPERIMENT_regabiargs MOVD $ret+16(FP), R8 +#endif B memeqbody<>(SB) eq: - MOVD $1, R3 - MOVB R3, ret+16(FP) + MOVD $1, R0 +#ifndef GOEXPERIMENT_regabiargs + MOVB R0, ret+16(FP) +#endif RET // input: // R0: pointer a -// R1: data len -// R2: pointer b +// R1: pointer b +// R2: data len +#ifdef GOEXPERIMENT_regabiargs +// at return: result in R0 +#else // R8: address to put result +#endif + TEXT memeqbody<>(SB),NOSPLIT,$0 - CMP $1, R1 + CMP $1, R2 // handle 1-byte special case for better performance BEQ one - CMP $16, R1 + CMP $16, R2 // handle specially if length < 16 BLO tail - BIC $0x3f, R1, R3 + BIC $0x3f, R2, R3 CBZ R3, chunk16 // work with 64-byte chunks ADD R3, R0, R6 // end of chunks chunk64_loop: VLD1.P (R0), [V0.D2, V1.D2, V2.D2, V3.D2] - VLD1.P (R2), [V4.D2, V5.D2, V6.D2, V7.D2] + VLD1.P (R1), [V4.D2, V5.D2, V6.D2, V7.D2] VCMEQ V0.D2, V4.D2, V8.D2 VCMEQ V1.D2, V5.D2, V9.D2 VCMEQ V2.D2, V6.D2, V10.D2 @@ -66,66 +83,72 @@ chunk64_loop: CBZ R4, not_equal CBZ R5, not_equal BNE chunk64_loop - AND $0x3f, R1, R1 - CBZ R1, equal + AND $0x3f, R2, R2 + CBZ R2, equal chunk16: // work with 16-byte chunks - BIC $0xf, R1, R3 + BIC $0xf, R2, R3 CBZ R3, tail ADD R3, R0, R6 // end of chunks chunk16_loop: LDP.P 16(R0), (R4, R5) - LDP.P 16(R2), (R7, R9) + LDP.P 16(R1), (R7, R9) EOR R4, R7 CBNZ R7, not_equal EOR R5, R9 CBNZ R9, not_equal CMP R0, R6 BNE chunk16_loop - AND $0xf, R1, R1 - CBZ R1, equal + AND $0xf, R2, R2 + CBZ R2, equal tail: // special compare of tail with length < 16 - TBZ $3, R1, lt_8 + TBZ $3, R2, lt_8 MOVD (R0), R4 - MOVD (R2), R5 + MOVD (R1), R5 EOR R4, R5 CBNZ R5, not_equal - SUB $8, R1, R6 // offset of the last 8 bytes + SUB $8, R2, R6 // offset of the last 8 bytes MOVD (R0)(R6), R4 - MOVD (R2)(R6), R5 + MOVD (R1)(R6), R5 EOR R4, R5 CBNZ R5, not_equal B equal lt_8: - TBZ $2, R1, lt_4 + TBZ $2, R2, lt_4 MOVWU (R0), R4 - MOVWU (R2), R5 + MOVWU (R1), R5 EOR R4, R5 CBNZ R5, not_equal - SUB $4, R1, R6 // offset of the last 4 bytes + SUB $4, R2, R6 // offset of the last 4 bytes MOVWU (R0)(R6), R4 - MOVWU (R2)(R6), R5 + MOVWU (R1)(R6), R5 EOR R4, R5 CBNZ R5, not_equal B equal lt_4: - TBZ $1, R1, lt_2 + TBZ $1, R2, lt_2 MOVHU.P 2(R0), R4 - MOVHU.P 2(R2), R5 + MOVHU.P 2(R1), R5 CMP R4, R5 BNE not_equal lt_2: - TBZ $0, R1, equal + TBZ $0, R2, equal one: MOVBU (R0), R4 - MOVBU (R2), R5 + MOVBU (R1), R5 CMP R4, R5 BNE not_equal equal: MOVD $1, R0 +#ifndef GOEXPERIMENT_regabiargs MOVB R0, (R8) +#endif RET not_equal: +#ifdef GOEXPERIMENT_regabiargs + MOVB ZR, R0 +#else MOVB ZR, (R8) +#endif RET diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s index 170e4406fcb..4babcc7fcbc 100644 --- a/src/runtime/asm_arm64.s +++ b/src/runtime/asm_arm64.s @@ -536,12 +536,14 @@ CALLFN(·call536870912, 536870912) CALLFN(·call1073741824, 1073741824) // func memhash32(p unsafe.Pointer, h uintptr) uintptr -TEXT runtime·memhash32(SB),NOSPLIT|NOFRAME,$0-24 - MOVB runtime·useAeshash(SB), R0 - CBZ R0, noaes +TEXT runtime·memhash32(SB),NOSPLIT|NOFRAME,$0-24 + MOVB runtime·useAeshash(SB), R10 + CBZ R10, noaes +#ifndef GOEXPERIMENT_regabiargs MOVD p+0(FP), R0 MOVD h+8(FP), R1 MOVD $ret+16(FP), R2 +#endif MOVD $runtime·aeskeysched+0(SB), R3 VEOR V0.B16, V0.B16, V0.B16 @@ -555,18 +557,24 @@ TEXT runtime·memhash32(SB),NOSPLIT|NOFRAME,$0-24 AESMC V0.B16, V0.B16 AESE V2.B16, V0.B16 +#ifdef GOEXPERIMENT_regabiargs + VMOV V0.D[0], R0 +#else VST1 [V0.D1], (R2) +#endif RET noaes: - B runtime·memhash32Fallback(SB) + B runtime·memhash32Fallback(SB) // func memhash64(p unsafe.Pointer, h uintptr) uintptr -TEXT runtime·memhash64(SB),NOSPLIT|NOFRAME,$0-24 - MOVB runtime·useAeshash(SB), R0 - CBZ R0, noaes +TEXT runtime·memhash64(SB),NOSPLIT|NOFRAME,$0-24 + MOVB runtime·useAeshash(SB), R10 + CBZ R10, noaes +#ifndef GOEXPERIMENT_regabiargs MOVD p+0(FP), R0 MOVD h+8(FP), R1 MOVD $ret+16(FP), R2 +#endif MOVD $runtime·aeskeysched+0(SB), R3 VEOR V0.B16, V0.B16, V0.B16 @@ -580,75 +588,89 @@ TEXT runtime·memhash64(SB),NOSPLIT|NOFRAME,$0-24 AESMC V0.B16, V0.B16 AESE V2.B16, V0.B16 +#ifdef GOEXPERIMENT_regabiargs + VMOV V0.D[0], R0 +#else VST1 [V0.D1], (R2) +#endif RET noaes: - B runtime·memhash64Fallback(SB) + B runtime·memhash64Fallback(SB) // func memhash(p unsafe.Pointer, h, size uintptr) uintptr -TEXT runtime·memhash(SB),NOSPLIT|NOFRAME,$0-32 - MOVB runtime·useAeshash(SB), R0 - CBZ R0, noaes +TEXT runtime·memhash(SB),NOSPLIT|NOFRAME,$0-32 + MOVB runtime·useAeshash(SB), R10 + CBZ R10, noaes +#ifndef GOEXPERIMENT_regabiargs MOVD p+0(FP), R0 - MOVD s+16(FP), R1 - MOVD h+8(FP), R3 - MOVD $ret+24(FP), R2 + MOVD h+8(FP), R1 + MOVD s+16(FP), R2 + MOVD $ret+24(FP), R8 +#endif B aeshashbody<>(SB) noaes: - B runtime·memhashFallback(SB) + B runtime·memhashFallback(SB) // func strhash(p unsafe.Pointer, h uintptr) uintptr -TEXT runtime·strhash(SB),NOSPLIT|NOFRAME,$0-24 - MOVB runtime·useAeshash(SB), R0 - CBZ R0, noaes - MOVD p+0(FP), R10 // string pointer - LDP (R10), (R0, R1) //string data/ length - MOVD h+8(FP), R3 - MOVD $ret+16(FP), R2 // return adddress +TEXT runtime·strhash(SB),NOSPLIT|NOFRAME,$0-24 + MOVB runtime·useAeshash(SB), R10 + CBZ R10, noaes +#ifdef GOEXPERIMENT_regabiargs + LDP (R0), (R0, R2) // string data / length +#else + MOVD p+0(FP), R10 // string pointer + LDP (R10), (R0, R2) // string data / length + MOVD h+8(FP), R1 + MOVD $ret+16(FP), R8 // return adddress +#endif B aeshashbody<>(SB) noaes: - B runtime·strhashFallback(SB) + B runtime·strhashFallback(SB) // R0: data -// R1: length -// R2: address to put return value -// R3: seed data +// R1: seed data +// R2: length +#ifdef GOEXPERIMENT_regabiargs +// At return, R0 = return value +#else +// R8: address to put return value +#endif TEXT aeshashbody<>(SB),NOSPLIT|NOFRAME,$0 VEOR V30.B16, V30.B16, V30.B16 - VMOV R3, V30.D[0] - VMOV R1, V30.D[1] // load length into seed + VMOV R1, V30.D[0] + VMOV R2, V30.D[1] // load length into seed MOVD $runtime·aeskeysched+0(SB), R4 VLD1.P 16(R4), [V0.B16] AESE V30.B16, V0.B16 AESMC V0.B16, V0.B16 - CMP $16, R1 + CMP $16, R2 BLO aes0to15 BEQ aes16 - CMP $32, R1 + CMP $32, R2 BLS aes17to32 - CMP $64, R1 + CMP $64, R2 BLS aes33to64 - CMP $128, R1 + CMP $128, R2 BLS aes65to128 B aes129plus aes0to15: - CBZ R1, aes0 + CBZ R2, aes0 VEOR V2.B16, V2.B16, V2.B16 - TBZ $3, R1, less_than_8 + TBZ $3, R2, less_than_8 VLD1.P 8(R0), V2.D[0] less_than_8: - TBZ $2, R1, less_than_4 + TBZ $2, R2, less_than_4 VLD1.P 4(R0), V2.S[2] less_than_4: - TBZ $1, R1, less_than_2 + TBZ $1, R2, less_than_2 VLD1.P 2(R0), V2.H[6] less_than_2: - TBZ $0, R1, done + TBZ $0, R2, done VLD1 (R0), V2.B[14] done: AESE V0.B16, V2.B16 @@ -657,11 +679,21 @@ done: AESMC V2.B16, V2.B16 AESE V0.B16, V2.B16 - VST1 [V2.D1], (R2) +#ifdef GOEXPERIMENT_regabiargs + VMOV V2.D[0], R0 +#else + VST1 [V2.D1], (R8) +#endif RET + aes0: - VST1 [V0.D1], (R2) +#ifdef GOEXPERIMENT_regabiargs + VMOV V0.D[0], R0 +#else + VST1 [V0.D1], (R8) +#endif RET + aes16: VLD1 (R0), [V2.B16] B done @@ -671,7 +703,7 @@ aes17to32: VLD1 (R4), [V1.B16] AESE V30.B16, V1.B16 AESMC V1.B16, V1.B16 - SUB $16, R1, R10 + SUB $16, R2, R10 VLD1.P (R0)(R10), [V2.B16] VLD1 (R0), [V3.B16] @@ -689,7 +721,11 @@ aes17to32: AESE V1.B16, V3.B16 VEOR V3.B16, V2.B16, V2.B16 - VST1 [V2.D1], (R2) +#ifdef GOEXPERIMENT_regabiargs + VMOV V2.D[0], R0 +#else + VST1 [V2.D1], (R8) +#endif RET aes33to64: @@ -700,7 +736,7 @@ aes33to64: AESMC V2.B16, V2.B16 AESE V30.B16, V3.B16 AESMC V3.B16, V3.B16 - SUB $32, R1, R10 + SUB $32, R2, R10 VLD1.P (R0)(R10), [V4.B16, V5.B16] VLD1 (R0), [V6.B16, V7.B16] @@ -732,7 +768,11 @@ aes33to64: VEOR V7.B16, V5.B16, V5.B16 VEOR V5.B16, V4.B16, V4.B16 - VST1 [V4.D1], (R2) +#ifdef GOEXPERIMENT_regabiargs + VMOV V4.D[0], R0 +#else + VST1 [V4.D1], (R8) +#endif RET aes65to128: @@ -753,7 +793,7 @@ aes65to128: AESE V30.B16, V7.B16 AESMC V7.B16, V7.B16 - SUB $64, R1, R10 + SUB $64, R2, R10 VLD1.P (R0)(R10), [V8.B16, V9.B16, V10.B16, V11.B16] VLD1 (R0), [V12.B16, V13.B16, V14.B16, V15.B16] AESE V0.B16, V8.B16 @@ -807,7 +847,11 @@ aes65to128: VEOR V11.B16, V9.B16, V9.B16 VEOR V9.B16, V8.B16, V8.B16 - VST1 [V8.D1], (R2) +#ifdef GOEXPERIMENT_regabiargs + VMOV V8.D[0], R0 +#else + VST1 [V8.D1], (R8) +#endif RET aes129plus: @@ -828,12 +872,12 @@ aes129plus: AESMC V6.B16, V6.B16 AESE V30.B16, V7.B16 AESMC V7.B16, V7.B16 - ADD R0, R1, R10 + ADD R0, R2, R10 SUB $128, R10, R10 VLD1.P 64(R10), [V8.B16, V9.B16, V10.B16, V11.B16] VLD1 (R10), [V12.B16, V13.B16, V14.B16, V15.B16] - SUB $1, R1, R1 - LSR $7, R1, R1 + SUB $1, R2, R2 + LSR $7, R2, R2 aesloop: AESE V8.B16, V0.B16 @@ -872,8 +916,8 @@ aesloop: AESMC V6.B16, V6.B16 AESE V15.B16, V7.B16 AESMC V7.B16, V7.B16 - SUB $1, R1, R1 - CBNZ R1, aesloop + SUB $1, R2, R2 + CBNZ R2, aesloop AESE V8.B16, V0.B16 AESMC V0.B16, V0.B16 @@ -926,7 +970,11 @@ aesloop: VEOR V4.B16, V6.B16, V4.B16 VEOR V4.B16, V0.B16, V0.B16 - VST1 [V0.D1], (R2) +#ifdef GOEXPERIMENT_regabiargs + VMOV V0.D[0], R0 +#else + VST1 [V0.D1], (R8) +#endif RET TEXT runtime·procyield(SB),NOSPLIT,$0-0 diff --git a/src/runtime/memclr_arm64.s b/src/runtime/memclr_arm64.s index c1a0dcef584..b80cca6a1cd 100644 --- a/src/runtime/memclr_arm64.s +++ b/src/runtime/memclr_arm64.s @@ -8,9 +8,11 @@ // func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr) // Also called from assembly in sys_windows_arm64.s without g (but using Go stack convention). -TEXT runtime·memclrNoHeapPointers(SB),NOSPLIT,$0-16 +TEXT runtime·memclrNoHeapPointers(SB),NOSPLIT,$0-16 +#ifndef GOEXPERIMENT_regabiargs MOVD ptr+0(FP), R0 MOVD n+8(FP), R1 +#endif CMP $16, R1 // If n is equal to 16 bytes, use zero_exact_16 to zero diff --git a/src/runtime/memmove_arm64.s b/src/runtime/memmove_arm64.s index 43d27629e5b..bee3b00c47d 100644 --- a/src/runtime/memmove_arm64.s +++ b/src/runtime/memmove_arm64.s @@ -26,10 +26,12 @@ // The loop tail is handled by always copying 64 bytes from the end. // func memmove(to, from unsafe.Pointer, n uintptr) -TEXT runtime·memmove(SB), NOSPLIT|NOFRAME, $0-24 +TEXT runtime·memmove(SB), NOSPLIT|NOFRAME, $0-24 +#ifndef GOEXPERIMENT_regabiargs MOVD to+0(FP), R0 MOVD from+8(FP), R1 MOVD n+16(FP), R2 +#endif CBZ R2, copy0 // Small copies: 1..16 bytes From 3de49868526d5bfae2f9bda8be1a60c022cf3363 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 2 Jun 2021 19:43:28 -0400 Subject: [PATCH 266/940] [dev.typeparams] runtime: call cgocallbackg indirectly on ARM64 This is CL 312669, for ARM64. cgocallback calls cgocallbackg after switching the stack. Call it indirectly to bypass the linker's nosplit check. In particular, this avoids a nosplit stack overflow on Windows when register ABI is enabled. Change-Id: I7054a750fb0ec2579d46004f94b46b6f7b9e3a21 Reviewed-on: https://go-review.googlesource.com/c/go/+/324734 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/runtime/asm_arm64.s | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s index 4babcc7fcbc..be4313d35d5 100644 --- a/src/runtime/asm_arm64.s +++ b/src/runtime/asm_arm64.s @@ -1196,7 +1196,8 @@ havem: MOVD R1, 8(RSP) MOVD R2, 16(RSP) MOVD R3, 24(RSP) - BL runtime·cgocallbackg(SB) + MOVD $runtime·cgocallbackg(SB), R0 + CALL (R0) // indirect call to bypass nosplit check. We're on a different stack now. // Restore g->sched (== m->curg->sched) from saved values. MOVD 0(RSP), R5 From 28bd325e418a0ca1c70a024764aa74e25aacab12 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 2 Jun 2021 19:52:39 -0400 Subject: [PATCH 267/940] [dev.typeparams] runtime: use ABIInternal callbackWrap in callbackasm1 on ARM64 On Windows/ARM64, callbackasm1 calls callbackWrap via cgocallback. cgocallback uses ABIInternal calling convention to call the function. Pass the ABIInternal entry point to cgocallback. Change-Id: I79d21b77525f6ac8dd50d34f4f304749419b2ad4 Reviewed-on: https://go-review.googlesource.com/c/go/+/324735 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/runtime/sys_windows_arm64.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/sys_windows_arm64.s b/src/runtime/sys_windows_arm64.s index e8593715089..44145c53fb7 100644 --- a/src/runtime/sys_windows_arm64.s +++ b/src/runtime/sys_windows_arm64.s @@ -339,7 +339,7 @@ TEXT runtime·callbackasm1(SB),NOSPLIT,$208-0 MOVD R0, callbackArgs_result(R13) // result // Call cgocallback, which will call callbackWrap(frame). - MOVD $·callbackWrap(SB), R0 // PC of function to call + MOVD $·callbackWrap(SB), R0 // PC of function to call, cgocallback takes an ABIInternal entry-point MOVD R13, R1 // frame (&callbackArgs{...}) MOVD $0, R2 // context MOVD R0, (1*8)(RSP) From e0d029f75846f84f79e63f6100c57047f4a3fa98 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Wed, 2 Jun 2021 17:44:43 -0400 Subject: [PATCH 268/940] runtime: avoid gp.lockedm race in exitsyscall0 Following https://golang.org/cl/291329, exitsyscall0 accesses gp.lockedm after releasing gp to the global runq. This creates a race window where another M may schedule the (unlocked) G, which subsequently calls LockOSThread, setting gp.lockedm and thus causing exitsyscall0 to think it should call stoplockedm. Avoid this race by checking if gp is locked before releasing it to the global runq. Fixes #46524 Change-Id: I3acdaf09e7a2178725adbe61e985130e9ebd0680 Reviewed-on: https://go-review.googlesource.com/c/go/+/324350 Trust: Michael Pratt Run-TryBot: Michael Pratt TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor Reviewed-by: Michael Knyszek --- src/runtime/proc.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/runtime/proc.go b/src/runtime/proc.go index ded406cc28d..59160c6525f 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -4083,8 +4083,16 @@ func exitsyscall0(gp *g) { if schedEnabled(gp) { _p_ = pidleget() } + var locked bool if _p_ == nil { globrunqput(gp) + + // Below, we stoplockedm if gp is locked. globrunqput releases + // ownership of gp, so we must check if gp is locked prior to + // committing the release by unlocking sched.lock, otherwise we + // could race with another M transitioning gp from unlocked to + // locked. + locked = gp.lockedm != 0 } else if atomic.Load(&sched.sysmonwait) != 0 { atomic.Store(&sched.sysmonwait, 0) notewakeup(&sched.sysmonnote) @@ -4094,7 +4102,7 @@ func exitsyscall0(gp *g) { acquirep(_p_) execute(gp, false) // Never returns. } - if gp.lockedm != 0 { + if locked { // Wait until another thread schedules gp and so m again. // // N.B. lockedm must be this M, as this g was running on this M From 6d9830111402d9bd69893a8ad6074ac92a5ddd0d Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Thu, 3 Jun 2021 14:50:10 -0400 Subject: [PATCH 269/940] cmd/link: use correct alignment in PE DWARF sections Set the correct section flags to insure that .debug_* sections are using 1-byte alignment instead of the default. This seems to be important for later versions of LLVM-mingw on windows (shows up on the windows/arm64 builder). Updates #46406. Change-Id: I023d5208374f867552ba68b45011f7990159868f Reviewed-on: https://go-review.googlesource.com/c/go/+/324763 Trust: Than McIntosh Reviewed-by: Cherry Mui Run-TryBot: Than McIntosh TryBot-Result: Go Bot --- src/cmd/link/internal/ld/pe.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go index 3540c07da10..8eb4231c3ab 100644 --- a/src/cmd/link/internal/ld/pe.go +++ b/src/cmd/link/internal/ld/pe.go @@ -475,7 +475,7 @@ func (f *peFile) addDWARFSection(name string, size int) *peSection { off := f.stringTable.add(name) h := f.addSection(name, size, size) h.shortName = fmt.Sprintf("/%d", off) - h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_CNT_INITIALIZED_DATA + h.characteristics = IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_CNT_INITIALIZED_DATA return h } From e9ba0750b63652514bc527690b39fe8b3651ad31 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 3 Jun 2021 15:23:22 -0400 Subject: [PATCH 270/940] [dev.typeparams] reflect: guard abi_test.go with regabiargs build tag The test in abi_test.go relies on the compiler to generate register-ABI calls using a magic name. As of CL 300150 the name loses its magic. Guard it with regabiargs for the use of register-ABI calls. Change-Id: Ib8b3c24f71ea5161d607c9becfb3027ceee40ac1 Reviewed-on: https://go-review.googlesource.com/c/go/+/324767 Trust: Cherry Mui Run-TryBot: Cherry Mui Reviewed-by: Michael Knyszek TryBot-Result: Go Bot --- src/reflect/abi_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/reflect/abi_test.go b/src/reflect/abi_test.go index 1a2a48b5ed9..26e77f14dda 100644 --- a/src/reflect/abi_test.go +++ b/src/reflect/abi_test.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build goexperiment.regabireflect -// +build goexperiment.regabireflect +//go:build goexperiment.regabireflect && goexperiment.regabiargs +// +build goexperiment.regabireflect,goexperiment.regabiargs package reflect_test From 1c947e4f31331ffbc0397a7781c443903f1da473 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Thu, 3 Jun 2021 10:59:35 -0700 Subject: [PATCH 271/940] [dev.typeparams] cmd/compile: properly copy tilde value for unions in types2-to-types1 conversion Change-Id: I2211020141886b348cddf9e33ab31b71c8478987 Reviewed-on: https://go-review.googlesource.com/c/go/+/324811 Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Robert Griesemer Trust: Dan Scales --- src/cmd/compile/internal/noder/types.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go index f34cf146bbd..f0061e79d70 100644 --- a/src/cmd/compile/internal/noder/types.go +++ b/src/cmd/compile/internal/noder/types.go @@ -239,8 +239,9 @@ func (g *irgen) typ0(typ types2.Type) *types.Type { tlist := make([]*types.Type, nt) tildes := make([]bool, nt) for i := range tlist { - term, _ := typ.Term(i) + term, tilde := typ.Term(i) tlist[i] = g.typ1(term) + tildes[i] = tilde } return types.NewUnion(tlist, tildes) From 6b1e4430bb79674ff523240608f106a1aeb7302e Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 3 Jun 2021 12:23:14 -0400 Subject: [PATCH 272/940] [dev.typeparams] cmd/compile: implement clobberdead mode on ARM64 For debugging. Change-Id: I5875ccd2413b8ffd2ec97a0ace66b5cae7893b24 Reviewed-on: https://go-review.googlesource.com/c/go/+/324765 Trust: Cherry Mui Run-TryBot: Cherry Mui Reviewed-by: Than McIntosh TryBot-Result: Go Bot --- src/cmd/compile/internal/arm64/ssa.go | 30 +++++++++++++++++++++++++-- test/codegen/clobberdead.go | 7 +++++-- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/cmd/compile/internal/arm64/ssa.go b/src/cmd/compile/internal/arm64/ssa.go index 74308a18f60..c3319f94912 100644 --- a/src/cmd/compile/internal/arm64/ssa.go +++ b/src/cmd/compile/internal/arm64/ssa.go @@ -1114,8 +1114,34 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { v.Fatalf("FlagConstant op should never make it to codegen %v", v.LongString()) case ssa.OpARM64InvertFlags: v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString()) - case ssa.OpClobber, ssa.OpClobberReg: - // TODO: implement for clobberdead experiment. Nop is ok for now. + case ssa.OpClobber: + // MOVW $0xdeaddead, REGTMP + // MOVW REGTMP, (slot) + // MOVW REGTMP, 4(slot) + p := s.Prog(arm64.AMOVW) + p.From.Type = obj.TYPE_CONST + p.From.Offset = 0xdeaddead + p.To.Type = obj.TYPE_REG + p.To.Reg = arm64.REGTMP + p = s.Prog(arm64.AMOVW) + p.From.Type = obj.TYPE_REG + p.From.Reg = arm64.REGTMP + p.To.Type = obj.TYPE_MEM + p.To.Reg = arm64.REGSP + ssagen.AddAux(&p.To, v) + p = s.Prog(arm64.AMOVW) + p.From.Type = obj.TYPE_REG + p.From.Reg = arm64.REGTMP + p.To.Type = obj.TYPE_MEM + p.To.Reg = arm64.REGSP + ssagen.AddAux2(&p.To, v, v.AuxInt+4) + case ssa.OpClobberReg: + x := uint64(0xdeaddeaddeaddead) + p := s.Prog(arm64.AMOVD) + p.From.Type = obj.TYPE_CONST + p.From.Offset = int64(x) + p.To.Type = obj.TYPE_REG + p.To.Reg = v.Reg() default: v.Fatalf("genValue not implemented: %s", v.LongString()) } diff --git a/test/codegen/clobberdead.go b/test/codegen/clobberdead.go index f8d964cba68..c490790bb63 100644 --- a/test/codegen/clobberdead.go +++ b/test/codegen/clobberdead.go @@ -1,6 +1,6 @@ // asmcheck -gcflags=-clobberdead -// +build amd64 +// +build amd64 arm64 // Copyright 2021 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -13,15 +13,18 @@ type T [2]*int // contain pointer, not SSA-able (so locals are not registerized) var p1, p2, p3 T func F() { - // 3735936685 is 0xdeaddead + // 3735936685 is 0xdeaddead. On ARM64 R27 is REGTMP. // clobber x, y at entry. not clobber z (stack object). // amd64:`MOVL\t\$3735936685, ""\.x`, `MOVL\t\$3735936685, ""\.y`, -`MOVL\t\$3735936685, ""\.z` + // arm64:`MOVW\tR27, ""\.x`, `MOVW\tR27, ""\.y`, -`MOVW\tR27, ""\.z` x, y, z := p1, p2, p3 addrTaken(&z) // x is dead at the call (the value of x is loaded before the CALL), y is not // amd64:`MOVL\t\$3735936685, ""\.x`, -`MOVL\t\$3735936685, ""\.y` + // arm64:`MOVW\tR27, ""\.x`, -`MOVW\tR27, ""\.y` use(x) // amd64:`MOVL\t\$3735936685, ""\.x`, `MOVL\t\$3735936685, ""\.y` + // arm64:`MOVW\tR27, ""\.x`, `MOVW\tR27, ""\.y` use(y) } From 55b4310acdbd7bc7253936c44a845a98d82eaae7 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 3 Jun 2021 12:26:18 -0400 Subject: [PATCH 273/940] [dev.typeparams] runtime: crash the GC at clobberdead pointer on ARM64 Extend CL 310330 to ARM64, which now has clobberdead mode implemented in the compiler. Change-Id: I07f6951d81a0797ef7a74e48b79db5cea2bf876b Reviewed-on: https://go-review.googlesource.com/c/go/+/324766 Trust: Cherry Mui Run-TryBot: Cherry Mui Reviewed-by: Michael Knyszek TryBot-Result: Go Bot --- src/runtime/mbitmap.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go index 32b8db7a502..819acf40bd6 100644 --- a/src/runtime/mbitmap.go +++ b/src/runtime/mbitmap.go @@ -386,10 +386,10 @@ func findObject(p, refBase, refOff uintptr) (base uintptr, s *mspan, objIndex ui // If s is nil, the virtual address has never been part of the heap. // This pointer may be to some mmap'd region, so we allow it. if s == nil { - if GOARCH == "amd64" && p == clobberdeadPtr && debug.invalidptr != 0 { - // Crash if clobberdeadPtr is seen. Only on AMD64 for now, as - // it is the only platform where compiler's clobberdead mode is - // implemented. On AMD64 clobberdeadPtr cannot be a valid address. + if (GOARCH == "amd64" || GOARCH == "arm64") && p == clobberdeadPtr && debug.invalidptr != 0 { + // Crash if clobberdeadPtr is seen. Only on AMD64 and ARM64 for now, + // as they are the only platform where compiler's clobberdead mode is + // implemented. On these platforms clobberdeadPtr cannot be a valid address. badPointer(s, p, refBase, refOff) } return From a2d6a2caebec473de95e29c48f076b01b7ab5af0 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 3 Jun 2021 15:17:51 -0400 Subject: [PATCH 274/940] [dev.typeparams] internal/buildcfg: turn on regabiwrappers by default on ARM64 Change-Id: I8db0a797a745630ec35af3e56406fcb250ea59fe Reviewed-on: https://go-review.googlesource.com/c/go/+/324768 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek Reviewed-by: Than McIntosh --- src/internal/buildcfg/exp.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/internal/buildcfg/exp.go b/src/internal/buildcfg/exp.go index 196d6af4a60..1fc53324c11 100644 --- a/src/internal/buildcfg/exp.go +++ b/src/internal/buildcfg/exp.go @@ -21,12 +21,13 @@ import ( var Experiment goexperiment.Flags = parseExperiments() var regabiSupported = GOARCH == "amd64" +var regabiDeveloping = GOARCH == "arm64" // experimentBaseline specifies the experiment flags that are enabled by // default in the current toolchain. This is, in effect, the "control" // configuration and any variation from this is an experiment. var experimentBaseline = goexperiment.Flags{ - RegabiWrappers: regabiSupported, + RegabiWrappers: regabiSupported || regabiDeveloping, RegabiG: regabiSupported, RegabiReflect: regabiSupported, RegabiDefer: true, From 026480d06bd0b72e147953281b328c0283128e52 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 3 Jun 2021 13:05:22 -0700 Subject: [PATCH 275/940] [dev.typeparams] cmd/compile: allow nil Syms in Sym.Less Allows sorting interfaces that contain embedded anonymous types. Fixes #46556. Change-Id: If19afa1d62432323b2e98957087867afbf3f9097 Reviewed-on: https://go-review.googlesource.com/c/go/+/324812 Trust: Matthew Dempsky Trust: Dan Scales Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/types/sym.go | 8 ++++++++ test/fixedbugs/issue46556.go | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 test/fixedbugs/issue46556.go diff --git a/src/cmd/compile/internal/types/sym.go b/src/cmd/compile/internal/types/sym.go index 534cf7e2376..fb642f52f88 100644 --- a/src/cmd/compile/internal/types/sym.go +++ b/src/cmd/compile/internal/types/sym.go @@ -110,6 +110,14 @@ func (a *Sym) Less(b *Sym) bool { return false } + // Nil before non-nil. + if a == nil { + return true + } + if b == nil { + return false + } + // Exported symbols before non-exported. ea := IsExported(a.Name) eb := IsExported(b.Name) diff --git a/test/fixedbugs/issue46556.go b/test/fixedbugs/issue46556.go new file mode 100644 index 00000000000..b159f61b0c5 --- /dev/null +++ b/test/fixedbugs/issue46556.go @@ -0,0 +1,16 @@ +// compile + +// Copyright 2021 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 + +type A = interface{} +type B interface{} + +// Test that embedding both anonymous and defined types is supported. +type C interface { + A + B +} From 5f034f9b46f32010434d64aa376bb118e899253a Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 3 Jun 2021 15:18:36 -0400 Subject: [PATCH 276/940] [dev.typeparams] internal/buildcfg: turn on regabireflect by default on ARM64 Change-Id: I4a0a093b07a287cc3a3e0ee939e7ee82d8e9b1aa Reviewed-on: https://go-review.googlesource.com/c/go/+/324889 Trust: Cherry Mui Run-TryBot: Cherry Mui Reviewed-by: Michael Knyszek Reviewed-by: Than McIntosh TryBot-Result: Go Bot --- src/internal/buildcfg/exp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/buildcfg/exp.go b/src/internal/buildcfg/exp.go index 1fc53324c11..352aebd2276 100644 --- a/src/internal/buildcfg/exp.go +++ b/src/internal/buildcfg/exp.go @@ -29,7 +29,7 @@ var regabiDeveloping = GOARCH == "arm64" var experimentBaseline = goexperiment.Flags{ RegabiWrappers: regabiSupported || regabiDeveloping, RegabiG: regabiSupported, - RegabiReflect: regabiSupported, + RegabiReflect: regabiSupported || regabiDeveloping, RegabiDefer: true, RegabiArgs: regabiSupported, } From 4d2b528795fe2534398d1b1a978e1037d4a9d2f0 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 3 Jun 2021 10:30:47 -0400 Subject: [PATCH 277/940] [dev.typeparams] internal/buildcfg: turn on register ABI by default on ARM64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This CL enables all regabi experiments on ARM64 by default. regabiwrappers and regabireflect are enabled in the previous CLs. regabidefer is already enabled everywhere. regabig is no-op on ARM64 as it already has a G register. regabiargs is enabled in this CL. Go1 benchmarks results (GOEXPERIMENT=regabi vs. none, on macOS/ARM64): name old time/op new time/op delta BinaryTree17-8 1.20s ± 1% 1.02s ± 0% -15.08% (p=0.000 n=9+9) Fannkuch11-8 1.55s ± 0% 1.57s ± 0% +1.53% (p=0.000 n=9+8) FmtFprintfEmpty-8 22.5ns ± 3% 14.7ns ± 1% -34.47% (p=0.000 n=10+8) FmtFprintfString-8 38.4ns ± 0% 28.8ns ± 0% -24.99% (p=0.000 n=9+9) FmtFprintfInt-8 38.7ns ± 2% 34.5ns ± 0% -10.79% (p=0.000 n=10+7) FmtFprintfIntInt-8 61.1ns ± 1% 57.9ns ± 0% -5.23% (p=0.000 n=10+8) FmtFprintfPrefixedInt-8 69.9ns ± 0% 64.4ns ± 0% -7.78% (p=0.000 n=8+8) FmtFprintfFloat-8 106ns ± 0% 76ns ± 0% -28.12% (p=0.000 n=7+10) FmtManyArgs-8 273ns ± 0% 236ns ± 1% -13.57% (p=0.000 n=9+10) GobDecode-8 3.09ms ± 1% 2.02ms ± 0% -34.70% (p=0.000 n=9+10) GobEncode-8 2.45ms ± 1% 1.44ms ± 1% -41.26% (p=0.000 n=10+10) Gzip-8 128ms ± 0% 124ms ± 0% -2.89% (p=0.000 n=7+8) Gunzip-8 23.6ms ± 1% 19.8ms ± 0% -16.15% (p=0.000 n=10+9) HTTPClientServer-8 27.4µs ± 1% 26.3µs ± 0% -4.05% (p=0.000 n=10+10) JSONEncode-8 4.47ms ± 1% 3.45ms ± 1% -22.73% (p=0.000 n=10+9) JSONDecode-8 21.5ms ± 0% 17.2ms ± 0% -19.78% (p=0.000 n=9+9) Mandelbrot200-8 2.33ms ± 1% 2.33ms ± 1% ~ (p=0.842 n=9+10) GoParse-8 1.62ms ± 1% 1.32ms ± 1% -18.67% (p=0.000 n=10+10) RegexpMatchEasy0_32-8 33.1ns ± 0% 26.3ns ± 0% -20.50% (p=0.000 n=8+10) RegexpMatchEasy0_1K-8 121ns ± 6% 121ns ± 8% ~ (p=0.926 n=10+10) RegexpMatchEasy1_32-8 31.4ns ± 0% 24.7ns ± 0% -21.50% (p=0.000 n=9+10) RegexpMatchEasy1_1K-8 177ns ± 0% 140ns ± 0% -20.70% (p=0.000 n=10+9) RegexpMatchMedium_32-8 3.02ns ± 3% 2.12ns ± 0% -29.73% (p=0.000 n=10+10) RegexpMatchMedium_1K-8 19.8µs ± 2% 17.1µs ± 0% -13.50% (p=0.000 n=9+9) RegexpMatchHard_32-8 940ns ± 0% 872ns ± 0% -7.20% (p=0.000 n=9+8) RegexpMatchHard_1K-8 28.5µs ± 1% 26.5µs ± 0% -7.06% (p=0.000 n=10+10) Revcomp-8 186ms ± 1% 179ms ± 1% -3.66% (p=0.000 n=10+10) Template-8 30.3ms ± 0% 22.3ms ± 0% -26.58% (p=0.000 n=8+9) TimeParse-8 133ns ± 0% 117ns ± 0% -12.40% (p=0.000 n=10+10) TimeFormat-8 176ns ± 0% 141ns ± 0% -19.92% (p=0.000 n=8+9) [Geo mean] 21.4µs 17.8µs -16.81% name old speed new speed delta GobDecode-8 249MB/s ± 1% 381MB/s ± 0% +53.13% (p=0.000 n=9+10) GobEncode-8 314MB/s ± 1% 534MB/s ± 1% +70.25% (p=0.000 n=10+10) Gzip-8 152MB/s ± 0% 156MB/s ± 0% +2.97% (p=0.000 n=7+8) Gunzip-8 822MB/s ± 1% 981MB/s ± 0% +19.26% (p=0.000 n=10+9) JSONEncode-8 434MB/s ± 1% 562MB/s ± 1% +29.41% (p=0.000 n=10+9) JSONDecode-8 90.3MB/s ± 0% 112.5MB/s ± 0% +24.66% (p=0.000 n=9+9) GoParse-8 35.7MB/s ± 1% 43.9MB/s ± 1% +22.96% (p=0.000 n=10+10) RegexpMatchEasy0_32-8 967MB/s ± 0% 1216MB/s ± 0% +25.78% (p=0.000 n=8+10) RegexpMatchEasy0_1K-8 8.46GB/s ± 6% 8.45GB/s ± 7% ~ (p=0.912 n=10+10) RegexpMatchEasy1_32-8 1.02GB/s ± 0% 1.30GB/s ± 0% +27.40% (p=0.000 n=9+10) RegexpMatchEasy1_1K-8 5.78GB/s ± 0% 7.29GB/s ± 0% +26.10% (p=0.000 n=10+9) RegexpMatchMedium_32-8 331MB/s ± 2% 471MB/s ± 0% +42.29% (p=0.000 n=10+10) RegexpMatchMedium_1K-8 51.7MB/s ± 2% 59.8MB/s ± 0% +15.60% (p=0.000 n=9+9) RegexpMatchHard_32-8 34.0MB/s ± 0% 36.7MB/s ± 0% +7.75% (p=0.000 n=9+8) RegexpMatchHard_1K-8 35.9MB/s ± 1% 38.6MB/s ± 0% +7.59% (p=0.000 n=10+10) Revcomp-8 1.37GB/s ± 1% 1.42GB/s ± 1% +3.79% (p=0.000 n=10+10) Template-8 64.0MB/s ± 0% 87.1MB/s ± 0% +36.20% (p=0.000 n=8+9) [Geo mean] 299MB/s 368MB/s +23.16% Binary sizes: old new hello 1180994 1162626 -1.6% cmd/compile 23455858 22833970 -2.7% cmd/link 6425010 6332978 -1.4% Text sizes: old new hello 458752 425984 -7.1% cmd/compile 10190848 9355264 -8.2% cmd/link 2621440 2441216 -6.9% Change-Id: I52c10c11bb8fe5952b7043f9dbf09573ef71d2b0 Reviewed-on: https://go-review.googlesource.com/c/go/+/324890 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek Reviewed-by: Than McIntosh Reviewed-by: Jeremy Faller --- src/internal/buildcfg/exp.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/internal/buildcfg/exp.go b/src/internal/buildcfg/exp.go index 352aebd2276..38a20456391 100644 --- a/src/internal/buildcfg/exp.go +++ b/src/internal/buildcfg/exp.go @@ -20,16 +20,16 @@ import ( // was built with.) var Experiment goexperiment.Flags = parseExperiments() -var regabiSupported = GOARCH == "amd64" -var regabiDeveloping = GOARCH == "arm64" +var regabiSupported = GOARCH == "amd64" || GOARCH == "arm64" +var regabiDeveloping = false // experimentBaseline specifies the experiment flags that are enabled by // default in the current toolchain. This is, in effect, the "control" // configuration and any variation from this is an experiment. var experimentBaseline = goexperiment.Flags{ - RegabiWrappers: regabiSupported || regabiDeveloping, + RegabiWrappers: regabiSupported, RegabiG: regabiSupported, - RegabiReflect: regabiSupported || regabiDeveloping, + RegabiReflect: regabiSupported, RegabiDefer: true, RegabiArgs: regabiSupported, } From b29b123e079183a05abc1066007a51d4f565cd88 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 3 Jun 2021 18:00:53 -0700 Subject: [PATCH 278/940] cmd/compile: remove spurious ir.Dump This ir.Dump call is a debugging artifact introduced in golang.org/cl/274103, which should never be printed for valid, non-generic code, but evidently can now sometimes appear due to how the parser handles invalid syntax. The parser should probably not recognize "x[2]" as a type expression in non-generics mode, but also probably we shouldn't try noding after reporting syntax errors. Either way, this diagnostic has outlived its usefulness, and noder's days are numbered anyway, so we might as well just remove it to save end users any confusion. Updates #46558. Change-Id: Ib68502ef834d610b883c2f2bb11d9b385bc66e37 Reviewed-on: https://go-review.googlesource.com/c/go/+/324991 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky Reviewed-by: Robert Griesemer TryBot-Result: Go Bot --- src/cmd/compile/internal/noder/noder.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go index 4c7c9fc322f..5fcad096c28 100644 --- a/src/cmd/compile/internal/noder/noder.go +++ b/src/cmd/compile/internal/noder/noder.go @@ -882,9 +882,6 @@ func (p *noder) typeExpr(typ syntax.Expr) ir.Ntype { if n == nil { return nil } - if _, ok := n.(ir.Ntype); !ok { - ir.Dump("NOT NTYPE", n) - } return n.(ir.Ntype) } From 962d5c997af450af1de9a38eb6510cdfc86ea689 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 2 Jun 2021 12:22:50 -0700 Subject: [PATCH 279/940] cmd/compile,go/types: restrict use of unsafe.{Add,Slice} to go1.17 or newer This CL updates cmd/compile (including types2) and go/types to report errors about using unsafe.Add and unsafe.Slice when language compatibility is set to Go 1.16 or older. Fixes #46525. Change-Id: I1bfe025a672d9f4b929f443064ad1effd38d0363 Reviewed-on: https://go-review.googlesource.com/c/go/+/324369 Run-TryBot: Matthew Dempsky Reviewed-by: Robert Findley Reviewed-by: Robert Griesemer TryBot-Result: Go Bot Trust: Matthew Dempsky --- src/cmd/compile/internal/typecheck/func.go | 12 ++++++++++++ src/cmd/compile/internal/types2/builtins.go | 10 ++++++++++ src/go/types/builtins.go | 10 ++++++++++ test/fixedbugs/issue46525.go | 14 ++++++++++++++ 4 files changed, 46 insertions(+) create mode 100644 test/fixedbugs/issue46525.go diff --git a/src/cmd/compile/internal/typecheck/func.go b/src/cmd/compile/internal/typecheck/func.go index f381e1dbdc4..a6dfbbf569a 100644 --- a/src/cmd/compile/internal/typecheck/func.go +++ b/src/cmd/compile/internal/typecheck/func.go @@ -981,6 +981,12 @@ func tcRecover(n *ir.CallExpr) ir.Node { // tcUnsafeAdd typechecks an OUNSAFEADD node. func tcUnsafeAdd(n *ir.BinaryExpr) *ir.BinaryExpr { + if !types.AllowsGoVersion(curpkg(), 1, 17) { + base.ErrorfVers("go1.17", "unsafe.Add") + n.SetType(nil) + return n + } + n.X = AssignConv(Expr(n.X), types.Types[types.TUNSAFEPTR], "argument to unsafe.Add") n.Y = DefaultLit(Expr(n.Y), types.Types[types.TINT]) if n.X.Type() == nil || n.Y.Type() == nil { @@ -997,6 +1003,12 @@ func tcUnsafeAdd(n *ir.BinaryExpr) *ir.BinaryExpr { // tcUnsafeSlice typechecks an OUNSAFESLICE node. func tcUnsafeSlice(n *ir.BinaryExpr) *ir.BinaryExpr { + if !types.AllowsGoVersion(curpkg(), 1, 17) { + base.ErrorfVers("go1.17", "unsafe.Slice") + n.SetType(nil) + return n + } + n.X = Expr(n.X) n.Y = Expr(n.Y) if n.X.Type() == nil || n.Y.Type() == nil { diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index b9e178dd576..f90e06f2267 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -579,6 +579,11 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( case _Add: // unsafe.Add(ptr unsafe.Pointer, len IntegerType) unsafe.Pointer + if !check.allowVersion(check.pkg, 1, 17) { + check.error(call.Fun, "unsafe.Add requires go1.17 or later") + return + } + check.assignment(x, Typ[UnsafePointer], "argument to unsafe.Add") if x.mode == invalid { return @@ -675,6 +680,11 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( case _Slice: // unsafe.Slice(ptr *T, len IntegerType) []T + if !check.allowVersion(check.pkg, 1, 17) { + check.error(call.Fun, "unsafe.Slice requires go1.17 or later") + return + } + typ := asPointer(x.typ) if typ == nil { check.errorf(x, invalidArg+"%s is not a pointer", x) diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index 739051cc611..2a2d54da882 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -588,6 +588,11 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b case _Add: // unsafe.Add(ptr unsafe.Pointer, len IntegerType) unsafe.Pointer + if !check.allowVersion(check.pkg, 1, 17) { + check.errorf(call.Fun, _InvalidUnsafeAdd, "unsafe.Add requires go1.17 or later") + return + } + check.assignment(x, Typ[UnsafePointer], "argument to unsafe.Add") if x.mode == invalid { return @@ -684,6 +689,11 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b case _Slice: // unsafe.Slice(ptr *T, len IntegerType) []T + if !check.allowVersion(check.pkg, 1, 17) { + check.errorf(call.Fun, _InvalidUnsafeSlice, "unsafe.Slice requires go1.17 or later") + return + } + typ := asPointer(x.typ) if typ == nil { check.invalidArg(x, _InvalidUnsafeSlice, "%s is not a pointer", x) diff --git a/test/fixedbugs/issue46525.go b/test/fixedbugs/issue46525.go new file mode 100644 index 00000000000..164e1473ce6 --- /dev/null +++ b/test/fixedbugs/issue46525.go @@ -0,0 +1,14 @@ +// errorcheck -lang=go1.16 + +// Copyright 2021 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 "unsafe" + +func main() { + _ = unsafe.Add(unsafe.Pointer(nil), 0) // ERROR "unsafe.Add requires go1.17 or later" + _ = unsafe.Slice(new(byte), 1) // ERROR "unsafe.Slice requires go1.17 or later" +} From 2175e2f57331cbcd32bccc47fa7fe7a6874a69a3 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Sat, 29 May 2021 15:35:18 -0700 Subject: [PATCH 280/940] [dev.typeparams] cmd/compile: lazy import resolution for types2 This CL adds three new functions to the types2 API to support lazy import resolution: 1. A new Scope.InsertLazy method to allow recording that Objects exist in a particular Scope (in particular, package scopes) without having to yet fully construct those objects. Instead, types2 will call the provided `resolve` function if/when the object is actually needed. 2. Similarly, a new NewTypeNameLazy function to create TypeName objects without yet instantiating their underlying Named instance. 3. Finally, an InstantiateLazy method, that allows creating type instances without requiring any of the types to be expanded right away. Importantly, this requires providing a types2.Checker argument to handle recursive types correctly. The APIs as-is are a bit clumsy (esp. NewTypeNameLazy), but seem to work well for cmd/compile's needs. In particular, they simplify some of the complexities of handling recursive type definitions within the importer. Also, the current prototype is a bit fragile. It uses sync.Once to manage concurrent lazy resolution, which is frustrating to debug in the presence of reentrancy issues. It also means the importer needs to deal with concurrency as well. These aren't issues for types2 though as cmd/compile only walks the type-checked AST sequentially. Finally, it looks like some of the details of lazy type names are similar to the lazy "instance" stuff used for generics, so maybe there's opportunity for unifying them under a more general (but still internal) lazy type mechanism. I had originally intended for this CL to also update the types2 importer, but (1) it doesn't have access to the types2.Checker instance needed to call InstantiateLazy, and (2) it creates a new TypeName/TypeParam at each use rather than reusing them, which evidently works with types2.Instantiate but not types2.(*Checker).instantiate (i.e., InstantiateLazy). I spent a while trying to fix these issues, but kept running into more subtle issues. Instead, I've included my WIP "unified IR" CL as a followup CL that demonstrates these Lazy methods (see noder/reader2.go). Updates #46449. Change-Id: I4d1e8e649f6325a11790d25fd90c39fa07c8d41d Reviewed-on: https://go-review.googlesource.com/c/go/+/323569 Run-TryBot: Matthew Dempsky Trust: Matthew Dempsky Trust: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types2/check.go | 2 +- src/cmd/compile/internal/types2/decl.go | 7 +- .../compile/internal/types2/instantiate.go | 18 +++- src/cmd/compile/internal/types2/labels.go | 3 +- src/cmd/compile/internal/types2/lookup.go | 5 +- src/cmd/compile/internal/types2/object.go | 8 ++ src/cmd/compile/internal/types2/predicates.go | 2 +- src/cmd/compile/internal/types2/resolver.go | 19 ++-- src/cmd/compile/internal/types2/sanitize.go | 1 + src/cmd/compile/internal/types2/scope.go | 93 +++++++++++++++++-- src/cmd/compile/internal/types2/signature.go | 2 +- .../compile/internal/types2/sizeof_test.go | 2 +- src/cmd/compile/internal/types2/stmt.go | 3 +- src/cmd/compile/internal/types2/subst.go | 12 +-- src/cmd/compile/internal/types2/type.go | 46 +++++++-- src/cmd/compile/internal/types2/typestring.go | 4 +- src/cmd/compile/internal/types2/typexpr.go | 2 +- 17 files changed, 186 insertions(+), 43 deletions(-) diff --git a/src/cmd/compile/internal/types2/check.go b/src/cmd/compile/internal/types2/check.go index f80a918467e..5d3c2c8ad25 100644 --- a/src/cmd/compile/internal/types2/check.go +++ b/src/cmd/compile/internal/types2/check.go @@ -71,7 +71,7 @@ type importKey struct { // A dotImportKey describes a dot-imported object in the given scope. type dotImportKey struct { scope *Scope - obj Object + name string } // A Checker maintains the state of the type checker. diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go index aa70f3880b8..00b4ef70107 100644 --- a/src/cmd/compile/internal/types2/decl.go +++ b/src/cmd/compile/internal/types2/decl.go @@ -522,7 +522,7 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init syntax.Expr) { // is detected, the result is Typ[Invalid]. If a cycle is detected and // n0.check != nil, the cycle is reported. func (n0 *Named) under() Type { - u := n0.underlying + u := n0.Underlying() if u == Typ[Invalid] { return u @@ -560,7 +560,7 @@ func (n0 *Named) under() Type { seen := map[*Named]int{n0: 0} path := []Object{n0.obj} for { - u = n.underlying + u = n.Underlying() if u == nil { u = Typ[Invalid] break @@ -764,7 +764,7 @@ func (check *Checker) collectMethods(obj *TypeName) { // and field names must be distinct." base := asNamed(obj.typ) // shouldn't fail but be conservative if base != nil { - if t, _ := base.underlying.(*Struct); t != nil { + if t, _ := base.Underlying().(*Struct); t != nil { for _, fld := range t.fields { if fld.name != "_" { assert(mset.insert(fld) == nil) @@ -806,6 +806,7 @@ func (check *Checker) collectMethods(obj *TypeName) { } if base != nil { + base.expand() // TODO(mdempsky): Probably unnecessary. base.methods = append(base.methods, m) } } diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go index 0df52e851c9..85c897a9097 100644 --- a/src/cmd/compile/internal/types2/instantiate.go +++ b/src/cmd/compile/internal/types2/instantiate.go @@ -23,7 +23,7 @@ func Instantiate(pos syntax.Pos, typ Type, targs []Type) (res Type) { var tparams []*TypeName switch t := typ.(type) { case *Named: - tparams = t.tparams + tparams = t.TParams() case *Signature: tparams = t.tparams defer func() { @@ -61,3 +61,19 @@ func Instantiate(pos syntax.Pos, typ Type, targs []Type) (res Type) { smap := makeSubstMap(tparams, targs) return (*Checker)(nil).subst(pos, typ, smap) } + +// InstantiateLazy is like Instantiate, but avoids actually +// instantiating the type until needed. +func (check *Checker) InstantiateLazy(pos syntax.Pos, typ Type, targs []Type) (res Type) { + base := asNamed(typ) + if base == nil { + panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) + } + + return &instance{ + check: check, + pos: pos, + base: base, + targs: targs, + } +} diff --git a/src/cmd/compile/internal/types2/labels.go b/src/cmd/compile/internal/types2/labels.go index d3206988b54..6f02e2fc969 100644 --- a/src/cmd/compile/internal/types2/labels.go +++ b/src/cmd/compile/internal/types2/labels.go @@ -32,7 +32,8 @@ func (check *Checker) labels(body *syntax.BlockStmt) { } // spec: "It is illegal to define a label that is never used." - for _, obj := range all.elems { + for name, obj := range all.elems { + obj = resolve(name, obj) if lbl := obj.(*Label); !lbl.used { check.softErrorf(lbl.pos, "label %s declared but not used", lbl.name) } diff --git a/src/cmd/compile/internal/types2/lookup.go b/src/cmd/compile/internal/types2/lookup.go index eb2b17dd4de..93ed620449e 100644 --- a/src/cmd/compile/internal/types2/lookup.go +++ b/src/cmd/compile/internal/types2/lookup.go @@ -54,7 +54,7 @@ func (check *Checker) lookupFieldOrMethod(T Type, addressable bool, pkg *Package // pointer type but discard the result if it is a method since we would // not have found it for T (see also issue 8590). if t := asNamed(T); t != nil { - if p, _ := t.underlying.(*Pointer); p != nil { + if p, _ := t.Underlying().(*Pointer); p != nil { obj, index, indirect = check.rawLookupFieldOrMethod(p, false, pkg, name) if _, ok := obj.(*Func); ok { return nil, nil, false @@ -126,6 +126,7 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack seen[named] = true // look for a matching attached method + named.expand() if i, m := lookupMethod(named.methods, pkg, name); m != nil { // potential match // caution: method may not have a proper signature yet @@ -400,7 +401,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // In order to compare the signatures, substitute the receiver // type parameters of ftyp with V's instantiation type arguments. // This lazily instantiates the signature of method f. - if Vn != nil && len(Vn.tparams) > 0 { + if Vn != nil && len(Vn.TParams()) > 0 { // Be careful: The number of type arguments may not match // the number of receiver parameters. If so, an error was // reported earlier but the length discrepancy is still diff --git a/src/cmd/compile/internal/types2/object.go b/src/cmd/compile/internal/types2/object.go index 8ed55f1dbf9..82297ff17f1 100644 --- a/src/cmd/compile/internal/types2/object.go +++ b/src/cmd/compile/internal/types2/object.go @@ -276,6 +276,14 @@ func NewTypeName(pos syntax.Pos, pkg *Package, name string, typ Type) *TypeName return &TypeName{object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}} } +// NewTypeNameLazy returns a new defined type like NewTypeName, but it +// lazily calls resolve to finish constructing the Named object. +func NewTypeNameLazy(pos syntax.Pos, pkg *Package, name string, resolve func(named *Named) (tparams []*TypeName, underlying Type, methods []*Func)) *TypeName { + obj := NewTypeName(pos, pkg, name, nil) + NewNamed(obj, nil, nil).resolve = resolve + return obj +} + // IsAlias reports whether obj is an alias name for a type. func (obj *TypeName) IsAlias() bool { switch t := obj.typ.(type) { diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go index 74436836cd8..66de2490440 100644 --- a/src/cmd/compile/internal/types2/predicates.go +++ b/src/cmd/compile/internal/types2/predicates.go @@ -21,7 +21,7 @@ func isNamed(typ Type) bool { func isGeneric(typ Type) bool { // A parameterized type is only instantiated if it doesn't have an instantiation already. named, _ := typ.(*Named) - return named != nil && named.obj != nil && named.tparams != nil && named.targs == nil + return named != nil && named.obj != nil && named.TParams() != nil && named.targs == nil } func is(typ Type, what BasicInfo) bool { diff --git a/src/cmd/compile/internal/types2/resolver.go b/src/cmd/compile/internal/types2/resolver.go index 9b1482b14e1..018a20cfb2d 100644 --- a/src/cmd/compile/internal/types2/resolver.go +++ b/src/cmd/compile/internal/types2/resolver.go @@ -308,22 +308,26 @@ func (check *Checker) collectObjects() { check.dotImportMap = make(map[dotImportKey]*PkgName) } // merge imported scope with file scope - for _, obj := range imp.scope.elems { + for name, obj := range imp.scope.elems { + // Note: Avoid eager resolve(name, obj) here, so we only + // resolve dot-imported objects as needed. + // A package scope may contain non-exported objects, // do not import them! - if obj.Exported() { + if isExported(name) { // declare dot-imported object // (Do not use check.declare because it modifies the object // via Object.setScopePos, which leads to a race condition; // the object may be imported into more than one file scope // concurrently. See issue #32154.) - if alt := fileScope.Insert(obj); alt != nil { + if alt := fileScope.Lookup(name); alt != nil { var err error_ - err.errorf(s.LocalPkgName, "%s redeclared in this block", obj.Name()) + err.errorf(s.LocalPkgName, "%s redeclared in this block", alt.Name()) err.recordAltDecl(alt) check.report(&err) } else { - check.dotImportMap[dotImportKey{fileScope, obj}] = pkgName + fileScope.insert(name, obj) + check.dotImportMap[dotImportKey{fileScope, name}] = pkgName } } } @@ -469,8 +473,9 @@ func (check *Checker) collectObjects() { // verify that objects in package and file scopes have different names for _, scope := range fileScopes { - for _, obj := range scope.elems { - if alt := pkg.scope.Lookup(obj.Name()); alt != nil { + for name, obj := range scope.elems { + if alt := pkg.scope.Lookup(name); alt != nil { + obj = resolve(name, obj) var err error_ if pkg, ok := obj.(*PkgName); ok { err.errorf(alt, "%s already declared through import of %s", alt.Name(), pkg.Imported()) diff --git a/src/cmd/compile/internal/types2/sanitize.go b/src/cmd/compile/internal/types2/sanitize.go index 03aef90fe13..4e654e074fc 100644 --- a/src/cmd/compile/internal/types2/sanitize.go +++ b/src/cmd/compile/internal/types2/sanitize.go @@ -134,6 +134,7 @@ func (s sanitizer) typ(typ Type) Type { if debug && t.check != nil { panic("internal error: Named.check != nil") } + t.expand() if orig := s.typ(t.fromRHS); orig != t.fromRHS { t.fromRHS = orig } diff --git a/src/cmd/compile/internal/types2/scope.go b/src/cmd/compile/internal/types2/scope.go index ade0a79b31d..2f1814a6319 100644 --- a/src/cmd/compile/internal/types2/scope.go +++ b/src/cmd/compile/internal/types2/scope.go @@ -13,6 +13,7 @@ import ( "io" "sort" "strings" + "sync" ) // A Scope maintains a set of objects and links to its containing @@ -66,7 +67,7 @@ func (s *Scope) Child(i int) *Scope { return s.children[i] } // Lookup returns the object in scope s with the given name if such an // object exists; otherwise the result is nil. func (s *Scope) Lookup(name string) Object { - return s.elems[name] + return resolve(name, s.elems[name]) } // LookupParent follows the parent chain of scopes starting with s until @@ -81,7 +82,7 @@ func (s *Scope) Lookup(name string) Object { // whose scope is the scope of the package that exported them. func (s *Scope) LookupParent(name string, pos syntax.Pos) (*Scope, Object) { for ; s != nil; s = s.parent { - if obj := s.elems[name]; obj != nil && (!pos.IsKnown() || obj.scopePos().Cmp(pos) <= 0) { + if obj := s.Lookup(name); obj != nil && (!pos.IsKnown() || obj.scopePos().Cmp(pos) <= 0) { return s, obj } } @@ -95,19 +96,38 @@ func (s *Scope) LookupParent(name string, pos syntax.Pos) (*Scope, Object) { // if not already set, and returns nil. func (s *Scope) Insert(obj Object) Object { name := obj.Name() - if alt := s.elems[name]; alt != nil { + if alt := s.Lookup(name); alt != nil { return alt } - if s.elems == nil { - s.elems = make(map[string]Object) - } - s.elems[name] = obj + s.insert(name, obj) if obj.Parent() == nil { obj.setParent(s) } return nil } +// InsertLazy is like Insert, but allows deferring construction of the +// inserted object until it's accessed with Lookup. The Object +// returned by resolve must have the same name as given to InsertLazy. +// If s already contains an alternative object with the same name, +// InsertLazy leaves s unchanged and returns false. Otherwise it +// records the binding and returns true. The object's parent scope +// will be set to s after resolve is called. +func (s *Scope) InsertLazy(name string, resolve func() Object) bool { + if s.elems[name] != nil { + return false + } + s.insert(name, &lazyObject{parent: s, resolve: resolve}) + return true +} + +func (s *Scope) insert(name string, obj Object) { + if s.elems == nil { + s.elems = make(map[string]Object) + } + s.elems[name] = obj +} + // Squash merges s with its parent scope p by adding all // objects of s to p, adding all children of s to the // children of p, and removing s from p's children. @@ -117,7 +137,8 @@ func (s *Scope) Insert(obj Object) Object { func (s *Scope) Squash(err func(obj, alt Object)) { p := s.parent assert(p != nil) - for _, obj := range s.elems { + for name, obj := range s.elems { + obj = resolve(name, obj) obj.setParent(nil) if alt := p.Insert(obj); alt != nil { err(obj, alt) @@ -196,7 +217,7 @@ func (s *Scope) WriteTo(w io.Writer, n int, recurse bool) { indn1 := indn + ind for _, name := range s.Names() { - fmt.Fprintf(w, "%s%s\n", indn1, s.elems[name]) + fmt.Fprintf(w, "%s%s\n", indn1, s.Lookup(name)) } if recurse { @@ -214,3 +235,57 @@ func (s *Scope) String() string { s.WriteTo(&buf, 0, false) return buf.String() } + +// A lazyObject represents an imported Object that has not been fully +// resolved yet by its importer. +type lazyObject struct { + parent *Scope + resolve func() Object + obj Object + once sync.Once +} + +// resolve returns the Object represented by obj, resolving lazy +// objects as appropriate. +func resolve(name string, obj Object) Object { + if lazy, ok := obj.(*lazyObject); ok { + lazy.once.Do(func() { + obj := lazy.resolve() + + if _, ok := obj.(*lazyObject); ok { + panic("recursive lazy object") + } + if obj.Name() != name { + panic("lazy object has unexpected name") + } + + if obj.Parent() == nil { + obj.setParent(lazy.parent) + } + lazy.obj = obj + }) + + obj = lazy.obj + } + return obj +} + +// stub implementations so *lazyObject implements Object and we can +// store them directly into Scope.elems. +func (*lazyObject) Parent() *Scope { panic("unreachable") } +func (*lazyObject) Pos() syntax.Pos { panic("unreachable") } +func (*lazyObject) Pkg() *Package { panic("unreachable") } +func (*lazyObject) Name() string { panic("unreachable") } +func (*lazyObject) Type() Type { panic("unreachable") } +func (*lazyObject) Exported() bool { panic("unreachable") } +func (*lazyObject) Id() string { panic("unreachable") } +func (*lazyObject) String() string { panic("unreachable") } +func (*lazyObject) order() uint32 { panic("unreachable") } +func (*lazyObject) color() color { panic("unreachable") } +func (*lazyObject) setType(Type) { panic("unreachable") } +func (*lazyObject) setOrder(uint32) { panic("unreachable") } +func (*lazyObject) setColor(color color) { panic("unreachable") } +func (*lazyObject) setParent(*Scope) { panic("unreachable") } +func (*lazyObject) sameId(pkg *Package, name string) bool { panic("unreachable") } +func (*lazyObject) scopePos() syntax.Pos { panic("unreachable") } +func (*lazyObject) setScopePos(pos syntax.Pos) { panic("unreachable") } diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go index c8c4cca0a78..a7edc5ac03d 100644 --- a/src/cmd/compile/internal/types2/signature.go +++ b/src/cmd/compile/internal/types2/signature.go @@ -62,7 +62,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams [] // again when we type-check the signature. // TODO(gri) maybe the receiver should be marked as invalid instead? if recv := asNamed(check.genericType(rname, false)); recv != nil { - recvTParams = recv.tparams + recvTParams = recv.TParams() } } // provide type parameter bounds diff --git a/src/cmd/compile/internal/types2/sizeof_test.go b/src/cmd/compile/internal/types2/sizeof_test.go index daa039bf92a..3cb162764c8 100644 --- a/src/cmd/compile/internal/types2/sizeof_test.go +++ b/src/cmd/compile/internal/types2/sizeof_test.go @@ -31,7 +31,7 @@ func TestSizeof(t *testing.T) { {Interface{}, 52, 104}, {Map{}, 16, 32}, {Chan{}, 12, 24}, - {Named{}, 68, 136}, + {Named{}, 84, 160}, {TypeParam{}, 28, 48}, {instance{}, 52, 96}, {top{}, 0, 0}, diff --git a/src/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go index e9ffd4f5ca9..ab664321264 100644 --- a/src/cmd/compile/internal/types2/stmt.go +++ b/src/cmd/compile/internal/types2/stmt.go @@ -64,7 +64,8 @@ func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body func (check *Checker) usage(scope *Scope) { var unused []*Var - for _, elem := range scope.elems { + for name, elem := range scope.elems { + elem = resolve(name, elem) if v, _ := elem.(*Var); v != nil && !v.used { unused = append(unused, v) } diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index 35ca197d64c..dd8dd74161e 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -76,7 +76,7 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, poslis var tparams []*TypeName switch t := typ.(type) { case *Named: - tparams = t.tparams + tparams = t.TParams() case *Signature: tparams = t.tparams defer func() { @@ -347,7 +347,7 @@ func (subst *subster) typ(typ Type) Type { } } - if t.tparams == nil { + if t.TParams() == nil { dump(">>> %s is not parameterized", t) return t // type is not parameterized } @@ -357,7 +357,7 @@ func (subst *subster) typ(typ Type) Type { if len(t.targs) > 0 { // already instantiated dump(">>> %s already instantiated", t) - assert(len(t.targs) == len(t.tparams)) + assert(len(t.targs) == len(t.TParams())) // For each (existing) type argument targ, determine if it needs // to be substituted; i.e., if it is or contains a type parameter // that has a type argument for it. @@ -367,7 +367,7 @@ func (subst *subster) typ(typ Type) Type { if new_targ != targ { dump(">>> substituted %d targ %s => %s", i, targ, new_targ) if new_targs == nil { - new_targs = make([]Type, len(t.tparams)) + new_targs = make([]Type, len(t.TParams())) copy(new_targs, t.targs) } new_targs[i] = new_targ @@ -397,7 +397,7 @@ func (subst *subster) typ(typ Type) Type { // create a new named type and populate caches to avoid endless recursion tname := NewTypeName(subst.pos, t.obj.pkg, t.obj.name, nil) - named := subst.check.newNamed(tname, t, t.underlying, t.tparams, t.methods) // method signatures are updated lazily + named := subst.check.newNamed(tname, t, t.Underlying(), t.TParams(), t.methods) // method signatures are updated lazily named.targs = new_targs if subst.check != nil { subst.check.typMap[h] = named @@ -406,7 +406,7 @@ func (subst *subster) typ(typ Type) Type { // do the substitution dump(">>> subst %s with %s (new: %s)", t.underlying, subst.smap, new_targs) - named.underlying = subst.typOrNil(t.underlying) + named.underlying = subst.typOrNil(t.Underlying()) named.fromRHS = named.underlying // for cycle detection (Checker.validType) return named diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index 92f35f1279c..604520d27f8 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -6,6 +6,7 @@ package types2 import ( "cmd/compile/internal/syntax" + "sync" "sync/atomic" ) @@ -497,6 +498,9 @@ type Named struct { tparams []*TypeName // type parameters, or nil targs []Type // type arguments (after instantiation), or nil methods []*Func // methods declared for this type (not the method set of this type); signatures are type-checked lazily + + resolve func(*Named) ([]*TypeName, Type, []*Func) + once sync.Once } // NewNamed returns a new named type for the given type name, underlying type, and associated methods. @@ -509,6 +513,35 @@ func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named { return (*Checker)(nil).newNamed(obj, nil, underlying, nil, methods) } +func (t *Named) expand() *Named { + if t.resolve == nil { + return t + } + + t.once.Do(func() { + // TODO(mdempsky): Since we're passing t to resolve anyway + // (necessary because types2 expects the receiver type for methods + // on defined interface types to be the Named rather than the + // underlying Interface), maybe it should just handle calling + // SetTParams, SetUnderlying, and AddMethod instead? Those + // methods would need to support reentrant calls though. It would + // also make the API more future-proof towards further extensions + // (like SetTParams). + + tparams, underlying, methods := t.resolve(t) + + switch underlying.(type) { + case nil, *Named: + panic("invalid underlying type") + } + + t.tparams = tparams + t.underlying = underlying + t.methods = methods + }) + return t +} + // newNamed is like NewNamed but with a *Checker receiver and additional orig argument. func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams []*TypeName, methods []*Func) *Named { typ := &Named{check: check, obj: obj, orig: orig, fromRHS: underlying, underlying: underlying, tparams: tparams, methods: methods} @@ -550,10 +583,10 @@ func (t *Named) Orig() *Named { return t.orig } // TParams returns the type parameters of the named type t, or nil. // The result is non-nil for an (originally) parameterized type even if it is instantiated. -func (t *Named) TParams() []*TypeName { return t.tparams } +func (t *Named) TParams() []*TypeName { return t.expand().tparams } // SetTParams sets the type parameters of the named type t. -func (t *Named) SetTParams(tparams []*TypeName) { t.tparams = tparams } +func (t *Named) SetTParams(tparams []*TypeName) { t.expand().tparams = tparams } // TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated. func (t *Named) TArgs() []Type { return t.targs } @@ -562,10 +595,10 @@ func (t *Named) TArgs() []Type { return t.targs } func (t *Named) SetTArgs(args []Type) { t.targs = args } // NumMethods returns the number of explicit methods whose receiver is named type t. -func (t *Named) NumMethods() int { return len(t.methods) } +func (t *Named) NumMethods() int { return len(t.expand().methods) } // Method returns the i'th method of named type t for 0 <= i < t.NumMethods(). -func (t *Named) Method(i int) *Func { return t.methods[i] } +func (t *Named) Method(i int) *Func { return t.expand().methods[i] } // SetUnderlying sets the underlying type and marks t as complete. func (t *Named) SetUnderlying(underlying Type) { @@ -575,11 +608,12 @@ func (t *Named) SetUnderlying(underlying Type) { if _, ok := underlying.(*Named); ok { panic("types2.Named.SetUnderlying: underlying type must not be *Named") } - t.underlying = underlying + t.expand().underlying = underlying } // AddMethod adds method m unless it is already in the method list. func (t *Named) AddMethod(m *Func) { + t.expand() if i, _ := lookupMethod(t.methods, m.pkg, m.name); i < 0 { t.methods = append(t.methods, m) } @@ -743,7 +777,7 @@ func (t *Signature) Underlying() Type { return t } func (t *Interface) Underlying() Type { return t } func (t *Map) Underlying() Type { return t } func (t *Chan) Underlying() Type { return t } -func (t *Named) Underlying() Type { return t.underlying } +func (t *Named) Underlying() Type { return t.expand().underlying } func (t *TypeParam) Underlying() Type { return t } func (t *instance) Underlying() Type { return t } func (t *top) Underlying() Type { return t } diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go index 28583b62d9a..07ed510d118 100644 --- a/src/cmd/compile/internal/types2/typestring.go +++ b/src/cmd/compile/internal/types2/typestring.go @@ -272,9 +272,9 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { buf.WriteByte('[') writeTypeList(buf, t.targs, qf, visited) buf.WriteByte(']') - } else if t.tparams != nil { + } else if t.TParams() != nil { // parameterized type - writeTParamList(buf, t.tparams, qf, visited) + writeTParamList(buf, t.TParams(), qf, visited) } case *TypeParam: diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index b27b2a00df0..583bb464b20 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -58,7 +58,7 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *Named, wantType boo // If so, mark the respective package as used. // (This code is only needed for dot-imports. Without them, // we only have to mark variables, see *Var case below). - if pkgName := check.dotImportMap[dotImportKey{scope, obj}]; pkgName != nil { + if pkgName := check.dotImportMap[dotImportKey{scope, obj.Name()}]; pkgName != nil { pkgName.used = true } From 021444007590da4c1f6e504904e2871a1012c0bf Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Thu, 13 May 2021 13:19:14 +0200 Subject: [PATCH 281/940] syscall: do not pass console handles to PROC_THREAD_ATTRIBUTE_HANDLE_LIST on Windows 7 On Windows 7 (and below), console handles are not real kernel handles but are rather userspace objects, with information passed via special bits in the handle itself. That means they can't be passed in PROC_THREAD_ATTRIBUTE_HANDLE_LIST, even though they can be inherited. So, we filter the list passed to PROC_THREAD_ATTRIBUTE_HANDLE_LIST to not have any console handles on Windows 7. At the same time, it turns out that the presence of a NULL handle in the list is enough to render PROC_THREAD_ATTRIBUTE_HANDLE_LIST completely useless, so filter these out too. Console handles also can't be duplicated into parent processes, as inhertance always happens from the present process, so duplicate always into the present process even when a parent process is specified. Fixes #45914. Change-Id: I70b4ff4874dbf0507d9ec9278f63b9b4dd4f1999 Reviewed-on: https://go-review.googlesource.com/c/go/+/319310 Trust: Jason A. Donenfeld Trust: Alex Brainman Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Alex Brainman --- src/syscall/exec_windows.go | 54 ++++++++++++++++++++++++++++----- src/syscall/syscall_windows.go | 1 + src/syscall/zsyscall_windows.go | 7 +++++ 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go index 253e9e8c1f9..18d15028c3d 100644 --- a/src/syscall/exec_windows.go +++ b/src/syscall/exec_windows.go @@ -313,6 +313,17 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle } } + var maj, min, build uint32 + rtlGetNtVersionNumbers(&maj, &min, &build) + isWin7 := maj < 6 || (maj == 6 && min <= 1) + // NT kernel handles are divisible by 4, with the bottom 3 bits left as + // a tag. The fully set tag correlates with the types of handles we're + // concerned about here. Except, the kernel will interpret some + // special handle values, like -1, -2, and so forth, so kernelbase.dll + // checks to see that those bottom three bits are checked, but that top + // bit is not checked. + isLegacyWin7ConsoleHandle := func(handle Handle) bool { return isWin7 && handle&0x10000003 == 3 } + p, _ := GetCurrentProcess() parentProcess := p if sys.ParentProcess != 0 { @@ -321,7 +332,15 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle fd := make([]Handle, len(attr.Files)) for i := range attr.Files { if attr.Files[i] > 0 { - err := DuplicateHandle(p, Handle(attr.Files[i]), parentProcess, &fd[i], 0, true, DUPLICATE_SAME_ACCESS) + destinationProcessHandle := parentProcess + + // On Windows 7, console handles aren't real handles, and can only be duplicated + // into the current process, not a parent one, which amounts to the same thing. + if parentProcess != p && isLegacyWin7ConsoleHandle(Handle(attr.Files[i])) { + destinationProcessHandle = p + } + + err := DuplicateHandle(p, Handle(attr.Files[i]), destinationProcessHandle, &fd[i], 0, true, DUPLICATE_SAME_ACCESS) if err != nil { return 0, 0, err } @@ -351,19 +370,40 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle si.StdErr = fd[2] fd = append(fd, sys.AdditionalInheritedHandles...) + + // On Windows 7, console handles aren't real handles, so don't pass them + // through to PROC_THREAD_ATTRIBUTE_HANDLE_LIST. + for i := range fd { + if isLegacyWin7ConsoleHandle(fd[i]) { + fd[i] = 0 + } + } + + // The presence of a NULL handle in the list is enough to cause PROC_THREAD_ATTRIBUTE_HANDLE_LIST + // to treat the entire list as empty, so remove NULL handles. + j := 0 + for i := range fd { + if fd[i] != 0 { + fd[j] = fd[i] + j++ + } + } + fd = fd[:j] + // Do not accidentally inherit more than these handles. - err = updateProcThreadAttribute(si.ProcThreadAttributeList, 0, _PROC_THREAD_ATTRIBUTE_HANDLE_LIST, unsafe.Pointer(&fd[0]), uintptr(len(fd))*unsafe.Sizeof(fd[0]), nil, nil) - if err != nil { - return 0, 0, err + if len(fd) > 0 { + err = updateProcThreadAttribute(si.ProcThreadAttributeList, 0, _PROC_THREAD_ATTRIBUTE_HANDLE_LIST, unsafe.Pointer(&fd[0]), uintptr(len(fd))*unsafe.Sizeof(fd[0]), nil, nil) + if err != nil { + return 0, 0, err + } } pi := new(ProcessInformation) - flags := sys.CreationFlags | CREATE_UNICODE_ENVIRONMENT | _EXTENDED_STARTUPINFO_PRESENT if sys.Token != 0 { - err = CreateProcessAsUser(sys.Token, argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, !sys.NoInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi) + err = CreateProcessAsUser(sys.Token, argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, len(fd) > 0 && !sys.NoInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi) } else { - err = CreateProcess(argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, !sys.NoInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi) + err = CreateProcess(argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, len(fd) > 0 && !sys.NoInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi) } if err != nil { return 0, 0, err diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go index fc734effbbe..660179ae9e8 100644 --- a/src/syscall/syscall_windows.go +++ b/src/syscall/syscall_windows.go @@ -198,6 +198,7 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys FreeLibrary(handle Handle) (err error) //sys GetProcAddress(module Handle, procname string) (proc uintptr, err error) //sys GetVersion() (ver uint32, err error) +//sys rtlGetNtVersionNumbers(majorVersion *uint32, minorVersion *uint32, buildNumber *uint32) = ntdll.RtlGetNtVersionNumbers //sys formatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW //sys ExitProcess(exitcode uint32) //sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW diff --git a/src/syscall/zsyscall_windows.go b/src/syscall/zsyscall_windows.go index 10d0f54e8c7..b9e429693d7 100644 --- a/src/syscall/zsyscall_windows.go +++ b/src/syscall/zsyscall_windows.go @@ -41,6 +41,7 @@ var ( moddnsapi = NewLazyDLL(sysdll.Add("dnsapi.dll")) modiphlpapi = NewLazyDLL(sysdll.Add("iphlpapi.dll")) modkernel32 = NewLazyDLL(sysdll.Add("kernel32.dll")) + modntdll = NewLazyDLL(sysdll.Add("ntdll.dll")) modmswsock = NewLazyDLL(sysdll.Add("mswsock.dll")) modnetapi32 = NewLazyDLL(sysdll.Add("netapi32.dll")) modsecur32 = NewLazyDLL(sysdll.Add("secur32.dll")) @@ -167,6 +168,7 @@ var ( procNetApiBufferFree = modnetapi32.NewProc("NetApiBufferFree") procNetGetJoinInformation = modnetapi32.NewProc("NetGetJoinInformation") procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo") + procRtlGetNtVersionNumbers = modntdll.NewProc("RtlGetNtVersionNumbers") procGetUserNameExW = modsecur32.NewProc("GetUserNameExW") procTranslateNameW = modsecur32.NewProc("TranslateNameW") procCommandLineToArgvW = modshell32.NewProc("CommandLineToArgvW") @@ -1213,6 +1215,11 @@ func NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **by return } +func rtlGetNtVersionNumbers(majorVersion *uint32, minorVersion *uint32, buildNumber *uint32) { + Syscall(procRtlGetNtVersionNumbers.Addr(), 3, uintptr(unsafe.Pointer(majorVersion)), uintptr(unsafe.Pointer(minorVersion)), uintptr(unsafe.Pointer(buildNumber))) + return +} + func GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) { r1, _, e1 := Syscall(procGetUserNameExW.Addr(), 3, uintptr(nameFormat), uintptr(unsafe.Pointer(nameBuffre)), uintptr(unsafe.Pointer(nSize))) if r1&0xff == 0 { From 298149a915dd9b2ce74593f5f75584f8ed6d6414 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 6 May 2021 09:08:32 -0400 Subject: [PATCH 282/940] [dev.typeparams] go/types: use Checker-provided type parameter IDs when possible Incrementing type parameter subscripts for each type checking pass is distracting for an interactive program where packages are type-checked on each keystroke. We should perhaps hide the type parameter ID altogether, but for now at least add a layer of indirection so that type parameters for a single type-checked package can be stabilized. This change should have no effect on non-generic type checking. For #46003 Change-Id: I60d747e0a2bfb68e7d64e897eac23f609a2a4429 Reviewed-on: https://go-review.googlesource.com/c/go/+/321269 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/api_test.go | 1 - src/go/types/api_typeparams.go | 5 +++++ src/go/types/check.go | 1 + src/go/types/type.go | 17 ++++++++++++----- src/go/types/types_test.go | 8 -------- 5 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go index f37b91d5a4e..5a2d4a4ca38 100644 --- a/src/go/types/api_test.go +++ b/src/go/types/api_test.go @@ -353,7 +353,6 @@ func TestTypesInfo(t *testing.T) { } for _, test := range tests { - ResetId() // avoid renumbering of type parameter ids when adding tests if strings.HasPrefix(test.src, genericPkg) && !typeparams.Enabled { continue } diff --git a/src/go/types/api_typeparams.go b/src/go/types/api_typeparams.go index ed744c4dba6..ae2c5a7fd09 100644 --- a/src/go/types/api_typeparams.go +++ b/src/go/types/api_typeparams.go @@ -19,6 +19,11 @@ type ( func NewSum(types []Type) Type { return _NewSum(types) } +// NewTypeParam returns a new TypeParam. +func NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam { + return (*Checker)(nil).newTypeParam(obj, index, bound) +} + func (s *Signature) TParams() []*TypeName { return s._TParams() } func (s *Signature) SetTParams(tparams []*TypeName) { s._SetTParams(tparams) } diff --git a/src/go/types/check.go b/src/go/types/check.go index a923c3c6121..e82056e7225 100644 --- a/src/go/types/check.go +++ b/src/go/types/check.go @@ -86,6 +86,7 @@ type Checker struct { pkg *Package *Info version version // accepted language version + nextID uint64 // unique Id for type parameters (first valid Id is 1) objMap map[Object]*declInfo // maps package-level objects and (non-interface) methods to declaration info impMap map[importKey]*Package // maps (import path, source directory) to (complete or fake) package posMap map[*Interface][]token.Pos // maps interface types to lists of embedded interface positions diff --git a/src/go/types/type.go b/src/go/types/type.go index 2660ce4408c..2ea4d76d8b4 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -732,11 +732,11 @@ func (t *Named) AddMethod(m *Func) { // Note: This is a uint32 rather than a uint64 because the // respective 64 bit atomic instructions are not available // on all platforms. -var lastId uint32 +var lastID uint32 -// nextId returns a value increasing monotonically by 1 with +// nextID returns a value increasing monotonically by 1 with // each call, starting with 1. It may be called concurrently. -func nextId() uint64 { return uint64(atomic.AddUint32(&lastId, 1)) } +func nextID() uint64 { return uint64(atomic.AddUint32(&lastID, 1)) } // A _TypeParam represents a type parameter type. type _TypeParam struct { @@ -747,10 +747,17 @@ type _TypeParam struct { bound Type // *Named or *Interface; underlying type is always *Interface } -// newTypeParam returns a new TypeParam. func (check *Checker) newTypeParam(obj *TypeName, index int, bound Type) *_TypeParam { assert(bound != nil) - typ := &_TypeParam{check: check, id: nextId(), obj: obj, index: index, bound: bound} + + // Always increment lastID, even if it is not used. + id := nextID() + if check != nil { + check.nextID++ + id = check.nextID + } + + typ := &_TypeParam{check: check, id: id, obj: obj, index: index, bound: bound} if obj.typ == nil { obj.typ = typ } diff --git a/src/go/types/types_test.go b/src/go/types/types_test.go index 25cd9966282..e1a40f1f6e1 100644 --- a/src/go/types/types_test.go +++ b/src/go/types/types_test.go @@ -4,14 +4,6 @@ package types -import "sync/atomic" - -// Upon calling ResetId, nextId starts with 1 again. -// It may be called concurrently. This is only needed -// for tests where we may want to have a consistent -// numbering for each individual test case. -func ResetId() { atomic.StoreUint32(&lastId, 0) } - // SetGoVersion sets the unexported goVersion field on config, so that tests // which assert on behavior for older Go versions can set it. func SetGoVersion(config *Config, goVersion string) { From 410fa4c75b7487cc92f48e4b4ca037830348b963 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Wed, 19 May 2021 15:51:45 -0400 Subject: [PATCH 283/940] [dev.typeparams] go/types: rename Inferred.Targs to TArgs This is consistent with Named.TArgs. Change-Id: Ib25f7ac5b7242e169c8c1701dfa407f763f26125 Reviewed-on: https://go-review.googlesource.com/c/go/+/321289 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/api.go | 2 +- src/go/types/api_typeparams_test.go | 2 +- src/go/types/sanitize.go | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/go/types/api.go b/src/go/types/api.go index 8c0d9d22bf2..30f8ded744a 100644 --- a/src/go/types/api.go +++ b/src/go/types/api.go @@ -255,7 +255,7 @@ func (tv TypeAndValue) HasOk() bool { // _Inferred reports the _Inferred type arguments and signature // for a parameterized function call that uses type inference. type _Inferred struct { - Targs []Type + TArgs []Type Sig *Signature } diff --git a/src/go/types/api_typeparams_test.go b/src/go/types/api_typeparams_test.go index 15c9bf09f9d..517c58505b5 100644 --- a/src/go/types/api_typeparams_test.go +++ b/src/go/types/api_typeparams_test.go @@ -109,7 +109,7 @@ func TestInferredInfo(t *testing.T) { panic(fmt.Sprintf("unexpected call expression type %T", call)) } if ExprString(fun) == test.fun { - targs = inf.Targs + targs = inf.TArgs sig = inf.Sig break } diff --git a/src/go/types/sanitize.go b/src/go/types/sanitize.go index 727ec173eac..f167cdd8b63 100644 --- a/src/go/types/sanitize.go +++ b/src/go/types/sanitize.go @@ -27,9 +27,9 @@ func sanitizeInfo(info *Info) { inferred := getInferred(info) for e, inf := range inferred { changed := false - for i, targ := range inf.Targs { + for i, targ := range inf.TArgs { if typ := s.typ(targ); typ != targ { - inf.Targs[i] = typ + inf.TArgs[i] = typ changed = true } } From d7592ab4242484110ac8af636f9152faeb3197d6 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 3 Jun 2021 09:29:35 -0400 Subject: [PATCH 284/940] [dev.typeparams] go/types: implement types.Instantiate This is a straightforward port of CL 314773 to go/types. Change-Id: If9e2d6d99790d694615389acbe6ccb3c8c0bd1da Reviewed-on: https://go-review.googlesource.com/c/go/+/324729 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/instantiate.go | 63 +++++++++++++++++++++++++++++++++++++ src/go/types/subst.go | 31 +++++++++++------- 2 files changed, 83 insertions(+), 11 deletions(-) create mode 100644 src/go/types/instantiate.go diff --git a/src/go/types/instantiate.go b/src/go/types/instantiate.go new file mode 100644 index 00000000000..6f8c4983f4a --- /dev/null +++ b/src/go/types/instantiate.go @@ -0,0 +1,63 @@ +// Copyright 2021 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 types + +import ( + "fmt" + "go/token" +) + +// Instantiate instantiates the type typ with the given type arguments. +// typ must be a *Named or a *Signature type, it must be generic, and +// its number of type parameters must match the number of provided type +// arguments. The result is a new, instantiated (not generic) type of +// the same kind (either a *Named or a *Signature). The type arguments +// are not checked against the constraints of the type parameters. +// Any methods attached to a *Named are simply copied; they are not +// instantiated. +func Instantiate(pos token.Pos, typ Type, targs []Type) (res Type) { + // TODO(gri) This code is basically identical to the prolog + // in Checker.instantiate. Factor. + var tparams []*TypeName + switch t := typ.(type) { + case *Named: + tparams = t.tparams + case *Signature: + tparams = t.tparams + defer func() { + // If we had an unexpected failure somewhere don't panic below when + // asserting res.(*Signature). Check for *Signature in case Typ[Invalid] + // is returned. + if _, ok := res.(*Signature); !ok { + return + } + // If the signature doesn't use its type parameters, subst + // will not make a copy. In that case, make a copy now (so + // we can set tparams to nil w/o causing side-effects). + if t == res { + copy := *t + res = © + } + // After instantiating a generic signature, it is not generic + // anymore; we need to set tparams to nil. + res.(*Signature).tparams = nil + }() + + default: + panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) + } + + // the number of supplied types must match the number of type parameters + if len(targs) != len(tparams) { + panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, len(targs), len(tparams))) + } + + if len(tparams) == 0 { + return typ // nothing to do (minor optimization) + } + + smap := makeSubstMap(tparams, targs) + return (*Checker)(nil).subst(pos, typ, smap) +} diff --git a/src/go/types/subst.go b/src/go/types/subst.go index 931375f1f2b..d27f3645cc3 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -311,6 +311,9 @@ func (subst *subster) typ(typ Type) Type { embeddeds, ecopied := subst.typeList(t.embeddeds) if mcopied || types != t.types || ecopied { iface := &Interface{methods: methods, types: types, embeddeds: embeddeds} + if subst.check == nil { + panic("internal error: cannot instantiate interfaces yet") + } subst.check.posMap[iface] = subst.check.posMap[t] // satisfy completeInterface requirement subst.check.completeInterface(token.NoPos, iface) return iface @@ -330,12 +333,14 @@ func (subst *subster) typ(typ Type) Type { } case *Named: - subst.check.indent++ - defer func() { - subst.check.indent-- - }() - dump := func(format string, args ...interface{}) { - if trace { + // dump is for debugging + dump := func(string, ...interface{}) {} + if subst.check != nil && trace { + subst.check.indent++ + defer func() { + subst.check.indent-- + }() + dump = func(format string, args ...interface{}) { subst.check.trace(subst.pos, format, args...) } } @@ -381,10 +386,12 @@ func (subst *subster) typ(typ Type) Type { // before creating a new named type, check if we have this one already h := instantiatedHash(t, newTargs) dump(">>> new type hash: %s", h) - if named, found := subst.check.typMap[h]; found { - dump(">>> found %s", named) - subst.cache[t] = named - return named + if subst.check != nil { + if named, found := subst.check.typMap[h]; found { + dump(">>> found %s", named) + subst.cache[t] = named + return named + } } // create a new named type and populate caches to avoid endless recursion @@ -392,7 +399,9 @@ func (subst *subster) typ(typ Type) Type { named := subst.check.newNamed(tname, t.underlying, t.methods) // method signatures are updated lazily named.tparams = t.tparams // new type is still parameterized named.targs = newTargs - subst.check.typMap[h] = named + if subst.check != nil { + subst.check.typMap[h] = named + } subst.cache[t] = named // do the substitution From 655246f99a22950985a9ab9fc1e0bb4a8cb2ea7e Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 3 Jun 2021 09:45:01 -0400 Subject: [PATCH 285/940] [dev.typeparams] go/types: make TestManual work for directories This is a port of CL 315769 to go/types, adjusted for the additional testPkg indirection in go/types on top of testFiles, and to remove the colDelta argument. Change-Id: Ieb722d77866313a01645aeec49912c16cb475462 Reviewed-on: https://go-review.googlesource.com/c/go/+/324730 Trust: Robert Findley Trust: Robert Griesemer Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/check_test.go | 98 +++++++++++++++++++---------- src/go/types/testdata/check/tmp.go2 | 17 ----- src/go/types/testdata/manual.go2 | 9 +++ 3 files changed, 73 insertions(+), 51 deletions(-) delete mode 100644 src/go/types/testdata/check/tmp.go2 create mode 100644 src/go/types/testdata/manual.go2 diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go index 6c3b630a1b6..0926ac74319 100644 --- a/src/go/types/check_test.go +++ b/src/go/types/check_test.go @@ -202,7 +202,7 @@ func asGoVersion(s string) string { return "" } -func checkFiles(t *testing.T, sizes Sizes, goVersion string, filenames []string, srcs [][]byte, manual bool) { +func testFiles(t *testing.T, sizes Sizes, filenames []string, srcs [][]byte, manual bool) { if len(filenames) == 0 { t.Fatal("no source files") } @@ -225,6 +225,7 @@ func checkFiles(t *testing.T, sizes Sizes, goVersion string, filenames []string, } // if no Go version is given, consider the package name + goVersion := *goVersion if goVersion == "" { goVersion = asGoVersion(pkgName) } @@ -297,29 +298,48 @@ func checkFiles(t *testing.T, sizes Sizes, goVersion string, filenames []string, } } -// TestManual is for manual testing of input files, provided as a list -// of arguments after the test arguments (and a separating "--"). For -// instance, to check the files foo.go and bar.go, use: +// TestManual is for manual testing of a package - either provided +// as a list of filenames belonging to the package, or a directory +// name containing the package files - after the test arguments +// (and a separating "--"). For instance, to test the package made +// of the files foo.go and bar.go, use: // // go test -run Manual -- foo.go bar.go // -// Provide the -verify flag to verify errors against ERROR comments in -// the input files rather than having a list of errors reported. -// The accepted Go language version can be controlled with the -lang flag. +// If no source arguments are provided, the file testdata/manual.go2 +// is used instead. +// Provide the -verify flag to verify errors against ERROR comments +// in the input files rather than having a list of errors reported. +// The accepted Go language version can be controlled with the -lang +// flag. func TestManual(t *testing.T) { + testenv.MustHaveGoBuild(t) + filenames := flag.Args() if len(filenames) == 0 { - return + filenames = []string{filepath.FromSlash("testdata/manual.go2")} } - testenv.MustHaveGoBuild(t) + + info, err := os.Stat(filenames[0]) + if err != nil { + t.Fatalf("TestManual: %v", err) + } + DefPredeclaredTestFuncs() - testPkg(t, filenames, *goVersion, true) + if info.IsDir() { + if len(filenames) > 1 { + t.Fatal("TestManual: must have only one directory argument") + } + testDir(t, filenames[0], true) + } else { + testPkg(t, filenames, true) + } } func TestLongConstants(t *testing.T) { format := "package longconst\n\nconst _ = %s\nconst _ = %s // ERROR excessively long constant" src := fmt.Sprintf(format, strings.Repeat("1", 9999), strings.Repeat("1", 10001)) - checkFiles(t, nil, "", []string{"longconst.go"}, [][]byte{[]byte(src)}, false) + testFiles(t, nil, []string{"longconst.go"}, [][]byte{[]byte(src)}, false) } // TestIndexRepresentability tests that constant index operands must @@ -327,7 +347,7 @@ func TestLongConstants(t *testing.T) { // represent larger values. func TestIndexRepresentability(t *testing.T) { const src = "package index\n\nvar s []byte\nvar _ = s[int64 /* ERROR \"int64\\(1\\) << 40 \\(.*\\) overflows int\" */ (1) << 40]" - checkFiles(t, &StdSizes{4, 4}, "", []string{"index.go"}, [][]byte{[]byte(src)}, false) + testFiles(t, &StdSizes{4, 4}, []string{"index.go"}, [][]byte{[]byte(src)}, false) } func TestIssue46453(t *testing.T) { @@ -335,17 +355,17 @@ func TestIssue46453(t *testing.T) { t.Skip("type params are enabled") } const src = "package p\ntype _ comparable // ERROR \"undeclared name: comparable\"" - checkFiles(t, nil, "", []string{"issue46453.go"}, [][]byte{[]byte(src)}, false) + testFiles(t, nil, []string{"issue46453.go"}, [][]byte{[]byte(src)}, false) } -func TestCheck(t *testing.T) { DefPredeclaredTestFuncs(); testDir(t, "check") } -func TestExamples(t *testing.T) { testDir(t, "examples") } -func TestFixedbugs(t *testing.T) { testDir(t, "fixedbugs") } +func TestCheck(t *testing.T) { DefPredeclaredTestFuncs(); testDirFiles(t, "testdata/check", false) } +func TestExamples(t *testing.T) { testDirFiles(t, "testdata/examples", false) } +func TestFixedbugs(t *testing.T) { testDirFiles(t, "testdata/fixedbugs", false) } -func testDir(t *testing.T, dir string) { +func testDirFiles(t *testing.T, dir string, manual bool) { testenv.MustHaveGoBuild(t) + dir = filepath.FromSlash(dir) - dir = filepath.Join("testdata", dir) fis, err := os.ReadDir(dir) if err != nil { t.Error(err) @@ -355,28 +375,38 @@ func testDir(t *testing.T, dir string) { for _, fi := range fis { path := filepath.Join(dir, fi.Name()) - // if fi is a directory, its files make up a single package - var filenames []string + // If fi is a directory, its files make up a single package. if fi.IsDir() { - fis, err := os.ReadDir(path) - if err != nil { - t.Error(err) - continue - } - for _, fi := range fis { - filenames = append(filenames, filepath.Join(path, fi.Name())) - } + testDir(t, path, manual) } else { - filenames = []string{path} + t.Run(filepath.Base(path), func(t *testing.T) { + testPkg(t, []string{path}, manual) + }) } - t.Run(filepath.Base(path), func(t *testing.T) { - testPkg(t, filenames, "", false) - }) } } +func testDir(t *testing.T, dir string, manual bool) { + testenv.MustHaveGoBuild(t) + + fis, err := os.ReadDir(dir) + if err != nil { + t.Error(err) + return + } + + var filenames []string + for _, fi := range fis { + filenames = append(filenames, filepath.Join(dir, fi.Name())) + } + + t.Run(filepath.Base(dir), func(t *testing.T) { + testPkg(t, filenames, manual) + }) +} + // TODO(rFindley) reconcile the different test setup in go/types with types2. -func testPkg(t *testing.T, filenames []string, goVersion string, manual bool) { +func testPkg(t *testing.T, filenames []string, manual bool) { srcs := make([][]byte, len(filenames)) for i, filename := range filenames { src, err := os.ReadFile(filename) @@ -385,5 +415,5 @@ func testPkg(t *testing.T, filenames []string, goVersion string, manual bool) { } srcs[i] = src } - checkFiles(t, nil, goVersion, filenames, srcs, manual) + testFiles(t, nil, filenames, srcs, manual) } diff --git a/src/go/types/testdata/check/tmp.go2 b/src/go/types/testdata/check/tmp.go2 deleted file mode 100644 index dae78caff81..00000000000 --- a/src/go/types/testdata/check/tmp.go2 +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This file is meant as "dumping ground" for debugging code. - -package p - -// fun test case -type C[P interface{m()}] P - -func (r C[P]) m() { r.m() } - -func f[T interface{m(); n()}](x T) { - y := C[T](x) - y.m() -} diff --git a/src/go/types/testdata/manual.go2 b/src/go/types/testdata/manual.go2 new file mode 100644 index 00000000000..25e6f22f94b --- /dev/null +++ b/src/go/types/testdata/manual.go2 @@ -0,0 +1,9 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file is tested when running "go test -run Manual" +// without source arguments. Use for one-off debugging. + +package p + From cd6e9df446680d591c28c08d2cc768ec014cf29d Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 3 Jun 2021 09:49:21 -0400 Subject: [PATCH 286/940] [dev.typeparams] go/types: print "incomplete" for interfaces in debug mode only This is a straightforward port of CL 320150 to go/types. Fixes #46167 Change-Id: Id1845046f598ac4fefd68cda6a5a03b7a5fc5a4a Reviewed-on: https://go-review.googlesource.com/c/go/+/324731 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/types_test.go | 3 +++ src/go/types/typestring.go | 2 +- src/go/types/typestring_test.go | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/go/types/types_test.go b/src/go/types/types_test.go index e1a40f1f6e1..7990414f424 100644 --- a/src/go/types/types_test.go +++ b/src/go/types/types_test.go @@ -9,3 +9,6 @@ package types func SetGoVersion(config *Config, goVersion string) { config.goVersion = goVersion } + +// Debug is set if go/types is built with debug mode enabled. +const Debug = debug diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go index fe27f0f276c..ff93f3b3c31 100644 --- a/src/go/types/typestring.go +++ b/src/go/types/typestring.go @@ -227,7 +227,7 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { empty = false } } - if t.allMethods == nil || len(t.methods) > len(t.allMethods) { + if debug && (t.allMethods == nil || len(t.methods) > len(t.allMethods)) { if !empty { buf.WriteByte(' ') } diff --git a/src/go/types/typestring_test.go b/src/go/types/typestring_test.go index b16529dc641..55ee4b987f7 100644 --- a/src/go/types/typestring_test.go +++ b/src/go/types/typestring_test.go @@ -143,6 +143,10 @@ func TestTypeString(t *testing.T) { } func TestIncompleteInterfaces(t *testing.T) { + if !Debug { + t.Skip("requires type checker to be compiled with debug = true") + } + sig := NewSignature(nil, nil, nil, false) m := NewFunc(token.NoPos, nil, "m", sig) for _, test := range []struct { From e32fab145b488cf8bd1fb4a2466cb9be33ac3770 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 3 Jun 2021 09:52:05 -0400 Subject: [PATCH 287/940] [dev.typeparams] go/types: fix panic with nil package name This is a straightforward port of CL 320490 to go/types. Change-Id: I763c806c777f926a563d8f9384764e5b3f7f083c Reviewed-on: https://go-review.googlesource.com/c/go/+/324732 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/resolver.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go index 114647a2fff..4892218b754 100644 --- a/src/go/types/resolver.go +++ b/src/go/types/resolver.go @@ -276,7 +276,7 @@ func (check *Checker) collectObjects() { } if name == "init" { - check.errorf(d.spec.Name, _InvalidInitDecl, "cannot import package as init - init must be a func") + check.errorf(d.spec, _InvalidInitDecl, "cannot import package as init - init must be a func") return } From 62c40878e47c71b1e291e9c3064d76c16a6f9d69 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 3 Jun 2021 10:12:37 -0400 Subject: [PATCH 288/940] [dev.typeparams] go/types: better recv Var for method expressions This is a port of CL 320489 to go/types, adjusted to be consistent about named/unnamed parameters. TestEvalPos was failing without this addition. For #46209 Change-Id: Icdf86e84ebce8ccdb7846a63b5605e360e2b8781 Reviewed-on: https://go-review.googlesource.com/c/go/+/324733 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/call.go | 25 +++++++++++++++++++++++-- src/go/types/testdata/check/decls0.src | 8 ++++---- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/go/types/call.go b/src/go/types/call.go index 631ea426c6b..3a04121e984 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -575,17 +575,38 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) { check.recordSelection(e, MethodExpr, x.typ, m, index, indirect) + sig := m.typ.(*Signature) + if sig.recv == nil { + check.error(e, _InvalidDeclCycle, "illegal cycle in method declaration") + goto Error + } + // the receiver type becomes the type of the first function // argument of the method expression's function type var params []*Var - sig := m.typ.(*Signature) if sig.params != nil { params = sig.params.vars } + // Be consistent about named/unnamed parameters. + needName := true + for _, param := range params { + if param.Name() == "" { + needName = false + break + } + } + name := "" + if needName { + name = sig.recv.name + if name == "" { + name = "_" + } + } + params = append([]*Var{NewVar(sig.recv.pos, sig.recv.pkg, name, x.typ)}, params...) x.mode = value x.typ = &Signature{ tparams: sig.tparams, - params: NewTuple(append([]*Var{NewVar(token.NoPos, check.pkg, "_", x.typ)}, params...)...), + params: NewTuple(params...), results: sig.results, variadic: sig.variadic, } diff --git a/src/go/types/testdata/check/decls0.src b/src/go/types/testdata/check/decls0.src index 5ad8f53f65a..09904bb3030 100644 --- a/src/go/types/testdata/check/decls0.src +++ b/src/go/types/testdata/check/decls0.src @@ -187,10 +187,10 @@ func f4() (x *f4 /* ERROR "not a type" */ ) { return } // TODO(#43215) this should be detected as a cycle error func f5([unsafe.Sizeof(f5)]int) {} -func (S0) m1 (x S0 /* ERROR value .* is not a type */ .m1) {} -func (S0) m2 (x *S0 /* ERROR value .* is not a type */ .m2) {} -func (S0) m3 () (x S0 /* ERROR value .* is not a type */ .m3) { return } -func (S0) m4 () (x *S0 /* ERROR value .* is not a type */ .m4) { return } +func (S0) m1 (x S0 /* ERROR illegal cycle in method declaration */ .m1) {} +func (S0) m2 (x *S0 /* ERROR illegal cycle in method declaration */ .m2) {} +func (S0) m3 () (x S0 /* ERROR illegal cycle in method declaration */ .m3) { return } +func (S0) m4 () (x *S0 /* ERROR illegal cycle in method declaration */ .m4) { return } // interfaces may not have any blank methods type BlankI interface { From 090a17c99847166ac25ce33397e6adf83cc40a1d Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 3 Jun 2021 10:57:09 -0400 Subject: [PATCH 289/940] [dev.typeparams] go/types: use correct type parameter list in missingMethod This is a port of CL 321232 to go/types, adjusted to add a missing comment and to remove optional support for method type params. Fixes #46275 Change-Id: I63fcbb669e7607876a888fca89b9064568805448 Reviewed-on: https://go-review.googlesource.com/c/go/+/324751 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/lookup.go | 9 ++++++- .../types/testdata/fixedbugs/issue46275.go2 | 27 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 src/go/types/testdata/fixedbugs/issue46275.go2 diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go index 9c7bfd4bb97..3e89b6cc2b5 100644 --- a/src/go/types/lookup.go +++ b/src/go/types/lookup.go @@ -327,11 +327,15 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, return m, f } + // both methods must have the same number of type parameters ftyp := f.typ.(*Signature) mtyp := m.typ.(*Signature) if len(ftyp.tparams) != len(mtyp.tparams) { return m, f } + if len(ftyp.tparams) > 0 { + panic("internal error: method with type parameters") + } // If the methods have type parameters we don't care whether they // are the same or not, as long as they match up. Use unification @@ -385,6 +389,9 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, if len(ftyp.tparams) != len(mtyp.tparams) { return m, f } + if len(ftyp.tparams) > 0 { + panic("internal error: method with type parameters") + } // If V is a (instantiated) generic type, its methods are still // parameterized using the original (declaration) receiver type @@ -412,7 +419,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // TODO(gri) is this always correct? what about type bounds? // (Alternative is to rename/subst type parameters and compare.) u := newUnifier(check, true) - u.x.init(ftyp.tparams) + u.x.init(ftyp.rparams) if !u.unify(ftyp, mtyp) { return m, f } diff --git a/src/go/types/testdata/fixedbugs/issue46275.go2 b/src/go/types/testdata/fixedbugs/issue46275.go2 new file mode 100644 index 00000000000..0ebde31c8e9 --- /dev/null +++ b/src/go/types/testdata/fixedbugs/issue46275.go2 @@ -0,0 +1,27 @@ +// Copyright 2021 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 issue46275 + +type N[T any] struct { + *N[T] + t T +} + +func (n *N[T]) Elem() T { + return n.t +} + +type I interface { + Elem() string +} + +func _() { + var n1 *N[string] + var _ I = n1 + type NS N[string] + var n2 *NS + var _ I = n2 +} + From ffc74ad5d3241f3fed48816e25802967cfd6fb07 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 3 Jun 2021 11:04:50 -0400 Subject: [PATCH 290/940] [dev.typeparams] go/types: move interface checking into separate file This is a port of CL 321549 to go/types. Specifically, the same checker methods were moved. Change-Id: I491a8c5a985d71ebb23e4b34541a557da0af0cfc Reviewed-on: https://go-review.googlesource.com/c/go/+/324752 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/interface.go | 321 ++++++++++++++++++++++++++++++++++++++ src/go/types/typexpr.go | 310 ------------------------------------ 2 files changed, 321 insertions(+), 310 deletions(-) create mode 100644 src/go/types/interface.go diff --git a/src/go/types/interface.go b/src/go/types/interface.go new file mode 100644 index 00000000000..288e421cae1 --- /dev/null +++ b/src/go/types/interface.go @@ -0,0 +1,321 @@ +// Copyright 2021 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 types + +import ( + "go/ast" + "go/internal/typeparams" + "go/token" + "sort" +) + +func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, def *Named) { + var tlist *ast.Ident // "type" name of first entry in a type list declaration + var types []ast.Expr + for _, f := range iface.Methods.List { + if len(f.Names) > 0 { + // We have a method with name f.Names[0], or a type + // of a type list (name.Name == "type"). + // (The parser ensures that there's only one method + // and we don't care if a constructed AST has more.) + name := f.Names[0] + if name.Name == "_" { + check.errorf(name, _BlankIfaceMethod, "invalid method name _") + continue // ignore + } + + if name.Name == "type" { + // Always collect all type list entries, even from + // different type lists, under the assumption that + // the author intended to include all types. + types = append(types, f.Type) + if tlist != nil && tlist != name { + check.errorf(name, _Todo, "cannot have multiple type lists in an interface") + } + tlist = name + continue + } + + typ := check.typ(f.Type) + sig, _ := typ.(*Signature) + if sig == nil { + if typ != Typ[Invalid] { + check.invalidAST(f.Type, "%s is not a method signature", typ) + } + continue // ignore + } + + // Always type-check method type parameters but complain if they are not enabled. + // (This extra check is needed here because interface method signatures don't have + // a receiver specification.) + if sig.tparams != nil { + var at positioner = f.Type + if tparams := typeparams.Get(f.Type); tparams != nil { + at = tparams + } + check.errorf(at, _Todo, "methods cannot have type parameters") + } + + // use named receiver type if available (for better error messages) + var recvTyp Type = ityp + if def != nil { + recvTyp = def + } + sig.recv = NewVar(name.Pos(), check.pkg, "", recvTyp) + + m := NewFunc(name.Pos(), check.pkg, name.Name, sig) + check.recordDef(name, m) + ityp.methods = append(ityp.methods, m) + } else { + // We have an embedded type. completeInterface will + // eventually verify that we have an interface. + ityp.embeddeds = append(ityp.embeddeds, check.typ(f.Type)) + check.posMap[ityp] = append(check.posMap[ityp], f.Type.Pos()) + } + } + + // type constraints + ityp.types = _NewSum(check.collectTypeConstraints(iface.Pos(), types)) + + if len(ityp.methods) == 0 && ityp.types == nil && len(ityp.embeddeds) == 0 { + // empty interface + ityp.allMethods = markComplete + return + } + + // sort for API stability + sortMethods(ityp.methods) + sortTypes(ityp.embeddeds) + + check.later(func() { check.completeInterface(iface.Pos(), ityp) }) +} + +func (check *Checker) collectTypeConstraints(pos token.Pos, types []ast.Expr) []Type { + list := make([]Type, 0, len(types)) // assume all types are correct + for _, texpr := range types { + if texpr == nil { + check.invalidAST(atPos(pos), "missing type constraint") + continue + } + list = append(list, check.varType(texpr)) + } + + // Ensure that each type is only present once in the type list. Types may be + // interfaces, which may not be complete yet. It's ok to do this check at the + // end because it's not a requirement for correctness of the code. + // Note: This is a quadratic algorithm, but type lists tend to be short. + check.later(func() { + for i, t := range list { + if t := asInterface(t); t != nil { + check.completeInterface(types[i].Pos(), t) + } + if includes(list[:i], t) { + check.softErrorf(types[i], _Todo, "duplicate type %s in type list", t) + } + } + }) + + return list +} + +// includes reports whether typ is in list. +func includes(list []Type, typ Type) bool { + for _, e := range list { + if Identical(typ, e) { + return true + } + } + return false +} + +func (check *Checker) completeInterface(pos token.Pos, ityp *Interface) { + if ityp.allMethods != nil { + return + } + + // completeInterface may be called via the LookupFieldOrMethod, + // MissingMethod, Identical, or IdenticalIgnoreTags external API + // in which case check will be nil. In this case, type-checking + // must be finished and all interfaces should have been completed. + if check == nil { + panic("internal error: incomplete interface") + } + + if trace { + // Types don't generally have position information. + // If we don't have a valid pos provided, try to use + // one close enough. + if !pos.IsValid() && len(ityp.methods) > 0 { + pos = ityp.methods[0].pos + } + + check.trace(pos, "complete %s", ityp) + check.indent++ + defer func() { + check.indent-- + check.trace(pos, "=> %s (methods = %v, types = %v)", ityp, ityp.allMethods, ityp.allTypes) + }() + } + + // An infinitely expanding interface (due to a cycle) is detected + // elsewhere (Checker.validType), so here we simply assume we only + // have valid interfaces. Mark the interface as complete to avoid + // infinite recursion if the validType check occurs later for some + // reason. + ityp.allMethods = markComplete + + // Methods of embedded interfaces are collected unchanged; i.e., the identity + // of a method I.m's Func Object of an interface I is the same as that of + // the method m in an interface that embeds interface I. On the other hand, + // if a method is embedded via multiple overlapping embedded interfaces, we + // don't provide a guarantee which "original m" got chosen for the embedding + // interface. See also issue #34421. + // + // If we don't care to provide this identity guarantee anymore, instead of + // reusing the original method in embeddings, we can clone the method's Func + // Object and give it the position of a corresponding embedded interface. Then + // we can get rid of the mpos map below and simply use the cloned method's + // position. + + var seen objset + var methods []*Func + mpos := make(map[*Func]token.Pos) // method specification or method embedding position, for good error messages + addMethod := func(pos token.Pos, m *Func, explicit bool) { + switch other := seen.insert(m); { + case other == nil: + methods = append(methods, m) + mpos[m] = pos + case explicit: + check.errorf(atPos(pos), _DuplicateDecl, "duplicate method %s", m.name) + check.errorf(atPos(mpos[other.(*Func)]), _DuplicateDecl, "\tother declaration of %s", m.name) // secondary error, \t indented + default: + // We have a duplicate method name in an embedded (not explicitly declared) method. + // Check method signatures after all types are computed (issue #33656). + // If we're pre-go1.14 (overlapping embeddings are not permitted), report that + // error here as well (even though we could do it eagerly) because it's the same + // error message. + check.later(func() { + if !check.allowVersion(m.pkg, 1, 14) || !check.identical(m.typ, other.Type()) { + check.errorf(atPos(pos), _DuplicateDecl, "duplicate method %s", m.name) + check.errorf(atPos(mpos[other.(*Func)]), _DuplicateDecl, "\tother declaration of %s", m.name) // secondary error, \t indented + } + }) + } + } + + for _, m := range ityp.methods { + addMethod(m.pos, m, true) + } + + // collect types + allTypes := ityp.types + + posList := check.posMap[ityp] + for i, typ := range ityp.embeddeds { + pos := posList[i] // embedding position + utyp := under(typ) + etyp := asInterface(utyp) + if etyp == nil { + if utyp != Typ[Invalid] { + var format string + if _, ok := utyp.(*_TypeParam); ok { + format = "%s is a type parameter, not an interface" + } else { + format = "%s is not an interface" + } + // TODO: correct error code. + check.errorf(atPos(pos), _InvalidIfaceEmbed, format, typ) + } + continue + } + check.completeInterface(pos, etyp) + for _, m := range etyp.allMethods { + addMethod(pos, m, false) // use embedding position pos rather than m.pos + } + allTypes = intersect(allTypes, etyp.allTypes) + } + + if methods != nil { + sort.Sort(byUniqueMethodName(methods)) + ityp.allMethods = methods + } + ityp.allTypes = allTypes +} + +// intersect computes the intersection of the types x and y. +// Note: A incomming nil type stands for the top type. A top +// type result is returned as nil. +func intersect(x, y Type) (r Type) { + defer func() { + if r == theTop { + r = nil + } + }() + + switch { + case x == theBottom || y == theBottom: + return theBottom + case x == nil || x == theTop: + return y + case y == nil || x == theTop: + return x + } + + xtypes := unpackType(x) + ytypes := unpackType(y) + // Compute the list rtypes which includes only + // types that are in both xtypes and ytypes. + // Quadratic algorithm, but good enough for now. + // TODO(gri) fix this + var rtypes []Type + for _, x := range xtypes { + if includes(ytypes, x) { + rtypes = append(rtypes, x) + } + } + + if rtypes == nil { + return theBottom + } + return _NewSum(rtypes) +} + +func sortTypes(list []Type) { + sort.Stable(byUniqueTypeName(list)) +} + +// byUniqueTypeName named type lists can be sorted by their unique type names. +type byUniqueTypeName []Type + +func (a byUniqueTypeName) Len() int { return len(a) } +func (a byUniqueTypeName) Less(i, j int) bool { return sortName(a[i]) < sortName(a[j]) } +func (a byUniqueTypeName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } + +func sortName(t Type) string { + if named := asNamed(t); named != nil { + return named.obj.Id() + } + return "" +} + +func sortMethods(list []*Func) { + sort.Sort(byUniqueMethodName(list)) +} + +func assertSortedMethods(list []*Func) { + if !debug { + panic("internal error: assertSortedMethods called outside debug mode") + } + if !sort.IsSorted(byUniqueMethodName(list)) { + panic("internal error: methods not sorted") + } +} + +// byUniqueMethodName method lists can be sorted by their unique method names. +type byUniqueMethodName []*Func + +func (a byUniqueMethodName) Len() int { return len(a) } +func (a byUniqueMethodName) Less(i, j int) bool { return a[i].Id() < a[j].Id() } +func (a byUniqueMethodName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 5185c33fcbf..b1b4ff9a774 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -12,7 +12,6 @@ import ( "go/constant" "go/internal/typeparams" "go/token" - "sort" "strconv" "strings" ) @@ -758,277 +757,6 @@ func (check *Checker) declareInSet(oset *objset, pos token.Pos, obj Object) bool return true } -func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, def *Named) { - var tlist *ast.Ident // "type" name of first entry in a type list declaration - var types []ast.Expr - for _, f := range iface.Methods.List { - if len(f.Names) > 0 { - // We have a method with name f.Names[0], or a type - // of a type list (name.Name == "type"). - // (The parser ensures that there's only one method - // and we don't care if a constructed AST has more.) - name := f.Names[0] - if name.Name == "_" { - check.errorf(name, _BlankIfaceMethod, "invalid method name _") - continue // ignore - } - - if name.Name == "type" { - // Always collect all type list entries, even from - // different type lists, under the assumption that - // the author intended to include all types. - types = append(types, f.Type) - if tlist != nil && tlist != name { - check.errorf(name, _Todo, "cannot have multiple type lists in an interface") - } - tlist = name - continue - } - - typ := check.typ(f.Type) - sig, _ := typ.(*Signature) - if sig == nil { - if typ != Typ[Invalid] { - check.invalidAST(f.Type, "%s is not a method signature", typ) - } - continue // ignore - } - - // Always type-check method type parameters but complain if they are not enabled. - // (This extra check is needed here because interface method signatures don't have - // a receiver specification.) - if sig.tparams != nil { - var at positioner = f.Type - if tparams := typeparams.Get(f.Type); tparams != nil { - at = tparams - } - check.errorf(at, _Todo, "methods cannot have type parameters") - } - - // use named receiver type if available (for better error messages) - var recvTyp Type = ityp - if def != nil { - recvTyp = def - } - sig.recv = NewVar(name.Pos(), check.pkg, "", recvTyp) - - m := NewFunc(name.Pos(), check.pkg, name.Name, sig) - check.recordDef(name, m) - ityp.methods = append(ityp.methods, m) - } else { - // We have an embedded type. completeInterface will - // eventually verify that we have an interface. - ityp.embeddeds = append(ityp.embeddeds, check.typ(f.Type)) - check.posMap[ityp] = append(check.posMap[ityp], f.Type.Pos()) - } - } - - // type constraints - ityp.types = _NewSum(check.collectTypeConstraints(iface.Pos(), types)) - - if len(ityp.methods) == 0 && ityp.types == nil && len(ityp.embeddeds) == 0 { - // empty interface - ityp.allMethods = markComplete - return - } - - // sort for API stability - sortMethods(ityp.methods) - sortTypes(ityp.embeddeds) - - check.later(func() { check.completeInterface(iface.Pos(), ityp) }) -} - -func (check *Checker) completeInterface(pos token.Pos, ityp *Interface) { - if ityp.allMethods != nil { - return - } - - // completeInterface may be called via the LookupFieldOrMethod, - // MissingMethod, Identical, or IdenticalIgnoreTags external API - // in which case check will be nil. In this case, type-checking - // must be finished and all interfaces should have been completed. - if check == nil { - panic("internal error: incomplete interface") - } - - if trace { - // Types don't generally have position information. - // If we don't have a valid pos provided, try to use - // one close enough. - if !pos.IsValid() && len(ityp.methods) > 0 { - pos = ityp.methods[0].pos - } - - check.trace(pos, "complete %s", ityp) - check.indent++ - defer func() { - check.indent-- - check.trace(pos, "=> %s (methods = %v, types = %v)", ityp, ityp.allMethods, ityp.allTypes) - }() - } - - // An infinitely expanding interface (due to a cycle) is detected - // elsewhere (Checker.validType), so here we simply assume we only - // have valid interfaces. Mark the interface as complete to avoid - // infinite recursion if the validType check occurs later for some - // reason. - ityp.allMethods = markComplete - - // Methods of embedded interfaces are collected unchanged; i.e., the identity - // of a method I.m's Func Object of an interface I is the same as that of - // the method m in an interface that embeds interface I. On the other hand, - // if a method is embedded via multiple overlapping embedded interfaces, we - // don't provide a guarantee which "original m" got chosen for the embedding - // interface. See also issue #34421. - // - // If we don't care to provide this identity guarantee anymore, instead of - // reusing the original method in embeddings, we can clone the method's Func - // Object and give it the position of a corresponding embedded interface. Then - // we can get rid of the mpos map below and simply use the cloned method's - // position. - - var seen objset - var methods []*Func - mpos := make(map[*Func]token.Pos) // method specification or method embedding position, for good error messages - addMethod := func(pos token.Pos, m *Func, explicit bool) { - switch other := seen.insert(m); { - case other == nil: - methods = append(methods, m) - mpos[m] = pos - case explicit: - check.errorf(atPos(pos), _DuplicateDecl, "duplicate method %s", m.name) - check.errorf(atPos(mpos[other.(*Func)]), _DuplicateDecl, "\tother declaration of %s", m.name) // secondary error, \t indented - default: - // We have a duplicate method name in an embedded (not explicitly declared) method. - // Check method signatures after all types are computed (issue #33656). - // If we're pre-go1.14 (overlapping embeddings are not permitted), report that - // error here as well (even though we could do it eagerly) because it's the same - // error message. - check.later(func() { - if !check.allowVersion(m.pkg, 1, 14) || !check.identical(m.typ, other.Type()) { - check.errorf(atPos(pos), _DuplicateDecl, "duplicate method %s", m.name) - check.errorf(atPos(mpos[other.(*Func)]), _DuplicateDecl, "\tother declaration of %s", m.name) // secondary error, \t indented - } - }) - } - } - - for _, m := range ityp.methods { - addMethod(m.pos, m, true) - } - - // collect types - allTypes := ityp.types - - posList := check.posMap[ityp] - for i, typ := range ityp.embeddeds { - pos := posList[i] // embedding position - utyp := under(typ) - etyp := asInterface(utyp) - if etyp == nil { - if utyp != Typ[Invalid] { - var format string - if _, ok := utyp.(*_TypeParam); ok { - format = "%s is a type parameter, not an interface" - } else { - format = "%s is not an interface" - } - // TODO: correct error code. - check.errorf(atPos(pos), _InvalidIfaceEmbed, format, typ) - } - continue - } - check.completeInterface(pos, etyp) - for _, m := range etyp.allMethods { - addMethod(pos, m, false) // use embedding position pos rather than m.pos - } - allTypes = intersect(allTypes, etyp.allTypes) - } - - if methods != nil { - sort.Sort(byUniqueMethodName(methods)) - ityp.allMethods = methods - } - ityp.allTypes = allTypes -} - -// intersect computes the intersection of the types x and y. -// Note: A incomming nil type stands for the top type. A top -// type result is returned as nil. -func intersect(x, y Type) (r Type) { - defer func() { - if r == theTop { - r = nil - } - }() - - switch { - case x == theBottom || y == theBottom: - return theBottom - case x == nil || x == theTop: - return y - case y == nil || x == theTop: - return x - } - - xtypes := unpackType(x) - ytypes := unpackType(y) - // Compute the list rtypes which includes only - // types that are in both xtypes and ytypes. - // Quadratic algorithm, but good enough for now. - // TODO(gri) fix this - var rtypes []Type - for _, x := range xtypes { - if includes(ytypes, x) { - rtypes = append(rtypes, x) - } - } - - if rtypes == nil { - return theBottom - } - return _NewSum(rtypes) -} - -func sortTypes(list []Type) { - sort.Stable(byUniqueTypeName(list)) -} - -// byUniqueTypeName named type lists can be sorted by their unique type names. -type byUniqueTypeName []Type - -func (a byUniqueTypeName) Len() int { return len(a) } -func (a byUniqueTypeName) Less(i, j int) bool { return sortName(a[i]) < sortName(a[j]) } -func (a byUniqueTypeName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } - -func sortName(t Type) string { - if named := asNamed(t); named != nil { - return named.obj.Id() - } - return "" -} - -func sortMethods(list []*Func) { - sort.Sort(byUniqueMethodName(list)) -} - -func assertSortedMethods(list []*Func) { - if !debug { - panic("internal error: assertSortedMethods called outside debug mode") - } - if !sort.IsSorted(byUniqueMethodName(list)) { - panic("internal error: methods not sorted") - } -} - -// byUniqueMethodName method lists can be sorted by their unique method names. -type byUniqueMethodName []*Func - -func (a byUniqueMethodName) Len() int { return len(a) } -func (a byUniqueMethodName) Less(i, j int) bool { return a[i].Id() < a[j].Id() } -func (a byUniqueMethodName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } - func (check *Checker) tag(t *ast.BasicLit) string { if t != nil { if t.Kind == token.STRING { @@ -1162,41 +890,3 @@ func embeddedFieldIdent(e ast.Expr) *ast.Ident { } return nil // invalid embedded field } - -func (check *Checker) collectTypeConstraints(pos token.Pos, types []ast.Expr) []Type { - list := make([]Type, 0, len(types)) // assume all types are correct - for _, texpr := range types { - if texpr == nil { - check.invalidAST(atPos(pos), "missing type constraint") - continue - } - list = append(list, check.varType(texpr)) - } - - // Ensure that each type is only present once in the type list. Types may be - // interfaces, which may not be complete yet. It's ok to do this check at the - // end because it's not a requirement for correctness of the code. - // Note: This is a quadratic algorithm, but type lists tend to be short. - check.later(func() { - for i, t := range list { - if t := asInterface(t); t != nil { - check.completeInterface(types[i].Pos(), t) - } - if includes(list[:i], t) { - check.softErrorf(types[i], _Todo, "duplicate type %s in type list", t) - } - } - }) - - return list -} - -// includes reports whether typ is in list. -func includes(list []Type, typ Type) bool { - for _, e := range list { - if Identical(typ, e) { - return true - } - } - return false -} From 93a886a165ed39bcfb842f88f17fc2cd7d005ab9 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 3 Jun 2021 11:10:08 -0400 Subject: [PATCH 291/940] [dev.typeparams] go/types: move struct checking into separate file This is a port of CL 321589 to go/types. Specifically, the same checker methods were moved. Change-Id: If07d96faa77d2f9409d8895f970149c42cbfe440 Reviewed-on: https://go-review.googlesource.com/c/go/+/324753 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/struct.go | 154 ++++++++++++++++++++++++++++++++++++++++ src/go/types/typexpr.go | 144 ------------------------------------- 2 files changed, 154 insertions(+), 144 deletions(-) create mode 100644 src/go/types/struct.go diff --git a/src/go/types/struct.go b/src/go/types/struct.go new file mode 100644 index 00000000000..1fec9ea527c --- /dev/null +++ b/src/go/types/struct.go @@ -0,0 +1,154 @@ +// Copyright 2021 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 types + +import ( + "go/ast" + "go/token" + "strconv" +) + +func (check *Checker) structType(styp *Struct, e *ast.StructType) { + list := e.Fields + if list == nil { + return + } + + // struct fields and tags + var fields []*Var + var tags []string + + // for double-declaration checks + var fset objset + + // current field typ and tag + var typ Type + var tag string + add := func(ident *ast.Ident, embedded bool, pos token.Pos) { + if tag != "" && tags == nil { + tags = make([]string, len(fields)) + } + if tags != nil { + tags = append(tags, tag) + } + + name := ident.Name + fld := NewField(pos, check.pkg, name, typ, embedded) + // spec: "Within a struct, non-blank field names must be unique." + if name == "_" || check.declareInSet(&fset, pos, fld) { + fields = append(fields, fld) + check.recordDef(ident, fld) + } + } + + // addInvalid adds an embedded field of invalid type to the struct for + // fields with errors; this keeps the number of struct fields in sync + // with the source as long as the fields are _ or have different names + // (issue #25627). + addInvalid := func(ident *ast.Ident, pos token.Pos) { + typ = Typ[Invalid] + tag = "" + add(ident, true, pos) + } + + for _, f := range list.List { + typ = check.varType(f.Type) + tag = check.tag(f.Tag) + if len(f.Names) > 0 { + // named fields + for _, name := range f.Names { + add(name, false, name.Pos()) + } + } else { + // embedded field + // spec: "An embedded type must be specified as a type name T or as a + // pointer to a non-interface type name *T, and T itself may not be a + // pointer type." + pos := f.Type.Pos() + name := embeddedFieldIdent(f.Type) + if name == nil { + // TODO(rFindley): using invalidAST here causes test failures (all + // errors should have codes). Clean this up. + check.errorf(f.Type, _Todo, "invalid AST: embedded field type %s has no name", f.Type) + name = ast.NewIdent("_") + name.NamePos = pos + addInvalid(name, pos) + continue + } + add(name, true, pos) + + // Because we have a name, typ must be of the form T or *T, where T is the name + // of a (named or alias) type, and t (= deref(typ)) must be the type of T. + // We must delay this check to the end because we don't want to instantiate + // (via under(t)) a possibly incomplete type. + + // for use in the closure below + embeddedTyp := typ + embeddedPos := f.Type + + check.later(func() { + t, isPtr := deref(embeddedTyp) + switch t := optype(t).(type) { + case *Basic: + if t == Typ[Invalid] { + // error was reported before + return + } + // unsafe.Pointer is treated like a regular pointer + if t.kind == UnsafePointer { + check.errorf(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be unsafe.Pointer") + } + case *Pointer: + check.errorf(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be a pointer") + case *Interface: + if isPtr { + check.errorf(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be a pointer to an interface") + } + } + }) + } + } + + styp.fields = fields + styp.tags = tags +} + +func embeddedFieldIdent(e ast.Expr) *ast.Ident { + switch e := e.(type) { + case *ast.Ident: + return e + case *ast.StarExpr: + // *T is valid, but **T is not + if _, ok := e.X.(*ast.StarExpr); !ok { + return embeddedFieldIdent(e.X) + } + case *ast.SelectorExpr: + return e.Sel + case *ast.IndexExpr: + return embeddedFieldIdent(e.X) + } + return nil // invalid embedded field +} + +func (check *Checker) declareInSet(oset *objset, pos token.Pos, obj Object) bool { + if alt := oset.insert(obj); alt != nil { + check.errorf(atPos(pos), _DuplicateDecl, "%s redeclared", obj.Name()) + check.reportAltDecl(alt) + return false + } + return true +} + +func (check *Checker) tag(t *ast.BasicLit) string { + if t != nil { + if t.Kind == token.STRING { + if val, err := strconv.Unquote(t.Value); err == nil { + return val + } + } + check.invalidAST(t, "incorrect tag syntax: %q", t.Value) + } + return "" +} diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index b1b4ff9a774..c6c3dc049a2 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -12,7 +12,6 @@ import ( "go/constant" "go/internal/typeparams" "go/token" - "strconv" "strings" ) @@ -747,146 +746,3 @@ func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, type0 ast return } - -func (check *Checker) declareInSet(oset *objset, pos token.Pos, obj Object) bool { - if alt := oset.insert(obj); alt != nil { - check.errorf(atPos(pos), _DuplicateDecl, "%s redeclared", obj.Name()) - check.reportAltDecl(alt) - return false - } - return true -} - -func (check *Checker) tag(t *ast.BasicLit) string { - if t != nil { - if t.Kind == token.STRING { - if val, err := strconv.Unquote(t.Value); err == nil { - return val - } - } - check.invalidAST(t, "incorrect tag syntax: %q", t.Value) - } - return "" -} - -func (check *Checker) structType(styp *Struct, e *ast.StructType) { - list := e.Fields - if list == nil { - return - } - - // struct fields and tags - var fields []*Var - var tags []string - - // for double-declaration checks - var fset objset - - // current field typ and tag - var typ Type - var tag string - add := func(ident *ast.Ident, embedded bool, pos token.Pos) { - if tag != "" && tags == nil { - tags = make([]string, len(fields)) - } - if tags != nil { - tags = append(tags, tag) - } - - name := ident.Name - fld := NewField(pos, check.pkg, name, typ, embedded) - // spec: "Within a struct, non-blank field names must be unique." - if name == "_" || check.declareInSet(&fset, pos, fld) { - fields = append(fields, fld) - check.recordDef(ident, fld) - } - } - - // addInvalid adds an embedded field of invalid type to the struct for - // fields with errors; this keeps the number of struct fields in sync - // with the source as long as the fields are _ or have different names - // (issue #25627). - addInvalid := func(ident *ast.Ident, pos token.Pos) { - typ = Typ[Invalid] - tag = "" - add(ident, true, pos) - } - - for _, f := range list.List { - typ = check.varType(f.Type) - tag = check.tag(f.Tag) - if len(f.Names) > 0 { - // named fields - for _, name := range f.Names { - add(name, false, name.Pos()) - } - } else { - // embedded field - // spec: "An embedded type must be specified as a type name T or as a - // pointer to a non-interface type name *T, and T itself may not be a - // pointer type." - pos := f.Type.Pos() - name := embeddedFieldIdent(f.Type) - if name == nil { - // TODO(rFindley): using invalidAST here causes test failures (all - // errors should have codes). Clean this up. - check.errorf(f.Type, _Todo, "invalid AST: embedded field type %s has no name", f.Type) - name = ast.NewIdent("_") - name.NamePos = pos - addInvalid(name, pos) - continue - } - add(name, true, pos) - - // Because we have a name, typ must be of the form T or *T, where T is the name - // of a (named or alias) type, and t (= deref(typ)) must be the type of T. - // We must delay this check to the end because we don't want to instantiate - // (via under(t)) a possibly incomplete type. - - // for use in the closure below - embeddedTyp := typ - embeddedPos := f.Type - - check.later(func() { - t, isPtr := deref(embeddedTyp) - switch t := optype(t).(type) { - case *Basic: - if t == Typ[Invalid] { - // error was reported before - return - } - // unsafe.Pointer is treated like a regular pointer - if t.kind == UnsafePointer { - check.errorf(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be unsafe.Pointer") - } - case *Pointer: - check.errorf(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be a pointer") - case *Interface: - if isPtr { - check.errorf(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be a pointer to an interface") - } - } - }) - } - } - - styp.fields = fields - styp.tags = tags -} - -func embeddedFieldIdent(e ast.Expr) *ast.Ident { - switch e := e.(type) { - case *ast.Ident: - return e - case *ast.StarExpr: - // *T is valid, but **T is not - if _, ok := e.X.(*ast.StarExpr); !ok { - return embeddedFieldIdent(e.X) - } - case *ast.SelectorExpr: - return e.Sel - case *ast.IndexExpr: - return embeddedFieldIdent(e.X) - } - return nil // invalid embedded field -} From c6b62112292fa741d5708dfd63bd89eed3b6f8ee Mon Sep 17 00:00:00 2001 From: Aaron Sheah Date: Thu, 3 Jun 2021 17:43:36 +0000 Subject: [PATCH 292/940] doc/go1.17: document testing changes for Go 1.17 For #44513. Fixes #46024 Change-Id: Icf3877d1fcd67448fbc79a0ce3db3f319ad4a0e9 GitHub-Last-Rev: 8c015935c2e376134d81aa577bffdca7fc03170d GitHub-Pull-Request: golang/go#46324 Reviewed-on: https://go-review.googlesource.com/c/go/+/322109 Reviewed-by: Heschi Kreinick Trust: Jeremy Faller Trust: Dmitri Shuralyov --- doc/go1.17.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 27ef524286d..7438d894fe3 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -659,9 +659,8 @@ Do not send CLs removing the interior tags from such phrases.

testing

- TODO: https://golang.org/cl/310033: add -shuffle=off|on|N to alter the execution order of tests and benchmarks + Added a new testing flag -shuffle which controls the execution order of tests and benchmarks.

-

The new T.Setenv From 79cd407f88f640b889df7645bf3e0491ed25eac7 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Fri, 4 Jun 2021 10:56:06 -0400 Subject: [PATCH 293/940] syscall: regenerate zsyscall_windows.go The declaration order in CL 319310 does not match what the generator produces from scratch. That currently causes cmd/internal/moddeps.TestAllDependencies to fail, since it is explicitly checking for that kind of skew. Updates #45914 Change-Id: If2a9cabc3d54e21deba7cb438fa364df205f38ac Reviewed-on: https://go-review.googlesource.com/c/go/+/325112 Trust: Bryan C. Mills Trust: Jason A. Donenfeld Reviewed-by: Jason A. Donenfeld Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot --- src/syscall/zsyscall_windows.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/syscall/zsyscall_windows.go b/src/syscall/zsyscall_windows.go index b9e429693d7..7bfff16be6a 100644 --- a/src/syscall/zsyscall_windows.go +++ b/src/syscall/zsyscall_windows.go @@ -41,9 +41,9 @@ var ( moddnsapi = NewLazyDLL(sysdll.Add("dnsapi.dll")) modiphlpapi = NewLazyDLL(sysdll.Add("iphlpapi.dll")) modkernel32 = NewLazyDLL(sysdll.Add("kernel32.dll")) - modntdll = NewLazyDLL(sysdll.Add("ntdll.dll")) modmswsock = NewLazyDLL(sysdll.Add("mswsock.dll")) modnetapi32 = NewLazyDLL(sysdll.Add("netapi32.dll")) + modntdll = NewLazyDLL(sysdll.Add("ntdll.dll")) modsecur32 = NewLazyDLL(sysdll.Add("secur32.dll")) modshell32 = NewLazyDLL(sysdll.Add("shell32.dll")) moduserenv = NewLazyDLL(sysdll.Add("userenv.dll")) From 8e6dfe1b315ca0ef6497b28e16523c2dc4019503 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Mon, 17 May 2021 15:00:39 -0700 Subject: [PATCH 294/940] [dev.typeparams] cmd/compile: export/import of recursive generic types. Deal with export/import of recursive generic types. This includes typeparams which have bounds that reference the typeparam. There are three main changes: - Change export/import of typeparams to have an implicit "declaration" (doDecl). We need to do a declaration of typeparams (via the typeparam's package and unique name), because it may be referenced within its bound during its own definition. - We delay most of the processing of the Instantiate call until we finish the creation of the top-most type (similar to the way we delay CheckSize). This is because we can't do the full instantiation properly until the base type is fully defined (with methods). The functions delayDoInst() and resumeDoInst() delay and resume the processing of the instantiations. - To do the full needed type substitutions for type instantiations during import, I had to separate out the type subster in stencil.go and move it to subr.go in the typecheck package. The subster in stencil.go now does node substitution and makes use of the type subster to do type substitutions. Notable other changes: - In types/builtins.go, put the newly defined typeparam for a union type (related to use of real/imag, etc.) in the current package, rather than the builtin package, so exports/imports work properly. - In types2, allowed NewTypeParam() to be called with a nil bound, and allow setting the bound later. (Needed to import a typeparam whose bound refers to the typeparam itself.) - During import of typeparams in types2 (importer/import.go), we need to keep an index of the typeparams by their package and unique name (with id). Use a new map typParamIndex[] for that. Again, this is needed to deal with typeparams whose bounds refer to the typeparam itself. - Added several new tests absdiffimp.go and orderedmapsimp.go. Some of the orderemapsimp tests are commented out for now, because there are some issues with closures inside instantiations (relating to unexported names of closure structs). - Renamed some typeparams in test value.go to make them all T (to make typeparam uniqueness is working fine). Change-Id: Ib47ed9471c19ee8e9fbb34e8506907dad3021e5a Reviewed-on: https://go-review.googlesource.com/c/go/+/323029 Trust: Dan Scales Trust: Robert Griesemer Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/importer/iimport.go | 92 +++-- src/cmd/compile/internal/noder/stencil.go | 335 +---------------- src/cmd/compile/internal/noder/types.go | 13 +- src/cmd/compile/internal/typecheck/iexport.go | 74 ++-- src/cmd/compile/internal/typecheck/iimport.go | 178 ++++++++-- src/cmd/compile/internal/typecheck/subr.go | 336 +++++++++++++++++- src/cmd/compile/internal/types2/builtins.go | 6 +- src/cmd/compile/internal/types2/type.go | 22 +- test/typeparam/absdiff.go | 3 +- test/typeparam/absdiffimp.dir/a.go | 75 ++++ test/typeparam/absdiffimp.dir/main.go | 29 ++ test/typeparam/absdiffimp.go | 7 + test/typeparam/orderedmapsimp.dir/a.go | 226 ++++++++++++ test/typeparam/orderedmapsimp.dir/main.go | 67 ++++ test/typeparam/orderedmapsimp.go | 7 + test/typeparam/value.go | 6 +- 16 files changed, 1038 insertions(+), 438 deletions(-) create mode 100644 test/typeparam/absdiffimp.dir/a.go create mode 100644 test/typeparam/absdiffimp.dir/main.go create mode 100644 test/typeparam/absdiffimp.go create mode 100644 test/typeparam/orderedmapsimp.dir/a.go create mode 100644 test/typeparam/orderedmapsimp.dir/main.go create mode 100644 test/typeparam/orderedmapsimp.go diff --git a/src/cmd/compile/internal/importer/iimport.go b/src/cmd/compile/internal/importer/iimport.go index fd48bfc1796..fb39e93073c 100644 --- a/src/cmd/compile/internal/importer/iimport.go +++ b/src/cmd/compile/internal/importer/iimport.go @@ -51,6 +51,11 @@ const ( iexportVersionCurrent = iexportVersionGenerics + 1 ) +type ident struct { + pkg string + name string +} + const predeclReserved = 32 type itag uint64 @@ -124,6 +129,9 @@ func iImportData(imports map[string]*types2.Package, data []byte, path string) ( declData: declData, pkgIndex: make(map[*types2.Package]map[string]uint64), typCache: make(map[uint64]types2.Type), + // Separate map for typeparams, keyed by their package and unique + // name (name with subscript). + tparamIndex: make(map[ident]types2.Type), } for i, pt := range predeclared { @@ -202,9 +210,10 @@ type iimporter struct { pkgCache map[uint64]*types2.Package posBaseCache map[uint64]*syntax.PosBase - declData []byte - pkgIndex map[*types2.Package]map[string]uint64 - typCache map[uint64]types2.Type + declData []byte + pkgIndex map[*types2.Package]map[string]uint64 + typCache map[uint64]types2.Type + tparamIndex map[ident]types2.Type interfaceList []*types2.Interface } @@ -358,6 +367,28 @@ func (r *importReader) obj(name string) { } } + case 'P': + // We need to "declare" a typeparam in order to have a name that + // can be referenced recursively (if needed) in the type param's + // bound. + if r.p.exportVersion < iexportVersionGenerics { + errorf("unexpected type param type") + } + index := int(r.int64()) + name0, sub := parseSubscript(name) + tn := types2.NewTypeName(pos, r.currPkg, name0, nil) + t := (*types2.Checker)(nil).NewTypeParam(tn, index, nil) + if sub == 0 { + errorf("missing subscript") + } + t.SetId(sub) + // To handle recursive references to the typeparam within its + // bound, save the partial type in tparamIndex before reading the bounds. + id := ident{r.currPkg.Name(), name} + r.p.tparamIndex[id] = t + + t.SetBound(r.typ()) + case 'V': typ := r.typ() @@ -617,34 +648,15 @@ func (r *importReader) doType(base *types2.Named) types2.Type { if r.p.exportVersion < iexportVersionGenerics { errorf("unexpected type param type") } - r.currPkg = r.pkg() - pos := r.pos() - name := r.string() - - // Extract the subscript value from the type param name. We export - // and import the subscript value, so that all type params have - // unique names. - sub := uint64(0) - startsub := -1 - for i, r := range name { - if '₀' <= r && r < '₀'+10 { - if startsub == -1 { - startsub = i - } - sub = sub*10 + uint64(r-'₀') - } + pkg, name := r.qualifiedIdent() + id := ident{pkg.Name(), name} + if t, ok := r.p.tparamIndex[id]; ok { + // We're already in the process of importing this typeparam. + return t } - if startsub >= 0 { - name = name[:startsub] - } - index := int(r.int64()) - bound := r.typ() - tn := types2.NewTypeName(pos, r.currPkg, name, nil) - t := (*types2.Checker)(nil).NewTypeParam(tn, index, bound) - if sub >= 0 { - t.SetId(sub) - } - return t + // Otherwise, import the definition of the typeparam now. + r.p.doDecl(pkg, name) + return r.p.tparamIndex[id] case instType: if r.p.exportVersion < iexportVersionGenerics { @@ -753,3 +765,23 @@ func baseType(typ types2.Type) *types2.Named { n, _ := typ.(*types2.Named) return n } + +func parseSubscript(name string) (string, uint64) { + // Extract the subscript value from the type param name. We export + // and import the subscript value, so that all type params have + // unique names. + sub := uint64(0) + startsub := -1 + for i, r := range name { + if '₀' <= r && r < '₀'+10 { + if startsub == -1 { + startsub = i + } + sub = sub*10 + uint64(r-'₀') + } + } + if startsub >= 0 { + name = name[:startsub] + } + return name, sub +} diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 08c09c6fb13..3ba364f67cc 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -15,7 +15,6 @@ import ( "cmd/compile/internal/types" "fmt" "go/constant" - "strings" ) // For catching problems as we add more features @@ -425,13 +424,6 @@ func (g *irgen) instantiateMethods() { } -// genericSym returns the name of the base generic type for the type named by -// sym. It simply returns the name obtained by removing everything after the -// first bracket ("["). -func genericTypeName(sym *types.Sym) string { - return sym.Name[0:strings.Index(sym.Name, "[")] -} - // getInstantiationForNode returns the function/method instantiation for a // InstExpr node inst. func (g *irgen) getInstantiationForNode(inst *ir.InstExpr) *ir.Func { @@ -479,11 +471,7 @@ type subster struct { g *irgen isMethod bool // If a method is being instantiated newf *ir.Func // Func node for the new stenciled function - tparams []*types.Type - targs []*types.Type - // The substitution map from name nodes in the generic function to the - // name nodes in the new stenciled function. - vars map[*ir.Name]*ir.Name + ts typecheck.Tsubster } // genericSubst returns a new function with name newsym. The function is an @@ -526,9 +514,11 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*type g: g, isMethod: isMethod, newf: newf, - tparams: tparams, - targs: targs, - vars: make(map[*ir.Name]*ir.Name), + ts: typecheck.Tsubster{ + Tparams: tparams, + Targs: targs, + Vars: make(map[*ir.Name]*ir.Name), + }, } newf.Dcl = make([]*ir.Name, 0, len(gf.Dcl)+1) @@ -574,6 +564,9 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*type newf.Body.Prepend(g.checkDictionary(dictionaryName, targs)...) ir.CurFunc = savef + // Add any new, fully instantiated types seen during the substitution to + // g.instTypeList. + g.instTypeList = append(g.instTypeList, subst.ts.InstTypeList...) return newf } @@ -586,13 +579,13 @@ func (subst *subster) localvar(name *ir.Name) *ir.Name { if name.IsClosureVar() { m.SetIsClosureVar(true) } - m.SetType(subst.typ(name.Type())) + m.SetType(subst.ts.Typ(name.Type())) m.BuiltinOp = name.BuiltinOp m.Curfn = subst.newf m.Class = name.Class assert(name.Class != ir.PEXTERN && name.Class != ir.PFUNC) m.Func = name.Func - subst.vars[name] = m + subst.ts.Vars[name] = m m.SetTypecheck(1) return m } @@ -635,7 +628,7 @@ func (g *irgen) checkDictionary(name *ir.Name, targs []*types.Type) (code []ir.N return } -// node is like DeepCopy(), but substitutes ONAME nodes based on subst.vars, and +// node is like DeepCopy(), but substitutes ONAME nodes based on subst.ts.vars, and // also descends into closures. It substitutes type arguments for type parameters // in all the new nodes. func (subst *subster) node(n ir.Node) ir.Node { @@ -644,10 +637,10 @@ func (subst *subster) node(n ir.Node) ir.Node { edit = func(x ir.Node) ir.Node { switch x.Op() { case ir.OTYPE: - return ir.TypeNode(subst.typ(x.Type())) + return ir.TypeNode(subst.ts.Typ(x.Type())) case ir.ONAME: - if v := subst.vars[x.(*ir.Name)]; v != nil { + if v := subst.ts.Vars[x.(*ir.Name)]; v != nil { return v } return x @@ -673,7 +666,7 @@ func (subst *subster) node(n ir.Node) ir.Node { base.Fatalf(fmt.Sprintf("Nil type for %v", x)) } } else if x.Op() != ir.OCLOSURE { - m.SetType(subst.typ(x.Type())) + m.SetType(subst.ts.Typ(x.Type())) } } ir.EditChildren(m, edit) @@ -815,7 +808,7 @@ func (subst *subster) node(n ir.Node) ir.Node { m.(*ir.ClosureExpr).Func = newfn // Closure name can already have brackets, if it derives // from a generic method - newsym := typecheck.MakeInstName(oldfn.Nname.Sym(), subst.targs, subst.isMethod) + newsym := typecheck.MakeInstName(oldfn.Nname.Sym(), subst.ts.Targs, subst.isMethod) newfn.Nname = ir.NewNameAt(oldfn.Nname.Pos(), newsym) newfn.Nname.Func = newfn newfn.Nname.Defn = newfn @@ -828,7 +821,7 @@ func (subst *subster) node(n ir.Node) ir.Node { newfn.Dcl = subst.namelist(oldfn.Dcl) newfn.ClosureVars = subst.namelist(oldfn.ClosureVars) - typed(subst.typ(oldfn.Nname.Type()), newfn.Nname) + typed(subst.ts.Typ(oldfn.Nname.Type()), newfn.Nname) typed(newfn.Nname.Type(), m) newfn.SetTypecheck(1) @@ -867,298 +860,6 @@ func (subst *subster) list(l []ir.Node) []ir.Node { return s } -// tstruct substitutes type params in types of the fields of a structure type. For -// each field, tstruct copies the Nname, and translates it if Nname is in -// subst.vars. To always force the creation of a new (top-level) struct, -// regardless of whether anything changed with the types or names of the struct's -// fields, set force to true. -func (subst *subster) tstruct(t *types.Type, force bool) *types.Type { - if t.NumFields() == 0 { - if t.HasTParam() { - // For an empty struct, we need to return a new type, - // since it may now be fully instantiated (HasTParam - // becomes false). - return types.NewStruct(t.Pkg(), nil) - } - return t - } - var newfields []*types.Field - if force { - newfields = make([]*types.Field, t.NumFields()) - } - for i, f := range t.Fields().Slice() { - t2 := subst.typ(f.Type) - if (t2 != f.Type || f.Nname != nil) && newfields == nil { - newfields = make([]*types.Field, t.NumFields()) - for j := 0; j < i; j++ { - newfields[j] = t.Field(j) - } - } - if newfields != nil { - // TODO(danscales): make sure this works for the field - // names of embedded types (which should keep the name of - // the type param, not the instantiated type). - newfields[i] = types.NewField(f.Pos, f.Sym, t2) - if f.Nname != nil { - v := subst.vars[f.Nname.(*ir.Name)] - if v != nil { - // This is the case where we are - // translating the type of the function we - // are substituting, so its dcls are in - // the subst.vars table, and we want to - // change to reference the new dcl. - newfields[i].Nname = v - } else { - // This is the case where we are - // translating the type of a function - // reference inside the function we are - // substituting, so we leave the Nname - // value as is. - newfields[i].Nname = f.Nname - } - } - } - } - if newfields != nil { - return types.NewStruct(t.Pkg(), newfields) - } - return t - -} - -// tinter substitutes type params in types of the methods of an interface type. -func (subst *subster) tinter(t *types.Type) *types.Type { - if t.Methods().Len() == 0 { - return t - } - var newfields []*types.Field - for i, f := range t.Methods().Slice() { - t2 := subst.typ(f.Type) - if (t2 != f.Type || f.Nname != nil) && newfields == nil { - newfields = make([]*types.Field, t.Methods().Len()) - for j := 0; j < i; j++ { - newfields[j] = t.Methods().Index(j) - } - } - if newfields != nil { - newfields[i] = types.NewField(f.Pos, f.Sym, t2) - } - } - if newfields != nil { - return types.NewInterface(t.Pkg(), newfields) - } - return t -} - -// typ computes the type obtained by substituting any type parameter in t with the -// corresponding type argument in subst. If t contains no type parameters, the -// result is t; otherwise the result is a new type. It deals with recursive types -// by using TFORW types and finding partially or fully created types via sym.Def. -func (subst *subster) typ(t *types.Type) *types.Type { - if !t.HasTParam() && t.Kind() != types.TFUNC { - // Note: function types need to be copied regardless, as the - // types of closures may contain declarations that need - // to be copied. See #45738. - return t - } - - if t.Kind() == types.TTYPEPARAM { - for i, tp := range subst.tparams { - if tp == t { - return subst.targs[i] - } - } - // If t is a simple typeparam T, then t has the name/symbol 'T' - // and t.Underlying() == t. - // - // However, consider the type definition: 'type P[T any] T'. We - // might use this definition so we can have a variant of type T - // that we can add new methods to. Suppose t is a reference to - // P[T]. t has the name 'P[T]', but its kind is TTYPEPARAM, - // because P[T] is defined as T. If we look at t.Underlying(), it - // is different, because the name of t.Underlying() is 'T' rather - // than 'P[T]'. But the kind of t.Underlying() is also TTYPEPARAM. - // In this case, we do the needed recursive substitution in the - // case statement below. - if t.Underlying() == t { - // t is a simple typeparam that didn't match anything in tparam - return t - } - // t is a more complex typeparam (e.g. P[T], as above, whose - // definition is just T). - assert(t.Sym() != nil) - } - - var newsym *types.Sym - var neededTargs []*types.Type - var forw *types.Type - - if t.Sym() != nil { - // Translate the type params for this type according to - // the tparam/targs mapping from subst. - neededTargs = make([]*types.Type, len(t.RParams())) - for i, rparam := range t.RParams() { - neededTargs[i] = subst.typ(rparam) - } - // For a named (defined) type, we have to change the name of the - // type as well. We do this first, so we can look up if we've - // already seen this type during this substitution or other - // definitions/substitutions. - genName := genericTypeName(t.Sym()) - newsym = t.Sym().Pkg.Lookup(typecheck.InstTypeName(genName, neededTargs)) - if newsym.Def != nil { - // We've already created this instantiated defined type. - return newsym.Def.Type() - } - - // In order to deal with recursive generic types, create a TFORW - // type initially and set the Def field of its sym, so it can be - // found if this type appears recursively within the type. - forw = typecheck.NewIncompleteNamedType(t.Pos(), newsym) - //println("Creating new type by sub", newsym.Name, forw.HasTParam()) - forw.SetRParams(neededTargs) - // Copy the OrigSym from the re-instantiated type (which is the sym of - // the base generic type). - assert(t.OrigSym != nil) - forw.OrigSym = t.OrigSym - } - - var newt *types.Type - - switch t.Kind() { - case types.TTYPEPARAM: - if t.Sym() == newsym { - // The substitution did not change the type. - return t - } - // Substitute the underlying typeparam (e.g. T in P[T], see - // the example describing type P[T] above). - newt = subst.typ(t.Underlying()) - assert(newt != t) - - case types.TARRAY: - elem := t.Elem() - newelem := subst.typ(elem) - if newelem != elem { - newt = types.NewArray(newelem, t.NumElem()) - } - - case types.TPTR: - elem := t.Elem() - newelem := subst.typ(elem) - if newelem != elem { - newt = types.NewPtr(newelem) - } - - case types.TSLICE: - elem := t.Elem() - newelem := subst.typ(elem) - if newelem != elem { - newt = types.NewSlice(newelem) - } - - case types.TSTRUCT: - newt = subst.tstruct(t, false) - if newt == t { - newt = nil - } - - case types.TFUNC: - newrecvs := subst.tstruct(t.Recvs(), false) - newparams := subst.tstruct(t.Params(), false) - newresults := subst.tstruct(t.Results(), false) - if newrecvs != t.Recvs() || newparams != t.Params() || newresults != t.Results() { - // If any types have changed, then the all the fields of - // of recv, params, and results must be copied, because they have - // offset fields that are dependent, and so must have an - // independent copy for each new signature. - var newrecv *types.Field - if newrecvs.NumFields() > 0 { - if newrecvs == t.Recvs() { - newrecvs = subst.tstruct(t.Recvs(), true) - } - newrecv = newrecvs.Field(0) - } - if newparams == t.Params() { - newparams = subst.tstruct(t.Params(), true) - } - if newresults == t.Results() { - newresults = subst.tstruct(t.Results(), true) - } - newt = types.NewSignature(t.Pkg(), newrecv, t.TParams().FieldSlice(), newparams.FieldSlice(), newresults.FieldSlice()) - } - - case types.TINTER: - newt = subst.tinter(t) - if newt == t { - newt = nil - } - - case types.TMAP: - newkey := subst.typ(t.Key()) - newval := subst.typ(t.Elem()) - if newkey != t.Key() || newval != t.Elem() { - newt = types.NewMap(newkey, newval) - } - - case types.TCHAN: - elem := t.Elem() - newelem := subst.typ(elem) - if newelem != elem { - newt = types.NewChan(newelem, t.ChanDir()) - if !newt.HasTParam() { - // TODO(danscales): not sure why I have to do this - // only for channels..... - types.CheckSize(newt) - } - } - } - if newt == nil { - // Even though there were typeparams in the type, there may be no - // change if this is a function type for a function call (which will - // have its own tparams/targs in the function instantiation). - return t - } - - if t.Sym() == nil { - // Not a named type, so there was no forwarding type and there are - // no methods to substitute. - assert(t.Methods().Len() == 0) - return newt - } - - forw.SetUnderlying(newt) - newt = forw - - if t.Kind() != types.TINTER && t.Methods().Len() > 0 { - // Fill in the method info for the new type. - var newfields []*types.Field - newfields = make([]*types.Field, t.Methods().Len()) - for i, f := range t.Methods().Slice() { - t2 := subst.typ(f.Type) - oldsym := f.Nname.Sym() - newsym := typecheck.MakeInstName(oldsym, subst.targs, true) - // TODO: use newsym? - var nname *ir.Name - if newsym.Def != nil { - nname = newsym.Def.(*ir.Name) - } else { - nname = ir.NewNameAt(f.Pos, oldsym) - nname.SetType(t2) - oldsym.Def = nname - } - newfields[i] = types.NewField(f.Pos, f.Sym, t2) - newfields[i].Nname = nname - } - newt.Methods().Set(newfields) - if !newt.HasTParam() { - // Generate all the methods for a new fully-instantiated type. - subst.g.instTypeList = append(subst.g.instTypeList, newt) - } - } - return newt -} - // fields sets the Nname field for the Field nodes inside a type signature, based // on the corresponding in/out parameters in dcl. It depends on the in and out // parameters being in order in dcl. @@ -1178,7 +879,7 @@ func (subst *subster) fields(class ir.Class, oldfields []*types.Field, dcl []*ir newfields := make([]*types.Field, len(oldfields)) for j := range oldfields { newfields[j] = oldfields[j].Copy() - newfields[j].Type = subst.typ(oldfields[j].Type) + newfields[j].Type = subst.ts.Typ(oldfields[j].Type) // A PPARAM field will be missing from dcl if its name is // unspecified or specified as "_". So, we compare the dcl sym // with the field sym (or sym of the field's Nname node). (Unnamed diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go index f0061e79d70..b37793b2d08 100644 --- a/src/cmd/compile/internal/noder/types.go +++ b/src/cmd/compile/internal/noder/types.go @@ -316,13 +316,16 @@ func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) { tparams[i] = g.typ1(rparam.Type()) } assert(len(tparams) == len(targs)) - subst := &subster{ - g: g, - tparams: tparams, - targs: targs, + ts := typecheck.Tsubster{ + Tparams: tparams, + Targs: targs, } // Do the substitution of the type - meth2.SetType(subst.typ(meth.Type())) + meth2.SetType(ts.Typ(meth.Type())) + // Add any new fully instantiated types + // seen during the substitution to + // g.instTypeList. + g.instTypeList = append(g.instTypeList, ts.InstTypeList...) newsym.Def = meth2 } meth = meth2 diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index 66c356ee7c8..f635b79adab 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -506,6 +506,20 @@ func (p *iexporter) doDecl(n *ir.Name) { w.constExt(n) case ir.OTYPE: + if n.Type().Kind() == types.TTYPEPARAM && n.Type().Underlying() == n.Type() { + // Even though it has local scope, a typeparam requires a + // declaration via its package and unique name, because it + // may be referenced within its type bound during its own + // definition. + w.tag('P') + // A typeparam has a name, and has a type bound rather + // than an underlying type. + w.pos(n.Pos()) + w.int64(int64(n.Type().Index())) + w.typ(n.Type().Bound()) + break + } + if n.Alias() { // Alias. w.tag('A') @@ -519,9 +533,10 @@ func (p *iexporter) doDecl(n *ir.Name) { w.pos(n.Pos()) if base.Flag.G > 0 { - // Export any new typeparams needed for this type + // Export type parameters, if any, needed for this type w.typeList(n.Type().RParams()) } + underlying := n.Type().Underlying() if underlying == types.ErrorType.Underlying() { // For "type T error", use error as the @@ -837,26 +852,6 @@ func (w *exportWriter) startType(k itag) { } func (w *exportWriter) doTyp(t *types.Type) { - if t.Kind() == types.TTYPEPARAM { - assert(base.Flag.G > 0) - // A typeparam has a name, but doesn't have an underlying type. - // Just write out the details of the type param here. All other - // uses of this typeparam type will be written out as its unique - // type offset. - w.startType(typeParamType) - s := t.Sym() - w.setPkg(s.Pkg, true) - w.pos(t.Pos()) - - // We are writing out the name with the subscript, so that the - // typeparam name is unique. - w.string(s.Name) - w.int64(int64(t.Index())) - - w.typ(t.Bound()) - return - } - s := t.Sym() if s != nil && t.OrigSym != nil { assert(base.Flag.G > 0) @@ -880,6 +875,21 @@ func (w *exportWriter) doTyp(t *types.Type) { return } + // The 't.Underlying() == t' check is to confirm this is a base typeparam + // type, rather than a defined type with typeparam underlying type, like: + // type orderedAbs[T any] T + if t.Kind() == types.TTYPEPARAM && t.Underlying() == t { + assert(base.Flag.G > 0) + if s.Pkg == types.BuiltinPkg || s.Pkg == ir.Pkgs.Unsafe { + base.Fatalf("builtin type missing from typIndex: %v", t) + } + // Write out the first use of a type param as a qualified ident. + // This will force a "declaration" of the type param. + w.startType(typeParamType) + w.qualifiedIdent(t.Obj().(*ir.Name)) + return + } + if s != nil { if s.Pkg == types.BuiltinPkg || s.Pkg == ir.Pkgs.Unsafe { base.Fatalf("builtin type missing from typIndex: %v", t) @@ -1325,14 +1335,20 @@ func (w *exportWriter) funcExt(n *ir.Name) { // Inline body. if n.Type().HasTParam() { if n.Func.Inl != nil { - base.FatalfAt(n.Pos(), "generic function is marked inlineable") - } - // Populate n.Func.Inl, so body of exported generic function will - // be written out. - n.Func.Inl = &ir.Inline{ - Cost: 1, - Dcl: n.Func.Dcl, - Body: n.Func.Body, + // n.Func.Inl may already be set on a generic function if + // we imported it from another package, but shouldn't be + // set for a generic function in the local package. + if n.Sym().Pkg == types.LocalPkg { + base.FatalfAt(n.Pos(), "generic function is marked inlineable") + } + } else { + // Populate n.Func.Inl, so body of exported generic function will + // be written out. + n.Func.Inl = &ir.Inline{ + Cost: 1, + Dcl: n.Func.Dcl, + Body: n.Func.Body, + } } } if n.Func.Inl != nil { diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 96107b657b6..9e6115cbf7c 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -342,19 +342,22 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name { // declaration before recursing. n := importtype(r.p.ipkg, pos, sym) t := n.Type() - - // We also need to defer width calculations until - // after the underlying type has been assigned. - types.DeferCheckSize() - underlying := r.typ() - t.SetUnderlying(underlying) - types.ResumeCheckSize() - if rparams != nil { t.SetRParams(rparams) } + // We also need to defer width calculations until + // after the underlying type has been assigned. + types.DeferCheckSize() + deferDoInst() + underlying := r.typ() + t.SetUnderlying(underlying) + if underlying.IsInterface() { + // Finish up all type instantiations and CheckSize calls + // now that a top-level type is fully constructed. + resumeDoInst() + types.ResumeCheckSize() r.typeExt(t) return n } @@ -380,12 +383,38 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name { } t.Methods().Set(ms) + // Finish up all instantiations and CheckSize calls now + // that a top-level type is fully constructed. + resumeDoInst() + types.ResumeCheckSize() + r.typeExt(t) for _, m := range ms { r.methExt(m) } return n + case 'P': + if r.p.exportVersion < iexportVersionGenerics { + base.Fatalf("unexpected type param type") + } + if sym.Def != nil { + // Make sure we use the same type param type for the same + // name, whether it is created during types1-import or + // this types2-to-types1 translation. + return sym.Def.(*ir.Name) + } + index := int(r.int64()) + t := types.NewTypeParam(sym, index) + // Nname needed to save the pos. + nname := ir.NewDeclNameAt(pos, ir.OTYPE, sym) + sym.Def = nname + nname.SetType(t) + t.SetNod(nname) + + t.SetBound(r.typ()) + return nname + case 'V': typ := r.typ() @@ -545,7 +574,12 @@ func (r *importReader) pos() src.XPos { } func (r *importReader) typ() *types.Type { - return r.p.typAt(r.uint64()) + // If this is a top-level type call, defer type instantiations until the + // type is fully constructed. + deferDoInst() + t := r.p.typAt(r.uint64()) + resumeDoInst() + return t } func (r *importReader) exoticType() *types.Type { @@ -683,7 +717,13 @@ func (p *iimporter) typAt(off uint64) *types.Type { // are pushed to compile queue, then draining from the queue for compiling. // During this process, the size calculation is disabled, so it is not safe for // calculating size during SSA generation anymore. See issue #44732. - types.CheckSize(t) + // + // No need to calc sizes for re-instantiated generic types, and + // they are not necessarily resolved until the top-level type is + // defined (because of recursive types). + if t.OrigSym == nil || !t.HasTParam() { + types.CheckSize(t) + } p.typCache[off] = t } return t @@ -779,27 +819,18 @@ func (r *importReader) typ1() *types.Type { if r.p.exportVersion < iexportVersionGenerics { base.Fatalf("unexpected type param type") } - r.setPkg() - pos := r.pos() - name := r.string() - sym := r.currPkg.Lookup(name) - index := int(r.int64()) - bound := r.typ() - if sym.Def != nil { - // Make sure we use the same type param type for the same - // name, whether it is created during types1-import or - // this types2-to-types1 translation. - return sym.Def.Type() + // Similar to code for defined types, since we "declared" + // typeparams to deal with recursion (typeparam is used within its + // own type bound). + ident := r.qualifiedIdent() + if ident.Sym().Def != nil { + return ident.Sym().Def.(*ir.Name).Type() } - t := types.NewTypeParam(sym, index) - // Nname needed to save the pos. - nname := ir.NewDeclNameAt(pos, ir.OTYPE, sym) - sym.Def = nname - nname.SetType(t) - t.SetNod(nname) - - t.SetBound(bound) - return t + n := expandDecl(ident) + if n.Op() != ir.OTYPE { + base.Fatalf("expected OTYPE, got %v: %v, %v", n.Op(), n.Sym(), n) + } + return n.Type() case instType: if r.p.exportVersion < iexportVersionGenerics { @@ -1758,20 +1789,91 @@ func Instantiate(pos src.XPos, baseType *types.Type, targs []*types.Type) *types name := InstTypeName(baseSym.Name, targs) instSym := baseSym.Pkg.Lookup(name) if instSym.Def != nil { + // May match existing type from previous import or + // types2-to-types1 conversion, or from in-progress instantiation + // in the current type import stack. return instSym.Def.Type() } t := NewIncompleteNamedType(baseType.Pos(), instSym) t.SetRParams(targs) - // baseType may not yet be complete (since we are in the middle of - // importing it), but its underlying type will be updated when baseType's - // underlying type is finished. - t.SetUnderlying(baseType.Underlying()) - - // As with types2, the methods are the generic method signatures (without - // substitution). - t.Methods().Set(baseType.Methods().Slice()) t.OrigSym = baseSym + // baseType may still be TFORW or its methods may not be fully filled in + // (since we are in the middle of importing it). So, delay call to + // substInstType until we get back up to the top of the current top-most + // type import. + deferredInstStack = append(deferredInstStack, t) + return t } + +var deferredInstStack []*types.Type +var deferInst int + +// deferDoInst defers substitution on instantiated types until we are at the +// top-most defined type, so the base types are fully defined. +func deferDoInst() { + deferInst++ +} + +func resumeDoInst() { + if deferInst == 1 { + for len(deferredInstStack) > 0 { + t := deferredInstStack[0] + deferredInstStack = deferredInstStack[1:] + substInstType(t, t.OrigSym.Def.(*ir.Name).Type(), t.RParams()) + } + } + deferInst-- +} + +// doInst creates a new instantiation type (which will be added to +// deferredInstStack for completion later) for an incomplete type encountered +// during a type substitution for an instantiation. This is needed for +// instantiations of mutually recursive types. +func doInst(t *types.Type) *types.Type { + return Instantiate(t.Pos(), t.OrigSym.Def.(*ir.Name).Type(), t.RParams()) +} + +// substInstType completes the instantiation of a generic type by doing a +// substitution on the underlying type itself and any methods. t is the +// instantiation being created, baseType is the base generic type, and targs are +// the type arguments that baseType is being instantiated with. +func substInstType(t *types.Type, baseType *types.Type, targs []*types.Type) { + subst := Tsubster{ + Tparams: baseType.RParams(), + Targs: targs, + SubstForwFunc: doInst, + } + t.SetUnderlying(subst.Typ(baseType.Underlying())) + + newfields := make([]*types.Field, baseType.Methods().Len()) + for i, f := range baseType.Methods().Slice() { + recvType := f.Type.Recv().Type + if recvType.IsPtr() { + recvType = recvType.Elem() + } + // Substitute in the method using the type params used in the + // method (not the type params in the definition of the generic type). + subst := Tsubster{ + Tparams: recvType.RParams(), + Targs: targs, + SubstForwFunc: doInst, + } + t2 := subst.Typ(f.Type) + oldsym := f.Nname.Sym() + newsym := MakeInstName(oldsym, targs, true) + var nname *ir.Name + if newsym.Def != nil { + nname = newsym.Def.(*ir.Name) + } else { + nname = ir.NewNameAt(f.Pos, newsym) + nname.SetType(t2) + newsym.Def = nname + } + newfields[i] = types.NewField(f.Pos, f.Sym, t2) + newfields[i].Nname = nname + } + t.Methods().Set(newfields) +} diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index 3e7799b35b2..8ef49f91c83 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -890,7 +890,6 @@ func TypesOf(x []ir.Node) []*types.Type { // based on the name of the function fnsym and the targs. It replaces any // existing bracket type list in the name. makeInstName asserts that fnsym has // brackets in its name if and only if hasBrackets is true. -// TODO(danscales): remove the assertions and the hasBrackets argument later. // // Names of declared generic functions have no brackets originally, so hasBrackets // should be false. Names of generic methods already have brackets, since the new @@ -902,12 +901,24 @@ func TypesOf(x []ir.Node) []*types.Type { func MakeInstName(fnsym *types.Sym, targs []*types.Type, hasBrackets bool) *types.Sym { b := bytes.NewBufferString("") - // marker to distinguish generic instantiations from fully stenciled wrapper functions. + // Determine if the type args are concrete types or new typeparams. + hasTParam := false + for _, targ := range targs { + if hasTParam { + assert(targ.HasTParam()) + } else if targ.HasTParam() { + hasTParam = true + } + } + + // Marker to distinguish generic instantiations from fully stenciled wrapper functions. // Once we move to GC shape implementations, this prefix will not be necessary as the // GC shape naming will distinguish them. // e.g. f[8bytenonpointer] vs. f[int]. // For now, we use .inst.f[int] vs. f[int]. - b.WriteString(".inst.") + if !hasTParam { + b.WriteString(".inst.") + } name := fnsym.Name i := strings.Index(name, "[") @@ -942,10 +953,325 @@ func MakeInstName(fnsym *types.Sym, targs []*types.Type, hasBrackets bool) *type return fnsym.Pkg.Lookup(b.String()) } -// For catching problems as we add more features -// TODO(danscales): remove assertions or replace with base.FatalfAt() func assert(p bool) { if !p { panic("assertion failed") } } + +// General type substituter, for replacing typeparams with type args. +type Tsubster struct { + Tparams []*types.Type + Targs []*types.Type + // If non-nil, the substitution map from name nodes in the generic function to the + // name nodes in the new stenciled function. + Vars map[*ir.Name]*ir.Name + // New fully-instantiated generic types whose methods should be instantiated. + InstTypeList []*types.Type + // If non-nil, function to substitute an incomplete (TFORW) type. + SubstForwFunc func(*types.Type) *types.Type +} + +// Typ computes the type obtained by substituting any type parameter in t with the +// corresponding type argument in subst. If t contains no type parameters, the +// result is t; otherwise the result is a new type. It deals with recursive types +// by using TFORW types and finding partially or fully created types via sym.Def. +func (ts *Tsubster) Typ(t *types.Type) *types.Type { + if !t.HasTParam() && t.Kind() != types.TFUNC { + // Note: function types need to be copied regardless, as the + // types of closures may contain declarations that need + // to be copied. See #45738. + return t + } + + if t.Kind() == types.TTYPEPARAM { + for i, tp := range ts.Tparams { + if tp == t { + return ts.Targs[i] + } + } + // If t is a simple typeparam T, then t has the name/symbol 'T' + // and t.Underlying() == t. + // + // However, consider the type definition: 'type P[T any] T'. We + // might use this definition so we can have a variant of type T + // that we can add new methods to. Suppose t is a reference to + // P[T]. t has the name 'P[T]', but its kind is TTYPEPARAM, + // because P[T] is defined as T. If we look at t.Underlying(), it + // is different, because the name of t.Underlying() is 'T' rather + // than 'P[T]'. But the kind of t.Underlying() is also TTYPEPARAM. + // In this case, we do the needed recursive substitution in the + // case statement below. + if t.Underlying() == t { + // t is a simple typeparam that didn't match anything in tparam + return t + } + // t is a more complex typeparam (e.g. P[T], as above, whose + // definition is just T). + assert(t.Sym() != nil) + } + + var newsym *types.Sym + var neededTargs []*types.Type + var forw *types.Type + + if t.Sym() != nil { + // Translate the type params for this type according to + // the tparam/targs mapping from subst. + neededTargs = make([]*types.Type, len(t.RParams())) + for i, rparam := range t.RParams() { + neededTargs[i] = ts.Typ(rparam) + } + // For a named (defined) type, we have to change the name of the + // type as well. We do this first, so we can look up if we've + // already seen this type during this substitution or other + // definitions/substitutions. + genName := genericTypeName(t.Sym()) + newsym = t.Sym().Pkg.Lookup(InstTypeName(genName, neededTargs)) + if newsym.Def != nil { + // We've already created this instantiated defined type. + return newsym.Def.Type() + } + + // In order to deal with recursive generic types, create a TFORW + // type initially and set the Def field of its sym, so it can be + // found if this type appears recursively within the type. + forw = NewIncompleteNamedType(t.Pos(), newsym) + //println("Creating new type by sub", newsym.Name, forw.HasTParam()) + forw.SetRParams(neededTargs) + // Copy the OrigSym from the re-instantiated type (which is the sym of + // the base generic type). + assert(t.OrigSym != nil) + forw.OrigSym = t.OrigSym + } + + var newt *types.Type + + switch t.Kind() { + case types.TTYPEPARAM: + if t.Sym() == newsym { + // The substitution did not change the type. + return t + } + // Substitute the underlying typeparam (e.g. T in P[T], see + // the example describing type P[T] above). + newt = ts.Typ(t.Underlying()) + assert(newt != t) + + case types.TARRAY: + elem := t.Elem() + newelem := ts.Typ(elem) + if newelem != elem { + newt = types.NewArray(newelem, t.NumElem()) + } + + case types.TPTR: + elem := t.Elem() + newelem := ts.Typ(elem) + if newelem != elem { + newt = types.NewPtr(newelem) + } + + case types.TSLICE: + elem := t.Elem() + newelem := ts.Typ(elem) + if newelem != elem { + newt = types.NewSlice(newelem) + } + + case types.TSTRUCT: + newt = ts.tstruct(t, false) + if newt == t { + newt = nil + } + + case types.TFUNC: + newrecvs := ts.tstruct(t.Recvs(), false) + newparams := ts.tstruct(t.Params(), false) + newresults := ts.tstruct(t.Results(), false) + if newrecvs != t.Recvs() || newparams != t.Params() || newresults != t.Results() { + // If any types have changed, then the all the fields of + // of recv, params, and results must be copied, because they have + // offset fields that are dependent, and so must have an + // independent copy for each new signature. + var newrecv *types.Field + if newrecvs.NumFields() > 0 { + if newrecvs == t.Recvs() { + newrecvs = ts.tstruct(t.Recvs(), true) + } + newrecv = newrecvs.Field(0) + } + if newparams == t.Params() { + newparams = ts.tstruct(t.Params(), true) + } + if newresults == t.Results() { + newresults = ts.tstruct(t.Results(), true) + } + newt = types.NewSignature(t.Pkg(), newrecv, t.TParams().FieldSlice(), newparams.FieldSlice(), newresults.FieldSlice()) + } + + case types.TINTER: + newt = ts.tinter(t) + if newt == t { + newt = nil + } + + case types.TMAP: + newkey := ts.Typ(t.Key()) + newval := ts.Typ(t.Elem()) + if newkey != t.Key() || newval != t.Elem() { + newt = types.NewMap(newkey, newval) + } + + case types.TCHAN: + elem := t.Elem() + newelem := ts.Typ(elem) + if newelem != elem { + newt = types.NewChan(newelem, t.ChanDir()) + if !newt.HasTParam() { + // TODO(danscales): not sure why I have to do this + // only for channels..... + types.CheckSize(newt) + } + } + case types.TFORW: + if ts.SubstForwFunc != nil { + newt = ts.SubstForwFunc(t) + } else { + assert(false) + } + } + if newt == nil { + // Even though there were typeparams in the type, there may be no + // change if this is a function type for a function call (which will + // have its own tparams/targs in the function instantiation). + return t + } + + if t.Sym() == nil { + // Not a named type, so there was no forwarding type and there are + // no methods to substitute. + assert(t.Methods().Len() == 0) + return newt + } + + forw.SetUnderlying(newt) + newt = forw + + if t.Kind() != types.TINTER && t.Methods().Len() > 0 { + // Fill in the method info for the new type. + var newfields []*types.Field + newfields = make([]*types.Field, t.Methods().Len()) + for i, f := range t.Methods().Slice() { + t2 := ts.Typ(f.Type) + oldsym := f.Nname.Sym() + newsym := MakeInstName(oldsym, ts.Targs, true) + var nname *ir.Name + if newsym.Def != nil { + nname = newsym.Def.(*ir.Name) + } else { + nname = ir.NewNameAt(f.Pos, newsym) + nname.SetType(t2) + newsym.Def = nname + } + newfields[i] = types.NewField(f.Pos, f.Sym, t2) + newfields[i].Nname = nname + } + newt.Methods().Set(newfields) + if !newt.HasTParam() { + // Generate all the methods for a new fully-instantiated type. + ts.InstTypeList = append(ts.InstTypeList, newt) + } + } + return newt +} + +// tstruct substitutes type params in types of the fields of a structure type. For +// each field, tstruct copies the Nname, and translates it if Nname is in +// ts.vars. To always force the creation of a new (top-level) struct, +// regardless of whether anything changed with the types or names of the struct's +// fields, set force to true. +func (ts *Tsubster) tstruct(t *types.Type, force bool) *types.Type { + if t.NumFields() == 0 { + if t.HasTParam() { + // For an empty struct, we need to return a new type, + // since it may now be fully instantiated (HasTParam + // becomes false). + return types.NewStruct(t.Pkg(), nil) + } + return t + } + var newfields []*types.Field + if force { + newfields = make([]*types.Field, t.NumFields()) + } + for i, f := range t.Fields().Slice() { + t2 := ts.Typ(f.Type) + if (t2 != f.Type || f.Nname != nil) && newfields == nil { + newfields = make([]*types.Field, t.NumFields()) + for j := 0; j < i; j++ { + newfields[j] = t.Field(j) + } + } + if newfields != nil { + // TODO(danscales): make sure this works for the field + // names of embedded types (which should keep the name of + // the type param, not the instantiated type). + newfields[i] = types.NewField(f.Pos, f.Sym, t2) + if f.Nname != nil && ts.Vars != nil { + v := ts.Vars[f.Nname.(*ir.Name)] + if v != nil { + // This is the case where we are + // translating the type of the function we + // are substituting, so its dcls are in + // the subst.ts.vars table, and we want to + // change to reference the new dcl. + newfields[i].Nname = v + } else { + // This is the case where we are + // translating the type of a function + // reference inside the function we are + // substituting, so we leave the Nname + // value as is. + newfields[i].Nname = f.Nname + } + } + } + } + if newfields != nil { + return types.NewStruct(t.Pkg(), newfields) + } + return t + +} + +// tinter substitutes type params in types of the methods of an interface type. +func (ts *Tsubster) tinter(t *types.Type) *types.Type { + if t.Methods().Len() == 0 { + return t + } + var newfields []*types.Field + for i, f := range t.Methods().Slice() { + t2 := ts.Typ(f.Type) + if (t2 != f.Type || f.Nname != nil) && newfields == nil { + newfields = make([]*types.Field, t.Methods().Len()) + for j := 0; j < i; j++ { + newfields[j] = t.Methods().Index(j) + } + } + if newfields != nil { + newfields[i] = types.NewField(f.Pos, f.Sym, t2) + } + } + if newfields != nil { + return types.NewInterface(t.Pkg(), newfields) + } + return t +} + +// genericSym returns the name of the base generic type for the type named by +// sym. It simply returns the name obtained by removing everything after the +// first bracket ("["). +func genericTypeName(sym *types.Sym) string { + return sym.Name[0:strings.Index(sym.Name, "[")] +} diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index 20c4ff62a16..8e13b0ff187 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -767,8 +767,10 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { // uses of real() where the result is used to // define type and initialize a variable? - // construct a suitable new type parameter - tpar := NewTypeName(nopos, nil /* = Universe pkg */, "", nil) + // Construct a suitable new type parameter for the sum type. The + // type param is placed in the current package so export/import + // works as expected. + tpar := NewTypeName(nopos, check.pkg, "", nil) ptyp := check.NewTypeParam(tpar, 0, &emptyInterface) // assigns type to tpar as a side-effect tsum := newUnion(rtypes, tildes) ptyp.bound = &Interface{allMethods: markComplete, allTypes: tsum} diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index 604520d27f8..10cb651d0c2 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -640,9 +640,8 @@ type TypeParam struct { // Obj returns the type name for the type parameter t. func (t *TypeParam) Obj() *TypeName { return t.obj } -// NewTypeParam returns a new TypeParam. +// NewTypeParam returns a new TypeParam. bound can be nil (and set later). func (check *Checker) NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam { - assert(bound != nil) // Always increment lastID, even if it is not used. id := nextID() if check != nil { @@ -679,11 +678,20 @@ func (t *TypeParam) Bound() *Interface { return iface } -// optype returns a type's operational type. Except for type parameters, -// the operational type is the same as the underlying type (as returned -// by under). For Type parameters, the operational type is determined -// by the corresponding type constraint. The result may be the top type, -// but it is never the incoming type parameter. +func (t *TypeParam) SetBound(bound Type) { + if bound == nil { + panic("types2.TypeParam.SetBound: bound must not be nil") + } + t.bound = bound +} + +// optype returns a type's operational type. Except for +// type parameters, the operational type is the same +// as the underlying type (as returned by under). For +// Type parameters, the operational type is determined +// by the corresponding type bound's type list. The +// result may be the bottom or top type, but it is never +// the incoming type parameter. func optype(typ Type) Type { if t := asTypeParam(typ); t != nil { // If the optype is typ, return the top type as we have diff --git a/test/typeparam/absdiff.go b/test/typeparam/absdiff.go index ecaa907795d..e76a998b4d3 100644 --- a/test/typeparam/absdiff.go +++ b/test/typeparam/absdiff.go @@ -48,8 +48,7 @@ type Complex interface { type orderedAbs[T orderedNumeric] T func (a orderedAbs[T]) Abs() orderedAbs[T] { - // TODO(danscales): orderedAbs[T] conversion shouldn't be needed - if a < orderedAbs[T](0) { + if a < 0 { return -a } return a diff --git a/test/typeparam/absdiffimp.dir/a.go b/test/typeparam/absdiffimp.dir/a.go new file mode 100644 index 00000000000..df81dcf5387 --- /dev/null +++ b/test/typeparam/absdiffimp.dir/a.go @@ -0,0 +1,75 @@ +// Copyright 2021 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 a + +import ( + "math" +) + +type Numeric interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~complex64 | ~complex128 +} + +// numericAbs matches numeric types with an Abs method. +type numericAbs[T any] interface { + Numeric + Abs() T +} + +// AbsDifference computes the absolute value of the difference of +// a and b, where the absolute value is determined by the Abs method. +func absDifference[T numericAbs[T]](a, b T) T { + d := a - b + return d.Abs() +} + +// orderedNumeric matches numeric types that support the < operator. +type orderedNumeric interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 +} + +// Complex matches the two complex types, which do not have a < operator. +type Complex interface { + ~complex64 | ~complex128 +} + +// orderedAbs is a helper type that defines an Abs method for +// ordered numeric types. +type orderedAbs[T orderedNumeric] T + +func (a orderedAbs[T]) Abs() orderedAbs[T] { + if a < 0 { + return -a + } + return a +} + +// complexAbs is a helper type that defines an Abs method for +// complex types. +type complexAbs[T Complex] T + +func (a complexAbs[T]) Abs() complexAbs[T] { + r := float64(real(a)) + i := float64(imag(a)) + d := math.Sqrt(r * r + i * i) + return complexAbs[T](complex(d, 0)) +} + +// OrderedAbsDifference returns the absolute value of the difference +// between a and b, where a and b are of an ordered type. +func OrderedAbsDifference[T orderedNumeric](a, b T) T { + return T(absDifference(orderedAbs[T](a), orderedAbs[T](b))) +} + +// ComplexAbsDifference returns the absolute value of the difference +// between a and b, where a and b are of a complex type. +func ComplexAbsDifference[T Complex](a, b T) T { + return T(absDifference(complexAbs[T](a), complexAbs[T](b))) +} diff --git a/test/typeparam/absdiffimp.dir/main.go b/test/typeparam/absdiffimp.dir/main.go new file mode 100644 index 00000000000..8eefdbdf384 --- /dev/null +++ b/test/typeparam/absdiffimp.dir/main.go @@ -0,0 +1,29 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "a" + "fmt" +) + +func main() { + if got, want := a.OrderedAbsDifference(1.0, -2.0), 3.0; got != want { + panic(fmt.Sprintf("got = %v, want = %v", got, want)) + } + if got, want := a.OrderedAbsDifference(-1.0, 2.0), 3.0; got != want { + panic(fmt.Sprintf("got = %v, want = %v", got, want)) + } + if got, want := a.OrderedAbsDifference(-20, 15), 35; got != want { + panic(fmt.Sprintf("got = %v, want = %v", got, want)) + } + + if got, want := a.ComplexAbsDifference(5.0+2.0i, 2.0-2.0i), 5+0i; got != want { + panic(fmt.Sprintf("got = %v, want = %v", got, want)) + } + if got, want := a.ComplexAbsDifference(2.0-2.0i, 5.0+2.0i), 5+0i; got != want { + panic(fmt.Sprintf("got = %v, want = %v", got, want)) + } +} diff --git a/test/typeparam/absdiffimp.go b/test/typeparam/absdiffimp.go new file mode 100644 index 00000000000..76930e5e4f6 --- /dev/null +++ b/test/typeparam/absdiffimp.go @@ -0,0 +1,7 @@ +// rundir -G=3 + +// Copyright 2021 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 ignored diff --git a/test/typeparam/orderedmapsimp.dir/a.go b/test/typeparam/orderedmapsimp.dir/a.go new file mode 100644 index 00000000000..1b5827b4bb7 --- /dev/null +++ b/test/typeparam/orderedmapsimp.dir/a.go @@ -0,0 +1,226 @@ +// Copyright 2021 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 a + +import ( + "context" + "runtime" +) + +type Ordered interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string +} + +// Map is an ordered map. +type Map[K, V any] struct { + root *node[K, V] + compare func(K, K) int +} + +// node is the type of a node in the binary tree. +type node[K, V any] struct { + key K + val V + left, right *node[K, V] +} + +// New returns a new map. It takes a comparison function that compares two +// keys and returns < 0 if the first is less, == 0 if they are equal, +// > 0 if the first is greater. +func New[K, V any](compare func(K, K) int) *Map[K, V] { + return &Map[K, V]{compare: compare} +} + +// NewOrdered returns a new map whose key is an ordered type. +// This is like New, but does not require providing a compare function. +// The map compare function uses the obvious key ordering. +func NewOrdered[K Ordered, V any]() *Map[K, V] { + return New[K, V](func(k1, k2 K) int { + switch { + case k1 < k2: + return -1 + case k1 > k2: + return 1 + default: + return 0 + } + }) +} + +// find looks up key in the map, returning either a pointer to the slot of the +// node holding key, or a pointer to the slot where a node would go. +func (m *Map[K, V]) find(key K) **node[K, V] { + pn := &m.root + for *pn != nil { + switch cmp := m.compare(key, (*pn).key); { + case cmp < 0: + pn = &(*pn).left + case cmp > 0: + pn = &(*pn).right + default: + return pn + } + } + return pn +} + +// Insert inserts a new key/value into the map. +// If the key is already present, the value is replaced. +// Reports whether this is a new key. +func (m *Map[K, V]) Insert(key K, val V) bool { + pn := m.find(key) + if *pn != nil { + (*pn).val = val + return false + } + *pn = &node[K, V]{key: key, val: val} + return true +} + +// Find returns the value associated with a key, or the zero value +// if not present. The second result reports whether the key was found. +func (m *Map[K, V]) Find(key K) (V, bool) { + pn := m.find(key) + if *pn == nil { + var zero V + return zero, false + } + return (*pn).val, true +} + +// keyValue is a pair of key and value used while iterating. +type keyValue[K, V any] struct { + key K + val V +} + +// iterate returns an iterator that traverses the map. +// func (m *Map[K, V]) Iterate() *Iterator[K, V] { +// sender, receiver := Ranger[keyValue[K, V]]() +// var f func(*node[K, V]) bool +// f = func(n *node[K, V]) bool { +// if n == nil { +// return true +// } +// // Stop the traversal if Send fails, which means that +// // nothing is listening to the receiver. +// return f(n.left) && +// sender.Send(context.Background(), keyValue[K, V]{n.key, n.val}) && +// f(n.right) +// } +// go func() { +// f(m.root) +// sender.Close() +// }() +// return &Iterator[K, V]{receiver} +// } + +// Iterator is used to iterate over the map. +type Iterator[K, V any] struct { + r *Receiver[keyValue[K, V]] +} + +// Next returns the next key and value pair, and a boolean that reports +// whether they are valid. If not valid, we have reached the end of the map. +func (it *Iterator[K, V]) Next() (K, V, bool) { + keyval, ok := it.r.Next(context.Background()) + if !ok { + var zerok K + var zerov V + return zerok, zerov, false + } + return keyval.key, keyval.val, true +} + +// Equal reports whether two slices are equal: the same length and all +// elements equal. All floating point NaNs are considered equal. +func SliceEqual[Elem comparable](s1, s2 []Elem) bool { + if len(s1) != len(s2) { + return false + } + for i, v1 := range s1 { + v2 := s2[i] + if v1 != v2 { + isNaN := func(f Elem) bool { return f != f } + if !isNaN(v1) || !isNaN(v2) { + return false + } + } + } + return true +} + +// Ranger returns a Sender and a Receiver. The Receiver provides a +// Next method to retrieve values. The Sender provides a Send method +// to send values and a Close method to stop sending values. The Next +// method indicates when the Sender has been closed, and the Send +// method indicates when the Receiver has been freed. +// +// This is a convenient way to exit a goroutine sending values when +// the receiver stops reading them. +func Ranger[Elem any]() (*Sender[Elem], *Receiver[Elem]) { + c := make(chan Elem) + d := make(chan struct{}) + s := &Sender[Elem]{ + values: c, + done: d, + } + r := &Receiver[Elem] { + values: c, + done: d, + } + runtime.SetFinalizer(r, (*Receiver[Elem]).finalize) + return s, r +} + +// A Sender is used to send values to a Receiver. +type Sender[Elem any] struct { + values chan<- Elem + done <-chan struct{} +} + +// Send sends a value to the receiver. It reports whether the value was sent. +// The value will not be sent if the context is closed or the receiver +// is freed. +func (s *Sender[Elem]) Send(ctx context.Context, v Elem) bool { + select { + case <-ctx.Done(): + return false + case s.values <- v: + return true + case <-s.done: + return false + } +} + +// Close tells the receiver that no more values will arrive. +// After Close is called, the Sender may no longer be used. +func (s *Sender[Elem]) Close() { + close(s.values) +} + +// A Receiver receives values from a Sender. +type Receiver[Elem any] struct { + values <-chan Elem + done chan<- struct{} +} + +// Next returns the next value from the channel. The bool result indicates +// whether the value is valid. +func (r *Receiver[Elem]) Next(ctx context.Context) (v Elem, ok bool) { + select { + case <-ctx.Done(): + case v, ok = <-r.values: + } + return v, ok +} + +// finalize is a finalizer for the receiver. +func (r *Receiver[Elem]) finalize() { + close(r.done) +} diff --git a/test/typeparam/orderedmapsimp.dir/main.go b/test/typeparam/orderedmapsimp.dir/main.go new file mode 100644 index 00000000000..77869ad9fcb --- /dev/null +++ b/test/typeparam/orderedmapsimp.dir/main.go @@ -0,0 +1,67 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "a" + "bytes" + "fmt" +) + +func TestMap() { + m := a.New[[]byte, int](bytes.Compare) + + if _, found := m.Find([]byte("a")); found { + panic(fmt.Sprintf("unexpectedly found %q in empty map", []byte("a"))) + } + + for _, c := range []int{ 'a', 'c', 'b' } { + if !m.Insert([]byte(string(c)), c) { + panic(fmt.Sprintf("key %q unexpectedly already present", []byte(string(c)))) + } + } + if m.Insert([]byte("c"), 'x') { + panic(fmt.Sprintf("key %q unexpectedly not present", []byte("c"))) + } + + if v, found := m.Find([]byte("a")); !found { + panic(fmt.Sprintf("did not find %q", []byte("a"))) + } else if v != 'a' { + panic(fmt.Sprintf("key %q returned wrong value %c, expected %c", []byte("a"), v, 'a')) + } + if v, found := m.Find([]byte("c")); !found { + panic(fmt.Sprintf("did not find %q", []byte("c"))) + } else if v != 'x' { + panic(fmt.Sprintf("key %q returned wrong value %c, expected %c", []byte("c"), v, 'x')) + } + + if _, found := m.Find([]byte("d")); found { + panic(fmt.Sprintf("unexpectedly found %q", []byte("d"))) + } + + // TODO(danscales): Iterate() has some things to be fixed with inlining in + // stenciled functions and using closures across packages. + + // gather := func(it *a.Iterator[[]byte, int]) []int { + // var r []int + // for { + // _, v, ok := it.Next() + // if !ok { + // return r + // } + // r = append(r, v) + // } + // } + // got := gather(m.Iterate()) + // want := []int{'a', 'b', 'x'} + // if !a.SliceEqual(got, want) { + // panic(fmt.Sprintf("Iterate returned %v, want %v", got, want)) + // } + +} + +func main() { + TestMap() +} diff --git a/test/typeparam/orderedmapsimp.go b/test/typeparam/orderedmapsimp.go new file mode 100644 index 00000000000..76930e5e4f6 --- /dev/null +++ b/test/typeparam/orderedmapsimp.go @@ -0,0 +1,7 @@ +// rundir -G=3 + +// Copyright 2021 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 ignored diff --git a/test/typeparam/value.go b/test/typeparam/value.go index 5dd7449d9c7..6c6dabcf7ca 100644 --- a/test/typeparam/value.go +++ b/test/typeparam/value.go @@ -12,7 +12,7 @@ type value[T any] struct { val T } -func get[T2 any](v *value[T2]) T2 { +func get[T any](v *value[T]) T { return v.val } @@ -20,11 +20,11 @@ func set[T any](v *value[T], val T) { v.val = val } -func (v *value[T2]) set(val T2) { +func (v *value[T]) set(val T) { v.val = val } -func (v *value[T2]) get() T2 { +func (v *value[T]) get() T { return v.val } From 46beeed0ac4cd409554167c315861eaf8ae68c4a Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 3 Jun 2021 18:25:47 -0400 Subject: [PATCH 295/940] [dev.typeparams] cmd/compile: allow go'd closure to escape when compiling runtime When compiling runtime, we don't allow closures to escape, because we don't want (implicit) allocations to occur when it is not okay to allocate (e.g. in the allocator itself). However, for go statement, it already allocates a new goroutine anyway. It is okay to allocate the closure. Allow it. Also include the closure's name when reporting error. Updates #40724. Change-Id: Id7574ed17cc27709609a059c4eaa67ba1c4436dc Reviewed-on: https://go-review.googlesource.com/c/go/+/325109 Trust: Cherry Mui Reviewed-by: Than McIntosh --- src/cmd/compile/internal/ir/expr.go | 1 + src/cmd/compile/internal/ir/func.go | 4 ++-- src/cmd/compile/internal/walk/order.go | 14 ++++++-------- test/fixedbugs/issue14999.go | 4 ++-- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/cmd/compile/internal/ir/expr.go b/src/cmd/compile/internal/ir/expr.go index 519120ed6b8..856b2556575 100644 --- a/src/cmd/compile/internal/ir/expr.go +++ b/src/cmd/compile/internal/ir/expr.go @@ -192,6 +192,7 @@ type ClosureExpr struct { miniExpr Func *Func `mknode:"-"` Prealloc *Name + IsGoWrap bool // whether this is wrapper closure of a go statement } func NewClosureExpr(pos src.XPos, fn *Func) *ClosureExpr { diff --git a/src/cmd/compile/internal/ir/func.go b/src/cmd/compile/internal/ir/func.go index ca6c8eca8b7..1d76813a4c3 100644 --- a/src/cmd/compile/internal/ir/func.go +++ b/src/cmd/compile/internal/ir/func.go @@ -301,8 +301,8 @@ func ClosureDebugRuntimeCheck(clo *ClosureExpr) { base.WarnfAt(clo.Pos(), "stack closure, captured vars = %v", clo.Func.ClosureVars) } } - if base.Flag.CompilingRuntime && clo.Esc() == EscHeap { - base.ErrorfAt(clo.Pos(), "heap-allocated closure, not allowed in runtime") + if base.Flag.CompilingRuntime && clo.Esc() == EscHeap && !clo.IsGoWrap { + base.ErrorfAt(clo.Pos(), "heap-allocated closure %s, not allowed in runtime", FuncName(clo.Func)) } } diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go index b733d3a29f6..19d9551566e 100644 --- a/src/cmd/compile/internal/walk/order.go +++ b/src/cmd/compile/internal/walk/order.go @@ -1570,8 +1570,9 @@ func (o *orderState) wrapGoDefer(n *ir.GoDeferStmt) { // only in-register results? if len(callArgs) == 0 && call.Op() == ir.OCALLFUNC && callX.Type().NumResults() == 0 { if c, ok := call.(*ir.CallExpr); ok && callX != nil && callX.Op() == ir.OCLOSURE { - cloFunc := callX.(*ir.ClosureExpr).Func - cloFunc.SetClosureCalled(false) + clo := callX.(*ir.ClosureExpr) + clo.Func.SetClosureCalled(false) + clo.IsGoWrap = true c.PreserveClosure = true } return @@ -1777,12 +1778,9 @@ func (o *orderState) wrapGoDefer(n *ir.GoDeferStmt) { // Set escape properties for closure. if n.Op() == ir.OGO { - // For "go", assume that the closure is going to escape - // (with an exception for the runtime, which doesn't - // permit heap-allocated closures). - if base.Ctxt.Pkgpath != "runtime" { - clo.SetEsc(ir.EscHeap) - } + // For "go", assume that the closure is going to escape. + clo.SetEsc(ir.EscHeap) + clo.IsGoWrap = true } else { // For defer, just use whatever result escape analysis // has determined for the defer. diff --git a/test/fixedbugs/issue14999.go b/test/fixedbugs/issue14999.go index b648441fc29..a25a50e519a 100644 --- a/test/fixedbugs/issue14999.go +++ b/test/fixedbugs/issue14999.go @@ -7,11 +7,11 @@ package p func f(x int) func(int) int { - return func(y int) int { return x + y } // ERROR "heap-allocated closure, not allowed in runtime" + return func(y int) int { return x + y } // ERROR "heap-allocated closure f\.func1, not allowed in runtime" } func g(x int) func(int) int { // ERROR "x escapes to heap, not allowed in runtime" - return func(y int) int { // ERROR "heap-allocated closure, not allowed in runtime" + return func(y int) int { // ERROR "heap-allocated closure g\.func1, not allowed in runtime" x += y return x + y } From 3298c749acc32eca0460f52866d169441eb0e076 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 3 Jun 2021 18:29:05 -0400 Subject: [PATCH 296/940] [dev.typeparams] runtime: undo go'd closure argument workaround In CL 298669 we added defer/go wrapping, and, as it is not allowed for closures to escape when compiling runtime, we worked around it by rewriting go'd closures to argumentless non-capturing closures, so it is not a real closure and so not needed to escape. Previous CL removes the restriction. Now we can undo the workaround. Updates #40724. Change-Id: Ic7bf129da4aee7b7fdb7157414eca943a6a27264 Reviewed-on: https://go-review.googlesource.com/c/go/+/325110 Trust: Cherry Mui Reviewed-by: Than McIntosh --- src/runtime/export_test.go | 20 ++++---------------- src/runtime/mgc.go | 15 +++++---------- src/runtime/mgcscavenge.go | 4 ++-- src/runtime/mgcsweep.go | 4 ++-- 4 files changed, 13 insertions(+), 30 deletions(-) diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index fa878c4946e..60c06c3f10e 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -145,40 +145,28 @@ func RunSchedLocalQueueStealTest() { } } -// Temporary to enable register ABI bringup. -// TODO(register args): convert back to local variables in RunSchedLocalQueueEmptyTest that -// get passed to the "go" stmts there. -var RunSchedLocalQueueEmptyState struct { - done chan bool - ready *uint32 - p *p -} - func RunSchedLocalQueueEmptyTest(iters int) { // Test that runq is not spuriously reported as empty. // Runq emptiness affects scheduling decisions and spurious emptiness // can lead to underutilization (both runnable Gs and idle Ps coexist // for arbitrary long time). done := make(chan bool, 1) - RunSchedLocalQueueEmptyState.done = done p := new(p) - RunSchedLocalQueueEmptyState.p = p gs := make([]g, 2) ready := new(uint32) - RunSchedLocalQueueEmptyState.ready = ready for i := 0; i < iters; i++ { *ready = 0 next0 := (i & 1) == 0 next1 := (i & 2) == 0 runqput(p, &gs[0], next0) go func() { - for atomic.Xadd(RunSchedLocalQueueEmptyState.ready, 1); atomic.Load(RunSchedLocalQueueEmptyState.ready) != 2; { + for atomic.Xadd(ready, 1); atomic.Load(ready) != 2; { } - if runqempty(RunSchedLocalQueueEmptyState.p) { - //println("next:", next0, next1) + if runqempty(p) { + println("next:", next0, next1) throw("queue is empty") } - RunSchedLocalQueueEmptyState.done <- true + done <- true }() for atomic.Xadd(ready, 1); atomic.Load(ready) != 2; { } diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index 45856635353..c239fa0f636 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -167,22 +167,17 @@ func gcinit() { lockInit(&work.wbufSpans.lock, lockRankWbufSpans) } -// Temporary in order to enable register ABI work. -// TODO(register args): convert back to local chan in gcenabled, passed to "go" stmts. -var gcenable_setup chan int - // gcenable is called after the bulk of the runtime initialization, // just before we're about to start letting user code run. // It kicks off the background sweeper goroutine, the background // scavenger goroutine, and enables GC. func gcenable() { // Kick off sweeping and scavenging. - gcenable_setup = make(chan int, 2) - go bgsweep() - go bgscavenge() - <-gcenable_setup - <-gcenable_setup - gcenable_setup = nil + c := make(chan int, 2) + go bgsweep(c) + go bgscavenge(c) + <-c + <-c memstats.enablegc = true // now that runtime is initialized, GC is okay } diff --git a/src/runtime/mgcscavenge.go b/src/runtime/mgcscavenge.go index 7578129f9d1..9cb61ed0a61 100644 --- a/src/runtime/mgcscavenge.go +++ b/src/runtime/mgcscavenge.go @@ -249,7 +249,7 @@ func scavengeSleep(ns int64) int64 { // The background scavenger maintains the RSS of the application below // the line described by the proportional scavenging statistics in // the mheap struct. -func bgscavenge() { +func bgscavenge(c chan int) { scavenge.g = getg() lockInit(&scavenge.lock, lockRankScavenge) @@ -261,7 +261,7 @@ func bgscavenge() { wakeScavenger() } - gcenable_setup <- 1 + c <- 1 goparkunlock(&scavenge.lock, waitReasonGCScavengeWait, traceEvGoBlock, 1) // Exponentially-weighted moving average of the fraction of time this diff --git a/src/runtime/mgcsweep.go b/src/runtime/mgcsweep.go index 8fe3a653407..1812644623b 100644 --- a/src/runtime/mgcsweep.go +++ b/src/runtime/mgcsweep.go @@ -153,13 +153,13 @@ func finishsweep_m() { nextMarkBitArenaEpoch() } -func bgsweep() { +func bgsweep(c chan int) { sweep.g = getg() lockInit(&sweep.lock, lockRankSweep) lock(&sweep.lock) sweep.parked = true - gcenable_setup <- 1 + c <- 1 goparkunlock(&sweep.lock, waitReasonGCSweepWait, traceEvGoBlock, 1) for { From 4cf7f5f6947c1e3200d669ae7b8016f7431d718c Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Fri, 4 Jun 2021 11:09:25 -0400 Subject: [PATCH 297/940] [dev.typeparams] test: test regabidefers in live.go Previously, live.go is conditioned on not using regabidefers. Now we have regabidefers enabled by default everywhere, and we may remove the fallback path in the near future, test that configuration instead. Change-Id: Idf910aee323bdd6478bc7a2062b2052d82ce003f Reviewed-on: https://go-review.googlesource.com/c/go/+/325111 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- test/live.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/live.go b/test/live.go index bc7b3849cf3..ee51134371e 100644 --- a/test/live.go +++ b/test/live.go @@ -1,5 +1,5 @@ // errorcheckwithauto -0 -l -live -wb=0 -d=ssa/insert_resched_checks/off -// +build !ppc64,!ppc64le,!goexperiment.regabi,!goexperiment.regabidefer +// +build !ppc64,!ppc64le,goexperiment.regabidefer,!goexperiment.regabiargs // ppc64 needs a better tighten pass to make f18 pass // rescheduling checks need to be turned off because there are some live variables across the inserted check call @@ -424,7 +424,7 @@ func f27defer(b bool) { } defer call27(func() { x++ }) // ERROR "stack object .autotmp_[0-9]+ struct \{" printnl() // ERROR "live at call to printnl: .autotmp_[0-9]+ .autotmp_[0-9]+" - return // ERROR "live at call to call27: .autotmp_[0-9]+" + return // ERROR "live at indirect call: .autotmp_[0-9]+" } // and newproc (go) escapes to the heap @@ -432,9 +432,9 @@ func f27defer(b bool) { func f27go(b bool) { x := 0 if b { - go call27(func() { x++ }) // ERROR "live at call to newobject: &x$" "live at call to newproc: &x$" + go call27(func() { x++ }) // ERROR "live at call to newobject: &x$" "live at call to newobject: &x .autotmp_[0-9]+$" "live at call to newproc: &x$" // allocate two closures, the func literal, and the wrapper for go } - go call27(func() { x++ }) // ERROR "live at call to newobject: &x$" + go call27(func() { x++ }) // ERROR "live at call to newobject: &x$" "live at call to newobject: .autotmp_[0-9]+$" // allocate two closures, the func literal, and the wrapper for go printnl() } From 105c5b50e0098720b9e24aea5efa8e161c31db6d Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Tue, 25 May 2021 16:23:16 +0200 Subject: [PATCH 298/940] os: terminate windows processes via handle directly We already have a handle to the process, so use that for termination, rather than doing a new lookup based on the PID. Change-Id: I2958c1817f12f3dd783412baacbf629049f6956a Reviewed-on: https://go-review.googlesource.com/c/go/+/322509 Trust: Jason A. Donenfeld Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/os/exec_windows.go | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/os/exec_windows.go b/src/os/exec_windows.go index 5710401acdb..b59a01a75e9 100644 --- a/src/os/exec_windows.go +++ b/src/os/exec_windows.go @@ -45,16 +45,6 @@ func (p *Process) wait() (ps *ProcessState, err error) { return &ProcessState{p.Pid, syscall.WaitStatus{ExitCode: ec}, &u}, nil } -func terminateProcess(pid, exitcode int) error { - h, e := syscall.OpenProcess(syscall.PROCESS_TERMINATE, false, uint32(pid)) - if e != nil { - return NewSyscallError("OpenProcess", e) - } - defer syscall.CloseHandle(h) - e = syscall.TerminateProcess(h, uint32(exitcode)) - return NewSyscallError("TerminateProcess", e) -} - func (p *Process) signal(sig Signal) error { handle := atomic.LoadUintptr(&p.handle) if handle == uintptr(syscall.InvalidHandle) { @@ -64,9 +54,15 @@ func (p *Process) signal(sig Signal) error { return ErrProcessDone } if sig == Kill { - err := terminateProcess(p.Pid, 1) + var terminationHandle syscall.Handle + e := syscall.DuplicateHandle(^syscall.Handle(0), syscall.Handle(handle), ^syscall.Handle(0), &terminationHandle, syscall.PROCESS_TERMINATE, false, 0) + if e != nil { + return NewSyscallError("DuplicateHandle", e) + } runtime.KeepAlive(p) - return err + defer syscall.CloseHandle(terminationHandle) + e = syscall.TerminateProcess(syscall.Handle(terminationHandle), 1) + return NewSyscallError("TerminateProcess", e) } // TODO(rsc): Handle Interrupt too? return syscall.Errno(syscall.EWINDOWS) From 3a9d906edcfd0fa574ecd5498f8999b56f1e5fa1 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Tue, 25 May 2021 16:24:41 +0200 Subject: [PATCH 299/940] os: avoid finalizer race in windows process object If proc.Release is called concurrently, a handle will be double-freed. Change-Id: I0c0c32e312e07bc8615e0bf9e9b691214444d8d5 Reviewed-on: https://go-review.googlesource.com/c/go/+/322510 Trust: Jason A. Donenfeld Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/os/exec_windows.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/os/exec_windows.go b/src/os/exec_windows.go index b59a01a75e9..239bed198f7 100644 --- a/src/os/exec_windows.go +++ b/src/os/exec_windows.go @@ -69,7 +69,7 @@ func (p *Process) signal(sig Signal) error { } func (p *Process) release() error { - handle := atomic.LoadUintptr(&p.handle) + handle := atomic.SwapUintptr(&p.handle, uintptr(syscall.InvalidHandle)) if handle == uintptr(syscall.InvalidHandle) { return syscall.EINVAL } @@ -77,7 +77,6 @@ func (p *Process) release() error { if e != nil { return NewSyscallError("CloseHandle", e) } - atomic.StoreUintptr(&p.handle, uintptr(syscall.InvalidHandle)) // no need for a finalizer anymore runtime.SetFinalizer(p, nil) return nil From 831f9376d8d730b16fb33dfd775618dffe13ce7a Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Fri, 12 Mar 2021 13:53:11 -0800 Subject: [PATCH 300/940] net/http: fix ResponseWriter.ReadFrom with short reads CL 249238 changes ResponseWriter.ReadFrom to probe the source with a single read of sniffLen bytes before writing the response header. If the source returns less than sniffLen bytes without reaching EOF, this can cause Content-Type and Content-Length detection to fail. Fix ResponseWrite.ReadFrom to copy a full sniffLen bytes from the source as a probe. Drop the explicit call to w.WriteHeader; writing the probe will trigger a WriteHeader call. Consistently use io.CopyBuffer; ReadFrom has already acquired a copy buffer, so it may as well use it. Fixes #44953. Change-Id: Ic49305fb827a2bd7da4764b68d64b797b5157dc0 Reviewed-on: https://go-review.googlesource.com/c/go/+/301449 Trust: Damien Neil Run-TryBot: Damien Neil TryBot-Result: Go Bot Reviewed-by: Brad Fitzpatrick --- src/net/http/server.go | 40 +++--------- src/net/http/sniff_test.go | 122 +++++++++++++++++++++++++++++-------- 2 files changed, 107 insertions(+), 55 deletions(-) diff --git a/src/net/http/server.go b/src/net/http/server.go index 4e73508973a..430019de509 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -577,37 +577,17 @@ func (w *response) ReadFrom(src io.Reader) (n int64, err error) { return io.CopyBuffer(writerOnly{w}, src, buf) } - // sendfile path: - - // Do not start actually writing response until src is readable. - // If body length is <= sniffLen, sendfile/splice path will do - // little anyway. This small read also satisfies sniffing the - // body in case Content-Type is missing. - nr, er := src.Read(buf[:sniffLen]) - atEOF := errors.Is(er, io.EOF) - n += int64(nr) - - if nr > 0 { - // Write the small amount read normally. - nw, ew := w.Write(buf[:nr]) - if ew != nil { - err = ew - } else if nr != nw { - err = io.ErrShortWrite + // Copy the first sniffLen bytes before switching to ReadFrom. + // This ensures we don't start writing the response before the + // source is available (see golang.org/issue/5660) and provides + // enough bytes to perform Content-Type sniffing when required. + if !w.cw.wroteHeader { + n0, err := io.CopyBuffer(writerOnly{w}, io.LimitReader(src, sniffLen), buf) + n += n0 + if err != nil || n0 < sniffLen { + return n, err } } - if err == nil && er != nil && !atEOF { - err = er - } - - // Do not send StatusOK in the error case where nothing has been written. - if err == nil && !w.wroteHeader { - w.WriteHeader(StatusOK) // nr == 0, no error (or EOF) - } - - if err != nil || atEOF { - return n, err - } w.w.Flush() // get rid of any previous writes w.cw.flush() // make sure Header is written; flush data to rwc @@ -620,7 +600,7 @@ func (w *response) ReadFrom(src io.Reader) (n int64, err error) { return n, err } - n0, err := io.Copy(writerOnly{w}, src) + n0, err := io.CopyBuffer(writerOnly{w}, src, buf) n += n0 return n, err } diff --git a/src/net/http/sniff_test.go b/src/net/http/sniff_test.go index 8d5350374dd..e91335729af 100644 --- a/src/net/http/sniff_test.go +++ b/src/net/http/sniff_test.go @@ -157,9 +157,25 @@ func testServerIssue5953(t *testing.T, h2 bool) { resp.Body.Close() } -func TestContentTypeWithCopy_h1(t *testing.T) { testContentTypeWithCopy(t, h1Mode) } -func TestContentTypeWithCopy_h2(t *testing.T) { testContentTypeWithCopy(t, h2Mode) } -func testContentTypeWithCopy(t *testing.T, h2 bool) { +type byteAtATimeReader struct { + buf []byte +} + +func (b *byteAtATimeReader) Read(p []byte) (n int, err error) { + if len(p) < 1 { + return 0, nil + } + if len(b.buf) == 0 { + return 0, io.EOF + } + p[0] = b.buf[0] + b.buf = b.buf[1:] + return 1, nil +} + +func TestContentTypeWithVariousSources_h1(t *testing.T) { testContentTypeWithVariousSources(t, h1Mode) } +func TestContentTypeWithVariousSources_h2(t *testing.T) { testContentTypeWithVariousSources(t, h2Mode) } +func testContentTypeWithVariousSources(t *testing.T, h2 bool) { defer afterTest(t) const ( @@ -167,30 +183,86 @@ func testContentTypeWithCopy(t *testing.T, h2 bool) { expected = "text/html; charset=utf-8" ) - cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { - // Use io.Copy from a bytes.Buffer to trigger ReadFrom. - buf := bytes.NewBuffer([]byte(input)) - n, err := io.Copy(w, buf) - if int(n) != len(input) || err != nil { - t.Errorf("io.Copy(w, %q) = %v, %v want %d, nil", input, n, err, len(input)) - } - })) - defer cst.close() + for _, test := range []struct { + name string + handler func(ResponseWriter, *Request) + }{{ + name: "write", + handler: func(w ResponseWriter, r *Request) { + // Write the whole input at once. + n, err := w.Write([]byte(input)) + if int(n) != len(input) || err != nil { + t.Errorf("w.Write(%q) = %v, %v want %d, nil", input, n, err, len(input)) + } + }, + }, { + name: "write one byte at a time", + handler: func(w ResponseWriter, r *Request) { + // Write the input one byte at a time. + buf := []byte(input) + for i := range buf { + n, err := w.Write(buf[i : i+1]) + if n != 1 || err != nil { + t.Errorf("w.Write(%q) = %v, %v want 1, nil", input, n, err) + } + } + }, + }, { + name: "copy from Reader", + handler: func(w ResponseWriter, r *Request) { + // Use io.Copy from a plain Reader. + type readerOnly struct{ io.Reader } + buf := bytes.NewBuffer([]byte(input)) + n, err := io.Copy(w, readerOnly{buf}) + if int(n) != len(input) || err != nil { + t.Errorf("io.Copy(w, %q) = %v, %v want %d, nil", input, n, err, len(input)) + } + }, + }, { + name: "copy from bytes.Buffer", + handler: func(w ResponseWriter, r *Request) { + // Use io.Copy from a bytes.Buffer to trigger ReadFrom. + buf := bytes.NewBuffer([]byte(input)) + n, err := io.Copy(w, buf) + if int(n) != len(input) || err != nil { + t.Errorf("io.Copy(w, %q) = %v, %v want %d, nil", input, n, err, len(input)) + } + }, + }, { + name: "copy one byte at a time", + handler: func(w ResponseWriter, r *Request) { + // Use io.Copy from a Reader that returns one byte at a time. + n, err := io.Copy(w, &byteAtATimeReader{[]byte(input)}) + if int(n) != len(input) || err != nil { + t.Errorf("io.Copy(w, %q) = %v, %v want %d, nil", input, n, err, len(input)) + } + }, + }} { + t.Run(test.name, func(t *testing.T) { + cst := newClientServerTest(t, h2, HandlerFunc(test.handler)) + defer cst.close() + + resp, err := cst.c.Get(cst.ts.URL) + if err != nil { + t.Fatalf("Get: %v", err) + } + if ct := resp.Header.Get("Content-Type"); ct != expected { + t.Errorf("Content-Type = %q, want %q", ct, expected) + } + if want, got := resp.Header.Get("Content-Length"), fmt.Sprint(len(input)); want != got { + t.Errorf("Content-Length = %q, want %q", want, got) + } + data, err := io.ReadAll(resp.Body) + if err != nil { + t.Errorf("reading body: %v", err) + } else if !bytes.Equal(data, []byte(input)) { + t.Errorf("data is %q, want %q", data, input) + } + resp.Body.Close() + + }) - resp, err := cst.c.Get(cst.ts.URL) - if err != nil { - t.Fatalf("Get: %v", err) } - if ct := resp.Header.Get("Content-Type"); ct != expected { - t.Errorf("Content-Type = %q, want %q", ct, expected) - } - data, err := io.ReadAll(resp.Body) - if err != nil { - t.Errorf("reading body: %v", err) - } else if !bytes.Equal(data, []byte(input)) { - t.Errorf("data is %q, want %q", data, input) - } - resp.Body.Close() } func TestSniffWriteSize_h1(t *testing.T) { testSniffWriteSize(t, h1Mode) } From de614651561c6d5bfe1e68bddaf0dedab9a0ecb0 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Tue, 1 Jun 2021 10:49:14 -0700 Subject: [PATCH 301/940] [dev.typeparams] cmd/compile: allow inlining in instantiated functions Change markType to scan generic types and methods, so that inlineable functions inside generic functions/methods will be properly marked for export, which means inlining inside instantiated functions will work correctly. Also, fix handling of closures for instantiated functions. Some code needs to be adjusted, since instantiated functions/methods are compiled as if in the package of the source generic function/type, rather than in the local package. When we create the closure struct, we want to make sure that the .F field has the same package as the other fields for the closure variables. Also, we need to disable a check in tcCompLit() when being done for an instantiated function, since fields of the closure struct will be from the source package, not the local package. Re-enabled part of the orderedmapsimp test that was disabled because of these issues. Change-Id: Ic4dba8917da0a36b17c0bdb69d6d6edfdf14104a Reviewed-on: https://go-review.googlesource.com/c/go/+/324331 Trust: Dan Scales Run-TryBot: Dan Scales Reviewed-by: Keith Randall --- src/cmd/compile/internal/gc/export.go | 12 +++--- src/cmd/compile/internal/noder/decl.go | 10 +++++ src/cmd/compile/internal/noder/stencil.go | 2 - .../compile/internal/reflectdata/reflect.go | 4 +- src/cmd/compile/internal/typecheck/expr.go | 15 +++++++- src/cmd/compile/internal/typecheck/func.go | 19 +++++++++- src/cmd/compile/internal/typecheck/iexport.go | 21 ++-------- src/cmd/compile/internal/types/type.go | 18 ++++++++- test/typeparam/orderedmapsimp.dir/a.go | 38 +++++++++---------- test/typeparam/orderedmapsimp.dir/main.go | 33 ++++++++-------- 10 files changed, 103 insertions(+), 69 deletions(-) diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go index e19d52fa952..a11e5fdd300 100644 --- a/src/cmd/compile/internal/gc/export.go +++ b/src/cmd/compile/internal/gc/export.go @@ -94,15 +94,14 @@ func (p *exporter) markObject(n ir.Node) { // markType recursively visits types reachable from t to identify // functions whose inline bodies may be needed. func (p *exporter) markType(t *types.Type) { + if t.IsInstantiatedGeneric() { + // Re-instantiated types don't add anything new, so don't follow them. + return + } if p.marked[t] { return } p.marked[t] = true - if t.HasTParam() { - // Don't deal with any generic types or their methods, since we - // will only be inlining actual instantiations, not generic methods. - return - } // If this is a named type, mark all of its associated // methods. Skip interface types because t.Methods contains @@ -159,5 +158,8 @@ func (p *exporter) markType(t *types.Type) { p.markType(f.Type) } } + + case types.TTYPEPARAM: + // No other type that needs to be followed. } } diff --git a/src/cmd/compile/internal/noder/decl.go b/src/cmd/compile/internal/noder/decl.go index 375eb418989..5c80b206713 100644 --- a/src/cmd/compile/internal/noder/decl.go +++ b/src/cmd/compile/internal/noder/decl.go @@ -109,6 +109,16 @@ func (g *irgen) funcDecl(out *ir.Nodes, decl *syntax.FuncDecl) { } g.funcBody(fn, decl.Recv, decl.Type, decl.Body) + if fn.Type().HasTParam() && fn.Body != nil { + // Set pointers to the dcls/body of a generic function/method in + // the Inl struct, so it is marked for export, is available for + // stenciling, and works with Inline_Flood(). + fn.Inl = &ir.Inline{ + Cost: 1, + Dcl: fn.Dcl, + Body: fn.Body, + } + } out.Append(fn) } diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 3ba364f67cc..8145f9e8f9a 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -17,8 +17,6 @@ import ( "go/constant" ) -// For catching problems as we add more features -// TODO(danscales): remove assertions or replace with base.FatalfAt() func assert(p bool) { if !p { panic("assertion failed") diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index 604cec6096d..0fcb7e3d6db 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -949,7 +949,7 @@ func writeType(t *types.Type) *obj.LSym { // in the local package, even if they may be marked as part of // another package (the package of their base generic type). if tbase.Sym() != nil && tbase.Sym().Pkg != types.LocalPkg && - !tbase.IsInstantiated() { + !tbase.IsFullyInstantiated() { if i := typecheck.BaseTypeIndex(t); i >= 0 { lsym.Pkg = tbase.Sym().Pkg.Prefix lsym.SymIdx = int32(i) @@ -1795,7 +1795,7 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy // instantiated methods. if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type && rcvr.Elem().Sym() != nil && rcvr.Elem().Sym().Pkg != types.LocalPkg && - !rcvr.Elem().IsInstantiated() { + !rcvr.Elem().IsFullyInstantiated() { return lsym } diff --git a/src/cmd/compile/internal/typecheck/expr.go b/src/cmd/compile/internal/typecheck/expr.go index 24d141e8a2c..30d864320f6 100644 --- a/src/cmd/compile/internal/typecheck/expr.go +++ b/src/cmd/compile/internal/typecheck/expr.go @@ -311,8 +311,19 @@ func tcCompLit(n *ir.CompLitExpr) (res ir.Node) { f := t.Field(i) s := f.Sym - if s != nil && !types.IsExported(s.Name) && s.Pkg != types.LocalPkg { - base.Errorf("implicit assignment of unexported field '%s' in %v literal", s.Name, t) + + // Do the test for assigning to unexported fields. + // But if this is an instantiated function, then + // the function has already been typechecked. In + // that case, don't do the test, since it can fail + // for the closure structs created in + // walkClosure(), because the instantiated + // function is compiled as if in the source + // package of the generic function. + if !(ir.CurFunc != nil && strings.Index(ir.CurFunc.Nname.Sym().Name, "[") >= 0) { + if s != nil && !types.IsExported(s.Name) && s.Pkg != types.LocalPkg { + base.Errorf("implicit assignment of unexported field '%s' in %v literal", s.Name, t) + } } // No pushtype allowed here. Must name fields for that. n1 = AssignConv(n1, f.Type, "field value") diff --git a/src/cmd/compile/internal/typecheck/func.go b/src/cmd/compile/internal/typecheck/func.go index 760b8868ab7..f9ee686f9e9 100644 --- a/src/cmd/compile/internal/typecheck/func.go +++ b/src/cmd/compile/internal/typecheck/func.go @@ -74,8 +74,25 @@ func ClosureType(clo *ir.ClosureExpr) *types.Type { // The information appears in the binary in the form of type descriptors; // the struct is unnamed so that closures in multiple packages with the // same struct type can share the descriptor. + + // Make sure the .F field is in the same package as the rest of the + // fields. This deals with closures in instantiated functions, which are + // compiled as if from the source package of the generic function. + var pkg *types.Pkg + if len(clo.Func.ClosureVars) == 0 { + pkg = types.LocalPkg + } else { + for _, v := range clo.Func.ClosureVars { + if pkg == nil { + pkg = v.Sym().Pkg + } else if pkg != v.Sym().Pkg { + base.Fatalf("Closure variables from multiple packages") + } + } + } + fields := []*types.Field{ - types.NewField(base.Pos, Lookup(".F"), types.Types[types.TUINTPTR]), + types.NewField(base.Pos, pkg.Lookup(".F"), types.Types[types.TUINTPTR]), } for _, v := range clo.Func.ClosureVars { typ := v.Type() diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index f635b79adab..236f6ed789b 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -1332,24 +1332,9 @@ func (w *exportWriter) funcExt(n *ir.Name) { } } - // Inline body. - if n.Type().HasTParam() { - if n.Func.Inl != nil { - // n.Func.Inl may already be set on a generic function if - // we imported it from another package, but shouldn't be - // set for a generic function in the local package. - if n.Sym().Pkg == types.LocalPkg { - base.FatalfAt(n.Pos(), "generic function is marked inlineable") - } - } else { - // Populate n.Func.Inl, so body of exported generic function will - // be written out. - n.Func.Inl = &ir.Inline{ - Cost: 1, - Dcl: n.Func.Dcl, - Body: n.Func.Body, - } - } + // Write out inline body or body of a generic function/method. + if n.Type().HasTParam() && n.Func.Body != nil && n.Func.Inl == nil { + base.FatalfAt(n.Pos(), "generic function is not marked inlineable") } if n.Func.Inl != nil { w.uint64(1 + uint64(n.Func.Inl.Cost)) diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index 7a05230a78e..a3a6050c526 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -8,6 +8,7 @@ import ( "cmd/compile/internal/base" "cmd/internal/src" "fmt" + "strings" "sync" ) @@ -279,10 +280,23 @@ func (t *Type) SetRParams(rparams []*Type) { } } -// IsInstantiated reports whether t is a fully instantiated generic type; i.e. an +// IsBaseGeneric returns true if t is a generic type (not reinstantiated with +// another type params or fully instantiated. +func (t *Type) IsBaseGeneric() bool { + return len(t.RParams()) > 0 && strings.Index(t.Sym().Name, "[") < 0 +} + +// IsInstantiatedGeneric returns t if t ia generic type that has been +// reinstantiated with new typeparams (i.e. is not fully instantiated). +func (t *Type) IsInstantiatedGeneric() bool { + return len(t.RParams()) > 0 && strings.Index(t.Sym().Name, "[") >= 0 && + t.HasTParam() +} + +// IsFullyInstantiated reports whether t is a fully instantiated generic type; i.e. an // instantiated generic type where all type arguments are non-generic or fully // instantiated generic types. -func (t *Type) IsInstantiated() bool { +func (t *Type) IsFullyInstantiated() bool { return len(t.RParams()) > 0 && !t.HasTParam() } diff --git a/test/typeparam/orderedmapsimp.dir/a.go b/test/typeparam/orderedmapsimp.dir/a.go index 1b5827b4bb7..37fc3e79b9f 100644 --- a/test/typeparam/orderedmapsimp.dir/a.go +++ b/test/typeparam/orderedmapsimp.dir/a.go @@ -100,25 +100,25 @@ type keyValue[K, V any] struct { } // iterate returns an iterator that traverses the map. -// func (m *Map[K, V]) Iterate() *Iterator[K, V] { -// sender, receiver := Ranger[keyValue[K, V]]() -// var f func(*node[K, V]) bool -// f = func(n *node[K, V]) bool { -// if n == nil { -// return true -// } -// // Stop the traversal if Send fails, which means that -// // nothing is listening to the receiver. -// return f(n.left) && -// sender.Send(context.Background(), keyValue[K, V]{n.key, n.val}) && -// f(n.right) -// } -// go func() { -// f(m.root) -// sender.Close() -// }() -// return &Iterator[K, V]{receiver} -// } +func (m *Map[K, V]) Iterate() *Iterator[K, V] { + sender, receiver := Ranger[keyValue[K, V]]() + var f func(*node[K, V]) bool + f = func(n *node[K, V]) bool { + if n == nil { + return true + } + // Stop the traversal if Send fails, which means that + // nothing is listening to the receiver. + return f(n.left) && + sender.Send(context.Background(), keyValue[K, V]{n.key, n.val}) && + f(n.right) + } + go func() { + f(m.root) + sender.Close() + }() + return &Iterator[K, V]{receiver} +} // Iterator is used to iterate over the map. type Iterator[K, V any] struct { diff --git a/test/typeparam/orderedmapsimp.dir/main.go b/test/typeparam/orderedmapsimp.dir/main.go index 77869ad9fcb..ac4cee6a781 100644 --- a/test/typeparam/orderedmapsimp.dir/main.go +++ b/test/typeparam/orderedmapsimp.dir/main.go @@ -41,24 +41,21 @@ func TestMap() { panic(fmt.Sprintf("unexpectedly found %q", []byte("d"))) } - // TODO(danscales): Iterate() has some things to be fixed with inlining in - // stenciled functions and using closures across packages. - - // gather := func(it *a.Iterator[[]byte, int]) []int { - // var r []int - // for { - // _, v, ok := it.Next() - // if !ok { - // return r - // } - // r = append(r, v) - // } - // } - // got := gather(m.Iterate()) - // want := []int{'a', 'b', 'x'} - // if !a.SliceEqual(got, want) { - // panic(fmt.Sprintf("Iterate returned %v, want %v", got, want)) - // } + gather := func(it *a.Iterator[[]byte, int]) []int { + var r []int + for { + _, v, ok := it.Next() + if !ok { + return r + } + r = append(r, v) + } + } + got := gather(m.Iterate()) + want := []int{'a', 'b', 'x'} + if !a.SliceEqual(got, want) { + panic(fmt.Sprintf("Iterate returned %v, want %v", got, want)) + } } From bad388744b57cb49f364971e21d6a2300545f0fb Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 3 Jun 2021 15:39:23 -0700 Subject: [PATCH 302/940] [dev.typeparams] cmd/compile: handle dictionaries for top-level instantiations There's no outer function in these cases, so we won't be reading the dictionary as a subdictionary from the outer scope's dictionary. It will always be a compile-time constant. Change-Id: I754b126652a6ffb62255734d53fcec29d77cfa9e Reviewed-on: https://go-review.googlesource.com/c/go/+/324949 Trust: Keith Randall Trust: Dan Scales Reviewed-by: Dan Scales --- src/cmd/compile/internal/noder/stencil.go | 68 ++++++++++++++++------- test/typeparam/dictionaryCapture.go | 28 ++++++++++ 2 files changed, 77 insertions(+), 19 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 8145f9e8f9a..25a4bf775f1 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -144,13 +144,19 @@ func (g *irgen) stencil() { // call. if closureRequired { var edit func(ir.Node) ir.Node + var outer *ir.Func + if f, ok := decl.(*ir.Func); ok { + outer = f + } edit = func(x ir.Node) ir.Node { ir.EditChildren(x, edit) switch { case x.Op() == ir.OFUNCINST: - return g.buildClosure(decl.(*ir.Func), x) + // TODO: only set outer!=nil if this instantiation uses + // a type parameter from outer. See comment in buildClosure. + return g.buildClosure(outer, x) case x.Op() == ir.OMETHEXPR && len(deref(x.(*ir.SelectorExpr).X.Type()).RParams()) > 0: // TODO: test for ptr-to-method case - return g.buildClosure(decl.(*ir.Func), x) + return g.buildClosure(outer, x) } return x } @@ -170,7 +176,8 @@ func (g *irgen) stencil() { } // buildClosure makes a closure to implement x, a OFUNCINST or OMETHEXPR -// of generic type. outer is the containing function. +// of generic type. outer is the containing function (or nil if closure is +// in a global assignment instead of a function). func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { pos := x.Pos() var target *ir.Func // target instantiated function/method @@ -276,19 +283,25 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { fn.SetIsHiddenClosure(true) // This is the dictionary we want to use. - // Note: for now this is a compile-time constant, so we don't really need a closure - // to capture it (a wrapper function would work just as well). But eventually it - // will be a read of a subdictionary from the parent dictionary. - dictVar := ir.NewNameAt(pos, typecheck.LookupNum(".dict", g.dnum)) - g.dnum++ - dictVar.Class = ir.PAUTO - typed(types.Types[types.TUINTPTR], dictVar) - dictVar.Curfn = outer - dictAssign := ir.NewAssignStmt(pos, dictVar, dictValue) - dictAssign.SetTypecheck(1) - dictVar.Defn = dictAssign - outer.Dcl = append(outer.Dcl, dictVar) - + // It may be a constant, or it may be a dictionary acquired from the outer function's dictionary. + // For the latter, dictVar is a variable in the outer function's scope, set to the subdictionary + // read from the outer function's dictionary. + var dictVar *ir.Name + var dictAssign *ir.AssignStmt + if outer != nil { + // Note: for now this is a compile-time constant, so we don't really need a closure + // to capture it (a wrapper function would work just as well). But eventually it + // will be a read of a subdictionary from the parent dictionary. + dictVar = ir.NewNameAt(pos, typecheck.LookupNum(".dict", g.dnum)) + g.dnum++ + dictVar.Class = ir.PAUTO + typed(types.Types[types.TUINTPTR], dictVar) + dictVar.Curfn = outer + dictAssign = ir.NewAssignStmt(pos, dictVar, dictValue) + dictAssign.SetTypecheck(1) + dictVar.Defn = dictAssign + outer.Dcl = append(outer.Dcl, dictVar) + } // assign the receiver to a temporary. var rcvrVar *ir.Name var rcvrAssign ir.Node @@ -335,6 +348,7 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { sym := typecheck.ClosureName(outer) sym.SetFunc(true) fn.Nname = ir.NewNameAt(pos, sym) + fn.Nname.Class = ir.PFUNC fn.Nname.Func = fn fn.Nname.Defn = fn typed(closureType, fn.Nname) @@ -343,8 +357,18 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { // Build body of closure. This involves just calling the wrapped function directly // with the additional dictionary argument. - // First, capture the dictionary variable for use in the closure. - dict2Var := ir.CaptureName(pos, fn, dictVar) + // First, figure out the dictionary argument. + var dict2Var ir.Node + if outer != nil { + // If there's an outer function, the dictionary value will be read from + // the dictionary of the outer function. + // TODO: only use a subdictionary if any of the instantiating types + // depend on the type params of the outer function. + dict2Var = ir.CaptureName(pos, fn, dictVar) + } else { + // No outer function, instantiating types are known concrete types. + dict2Var = dictValue + } // Also capture the receiver variable. var rcvr2Var *ir.Name if rcvrValue != nil { @@ -376,13 +400,19 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { typecheck.Stmt(innerCall) ir.CurFunc = nil fn.Body = []ir.Node{innerCall} + if outer == nil { + g.target.Decls = append(g.target.Decls, fn) + } // We're all done with the captured dictionary (and receiver, for method values). ir.FinishCaptureNames(pos, outer, fn) // Make a closure referencing our new internal function. c := ir.NewClosureExpr(pos, fn) - init := []ir.Node{dictAssign} + var init []ir.Node + if outer != nil { + init = append(init, dictAssign) + } if rcvrValue != nil { init = append(init, rcvrAssign) } diff --git a/test/typeparam/dictionaryCapture.go b/test/typeparam/dictionaryCapture.go index 9ce7c540ca4..bb35df53098 100644 --- a/test/typeparam/dictionaryCapture.go +++ b/test/typeparam/dictionaryCapture.go @@ -17,6 +17,7 @@ func main() { methodExpressions() methodValues() interfaceMethods() + globals() } func g0[T any](x T) { @@ -98,3 +99,30 @@ func interfaceMethods() { is7(y.(interface{g1()int}).g1()) is77(y.(interface{g2()(int,int)}).g2()) } + +// Also check for instantiations outside functions. +var gg0 = g0[int] +var gg1 = g1[int] +var gg2 = g2[int] + +var hh0 = s[int].g0 +var hh1 = s[int].g1 +var hh2 = s[int].g2 + +var xtop = s[int]{a:7} +var ii0 = x.g0 +var ii1 = x.g1 +var ii2 = x.g2 + +func globals() { + gg0(7) + is7(gg1(7)) + is77(gg2(7)) + x := s[int]{a:7} + hh0(x) + is7(hh1(x)) + is77(hh2(x)) + ii0() + is7(ii1()) + is77(ii2()) +} From 95939e8de71d9e8d8deea3d1605bd34130588292 Mon Sep 17 00:00:00 2001 From: sryoya Date: Sat, 5 Jun 2021 03:12:03 +0900 Subject: [PATCH 303/940] cmd/compile/internal/abi: fix typo in comment Change-Id: I196045314b2b0e908d7b31ac0cea5b25404f3ee0 Reviewed-on: https://go-review.googlesource.com/c/go/+/325249 Reviewed-by: Matthew Dempsky Trust: Keith Randall --- src/cmd/compile/internal/abi/abiutils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go index cb8e9d7b0fe..b8ea1955d13 100644 --- a/src/cmd/compile/internal/abi/abiutils.go +++ b/src/cmd/compile/internal/abi/abiutils.go @@ -449,7 +449,7 @@ func (config *ABIConfig) ABIAnalyze(t *types.Type, setNname bool) *ABIParamResul // parameterUpdateMu protects the Offset field of function/method parameters (a subset of structure Fields) var parameterUpdateMu sync.Mutex -// FieldOffsetOf returns a concurency-safe version of f.Offset +// FieldOffsetOf returns a concurrency-safe version of f.Offset func FieldOffsetOf(f *types.Field) int64 { parameterUpdateMu.Lock() defer parameterUpdateMu.Unlock() From a94e4f5a8590e7c8d3aa058fb592561d870285a9 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 4 Jun 2021 00:01:22 -0700 Subject: [PATCH 304/940] [dev.typeparams] cmd/compile: point StructKeyExpr at the types.Field When constructing struct literals, importers need a way to specify precisely which field to initialize without worrying about visibility or those fields being blank. (A blank field doesn't actually need to be initialized, but the expression needs to be evaluated still, and with the right order-of-operations.) This CL changes StructKeyExpr's Field field to point directly to the corresponding types.Field, rather than merely holding a copy of its Sym and Offset. This is akin to past changes to add SelectorExpr.Selection. Change-Id: I95b72b1788f73206fcebc22b456cf6b1186db6a7 Reviewed-on: https://go-review.googlesource.com/c/go/+/325031 Trust: Matthew Dempsky Reviewed-by: Cuong Manh Le Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot --- src/cmd/compile/internal/ir/expr.go | 10 +- src/cmd/compile/internal/noder/expr.go | 6 +- src/cmd/compile/internal/noder/transform.go | 43 +++--- src/cmd/compile/internal/staticinit/sched.go | 4 +- src/cmd/compile/internal/typecheck/expr.go | 138 +++++++++--------- src/cmd/compile/internal/typecheck/iexport.go | 5 +- src/cmd/compile/internal/typecheck/iimport.go | 6 +- src/cmd/compile/internal/walk/closure.go | 3 + src/cmd/compile/internal/walk/complit.go | 4 +- 9 files changed, 107 insertions(+), 112 deletions(-) diff --git a/src/cmd/compile/internal/ir/expr.go b/src/cmd/compile/internal/ir/expr.go index 856b2556575..bcc0e412d58 100644 --- a/src/cmd/compile/internal/ir/expr.go +++ b/src/cmd/compile/internal/ir/expr.go @@ -324,20 +324,18 @@ func NewKeyExpr(pos src.XPos, key, value Node) *KeyExpr { // A StructKeyExpr is an Field: Value composite literal key. type StructKeyExpr struct { miniExpr - Field *types.Sym - Value Node - Offset int64 + Field *types.Field + Value Node } -func NewStructKeyExpr(pos src.XPos, field *types.Sym, value Node) *StructKeyExpr { +func NewStructKeyExpr(pos src.XPos, field *types.Field, value Node) *StructKeyExpr { n := &StructKeyExpr{Field: field, Value: value} n.pos = pos n.op = OSTRUCTKEY - n.Offset = types.BADWIDTH return n } -func (n *StructKeyExpr) Sym() *types.Sym { return n.Field } +func (n *StructKeyExpr) Sym() *types.Sym { return n.Field.Sym } // An InlinedCallExpr is an inlined function call. type InlinedCallExpr struct { diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go index c901dc55345..d6c75845ce5 100644 --- a/src/cmd/compile/internal/noder/expr.go +++ b/src/cmd/compile/internal/noder/expr.go @@ -355,11 +355,13 @@ func (g *irgen) compLit(typ types2.Type, lit *syntax.CompositeLit) ir.Node { for i, elem := range lit.ElemList { switch elem := elem.(type) { case *syntax.KeyValueExpr: + var key ir.Node if isStruct { - exprs[i] = ir.NewStructKeyExpr(g.pos(elem), g.name(elem.Key.(*syntax.Name)), g.expr(elem.Value)) + key = ir.NewIdent(g.pos(elem.Key), g.name(elem.Key.(*syntax.Name))) } else { - exprs[i] = ir.NewKeyExpr(g.pos(elem), g.expr(elem.Key), g.expr(elem.Value)) + key = g.expr(elem.Key) } + exprs[i] = ir.NewKeyExpr(g.pos(elem), key, g.expr(elem.Value)) default: exprs[i] = g.expr(elem) } diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go index 90d38fe5144..a084f0b7be2 100644 --- a/src/cmd/compile/internal/noder/transform.go +++ b/src/cmd/compile/internal/noder/transform.go @@ -937,9 +937,7 @@ func transformCompLit(n *ir.CompLitExpr) (res ir.Node) { f := t.Field(i) n1 = assignconvfn(n1, f.Type) - sk := ir.NewStructKeyExpr(base.Pos, f.Sym, n1) - sk.Offset = f.Offset - ls[i] = sk + ls[i] = ir.NewStructKeyExpr(base.Pos, f, n1) } assert(len(ls) >= t.NumFields()) } else { @@ -948,33 +946,26 @@ func transformCompLit(n *ir.CompLitExpr) (res ir.Node) { for i, l := range ls { ir.SetPos(l) - if l.Op() == ir.OKEY { - kv := l.(*ir.KeyExpr) - key := kv.Key + kv := l.(*ir.KeyExpr) + key := kv.Key - // Sym might have resolved to name in other top-level - // package, because of import dot. Redirect to correct sym - // before we do the lookup. - s := key.Sym() - if id, ok := key.(*ir.Ident); ok && typecheck.DotImportRefs[id] != nil { - s = typecheck.Lookup(s.Name) - } - - // An OXDOT uses the Sym field to hold - // the field to the right of the dot, - // so s will be non-nil, but an OXDOT - // is never a valid struct literal key. - assert(!(s == nil || s.Pkg != types.LocalPkg || key.Op() == ir.OXDOT || s.IsBlank())) - - l = ir.NewStructKeyExpr(l.Pos(), s, kv.Value) - ls[i] = l + // Sym might have resolved to name in other top-level + // package, because of import dot. Redirect to correct sym + // before we do the lookup. + s := key.Sym() + if id, ok := key.(*ir.Ident); ok && typecheck.DotImportRefs[id] != nil { + s = typecheck.Lookup(s.Name) } - assert(l.Op() == ir.OSTRUCTKEY) - l := l.(*ir.StructKeyExpr) + // An OXDOT uses the Sym field to hold + // the field to the right of the dot, + // so s will be non-nil, but an OXDOT + // is never a valid struct literal key. + assert(!(s == nil || s.Pkg != types.LocalPkg || key.Op() == ir.OXDOT || s.IsBlank())) - f := typecheck.Lookdot1(nil, l.Field, t, t.Fields(), 0) - l.Offset = f.Offset + f := typecheck.Lookdot1(nil, s, t, t.Fields(), 0) + l := ir.NewStructKeyExpr(l.Pos(), f, kv.Value) + ls[i] = l l.Value = assignconvfn(l.Value, f.Type) } diff --git a/src/cmd/compile/internal/staticinit/sched.go b/src/cmd/compile/internal/staticinit/sched.go index 0c97b6de747..9329a469899 100644 --- a/src/cmd/compile/internal/staticinit/sched.go +++ b/src/cmd/compile/internal/staticinit/sched.go @@ -403,10 +403,10 @@ func (s *Schedule) initplan(n ir.Node) { base.Fatalf("initplan structlit") } a := a.(*ir.StructKeyExpr) - if a.Field.IsBlank() { + if a.Sym().IsBlank() { continue } - s.addvalue(p, a.Offset, a.Value) + s.addvalue(p, a.Field.Offset, a.Value) } case ir.OMAPLIT: diff --git a/src/cmd/compile/internal/typecheck/expr.go b/src/cmd/compile/internal/typecheck/expr.go index 30d864320f6..d52f0110728 100644 --- a/src/cmd/compile/internal/typecheck/expr.go +++ b/src/cmd/compile/internal/typecheck/expr.go @@ -327,9 +327,7 @@ func tcCompLit(n *ir.CompLitExpr) (res ir.Node) { } // No pushtype allowed here. Must name fields for that. n1 = AssignConv(n1, f.Type, "field value") - sk := ir.NewStructKeyExpr(base.Pos, f.Sym, n1) - sk.Offset = f.Offset - ls[i] = sk + ls[i] = ir.NewStructKeyExpr(base.Pos, f, n1) } if len(ls) < t.NumFields() { base.Errorf("too few values in %v", n) @@ -339,77 +337,33 @@ func tcCompLit(n *ir.CompLitExpr) (res ir.Node) { // keyed list ls := n.List - for i, l := range ls { - ir.SetPos(l) + for i, n := range ls { + ir.SetPos(n) - if l.Op() == ir.OKEY { - kv := l.(*ir.KeyExpr) - key := kv.Key - - // Sym might have resolved to name in other top-level - // package, because of import dot. Redirect to correct sym - // before we do the lookup. - s := key.Sym() - if id, ok := key.(*ir.Ident); ok && DotImportRefs[id] != nil { - s = Lookup(s.Name) - } - - // An OXDOT uses the Sym field to hold - // the field to the right of the dot, - // so s will be non-nil, but an OXDOT - // is never a valid struct literal key. - if s == nil || s.Pkg != types.LocalPkg || key.Op() == ir.OXDOT || s.IsBlank() { - base.Errorf("invalid field name %v in struct initializer", key) - continue - } - - l = ir.NewStructKeyExpr(l.Pos(), s, kv.Value) - ls[i] = l - } - - if l.Op() != ir.OSTRUCTKEY { - if !errored { - base.Errorf("mixture of field:value and value initializers") - errored = true - } - ls[i] = Expr(ls[i]) - continue - } - l := l.(*ir.StructKeyExpr) - - f := Lookdot1(nil, l.Field, t, t.Fields(), 0) - if f == nil { - if ci := Lookdot1(nil, l.Field, t, t.Fields(), 2); ci != nil { // Case-insensitive lookup. - if visible(ci.Sym) { - base.Errorf("unknown field '%v' in struct literal of type %v (but does have %v)", l.Field, t, ci.Sym) - } else if nonexported(l.Field) && l.Field.Name == ci.Sym.Name { // Ensure exactness before the suggestion. - base.Errorf("cannot refer to unexported field '%v' in struct literal of type %v", l.Field, t) - } else { - base.Errorf("unknown field '%v' in struct literal of type %v", l.Field, t) + sk, ok := n.(*ir.StructKeyExpr) + if !ok { + kv, ok := n.(*ir.KeyExpr) + if !ok { + if !errored { + base.Errorf("mixture of field:value and value initializers") + errored = true } + ls[i] = Expr(n) continue } - var f *types.Field - p, _ := dotpath(l.Field, t, &f, true) - if p == nil || f.IsMethod() { - base.Errorf("unknown field '%v' in struct literal of type %v", l.Field, t) + + sk = tcStructLitKey(t, kv) + if sk == nil { continue } - // dotpath returns the parent embedded types in reverse order. - var ep []string - for ei := len(p) - 1; ei >= 0; ei-- { - ep = append(ep, p[ei].field.Sym.Name) - } - ep = append(ep, l.Field.Name) - base.Errorf("cannot use promoted field %v in struct literal of type %v", strings.Join(ep, "."), t) - continue + + fielddup(sk.Sym().Name, hash) } - fielddup(f.Sym.Name, hash) - l.Offset = f.Offset // No pushtype allowed here. Tried and rejected. - l.Value = Expr(l.Value) - l.Value = AssignConv(l.Value, f.Type, "field value") + sk.Value = Expr(sk.Value) + sk.Value = AssignConv(sk.Value, sk.Field.Type, "field value") + ls[i] = sk } } @@ -420,6 +374,60 @@ func tcCompLit(n *ir.CompLitExpr) (res ir.Node) { return n } +// tcStructLitKey typechecks an OKEY node that appeared within a +// struct literal. +func tcStructLitKey(typ *types.Type, kv *ir.KeyExpr) *ir.StructKeyExpr { + key := kv.Key + + // Sym might have resolved to name in other top-level + // package, because of import dot. Redirect to correct sym + // before we do the lookup. + sym := key.Sym() + if id, ok := key.(*ir.Ident); ok && DotImportRefs[id] != nil { + sym = Lookup(sym.Name) + } + + // An OXDOT uses the Sym field to hold + // the field to the right of the dot, + // so s will be non-nil, but an OXDOT + // is never a valid struct literal key. + if sym == nil || sym.Pkg != types.LocalPkg || key.Op() == ir.OXDOT || sym.IsBlank() { + base.Errorf("invalid field name %v in struct initializer", key) + return nil + } + + if f := Lookdot1(nil, sym, typ, typ.Fields(), 0); f != nil { + return ir.NewStructKeyExpr(kv.Pos(), f, kv.Value) + } + + if ci := Lookdot1(nil, sym, typ, typ.Fields(), 2); ci != nil { // Case-insensitive lookup. + if visible(ci.Sym) { + base.Errorf("unknown field '%v' in struct literal of type %v (but does have %v)", sym, typ, ci.Sym) + } else if nonexported(sym) && sym.Name == ci.Sym.Name { // Ensure exactness before the suggestion. + base.Errorf("cannot refer to unexported field '%v' in struct literal of type %v", sym, typ) + } else { + base.Errorf("unknown field '%v' in struct literal of type %v", sym, typ) + } + return nil + } + + var f *types.Field + p, _ := dotpath(sym, typ, &f, true) + if p == nil || f.IsMethod() { + base.Errorf("unknown field '%v' in struct literal of type %v", sym, typ) + return nil + } + + // dotpath returns the parent embedded types in reverse order. + var ep []string + for ei := len(p) - 1; ei >= 0; ei-- { + ep = append(ep, p[ei].field.Sym.Name) + } + ep = append(ep, sym.Name) + base.Errorf("cannot use promoted field %v in struct literal of type %v", strings.Join(ep, "."), typ) + return nil +} + // tcConv typechecks an OCONV node. func tcConv(n *ir.ConvExpr) ir.Node { types.CheckSize(n.Type()) // ensure width is calculated for backend diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index 236f6ed789b..3bfbea11c02 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -2062,11 +2062,8 @@ func (w *exportWriter) fieldList(list ir.Nodes) { for _, n := range list { n := n.(*ir.StructKeyExpr) w.pos(n.Pos()) - w.selector(n.Field) + w.exoticField(n.Field) w.expr(n.Value) - if go117ExportTypes { - w.uint64(uint64(n.Offset)) - } } } diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 9e6115cbf7c..45a177951ef 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -1719,11 +1719,7 @@ func (r *importReader) op() ir.Op { func (r *importReader) fieldList() []ir.Node { list := make([]ir.Node, r.uint64()) for i := range list { - x := ir.NewStructKeyExpr(r.pos(), r.selector(), r.expr()) - if go117ExportTypes { - x.Offset = int64(r.uint64()) - } - list[i] = x + list[i] = ir.NewStructKeyExpr(r.pos(), r.exoticField(), r.expr()) } return list } diff --git a/src/cmd/compile/internal/walk/closure.go b/src/cmd/compile/internal/walk/closure.go index 2194e1c5b0c..feda3c3b4f8 100644 --- a/src/cmd/compile/internal/walk/closure.go +++ b/src/cmd/compile/internal/walk/closure.go @@ -122,6 +122,9 @@ func walkClosure(clo *ir.ClosureExpr, init *ir.Nodes) ir.Node { clos := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ), nil) clos.SetEsc(clo.Esc()) clos.List = append([]ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, clofn.Nname)}, closureArgs(clo)...) + for i, value := range clos.List { + clos.List[i] = ir.NewStructKeyExpr(base.Pos, typ.Field(i), value) + } addr := typecheck.NodAddr(clos) addr.SetEsc(clo.Esc()) diff --git a/src/cmd/compile/internal/walk/complit.go b/src/cmd/compile/internal/walk/complit.go index abd920d6461..6c6b4982a05 100644 --- a/src/cmd/compile/internal/walk/complit.go +++ b/src/cmd/compile/internal/walk/complit.go @@ -218,11 +218,11 @@ func fixedlit(ctxt initContext, kind initKind, n *ir.CompLitExpr, var_ ir.Node, case ir.OSTRUCTLIT: splitnode = func(rn ir.Node) (ir.Node, ir.Node) { r := rn.(*ir.StructKeyExpr) - if r.Field.IsBlank() || isBlank { + if r.Sym().IsBlank() || isBlank { return ir.BlankNode, r.Value } ir.SetPos(r) - return ir.NewSelectorExpr(base.Pos, ir.ODOT, var_, r.Field), r.Value + return ir.NewSelectorExpr(base.Pos, ir.ODOT, var_, r.Sym()), r.Value } default: base.Fatalf("fixedlit bad op: %v", n.Op()) From 692399fbaa09578314f8583e49505c6784e8d335 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 3 Jun 2021 20:53:08 -0700 Subject: [PATCH 305/940] [dev.typeparams] cmd/compile/internal/syntax: not all index expressions can be instantiated types An index expression followed by an opening "{" may indicate a composite literal but only if the index expression can be a type. Exclude cases where the index expression cannot be a type (e.g. s[0], a[i+j], etc.). This leads to a better error message in code that is erroneous. Fixes #46558. Change-Id: Ida9291ca30683c211812dfb95abe4969f44c474f Reviewed-on: https://go-review.googlesource.com/c/go/+/325009 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/syntax/parser.go | 17 ++++++++++++++++- .../internal/syntax/testdata/issue46558.src | 14 ++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 src/cmd/compile/internal/syntax/testdata/issue46558.src diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go index 0e711a0113f..503dea7fae6 100644 --- a/src/cmd/compile/internal/syntax/parser.go +++ b/src/cmd/compile/internal/syntax/parser.go @@ -1100,7 +1100,7 @@ loop: complit_ok = true } case *IndexExpr: - if p.xnest >= 0 { + if p.xnest >= 0 && !isValue(t) { // x is possibly a composite literal type complit_ok = true } @@ -1127,6 +1127,21 @@ loop: return x } +// isValue reports whether x syntactically must be a value (and not a type) expression. +func isValue(x Expr) bool { + switch x := x.(type) { + case *BasicLit, *CompositeLit, *FuncLit, *SliceExpr, *AssertExpr, *TypeSwitchGuard, *CallExpr: + return true + case *Operation: + return x.Op != Mul || x.Y != nil // *T may be a type + case *ParenExpr: + return isValue(x.X) + case *IndexExpr: + return isValue(x.X) || isValue(x.Index) + } + return false +} + // Element = Expression | LiteralValue . func (p *parser) bare_complitexpr() Expr { if trace { diff --git a/src/cmd/compile/internal/syntax/testdata/issue46558.src b/src/cmd/compile/internal/syntax/testdata/issue46558.src new file mode 100644 index 00000000000..a22b6008258 --- /dev/null +++ b/src/cmd/compile/internal/syntax/testdata/issue46558.src @@ -0,0 +1,14 @@ +// Copyright 2021 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 + +func F(s string) { + switch s[0] { + case 'a': + case s[2] { // ERROR unexpected { + case 'b': + } + } +} // ERROR non-declaration statement From 246a5570bea7b60fa2c1f0e8d4bdca527dd7c224 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 3 Jun 2021 21:58:32 -0700 Subject: [PATCH 306/940] [dev.typeparams] cmd/compile: rename (types2.Inferred.)Targs to TArgs This is consistent with Named.TArgs. This is a straight-forward port of https://golang.org/cl/321289 plus the necessary compiler noder changes. Change-Id: I50791e5abe0d7f294293bed65cebc8dde8bf8c06 Reviewed-on: https://go-review.googlesource.com/c/go/+/325010 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/noder/expr.go | 12 ++++++------ src/cmd/compile/internal/types2/api.go | 2 +- src/cmd/compile/internal/types2/api_test.go | 2 +- src/cmd/compile/internal/types2/sanitize.go | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go index d6c75845ce5..7034a19b815 100644 --- a/src/cmd/compile/internal/noder/expr.go +++ b/src/cmd/compile/internal/noder/expr.go @@ -111,11 +111,11 @@ func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node { // The key for the Inferred map is the CallExpr (if inferring // types required the function arguments) or the IndexExpr below // (if types could be inferred without the function arguments). - if inferred, ok := g.info.Inferred[expr]; ok && len(inferred.Targs) > 0 { + if inferred, ok := g.info.Inferred[expr]; ok && len(inferred.TArgs) > 0 { // This is the case where inferring types required the // types of the function arguments. - targs := make([]ir.Node, len(inferred.Targs)) - for i, targ := range inferred.Targs { + targs := make([]ir.Node, len(inferred.TArgs)) + for i, targ := range inferred.TArgs { targs[i] = ir.TypeNode(g.typ(targ)) } if fun.Op() == ir.OFUNCINST { @@ -137,12 +137,12 @@ func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node { case *syntax.IndexExpr: var targs []ir.Node - if inferred, ok := g.info.Inferred[expr]; ok && len(inferred.Targs) > 0 { + if inferred, ok := g.info.Inferred[expr]; ok && len(inferred.TArgs) > 0 { // This is the partial type inference case where the types // can be inferred from other type arguments without using // the types of the function arguments. - targs = make([]ir.Node, len(inferred.Targs)) - for i, targ := range inferred.Targs { + targs = make([]ir.Node, len(inferred.TArgs)) + for i, targ := range inferred.TArgs { targs[i] = ir.TypeNode(g.typ(targ)) } } else if _, ok := expr.Index.(*syntax.ListExpr); ok { diff --git a/src/cmd/compile/internal/types2/api.go b/src/cmd/compile/internal/types2/api.go index 433250f02c8..4f7f35e61b2 100644 --- a/src/cmd/compile/internal/types2/api.go +++ b/src/cmd/compile/internal/types2/api.go @@ -361,7 +361,7 @@ func (tv TypeAndValue) HasOk() bool { // Inferred reports the inferred type arguments and signature // for a parameterized function call that uses type inference. type Inferred struct { - Targs []Type + TArgs []Type Sig *Signature } diff --git a/src/cmd/compile/internal/types2/api_test.go b/src/cmd/compile/internal/types2/api_test.go index 49d710067a8..c7f3e490aa0 100644 --- a/src/cmd/compile/internal/types2/api_test.go +++ b/src/cmd/compile/internal/types2/api_test.go @@ -514,7 +514,7 @@ func TestInferredInfo(t *testing.T) { panic(fmt.Sprintf("unexpected call expression type %T", call)) } if syntax.String(fun) == test.fun { - targs = inf.Targs + targs = inf.TArgs sig = inf.Sig break } diff --git a/src/cmd/compile/internal/types2/sanitize.go b/src/cmd/compile/internal/types2/sanitize.go index 4e654e074fc..406b46e574c 100644 --- a/src/cmd/compile/internal/types2/sanitize.go +++ b/src/cmd/compile/internal/types2/sanitize.go @@ -26,9 +26,9 @@ func sanitizeInfo(info *Info) { for e, inf := range info.Inferred { changed := false - for i, targ := range inf.Targs { + for i, targ := range inf.TArgs { if typ := s.typ(targ); typ != targ { - inf.Targs[i] = typ + inf.TArgs[i] = typ changed = true } } From 4e001a8d9eec1ec165b45a37e804c2cf42351bc5 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 3 Jun 2021 23:52:34 -0700 Subject: [PATCH 307/940] [dev.typeparams] runtime/race: make test compatible with types2 types2 correctly distinguishes variable assignment from use even within function literals. Whatever the outcome of #3059, the test cases in runtime/race need to be fixed to accomodate that. Change-Id: Ibe3547f07b681ff41225caabaf050872a48c98d1 Reviewed-on: https://go-review.googlesource.com/c/go/+/325030 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/runtime/race/output_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/runtime/race/output_test.go b/src/runtime/race/output_test.go index 99052071d00..63fcd847dc7 100644 --- a/src/runtime/race/output_test.go +++ b/src/runtime/race/output_test.go @@ -148,7 +148,7 @@ exit status 66 package main func main() { done := make(chan bool) - x := 0 + x := 0; _ = x go func() { x = 42 done <- true @@ -162,7 +162,7 @@ func main() { package main func main() { done := make(chan bool) - x := 0 + x := 0; _ = x go func() { x = 42 done <- true @@ -178,7 +178,7 @@ func main() { package main func main() { done := make(chan bool) - x := 0 + x := 0; _ = x go func() { x = 42 done <- true From 9d669ed47a502ca540c7f3329f84d89fc0c53971 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 4 Jun 2021 08:16:58 -0700 Subject: [PATCH 308/940] misc/cgo/errors: use expected column numbers The test was using the wrong column numbers, and was erroneously passing because there happened to be line numbers that matched those column numbers. Change the test harness to require the expected line number for the ERROR HERE regexp case, so that this doesn't happen again. Also rename a couple of variables in the test to avoid useless redeclaration errors. Fixes #46534 Change-Id: I2fcbf5e379c346de5346035c73d174a3980c0927 Reviewed-on: https://go-review.googlesource.com/c/go/+/324970 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- misc/cgo/errors/errors_test.go | 3 ++- misc/cgo/errors/testdata/err2.go | 12 ++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/misc/cgo/errors/errors_test.go b/misc/cgo/errors/errors_test.go index a077b594786..68a30a44fe4 100644 --- a/misc/cgo/errors/errors_test.go +++ b/misc/cgo/errors/errors_test.go @@ -40,7 +40,8 @@ func check(t *testing.T, file string) { if len(frags) == 1 { continue } - re, err := regexp.Compile(string(frags[1])) + frag := fmt.Sprintf(":%d:.*%s", i+1, frags[1]) + re, err := regexp.Compile(frag) if err != nil { t.Errorf("Invalid regexp after `ERROR HERE: `: %#q", frags[1]) continue diff --git a/misc/cgo/errors/testdata/err2.go b/misc/cgo/errors/testdata/err2.go index 1d22401aee5..a90598fe35b 100644 --- a/misc/cgo/errors/testdata/err2.go +++ b/misc/cgo/errors/testdata/err2.go @@ -40,15 +40,15 @@ func main() { C.foop = x // ERROR HERE // issue 13129: used to output error about C.unsignedshort with CC=clang - var x C.ushort - x = int(0) // ERROR HERE: C\.ushort + var x1 C.ushort + x1 = int(0) // ERROR HERE: C\.ushort // issue 13423 _ = C.fopen() // ERROR HERE // issue 13467 - var x rune = '✈' - var _ rune = C.transform(x) // ERROR HERE: C\.int + var x2 rune = '✈' + var _ rune = C.transform(x2) // ERROR HERE: C\.int // issue 13635: used to output error about C.unsignedchar. // This test tests all such types. @@ -91,10 +91,10 @@ func main() { // issue 26745 _ = func(i int) int { - return C.i + 1 // ERROR HERE: :13 + return C.i + 1 // ERROR HERE: 14 } _ = func(i int) { - C.fi(i) // ERROR HERE: :6 + C.fi(i) // ERROR HERE: 7 } C.fi = C.fi // ERROR HERE From e3cb3817049ca5e9d96543500b72117f6ca659b8 Mon Sep 17 00:00:00 2001 From: Sergey Zagursky Date: Fri, 4 Jun 2021 12:25:51 +0300 Subject: [PATCH 309/940] go/internal/gcimporter: don't waste CPU copying bytes in `io.ReadAll` `io.ReadAll` dynamically reallocates byte slice because it doesn't know its size in advance. We don't need to read an entire file into memory and therefore may use `bufio.Reader` to read its contents. Fixes #46564 Change-Id: Id504b1512662b6dea4775d523455896fa4162ab3 Reviewed-on: https://go-review.googlesource.com/c/go/+/325429 Reviewed-by: Dominik Honnef Reviewed-by: Matthew Dempsky Trust: Matthew Dempsky Trust: Dominik Honnef Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot --- src/go/internal/gcimporter/gcimporter.go | 11 ++++------- src/go/internal/gcimporter/iimport.go | 21 +++++++++++---------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/go/internal/gcimporter/gcimporter.go b/src/go/internal/gcimporter/gcimporter.go index b74daca2463..73cf6334fd6 100644 --- a/src/go/internal/gcimporter/gcimporter.go +++ b/src/go/internal/gcimporter/gcimporter.go @@ -145,17 +145,14 @@ func Import(fset *token.FileSet, packages map[string]*types.Package, path, srcDi err = fmt.Errorf("import %q: old textual export format no longer supported (recompile library)", path) case "$$B\n": - var data []byte - data, err = io.ReadAll(buf) - if err != nil { - break - } + var exportFormat byte + exportFormat, err = buf.ReadByte() // The indexed export format starts with an 'i'; the older // binary export format starts with a 'c', 'd', or 'v' // (from "version"). Select appropriate importer. - if len(data) > 0 && data[0] == 'i' { - _, pkg, err = iImportData(fset, packages, data[1:], id) + if err == nil && exportFormat == 'i' { + pkg, err = iImportData(fset, packages, buf, id) } else { err = fmt.Errorf("import %q: old binary export format no longer supported (recompile library)", path) } diff --git a/src/go/internal/gcimporter/iimport.go b/src/go/internal/gcimporter/iimport.go index a3184e7641a..76d47d08f1f 100644 --- a/src/go/internal/gcimporter/iimport.go +++ b/src/go/internal/gcimporter/iimport.go @@ -8,6 +8,7 @@ package gcimporter import ( + "bufio" "bytes" "encoding/binary" "fmt" @@ -20,7 +21,7 @@ import ( ) type intReader struct { - *bytes.Reader + *bufio.Reader path string } @@ -61,7 +62,7 @@ const ( // and returns the number of bytes consumed and a reference to the package. // If the export data version is not recognized or the format is otherwise // compromised, an error is returned. -func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) { +func iImportData(fset *token.FileSet, imports map[string]*types.Package, dataReader *bufio.Reader, path string) (pkg *types.Package, err error) { const currentVersion = 1 version := int64(-1) defer func() { @@ -74,7 +75,7 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data [] } }() - r := &intReader{bytes.NewReader(data), path} + r := &intReader{dataReader, path} version = int64(r.uint64()) switch version { @@ -86,10 +87,12 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data [] sLen := int64(r.uint64()) dLen := int64(r.uint64()) - whence, _ := r.Seek(0, io.SeekCurrent) - stringData := data[whence : whence+sLen] - declData := data[whence+sLen : whence+sLen+dLen] - r.Seek(sLen+dLen, io.SeekCurrent) + data := make([]byte, sLen+dLen) + if _, err := io.ReadFull(r, data); err != nil { + errorf("cannot read %d bytes of stringData and declData: %s", len(data), err) + } + stringData := data[:sLen] + declData := data[sLen:] p := iimporter{ ipath: path, @@ -165,9 +168,7 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data [] // package was imported completely and without errors localpkg.MarkComplete() - - consumed, _ := r.Seek(0, io.SeekCurrent) - return int(consumed), localpkg, nil + return localpkg, nil } type iimporter struct { From f4901341263adf7fc177e8e5e2e79576b490bb8f Mon Sep 17 00:00:00 2001 From: DQNEO Date: Mon, 31 May 2021 12:15:12 +0900 Subject: [PATCH 310/940] spec: improve wording by choosing an official term "keyword" Replace "reserved word" by "keyword" as the latter is the official term. Change-Id: I9f269759b872026034a9f47e4a761cff2d348ca0 Reviewed-on: https://go-review.googlesource.com/c/go/+/323729 Reviewed-by: Robert Griesemer Trust: Ian Lance Taylor Trust: Robert Griesemer --- doc/go_spec.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index e59b3554f28..7a2b3a80f0c 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -5020,7 +5020,7 @@ floating point, or string constants in case expressions. A type switch compares types rather than values. It is otherwise similar to an expression switch. It is marked by a special switch expression that has the form of a type assertion -using the reserved word type rather than an actual type: +using the keyword type rather than an actual type:


From e1fa26026db313463a09289c2105591de33cf7b8 Mon Sep 17 00:00:00 2001
From: DQNEO 
Date: Mon, 31 May 2021 12:33:28 +0900
Subject: [PATCH 311/940] spec: improve wording consistency by eliminating
 "specifier"

The word "specifier" is used once only here and technically not defined.

Change-Id: Ifc9f0582f4eb3c3011ba60d8008234de511d4be6
Reviewed-on: https://go-review.googlesource.com/c/go/+/323730
Reviewed-by: Robert Griesemer 
Trust: Ian Lance Taylor 
Trust: Robert Griesemer 
---
 doc/go_spec.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/doc/go_spec.html b/doc/go_spec.html
index 7a2b3a80f0c..561d44271a2 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -4909,7 +4909,7 @@ if x := f(); x < y {
 
 

"Switch" statements provide multi-way execution. -An expression or type specifier is compared to the "cases" +An expression or type is compared to the "cases" inside the "switch" to determine which branch to execute.

From 4c072c94dc2ffedd29d51d04aba2e1a6f2afd93f Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 4 Jun 2021 10:26:40 -0700 Subject: [PATCH 312/940] [dev.typeparams] cmd/compile: refactor import reading This CL restructures the gcimports importer to mmap the export data into memory as a string, and then pass that same string to both the typecheck and types2 importers. This is primarily motivated by preparation for unified IR; but it should also improve performance (fewer string copies) and reduces divergance between the two importers. Passes toolstash -cmp. Change-Id: I397f720693e9e6360bfcb5acb12609ab339d251f Reviewed-on: https://go-review.googlesource.com/c/go/+/325210 Run-TryBot: Matthew Dempsky Trust: Matthew Dempsky Trust: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- .../{typecheck => base}/mapfile_mmap.go | 4 +- .../{typecheck => base}/mapfile_read.go | 4 +- .../compile/internal/importer/gcimporter.go | 2 +- src/cmd/compile/internal/importer/iimport.go | 34 ++- src/cmd/compile/internal/noder/decl.go | 12 +- src/cmd/compile/internal/noder/import.go | 233 +++++++++++------- src/cmd/compile/internal/typecheck/iimport.go | 39 +-- 7 files changed, 173 insertions(+), 155 deletions(-) rename src/cmd/compile/internal/{typecheck => base}/mapfile_mmap.go (93%) rename src/cmd/compile/internal/{typecheck => base}/mapfile_read.go (85%) diff --git a/src/cmd/compile/internal/typecheck/mapfile_mmap.go b/src/cmd/compile/internal/base/mapfile_mmap.go similarity index 93% rename from src/cmd/compile/internal/typecheck/mapfile_mmap.go rename to src/cmd/compile/internal/base/mapfile_mmap.go index 298b385bcb0..c1616db8e9d 100644 --- a/src/cmd/compile/internal/typecheck/mapfile_mmap.go +++ b/src/cmd/compile/internal/base/mapfile_mmap.go @@ -5,7 +5,7 @@ //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd // +build darwin dragonfly freebsd linux netbsd openbsd -package typecheck +package base import ( "os" @@ -19,7 +19,7 @@ import ( // mapFile returns length bytes from the file starting at the // specified offset as a string. -func mapFile(f *os.File, offset, length int64) (string, error) { +func MapFile(f *os.File, offset, length int64) (string, error) { // POSIX mmap: "The implementation may require that off is a // multiple of the page size." x := offset & int64(os.Getpagesize()-1) diff --git a/src/cmd/compile/internal/typecheck/mapfile_read.go b/src/cmd/compile/internal/base/mapfile_read.go similarity index 85% rename from src/cmd/compile/internal/typecheck/mapfile_read.go rename to src/cmd/compile/internal/base/mapfile_read.go index 9637ab97abe..01796a9bab7 100644 --- a/src/cmd/compile/internal/typecheck/mapfile_read.go +++ b/src/cmd/compile/internal/base/mapfile_read.go @@ -5,14 +5,14 @@ //go:build !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd // +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd -package typecheck +package base import ( "io" "os" ) -func mapFile(f *os.File, offset, length int64) (string, error) { +func MapFile(f *os.File, offset, length int64) (string, error) { buf := make([]byte, length) _, err := io.ReadFull(io.NewSectionReader(f, offset, length), buf) if err != nil { diff --git a/src/cmd/compile/internal/importer/gcimporter.go b/src/cmd/compile/internal/importer/gcimporter.go index 6c5458fad18..ff40be65bbe 100644 --- a/src/cmd/compile/internal/importer/gcimporter.go +++ b/src/cmd/compile/internal/importer/gcimporter.go @@ -155,7 +155,7 @@ func Import(packages map[string]*types2.Package, path, srcDir string, lookup fun // binary export format starts with a 'c', 'd', or 'v' // (from "version"). Select appropriate importer. if len(data) > 0 && data[0] == 'i' { - _, pkg, err = iImportData(packages, data[1:], id) + pkg, err = ImportData(packages, string(data[1:]), id) } else { err = fmt.Errorf("import %q: old binary export format no longer supported (recompile library)", path) } diff --git a/src/cmd/compile/internal/importer/iimport.go b/src/cmd/compile/internal/importer/iimport.go index fb39e93073c..14e64891b80 100644 --- a/src/cmd/compile/internal/importer/iimport.go +++ b/src/cmd/compile/internal/importer/iimport.go @@ -8,7 +8,6 @@ package importer import ( - "bytes" "cmd/compile/internal/syntax" "cmd/compile/internal/types2" "encoding/binary" @@ -18,10 +17,11 @@ import ( "io" "math/big" "sort" + "strings" ) type intReader struct { - *bytes.Reader + *strings.Reader path string } @@ -82,7 +82,7 @@ const io_SeekCurrent = 1 // io.SeekCurrent (not defined in Go 1.4) // and returns the number of bytes consumed and a reference to the package. // If the export data version is not recognized or the format is otherwise // compromised, an error is returned. -func iImportData(imports map[string]*types2.Package, data []byte, path string) (_ int, pkg *types2.Package, err error) { +func ImportData(imports map[string]*types2.Package, data, path string) (pkg *types2.Package, err error) { const currentVersion = iexportVersionCurrent version := int64(-1) defer func() { @@ -95,7 +95,7 @@ func iImportData(imports map[string]*types2.Package, data []byte, path string) ( } }() - r := &intReader{bytes.NewReader(data), path} + r := &intReader{strings.NewReader(data), path} version = int64(r.uint64()) switch version { @@ -122,7 +122,6 @@ func iImportData(imports map[string]*types2.Package, data []byte, path string) ( version: int(version), stringData: stringData, - stringCache: make(map[uint64]string), pkgCache: make(map[uint64]*types2.Package), posBaseCache: make(map[uint64]*syntax.PosBase), @@ -196,8 +195,7 @@ func iImportData(imports map[string]*types2.Package, data []byte, path string) ( // package was imported completely and without errors localpkg.MarkComplete() - consumed, _ := r.Seek(0, io_SeekCurrent) - return int(consumed), localpkg, nil + return localpkg, nil } type iimporter struct { @@ -205,12 +203,11 @@ type iimporter struct { ipath string version int - stringData []byte - stringCache map[uint64]string + stringData string pkgCache map[uint64]*types2.Package posBaseCache map[uint64]*syntax.PosBase - declData []byte + declData string pkgIndex map[*types2.Package]map[string]uint64 typCache map[uint64]types2.Type tparamIndex map[ident]types2.Type @@ -233,24 +230,21 @@ func (p *iimporter) doDecl(pkg *types2.Package, name string) { // Reader.Reset is not available in Go 1.4. // Use bytes.NewReader for now. // r.declReader.Reset(p.declData[off:]) - r.declReader = *bytes.NewReader(p.declData[off:]) + r.declReader = *strings.NewReader(p.declData[off:]) r.obj(name) } func (p *iimporter) stringAt(off uint64) string { - if s, ok := p.stringCache[off]; ok { - return s - } + var x [binary.MaxVarintLen64]byte + n := copy(x[:], p.stringData[off:]) - slen, n := binary.Uvarint(p.stringData[off:]) + slen, n := binary.Uvarint(x[:n]) if n <= 0 { errorf("varint failed") } spos := off + uint64(n) - s := string(p.stringData[spos : spos+slen]) - p.stringCache[off] = s - return s + return p.stringData[spos : spos+slen] } func (p *iimporter) pkgAt(off uint64) *types2.Package { @@ -285,7 +279,7 @@ func (p *iimporter) typAt(off uint64, base *types2.Named) types2.Type { // Reader.Reset is not available in Go 1.4. // Use bytes.NewReader for now. // r.declReader.Reset(p.declData[off-predeclReserved:]) - r.declReader = *bytes.NewReader(p.declData[off-predeclReserved:]) + r.declReader = *strings.NewReader(p.declData[off-predeclReserved:]) t := r.doType(base) if base == nil || !isInterface(t) { @@ -296,7 +290,7 @@ func (p *iimporter) typAt(off uint64, base *types2.Named) types2.Type { type importReader struct { p *iimporter - declReader bytes.Reader + declReader strings.Reader currPkg *types2.Package prevPosBase *syntax.PosBase prevLine int64 diff --git a/src/cmd/compile/internal/noder/decl.go b/src/cmd/compile/internal/noder/decl.go index 5c80b206713..96abbe66ae1 100644 --- a/src/cmd/compile/internal/noder/decl.go +++ b/src/cmd/compile/internal/noder/decl.go @@ -41,21 +41,15 @@ func (g *irgen) decls(decls []syntax.Decl) []ir.Node { } func (g *irgen) importDecl(p *noder, decl *syntax.ImportDecl) { - // TODO(mdempsky): Merge with gcimports so we don't have to import - // packages twice. - g.pragmaFlags(decl.Pragma, 0) // Get the imported package's path, as resolved already by types2 // and gcimporter. This is the same path as would be computed by // parseImportPath. - path := pkgNameOf(g.info, decl).Imported().Path() - - ipkg := readImportFile(g.target, path) - if ipkg == ir.Pkgs.Unsafe { + switch pkgNameOf(g.info, decl).Imported().Path() { + case "unsafe": p.importedUnsafe = true - } - if ipkg.Path == "embed" { + case "embed": p.importedEmbed = true } } diff --git a/src/cmd/compile/internal/noder/import.go b/src/cmd/compile/internal/noder/import.go index 24d911ba381..8076b74650f 100644 --- a/src/cmd/compile/internal/noder/import.go +++ b/src/cmd/compile/internal/noder/import.go @@ -8,7 +8,6 @@ import ( "errors" "fmt" "internal/buildcfg" - "io" "os" pathpkg "path" "runtime" @@ -46,13 +45,8 @@ func (m *gcimports) ImportFrom(path, srcDir string, mode types2.ImportMode) (*ty panic("mode must be 0") } - path, err := resolveImportPath(path) - if err != nil { - return nil, err - } - - lookup := func(path string) (io.ReadCloser, error) { return openPackage(path) } - return importer.Import(m.packages, path, srcDir, lookup) + _, pkg, err := readImportFile(path, typecheck.Target, m.packages) + return pkg, err } func isDriveLetter(b byte) bool { @@ -182,7 +176,12 @@ func importfile(decl *syntax.ImportDecl) *types.Pkg { return nil } - pkg := readImportFile(typecheck.Target, path) + pkg, _, err := readImportFile(path, typecheck.Target, nil) + if err != nil { + base.Errorf("%s", err) + return nil + } + if pkg != ir.Pkgs.Unsafe && pkg.Height >= myheight { myheight = pkg.Height + 1 } @@ -203,136 +202,184 @@ func parseImportPath(pathLit *syntax.BasicLit) (string, error) { return "", err } - return resolveImportPath(path) + return path, err } -func readImportFile(target *ir.Package, path string) *types.Pkg { - importpkg := types.NewPkg(path, "") - if importpkg.Direct { - return importpkg // already fully loaded +// readImportFile reads the import file for the given package path and +// returns its types.Pkg representation. If packages is non-nil, the +// types2.Package representation is also returned. +func readImportFile(path string, target *ir.Package, packages map[string]*types2.Package) (pkg1 *types.Pkg, pkg2 *types2.Package, err error) { + path, err = resolveImportPath(path) + if err != nil { + return } - importpkg.Direct = true - target.Imports = append(target.Imports, importpkg) if path == "unsafe" { - return importpkg // initialized with universe + pkg1, pkg2 = ir.Pkgs.Unsafe, types2.Unsafe + + // TODO(mdempsky): Investigate if this actually matters. Why would + // the linker or runtime care whether a package imported unsafe? + if !pkg1.Direct { + pkg1.Direct = true + target.Imports = append(target.Imports, pkg1) + } + + return } + pkg1 = types.NewPkg(path, "") + if packages != nil { + pkg2 = packages[path] + assert(pkg1.Direct == (pkg2 != nil && pkg2.Complete())) + } + + if pkg1.Direct { + return + } + pkg1.Direct = true + target.Imports = append(target.Imports, pkg1) + f, err := openPackage(path) if err != nil { - base.Errorf("could not import %q: %v", path, err) - base.ErrorExit() + return } - imp := bio.NewReader(f) - defer imp.Close() - file := f.Name() + defer f.Close() + + r, end, err := findExportData(f) + if err != nil { + return + } + + if base.Debug.Export != 0 { + fmt.Printf("importing %s (%s)\n", path, f.Name()) + } + + var c byte + switch c, err = r.ReadByte(); { + case err != nil: + return + + case c != 'i': + // Indexed format is distinguished by an 'i' byte, + // whereas previous export formats started with 'c', 'd', or 'v'. + err = fmt.Errorf("unexpected package format byte: %v", c) + return + } + + // Map string (and data) section into memory as a single large + // string. This reduces heap fragmentation and allows + // returning individual substrings very efficiently. + pos := r.Offset() + data, err := base.MapFile(r.File(), pos, end-pos) + if err != nil { + return + } + + typecheck.ReadImports(pkg1, data) + + if packages != nil { + pkg2, err = importer.ImportData(packages, data, path) + if err != nil { + return + } + } + + err = addFingerprint(path, f, end) + return +} + +// findExportData returns a *bio.Reader positioned at the start of the +// binary export data section, and a file offset for where to stop +// reading. +func findExportData(f *os.File) (r *bio.Reader, end int64, err error) { + r = bio.NewReader(f) // check object header - p, err := imp.ReadString('\n') + line, err := r.ReadString('\n') if err != nil { - base.Errorf("import %s: reading input: %v", file, err) - base.ErrorExit() + return } - if p == "!\n" { // package archive + if line == "!\n" { // package archive // package export block should be first - sz := archive.ReadHeader(imp.Reader, "__.PKGDEF") + sz := int64(archive.ReadHeader(r.Reader, "__.PKGDEF")) if sz <= 0 { - base.Errorf("import %s: not a package file", file) - base.ErrorExit() + err = errors.New("not a package file") + return } - p, err = imp.ReadString('\n') + end = r.Offset() + sz + line, err = r.ReadString('\n') if err != nil { - base.Errorf("import %s: reading input: %v", file, err) - base.ErrorExit() + return } + } else { + // Not an archive; provide end of file instead. + // TODO(mdempsky): I don't think this happens anymore. + var fi os.FileInfo + fi, err = f.Stat() + if err != nil { + return + } + end = fi.Size() } - if !strings.HasPrefix(p, "go object ") { - base.Errorf("import %s: not a go object file: %s", file, p) - base.ErrorExit() + if !strings.HasPrefix(line, "go object ") { + err = fmt.Errorf("not a go object file: %s", line) + return } - q := objabi.HeaderString() - if p != q { - base.Errorf("import %s: object is [%s] expected [%s]", file, p, q) - base.ErrorExit() + if expect := objabi.HeaderString(); line != expect { + err = fmt.Errorf("object is [%s] expected [%s]", line, expect) + return } // process header lines - for { - p, err = imp.ReadString('\n') + for !strings.HasPrefix(line, "$$") { + line, err = r.ReadString('\n') if err != nil { - base.Errorf("import %s: reading input: %v", file, err) - base.ErrorExit() - } - if p == "\n" { - break // header ends with blank line + return } } // Expect $$B\n to signal binary import format. - - // look for $$ - var c byte - for { - c, err = imp.ReadByte() - if err != nil { - break - } - if c == '$' { - c, err = imp.ReadByte() - if c == '$' || err != nil { - break - } - } + if line != "$$B\n" { + err = errors.New("old export format no longer supported (recompile library)") + return } - // get character after $$ - if err == nil { - c, _ = imp.ReadByte() - } + return +} +// addFingerprint reads the linker fingerprint included at the end of +// the exportdata. +func addFingerprint(path string, f *os.File, end int64) error { + const eom = "\n$$\n" var fingerprint goobj.FingerprintType - switch c { - case '\n': - base.Errorf("cannot import %s: old export format no longer supported (recompile library)", path) - return nil - case 'B': - if base.Debug.Export != 0 { - fmt.Printf("importing %s (%s)\n", path, file) - } - imp.ReadByte() // skip \n after $$B - - c, err = imp.ReadByte() - if err != nil { - base.Errorf("import %s: reading input: %v", file, err) - base.ErrorExit() - } - - // Indexed format is distinguished by an 'i' byte, - // whereas previous export formats started with 'c', 'd', or 'v'. - if c != 'i' { - base.Errorf("import %s: unexpected package format byte: %v", file, c) - base.ErrorExit() - } - fingerprint = typecheck.ReadImports(importpkg, imp) - - default: - base.Errorf("no import in %q", path) - base.ErrorExit() + var buf [len(fingerprint) + len(eom)]byte + if _, err := f.ReadAt(buf[:], end-int64(len(buf))); err != nil { + return err } + // Caller should have given us the end position of the export data, + // which should end with the "\n$$\n" marker. As a consistency check + // to make sure we're reading at the right offset, make sure we + // found the marker. + if s := string(buf[len(fingerprint):]); s != eom { + return fmt.Errorf("expected $$ marker, but found %q", s) + } + + copy(fingerprint[:], buf[:]) + // assume files move (get installed) so don't record the full path if base.Flag.Cfg.PackageFile != nil { // If using a packageFile map, assume path_ can be recorded directly. base.Ctxt.AddImport(path, fingerprint) } else { // For file "/Users/foo/go/pkg/darwin_amd64/math.a" record "math.a". + file := f.Name() base.Ctxt.AddImport(file[len(file)-len(path)-len(".a"):], fingerprint) } - - return importpkg + return nil } // The linker uses the magic symbol prefixes "go." and "type." diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 45a177951ef..cafb18d7a88 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -12,7 +12,6 @@ import ( "encoding/binary" "fmt" "go/constant" - "io" "math/big" "os" "strings" @@ -20,8 +19,6 @@ import ( "cmd/compile/internal/base" "cmd/compile/internal/ir" "cmd/compile/internal/types" - "cmd/internal/bio" - "cmd/internal/goobj" "cmd/internal/obj" "cmd/internal/src" ) @@ -95,7 +92,7 @@ func importReaderFor(sym *types.Sym, importers map[*types.Sym]iimporterAndOffset } type intReader struct { - *bio.Reader + *strings.Reader pkg *types.Pkg } @@ -117,8 +114,8 @@ func (r *intReader) uint64() uint64 { return i } -func ReadImports(pkg *types.Pkg, in *bio.Reader) (fingerprint goobj.FingerprintType) { - ird := &intReader{in, pkg} +func ReadImports(pkg *types.Pkg, data string) { + ird := &intReader{strings.NewReader(data), pkg} version := ird.uint64() switch version { @@ -132,21 +129,15 @@ func ReadImports(pkg *types.Pkg, in *bio.Reader) (fingerprint goobj.FingerprintT base.ErrorExit() } - sLen := ird.uint64() - dLen := ird.uint64() + sLen := int64(ird.uint64()) + dLen := int64(ird.uint64()) - // Map string (and data) section into memory as a single large - // string. This reduces heap fragmentation and allows - // returning individual substrings very efficiently. - data, err := mapFile(in.File(), in.Offset(), int64(sLen+dLen)) - if err != nil { - base.Errorf("import %q: mapping input: %v", pkg.Path, err) - base.ErrorExit() - } - stringData := data[:sLen] - declData := data[sLen:] - - in.MustSeek(int64(sLen+dLen), os.SEEK_CUR) + // TODO(mdempsky): Replace os.SEEK_CUR with io.SeekCurrent after + // #44505 is fixed. + whence, _ := ird.Seek(0, os.SEEK_CUR) + stringData := data[whence : whence+sLen] + declData := data[whence+sLen : whence+sLen+dLen] + ird.Seek(sLen+dLen, os.SEEK_CUR) p := &iimporter{ exportVersion: version, @@ -208,14 +199,6 @@ func ReadImports(pkg *types.Pkg, in *bio.Reader) (fingerprint goobj.FingerprintT } } } - - // Fingerprint. - _, err = io.ReadFull(in, fingerprint[:]) - if err != nil { - base.Errorf("import %s: error reading fingerprint", pkg.Path) - base.ErrorExit() - } - return fingerprint } type iimporter struct { From a5be3eaee2cc0b8e5da216bdf545b9ca44789892 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 4 Jun 2021 13:14:32 -0700 Subject: [PATCH 313/940] [dev.typeparams] cmd/compile: refactor export writing This CL reorganizes export writing in preparation for unified IR: 1. It moves dumpexport into noder as noder.WriteExports so that it can be extended to include unified IR's export data. 2. Adds an "extensions" flag to typecheck.WriteExports to control whether the compiler-only extension data (e.g., function bodies and linker symbol info) is included in the exports. 3. It moves the gc.exporter type into typecheck and renames it to "crawler". The type originated as the implementation of the (pre-iexport) binary exporter, but since the removal of bexport it's been relegated to simply crawling the exported functions/bodies graph to identify which inline bodies need to be included. 4. It changes inline.Inline_Flood into the method crawler.markInlBody. Inline_Flood doesn't actually have anything to do with the rest of inlining; its current name and location are just historical quirks. Passes toolstash -cmp. Change-Id: I6445e2de9d3ce500a3aded5a8e20b09f46d23dbc Reviewed-on: https://go-review.googlesource.com/c/go/+/325212 Run-TryBot: Matthew Dempsky Trust: Matthew Dempsky Trust: Robert Griesemer Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/gc/export.go | 120 +------------ src/cmd/compile/internal/gc/obj.go | 3 +- src/cmd/compile/internal/inline/inl.go | 56 ------ src/cmd/compile/internal/noder/export.go | 26 +++ src/cmd/compile/internal/typecheck/crawler.go | 164 ++++++++++++++++++ src/cmd/compile/internal/typecheck/iexport.go | 38 +++- 6 files changed, 224 insertions(+), 183 deletions(-) create mode 100644 src/cmd/compile/internal/noder/export.go create mode 100644 src/cmd/compile/internal/typecheck/crawler.go diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go index a11e5fdd300..9bf3c7240ac 100644 --- a/src/cmd/compile/internal/gc/export.go +++ b/src/cmd/compile/internal/gc/export.go @@ -5,41 +5,16 @@ package gc import ( + "fmt" + "go/constant" + "cmd/compile/internal/base" - "cmd/compile/internal/inline" "cmd/compile/internal/ir" "cmd/compile/internal/typecheck" "cmd/compile/internal/types" "cmd/internal/bio" - "fmt" - "go/constant" ) -func exportf(bout *bio.Writer, format string, args ...interface{}) { - fmt.Fprintf(bout, format, args...) - if base.Debug.Export != 0 { - fmt.Printf(format, args...) - } -} - -func dumpexport(bout *bio.Writer) { - p := &exporter{marked: make(map[*types.Type]bool)} - for _, n := range typecheck.Target.Exports { - p.markObject(n) - } - - // The linker also looks for the $$ marker - use char after $$ to distinguish format. - exportf(bout, "\n$$B\n") // indicate binary export format - off := bout.Offset() - typecheck.WriteExports(bout.Writer) - size := bout.Offset() - off - exportf(bout, "\n$$\n") - - if base.Debug.Export != 0 { - fmt.Printf("BenchmarkExportSize:%s 1 %d bytes\n", base.Ctxt.Pkgpath, size) - } -} - func dumpasmhdr() { b, err := bio.Create(base.Flag.AsmHdr) if err != nil { @@ -74,92 +49,3 @@ func dumpasmhdr() { b.Close() } - -type exporter struct { - marked map[*types.Type]bool // types already seen by markType -} - -// markObject visits a reachable object. -func (p *exporter) markObject(n ir.Node) { - if n.Op() == ir.ONAME { - n := n.(*ir.Name) - if n.Class == ir.PFUNC { - inline.Inline_Flood(n, typecheck.Export) - } - } - - p.markType(n.Type()) -} - -// markType recursively visits types reachable from t to identify -// functions whose inline bodies may be needed. -func (p *exporter) markType(t *types.Type) { - if t.IsInstantiatedGeneric() { - // Re-instantiated types don't add anything new, so don't follow them. - return - } - if p.marked[t] { - return - } - p.marked[t] = true - - // If this is a named type, mark all of its associated - // methods. Skip interface types because t.Methods contains - // only their unexpanded method set (i.e., exclusive of - // interface embeddings), and the switch statement below - // handles their full method set. - if t.Sym() != nil && t.Kind() != types.TINTER { - for _, m := range t.Methods().Slice() { - if types.IsExported(m.Sym.Name) { - p.markObject(ir.AsNode(m.Nname)) - } - } - } - - // Recursively mark any types that can be produced given a - // value of type t: dereferencing a pointer; indexing or - // iterating over an array, slice, or map; receiving from a - // channel; accessing a struct field or interface method; or - // calling a function. - // - // Notably, we don't mark function parameter types, because - // the user already needs some way to construct values of - // those types. - switch t.Kind() { - case types.TPTR, types.TARRAY, types.TSLICE: - p.markType(t.Elem()) - - case types.TCHAN: - if t.ChanDir().CanRecv() { - p.markType(t.Elem()) - } - - case types.TMAP: - p.markType(t.Key()) - p.markType(t.Elem()) - - case types.TSTRUCT: - for _, f := range t.FieldSlice() { - if types.IsExported(f.Sym.Name) || f.Embedded != 0 { - p.markType(f.Type) - } - } - - case types.TFUNC: - for _, f := range t.Results().FieldSlice() { - p.markType(f.Type) - } - - case types.TINTER: - // TODO(danscales) - will have to deal with the types in interface - // elements here when implemented in types2 and represented in types1. - for _, f := range t.AllMethods().Slice() { - if types.IsExported(f.Sym.Name) { - p.markType(f.Type) - } - } - - case types.TTYPEPARAM: - // No other type that needs to be followed. - } -} diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go index 0b10cb8a9e1..a52696fbb6a 100644 --- a/src/cmd/compile/internal/gc/obj.go +++ b/src/cmd/compile/internal/gc/obj.go @@ -7,6 +7,7 @@ package gc import ( "cmd/compile/internal/base" "cmd/compile/internal/ir" + "cmd/compile/internal/noder" "cmd/compile/internal/objw" "cmd/compile/internal/reflectdata" "cmd/compile/internal/staticdata" @@ -103,7 +104,7 @@ func finishArchiveEntry(bout *bio.Writer, start int64, name string) { func dumpCompilerObj(bout *bio.Writer) { printObjHeader(bout) - dumpexport(bout) + noder.WriteExports(bout) } func dumpdata() { diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go index 594f280f039..e12a30f9369 100644 --- a/src/cmd/compile/internal/inline/inl.go +++ b/src/cmd/compile/internal/inline/inl.go @@ -225,62 +225,6 @@ func canDelayResults(fn *ir.Func) bool { return true } -// Inline_Flood marks n's inline body for export and recursively ensures -// all called functions are marked too. -func Inline_Flood(n *ir.Name, exportsym func(*ir.Name)) { - if n == nil { - return - } - if n.Op() != ir.ONAME || n.Class != ir.PFUNC { - base.Fatalf("Inline_Flood: unexpected %v, %v, %v", n, n.Op(), n.Class) - } - fn := n.Func - if fn == nil { - base.Fatalf("Inline_Flood: missing Func on %v", n) - } - if fn.Inl == nil { - return - } - - if fn.ExportInline() { - return - } - fn.SetExportInline(true) - - typecheck.ImportedBody(fn) - - var doFlood func(n ir.Node) - doFlood = func(n ir.Node) { - switch n.Op() { - case ir.OMETHEXPR, ir.ODOTMETH: - Inline_Flood(ir.MethodExprName(n), exportsym) - - case ir.ONAME: - n := n.(*ir.Name) - switch n.Class { - case ir.PFUNC: - Inline_Flood(n, exportsym) - exportsym(n) - case ir.PEXTERN: - exportsym(n) - } - - case ir.OCALLPART: - // Okay, because we don't yet inline indirect - // calls to method values. - case ir.OCLOSURE: - // VisitList doesn't visit closure bodies, so force a - // recursive call to VisitList on the body of the closure. - ir.VisitList(n.(*ir.ClosureExpr).Func.Body, doFlood) - } - } - - // Recursively identify all referenced functions for - // reexport. We want to include even non-called functions, - // because after inlining they might be callable. - ir.VisitList(ir.Nodes(fn.Inl.Body), doFlood) -} - // hairyVisitor visits a function body to determine its inlining // hairiness and whether or not it can be inlined. type hairyVisitor struct { diff --git a/src/cmd/compile/internal/noder/export.go b/src/cmd/compile/internal/noder/export.go new file mode 100644 index 00000000000..9fb3b4da109 --- /dev/null +++ b/src/cmd/compile/internal/noder/export.go @@ -0,0 +1,26 @@ +// Copyright 2021 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 noder + +import ( + "fmt" + + "cmd/compile/internal/base" + "cmd/compile/internal/typecheck" + "cmd/internal/bio" +) + +func WriteExports(out *bio.Writer) { + // The linker also looks for the $$ marker - use char after $$ to distinguish format. + out.WriteString("\n$$B\n") // indicate binary export format + off := out.Offset() + typecheck.WriteExports(out, true) + size := out.Offset() - off + out.WriteString("\n$$\n") + + if base.Debug.Export != 0 { + fmt.Printf("BenchmarkExportSize:%s 1 %d bytes\n", base.Ctxt.Pkgpath, size) + } +} diff --git a/src/cmd/compile/internal/typecheck/crawler.go b/src/cmd/compile/internal/typecheck/crawler.go new file mode 100644 index 00000000000..48fc61dbfd9 --- /dev/null +++ b/src/cmd/compile/internal/typecheck/crawler.go @@ -0,0 +1,164 @@ +// Copyright 2021 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 typecheck + +import ( + "cmd/compile/internal/base" + "cmd/compile/internal/ir" + "cmd/compile/internal/types" +) + +// crawlExports crawls the type/object graph rooted at the given list +// of exported objects. Any functions that are found to be potentially +// callable by importers are marked with ExportInline so that +// iexport.go knows to re-export their inline body. +func crawlExports(exports []*ir.Name) { + p := crawler{marked: make(map[*types.Type]bool)} + for _, n := range exports { + p.markObject(n) + } +} + +type crawler struct { + marked map[*types.Type]bool // types already seen by markType +} + +// markObject visits a reachable object. +func (p *crawler) markObject(n *ir.Name) { + if n.Op() == ir.ONAME && n.Class == ir.PFUNC { + p.markInlBody(n) + } + + p.markType(n.Type()) +} + +// markType recursively visits types reachable from t to identify +// functions whose inline bodies may be needed. +func (p *crawler) markType(t *types.Type) { + if t.IsInstantiatedGeneric() { + // Re-instantiated types don't add anything new, so don't follow them. + return + } + if p.marked[t] { + return + } + p.marked[t] = true + + // If this is a named type, mark all of its associated + // methods. Skip interface types because t.Methods contains + // only their unexpanded method set (i.e., exclusive of + // interface embeddings), and the switch statement below + // handles their full method set. + if t.Sym() != nil && t.Kind() != types.TINTER { + for _, m := range t.Methods().Slice() { + if types.IsExported(m.Sym.Name) { + p.markObject(m.Nname.(*ir.Name)) + } + } + } + + // Recursively mark any types that can be produced given a + // value of type t: dereferencing a pointer; indexing or + // iterating over an array, slice, or map; receiving from a + // channel; accessing a struct field or interface method; or + // calling a function. + // + // Notably, we don't mark function parameter types, because + // the user already needs some way to construct values of + // those types. + switch t.Kind() { + case types.TPTR, types.TARRAY, types.TSLICE: + p.markType(t.Elem()) + + case types.TCHAN: + if t.ChanDir().CanRecv() { + p.markType(t.Elem()) + } + + case types.TMAP: + p.markType(t.Key()) + p.markType(t.Elem()) + + case types.TSTRUCT: + for _, f := range t.FieldSlice() { + if types.IsExported(f.Sym.Name) || f.Embedded != 0 { + p.markType(f.Type) + } + } + + case types.TFUNC: + for _, f := range t.Results().FieldSlice() { + p.markType(f.Type) + } + + case types.TINTER: + // TODO(danscales) - will have to deal with the types in interface + // elements here when implemented in types2 and represented in types1. + for _, f := range t.AllMethods().Slice() { + if types.IsExported(f.Sym.Name) { + p.markType(f.Type) + } + } + + case types.TTYPEPARAM: + // No other type that needs to be followed. + } +} + +// markInlBody marks n's inline body for export and recursively +// ensures all called functions are marked too. +func (p *crawler) markInlBody(n *ir.Name) { + if n == nil { + return + } + if n.Op() != ir.ONAME || n.Class != ir.PFUNC { + base.Fatalf("markInlBody: unexpected %v, %v, %v", n, n.Op(), n.Class) + } + fn := n.Func + if fn == nil { + base.Fatalf("markInlBody: missing Func on %v", n) + } + if fn.Inl == nil { + return + } + + if fn.ExportInline() { + return + } + fn.SetExportInline(true) + + ImportedBody(fn) + + var doFlood func(n ir.Node) + doFlood = func(n ir.Node) { + switch n.Op() { + case ir.OMETHEXPR, ir.ODOTMETH: + p.markInlBody(ir.MethodExprName(n)) + + case ir.ONAME: + n := n.(*ir.Name) + switch n.Class { + case ir.PFUNC: + p.markInlBody(n) + Export(n) + case ir.PEXTERN: + Export(n) + } + + case ir.OCALLPART: + // Okay, because we don't yet inline indirect + // calls to method values. + case ir.OCLOSURE: + // VisitList doesn't visit closure bodies, so force a + // recursive call to VisitList on the body of the closure. + ir.VisitList(n.(*ir.ClosureExpr).Func.Body, doFlood) + } + } + + // Recursively identify all referenced functions for + // reexport. We want to include even non-called functions, + // because after inlining they might be callable. + ir.VisitList(fn.Inl.Body, doFlood) +} diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index 3bfbea11c02..6987bc99188 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -204,7 +204,6 @@ package typecheck import ( - "bufio" "bytes" "crypto/md5" "encoding/binary" @@ -264,13 +263,22 @@ const ( magic = 0x6742937dc293105 ) -func WriteExports(out *bufio.Writer) { +// WriteExports writes the indexed export format to out. If extensions +// is true, then the compiler-only extensions are included. +func WriteExports(out io.Writer, extensions bool) { + if extensions { + // If we're exporting inline bodies, invoke the crawler to mark + // which bodies to include. + crawlExports(Target.Exports) + } + p := iexporter{ allPkgs: map[*types.Pkg]bool{}, stringIndex: map[string]uint64{}, declIndex: map[*types.Sym]uint64{}, inlineIndex: map[*types.Sym]uint64{}, typIndex: map[*types.Type]uint64{}, + extensions: extensions, } for i, pt := range predeclared() { @@ -397,6 +405,8 @@ type iexporter struct { declIndex map[*types.Sym]uint64 inlineIndex map[*types.Sym]uint64 typIndex map[*types.Type]uint64 + + extensions bool } // stringOff returns the offset of s within the string section. @@ -467,7 +477,9 @@ func (p *iexporter) doDecl(n *ir.Name) { w.tag('V') w.pos(n.Pos()) w.typ(n.Type()) - w.varExt(n) + if w.p.extensions { + w.varExt(n) + } case ir.PFUNC: if ir.IsMethod(n) { @@ -487,7 +499,9 @@ func (p *iexporter) doDecl(n *ir.Name) { w.tparamList(n.Type().TParams().FieldSlice()) } w.signature(n.Type()) - w.funcExt(n) + if w.p.extensions { + w.funcExt(n) + } default: base.Fatalf("unexpected class: %v, %v", n, n.Class) @@ -503,7 +517,9 @@ func (p *iexporter) doDecl(n *ir.Name) { w.tag('C') w.pos(n.Pos()) w.value(n.Type(), n.Val()) - w.constExt(n) + if w.p.extensions { + w.constExt(n) + } case ir.OTYPE: if n.Type().Kind() == types.TTYPEPARAM && n.Type().Underlying() == n.Type() { @@ -551,7 +567,9 @@ func (p *iexporter) doDecl(n *ir.Name) { t := n.Type() if t.IsInterface() { - w.typeExt(t) + if w.p.extensions { + w.typeExt(t) + } break } @@ -567,9 +585,11 @@ func (p *iexporter) doDecl(n *ir.Name) { w.signature(m.Type) } - w.typeExt(t) - for _, m := range methods { - w.methExt(m) + if w.p.extensions { + w.typeExt(t) + for _, m := range methods { + w.methExt(m) + } } default: From c23294d6b356590d5ebcaf153048111ee9b30465 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Sat, 5 Jun 2021 21:23:48 -0700 Subject: [PATCH 314/940] [dev.typeparams] cmd/compile/internal/types2: return Universe for ((*Package)(nil)).Scope() For #46594. Change-Id: I53776cbdc1b8f6da511abe2c6659a7313d7a163a Reviewed-on: https://go-review.googlesource.com/c/go/+/325469 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/types2/package.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/types2/package.go b/src/cmd/compile/internal/types2/package.go index c5804a05adc..8044e7e6a76 100644 --- a/src/cmd/compile/internal/types2/package.go +++ b/src/cmd/compile/internal/types2/package.go @@ -48,7 +48,13 @@ func (pkg *Package) SetName(name string) { pkg.name = name } // Scope returns the (complete or incomplete) package scope // holding the objects declared at package level (TypeNames, // Consts, Vars, and Funcs). -func (pkg *Package) Scope() *Scope { return pkg.scope } +// For a nil pkg receiver, Scope returns the Universe scope. +func (pkg *Package) Scope() *Scope { + if pkg != nil { + return pkg.scope + } + return Universe +} // A package is complete if its scope contains (at least) all // exported objects; otherwise it is incomplete. From e3176bbc3ec7ab3889f02432f6fd088c90fc12dd Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 7 Jun 2021 10:24:11 -0400 Subject: [PATCH 315/940] crypto/tls: fix typo in Config.NextProtos docs Change-Id: I916df584859595067e5e86c35607869397dbbd8c Reviewed-on: https://go-review.googlesource.com/c/go/+/325651 Trust: Filippo Valsorda Run-TryBot: Filippo Valsorda TryBot-Result: Go Bot Reviewed-by: Dmitri Shuralyov --- src/crypto/tls/common.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go index 77957ef82bd..d561e61707e 100644 --- a/src/crypto/tls/common.go +++ b/src/crypto/tls/common.go @@ -619,7 +619,7 @@ type Config struct { // protocol will be one from this list, and the connection will fail // if there is no mutually supported protocol. If NextProtos is empty // or the peer doesn't support ALPN, the connection will succeed and - // ConnectionState.NegotiatedProtocol will be empty." + // ConnectionState.NegotiatedProtocol will be empty. NextProtos []string // ServerName is used to verify the hostname on the returned From 7406180012d828f536112c9bffb7d3edd9ea5c7e Mon Sep 17 00:00:00 2001 From: Branden J Brown Date: Wed, 2 Jun 2021 14:55:34 -0400 Subject: [PATCH 316/940] fmt: split package documentation into more sections The package-level documentation on fmt previously had only two formal sections, for printing and scanning. Because of this, the section on printing was very long, including some pseudo-sections describing particular features. This feature makes those pseudo-sections into proper sections, both to improve readability and so that those sections have hyperlinks on documentation sites. Fixes #46522 Change-Id: I38b7bc3447610faca446051da235edcbbd063f61 Reviewed-on: https://go-review.googlesource.com/c/go/+/324349 Reviewed-by: Rob Pike Reviewed-by: Dmitri Shuralyov Run-TryBot: Dmitri Shuralyov TryBot-Result: Go Bot Trust: Tobias Klauser --- src/fmt/doc.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fmt/doc.go b/src/fmt/doc.go index d05ee519c3d..c584cc9465e 100644 --- a/src/fmt/doc.go +++ b/src/fmt/doc.go @@ -189,7 +189,7 @@ When printing a struct, fmt cannot and therefore does not invoke formatting methods such as Error or String on unexported fields. - Explicit argument indexes: + Explicit argument indexes In Printf, Sprintf, and Fprintf, the default behavior is for each formatting verb to format successive arguments passed in the call. @@ -211,7 +211,7 @@ fmt.Sprintf("%d %d %#[1]x %#x", 16, 17) will yield "16 17 0x10 0x11". - Format errors: + Format errors If an invalid argument is given for a verb, such as providing a string to %d, the generated string will contain a From 821270787109408ae7c86a01ccc93162be9c020c Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 7 Jun 2021 10:22:05 -0400 Subject: [PATCH 317/940] crypto/elliptic: update P-521 docs to say it's constant-time This is true since CL 315274. Also adjust the P-256 note, since Add, Double, and IsOnCurve use the generic, non-constant-time implementation. Change-Id: I4b3b340f65bce91dcca30bcf86456cc8ce4dd4bb Reviewed-on: https://go-review.googlesource.com/c/go/+/325650 Trust: Filippo Valsorda Trust: Katie Hockman Run-TryBot: Filippo Valsorda Reviewed-by: Katie Hockman TryBot-Result: Go Bot --- src/crypto/elliptic/elliptic.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/crypto/elliptic/elliptic.go b/src/crypto/elliptic/elliptic.go index b8e5a3097d2..f072960bfed 100644 --- a/src/crypto/elliptic/elliptic.go +++ b/src/crypto/elliptic/elliptic.go @@ -455,7 +455,7 @@ func initP384() { // Multiple invocations of this function will return the same value, so it can // be used for equality checks and switch statements. // -// The cryptographic operations are implemented using constant-time algorithms. +// ScalarMult and ScalarBaseMult are implemented using constant-time algorithms. func P256() Curve { initonce.Do(initAll) return p256 @@ -479,7 +479,7 @@ func P384() Curve { // Multiple invocations of this function will return the same value, so it can // be used for equality checks and switch statements. // -// The cryptographic operations do not use constant-time algorithms. +// The cryptographic operations are implemented using constant-time algorithms. func P521() Curve { initonce.Do(initAll) return p521 From 991dca0112c9c81c384b32d413a693ff4751c3ab Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 3 Jun 2021 11:13:38 -0400 Subject: [PATCH 318/940] [dev.typeparams] go/types: move signature checking into separate file This is a port of CL 321590 to go/types. Specifically, the same checker methods were moved. Change-Id: If4522d316f29c6b6f887580aa037e6b6dedbb6ac Reviewed-on: https://go-review.googlesource.com/c/go/+/324754 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/signature.go | 274 ++++++++++++++++++++++++++++++++++++++ src/go/types/typexpr.go | 262 ------------------------------------ 2 files changed, 274 insertions(+), 262 deletions(-) create mode 100644 src/go/types/signature.go diff --git a/src/go/types/signature.go b/src/go/types/signature.go new file mode 100644 index 00000000000..5489b493baa --- /dev/null +++ b/src/go/types/signature.go @@ -0,0 +1,274 @@ +// Copyright 2021 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 types + +import ( + "fmt" + "go/ast" + "go/internal/typeparams" + "go/token" +) + +// funcType type-checks a function or method type. +func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast.FuncType) { + check.openScope(ftyp, "function") + check.scope.isFunc = true + check.recordScope(ftyp, check.scope) + sig.scope = check.scope + defer check.closeScope() + + var recvTyp ast.Expr // rewritten receiver type; valid if != nil + if recvPar != nil && len(recvPar.List) > 0 { + // collect generic receiver type parameters, if any + // - a receiver type parameter is like any other type parameter, except that it is declared implicitly + // - the receiver specification acts as local declaration for its type parameters, which may be blank + _, rname, rparams := check.unpackRecv(recvPar.List[0].Type, true) + if len(rparams) > 0 { + // Blank identifiers don't get declared and regular type-checking of the instantiated + // parameterized receiver type expression fails in Checker.collectParams of receiver. + // Identify blank type parameters and substitute each with a unique new identifier named + // "n_" (where n is the parameter index) and which cannot conflict with any user-defined + // name. + var smap map[*ast.Ident]*ast.Ident // substitution map from "_" to "n_" identifiers + for i, p := range rparams { + if p.Name == "_" { + new := *p + new.Name = fmt.Sprintf("%d_", i) + rparams[i] = &new // use n_ identifier instead of _ so it can be looked up + if smap == nil { + smap = make(map[*ast.Ident]*ast.Ident) + } + smap[p] = &new + } + } + if smap != nil { + // blank identifiers were found => use rewritten receiver type + recvTyp = isubst(recvPar.List[0].Type, smap) + } + sig.rparams = check.declareTypeParams(nil, rparams) + // determine receiver type to get its type parameters + // and the respective type parameter bounds + var recvTParams []*TypeName + if rname != nil { + // recv should be a Named type (otherwise an error is reported elsewhere) + // Also: Don't report an error via genericType since it will be reported + // again when we type-check the signature. + // TODO(gri) maybe the receiver should be marked as invalid instead? + if recv := asNamed(check.genericType(rname, false)); recv != nil { + recvTParams = recv.tparams + } + } + // provide type parameter bounds + // - only do this if we have the right number (otherwise an error is reported elsewhere) + if len(sig.rparams) == len(recvTParams) { + // We have a list of *TypeNames but we need a list of Types. + list := make([]Type, len(sig.rparams)) + for i, t := range sig.rparams { + list[i] = t.typ + } + smap := makeSubstMap(recvTParams, list) + for i, tname := range sig.rparams { + bound := recvTParams[i].typ.(*_TypeParam).bound + // bound is (possibly) parameterized in the context of the + // receiver type declaration. Substitute parameters for the + // current context. + // TODO(gri) should we assume now that bounds always exist? + // (no bound == empty interface) + if bound != nil { + bound = check.subst(tname.pos, bound, smap) + tname.typ.(*_TypeParam).bound = bound + } + } + } + } + } + + if tparams := typeparams.Get(ftyp); tparams != nil { + sig.tparams = check.collectTypeParams(tparams) + // Always type-check method type parameters but complain that they are not allowed. + // (A separate check is needed when type-checking interface method signatures because + // they don't have a receiver specification.) + if recvPar != nil { + check.errorf(tparams, _Todo, "methods cannot have type parameters") + } + } + + // Value (non-type) parameters' scope starts in the function body. Use a temporary scope for their + // declarations and then squash that scope into the parent scope (and report any redeclarations at + // that time). + scope := NewScope(check.scope, token.NoPos, token.NoPos, "function body (temp. scope)") + recvList, _ := check.collectParams(scope, recvPar, recvTyp, false) // use rewritten receiver type, if any + params, variadic := check.collectParams(scope, ftyp.Params, nil, true) + results, _ := check.collectParams(scope, ftyp.Results, nil, false) + scope.squash(func(obj, alt Object) { + check.errorf(obj, _DuplicateDecl, "%s redeclared in this block", obj.Name()) + check.reportAltDecl(alt) + }) + + if recvPar != nil { + // recv parameter list present (may be empty) + // spec: "The receiver is specified via an extra parameter section preceding the + // method name. That parameter section must declare a single parameter, the receiver." + var recv *Var + switch len(recvList) { + case 0: + // error reported by resolver + recv = NewParam(0, nil, "", Typ[Invalid]) // ignore recv below + default: + // more than one receiver + check.error(recvList[len(recvList)-1], _BadRecv, "method must have exactly one receiver") + fallthrough // continue with first receiver + case 1: + recv = recvList[0] + } + + // TODO(gri) We should delay rtyp expansion to when we actually need the + // receiver; thus all checks here should be delayed to later. + rtyp, _ := deref(recv.typ) + rtyp = expand(rtyp) + + // spec: "The receiver type must be of the form T or *T where T is a type name." + // (ignore invalid types - error was reported before) + if t := rtyp; t != Typ[Invalid] { + var err string + if T := asNamed(t); T != nil { + // spec: "The type denoted by T is called the receiver base type; it must not + // be a pointer or interface type and it must be declared in the same package + // as the method." + if T.obj.pkg != check.pkg { + err = "type not defined in this package" + } else { + switch u := optype(T).(type) { + case *Basic: + // unsafe.Pointer is treated like a regular pointer + if u.kind == UnsafePointer { + err = "unsafe.Pointer" + } + case *Pointer, *Interface: + err = "pointer or interface type" + } + } + } else { + err = "basic or unnamed type" + } + if err != "" { + check.errorf(recv, _InvalidRecv, "invalid receiver %s (%s)", recv.typ, err) + // ok to continue + } + } + sig.recv = recv + } + + sig.params = NewTuple(params...) + sig.results = NewTuple(results...) + sig.variadic = variadic +} + +// collectParams declares the parameters of list in scope and returns the corresponding +// variable list. If type0 != nil, it is used instead of the first type in list. +func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, type0 ast.Expr, variadicOk bool) (params []*Var, variadic bool) { + if list == nil { + return + } + + var named, anonymous bool + for i, field := range list.List { + ftype := field.Type + if i == 0 && type0 != nil { + ftype = type0 + } + if t, _ := ftype.(*ast.Ellipsis); t != nil { + ftype = t.Elt + if variadicOk && i == len(list.List)-1 && len(field.Names) <= 1 { + variadic = true + } else { + check.softErrorf(t, _MisplacedDotDotDot, "can only use ... with final parameter in list") + // ignore ... and continue + } + } + typ := check.varType(ftype) + // The parser ensures that f.Tag is nil and we don't + // care if a constructed AST contains a non-nil tag. + if len(field.Names) > 0 { + // named parameter + for _, name := range field.Names { + if name.Name == "" { + check.invalidAST(name, "anonymous parameter") + // ok to continue + } + par := NewParam(name.Pos(), check.pkg, name.Name, typ) + check.declare(scope, name, par, scope.pos) + params = append(params, par) + } + named = true + } else { + // anonymous parameter + par := NewParam(ftype.Pos(), check.pkg, "", typ) + check.recordImplicit(field, par) + params = append(params, par) + anonymous = true + } + } + + if named && anonymous { + check.invalidAST(list, "list contains both named and anonymous parameters") + // ok to continue + } + + // For a variadic function, change the last parameter's type from T to []T. + // Since we type-checked T rather than ...T, we also need to retro-actively + // record the type for ...T. + if variadic { + last := params[len(params)-1] + last.typ = &Slice{elem: last.typ} + check.recordTypeAndValue(list.List[len(list.List)-1].Type, typexpr, last.typ, nil) + } + + return +} + +// isubst returns an x with identifiers substituted per the substitution map smap. +// isubst only handles the case of (valid) method receiver type expressions correctly. +func isubst(x ast.Expr, smap map[*ast.Ident]*ast.Ident) ast.Expr { + switch n := x.(type) { + case *ast.Ident: + if alt := smap[n]; alt != nil { + return alt + } + case *ast.StarExpr: + X := isubst(n.X, smap) + if X != n.X { + new := *n + new.X = X + return &new + } + case *ast.IndexExpr: + elems := typeparams.UnpackExpr(n.Index) + var newElems []ast.Expr + for i, elem := range elems { + new := isubst(elem, smap) + if new != elem { + if newElems == nil { + newElems = make([]ast.Expr, len(elems)) + copy(newElems, elems) + } + newElems[i] = new + } + } + if newElems != nil { + index := typeparams.PackExpr(newElems) + new := *n + new.Index = index + return &new + } + case *ast.ParenExpr: + return isubst(n.X, smap) // no need to keep parentheses + default: + // Other receiver type expressions are invalid. + // It's fine to ignore those here as they will + // be checked elsewhere. + } + return x +} diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index c6c3dc049a2..97df908ae93 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -192,205 +192,6 @@ func (check *Checker) genericType(e ast.Expr, reportErr bool) Type { return typ } -// isubst returns an x with identifiers substituted per the substitution map smap. -// isubst only handles the case of (valid) method receiver type expressions correctly. -func isubst(x ast.Expr, smap map[*ast.Ident]*ast.Ident) ast.Expr { - switch n := x.(type) { - case *ast.Ident: - if alt := smap[n]; alt != nil { - return alt - } - case *ast.StarExpr: - X := isubst(n.X, smap) - if X != n.X { - new := *n - new.X = X - return &new - } - case *ast.IndexExpr: - elems := typeparams.UnpackExpr(n.Index) - var newElems []ast.Expr - for i, elem := range elems { - new := isubst(elem, smap) - if new != elem { - if newElems == nil { - newElems = make([]ast.Expr, len(elems)) - copy(newElems, elems) - } - newElems[i] = new - } - } - if newElems != nil { - index := typeparams.PackExpr(newElems) - new := *n - new.Index = index - return &new - } - case *ast.ParenExpr: - return isubst(n.X, smap) // no need to keep parentheses - default: - // Other receiver type expressions are invalid. - // It's fine to ignore those here as they will - // be checked elsewhere. - } - return x -} - -// funcType type-checks a function or method type. -func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast.FuncType) { - check.openScope(ftyp, "function") - check.scope.isFunc = true - check.recordScope(ftyp, check.scope) - sig.scope = check.scope - defer check.closeScope() - - var recvTyp ast.Expr // rewritten receiver type; valid if != nil - if recvPar != nil && len(recvPar.List) > 0 { - // collect generic receiver type parameters, if any - // - a receiver type parameter is like any other type parameter, except that it is declared implicitly - // - the receiver specification acts as local declaration for its type parameters, which may be blank - _, rname, rparams := check.unpackRecv(recvPar.List[0].Type, true) - if len(rparams) > 0 { - // Blank identifiers don't get declared and regular type-checking of the instantiated - // parameterized receiver type expression fails in Checker.collectParams of receiver. - // Identify blank type parameters and substitute each with a unique new identifier named - // "n_" (where n is the parameter index) and which cannot conflict with any user-defined - // name. - var smap map[*ast.Ident]*ast.Ident // substitution map from "_" to "n_" identifiers - for i, p := range rparams { - if p.Name == "_" { - new := *p - new.Name = fmt.Sprintf("%d_", i) - rparams[i] = &new // use n_ identifier instead of _ so it can be looked up - if smap == nil { - smap = make(map[*ast.Ident]*ast.Ident) - } - smap[p] = &new - } - } - if smap != nil { - // blank identifiers were found => use rewritten receiver type - recvTyp = isubst(recvPar.List[0].Type, smap) - } - sig.rparams = check.declareTypeParams(nil, rparams) - // determine receiver type to get its type parameters - // and the respective type parameter bounds - var recvTParams []*TypeName - if rname != nil { - // recv should be a Named type (otherwise an error is reported elsewhere) - // Also: Don't report an error via genericType since it will be reported - // again when we type-check the signature. - // TODO(gri) maybe the receiver should be marked as invalid instead? - if recv := asNamed(check.genericType(rname, false)); recv != nil { - recvTParams = recv.tparams - } - } - // provide type parameter bounds - // - only do this if we have the right number (otherwise an error is reported elsewhere) - if len(sig.rparams) == len(recvTParams) { - // We have a list of *TypeNames but we need a list of Types. - list := make([]Type, len(sig.rparams)) - for i, t := range sig.rparams { - list[i] = t.typ - } - smap := makeSubstMap(recvTParams, list) - for i, tname := range sig.rparams { - bound := recvTParams[i].typ.(*_TypeParam).bound - // bound is (possibly) parameterized in the context of the - // receiver type declaration. Substitute parameters for the - // current context. - // TODO(gri) should we assume now that bounds always exist? - // (no bound == empty interface) - if bound != nil { - bound = check.subst(tname.pos, bound, smap) - tname.typ.(*_TypeParam).bound = bound - } - } - } - } - } - - if tparams := typeparams.Get(ftyp); tparams != nil { - sig.tparams = check.collectTypeParams(tparams) - // Always type-check method type parameters but complain that they are not allowed. - // (A separate check is needed when type-checking interface method signatures because - // they don't have a receiver specification.) - if recvPar != nil { - check.errorf(tparams, _Todo, "methods cannot have type parameters") - } - } - - // Value (non-type) parameters' scope starts in the function body. Use a temporary scope for their - // declarations and then squash that scope into the parent scope (and report any redeclarations at - // that time). - scope := NewScope(check.scope, token.NoPos, token.NoPos, "function body (temp. scope)") - recvList, _ := check.collectParams(scope, recvPar, recvTyp, false) // use rewritten receiver type, if any - params, variadic := check.collectParams(scope, ftyp.Params, nil, true) - results, _ := check.collectParams(scope, ftyp.Results, nil, false) - scope.squash(func(obj, alt Object) { - check.errorf(obj, _DuplicateDecl, "%s redeclared in this block", obj.Name()) - check.reportAltDecl(alt) - }) - - if recvPar != nil { - // recv parameter list present (may be empty) - // spec: "The receiver is specified via an extra parameter section preceding the - // method name. That parameter section must declare a single parameter, the receiver." - var recv *Var - switch len(recvList) { - case 0: - // error reported by resolver - recv = NewParam(0, nil, "", Typ[Invalid]) // ignore recv below - default: - // more than one receiver - check.error(recvList[len(recvList)-1], _BadRecv, "method must have exactly one receiver") - fallthrough // continue with first receiver - case 1: - recv = recvList[0] - } - - // TODO(gri) We should delay rtyp expansion to when we actually need the - // receiver; thus all checks here should be delayed to later. - rtyp, _ := deref(recv.typ) - rtyp = expand(rtyp) - - // spec: "The receiver type must be of the form T or *T where T is a type name." - // (ignore invalid types - error was reported before) - if t := rtyp; t != Typ[Invalid] { - var err string - if T := asNamed(t); T != nil { - // spec: "The type denoted by T is called the receiver base type; it must not - // be a pointer or interface type and it must be declared in the same package - // as the method." - if T.obj.pkg != check.pkg { - err = "type not defined in this package" - } else { - switch u := optype(T).(type) { - case *Basic: - // unsafe.Pointer is treated like a regular pointer - if u.kind == UnsafePointer { - err = "unsafe.Pointer" - } - case *Pointer, *Interface: - err = "pointer or interface type" - } - } - } else { - err = "basic or unnamed type" - } - if err != "" { - check.errorf(recv, _InvalidRecv, "invalid receiver %s (%s)", recv.typ, err) - // ok to continue - } - } - sig.recv = recv - } - - sig.params = NewTuple(params...) - sig.results = NewTuple(results...) - sig.variadic = variadic -} - // goTypeName returns the Go type name for typ and // removes any occurrences of "types." from that name. func goTypeName(typ Type) string { @@ -683,66 +484,3 @@ func (check *Checker) typeList(list []ast.Expr) []Type { } return res } - -// collectParams declares the parameters of list in scope and returns the corresponding -// variable list. If type0 != nil, it is used instead of the first type in list. -func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, type0 ast.Expr, variadicOk bool) (params []*Var, variadic bool) { - if list == nil { - return - } - - var named, anonymous bool - for i, field := range list.List { - ftype := field.Type - if i == 0 && type0 != nil { - ftype = type0 - } - if t, _ := ftype.(*ast.Ellipsis); t != nil { - ftype = t.Elt - if variadicOk && i == len(list.List)-1 && len(field.Names) <= 1 { - variadic = true - } else { - check.softErrorf(t, _MisplacedDotDotDot, "can only use ... with final parameter in list") - // ignore ... and continue - } - } - typ := check.varType(ftype) - // The parser ensures that f.Tag is nil and we don't - // care if a constructed AST contains a non-nil tag. - if len(field.Names) > 0 { - // named parameter - for _, name := range field.Names { - if name.Name == "" { - check.invalidAST(name, "anonymous parameter") - // ok to continue - } - par := NewParam(name.Pos(), check.pkg, name.Name, typ) - check.declare(scope, name, par, scope.pos) - params = append(params, par) - } - named = true - } else { - // anonymous parameter - par := NewParam(ftype.Pos(), check.pkg, "", typ) - check.recordImplicit(field, par) - params = append(params, par) - anonymous = true - } - } - - if named && anonymous { - check.invalidAST(list, "list contains both named and anonymous parameters") - // ok to continue - } - - // For a variadic function, change the last parameter's type from T to []T. - // Since we type-checked T rather than ...T, we also need to retro-actively - // record the type for ...T. - if variadic { - last := params[len(params)-1] - last.typ = &Slice{elem: last.typ} - check.recordTypeAndValue(list.List[len(list.List)-1].Type, typexpr, last.typ, nil) - } - - return -} From 139595207570ae380e3947fa39e43205477b7bba Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 3 Jun 2021 11:37:26 -0400 Subject: [PATCH 319/940] [dev.typeparams] go/types: add Named.SetTParams and Named.Orig methods This is a port of CL 309832 to go/types, adjusted to not export the new API and to amend TestSizeof. Change-Id: I67efd3ba9b921c8431528eba1cd88ec1f41898bb Reviewed-on: https://go-review.googlesource.com/c/go/+/324755 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/decl.go | 9 ++++----- src/go/types/sanitize.go | 4 ++-- src/go/types/sizeof_test.go | 2 +- src/go/types/subst.go | 5 ++--- src/go/types/type.go | 27 ++++++++++++++++++++------- 5 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/go/types/decl.go b/src/go/types/decl.go index 9211febc6da..12ee51b9201 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -333,7 +333,7 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo { switch t.info { case unknown: t.info = marked - t.info = check.validType(t.orig, append(path, t.obj)) // only types of current package added to path + t.info = check.validType(t.fromRHS, append(path, t.obj)) // only types of current package added to path case marked: // cycle detected for i, tn := range path { @@ -692,9 +692,8 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) { } else { // defined type declaration - named := check.newNamed(obj, nil, nil) + named := check.newNamed(obj, nil, nil, nil, nil) def.setUnderlying(named) - obj.typ = named // make sure recursive type declarations terminate if tparams := typeparams.Get(tdecl); tparams != nil { check.openScope(tdecl, "type parameters") @@ -703,7 +702,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) { } // determine underlying type of named - named.orig = check.definedType(tdecl.Type, named) + named.fromRHS = check.definedType(tdecl.Type, named) // The underlying type of named may be itself a named type that is // incomplete: @@ -718,7 +717,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) { // and which has as its underlying type the named type B. // Determine the (final, unnamed) underlying type by resolving // any forward chain. - // TODO(gri) Investigate if we can just use named.origin here + // TODO(gri) Investigate if we can just use named.fromRHS here // and rely on lazy computation of the underlying type. named.underlying = under(named) } diff --git a/src/go/types/sanitize.go b/src/go/types/sanitize.go index f167cdd8b63..88fc3f83772 100644 --- a/src/go/types/sanitize.go +++ b/src/go/types/sanitize.go @@ -138,8 +138,8 @@ func (s sanitizer) typ(typ Type) Type { if debug && t.check != nil { panic("internal error: Named.check != nil") } - if orig := s.typ(t.orig); orig != t.orig { - t.orig = orig + if orig := s.typ(t.fromRHS); orig != t.fromRHS { + t.fromRHS = orig } if under := s.typ(t.underlying); under != t.underlying { t.underlying = under diff --git a/src/go/types/sizeof_test.go b/src/go/types/sizeof_test.go index 5a9d07ca418..3af9079a85c 100644 --- a/src/go/types/sizeof_test.go +++ b/src/go/types/sizeof_test.go @@ -30,7 +30,7 @@ func TestSizeof(t *testing.T) { {Interface{}, 60, 120}, {Map{}, 16, 32}, {Chan{}, 12, 24}, - {Named{}, 64, 128}, + {Named{}, 68, 136}, {_TypeParam{}, 28, 48}, {instance{}, 44, 88}, {bottom{}, 0, 0}, diff --git a/src/go/types/subst.go b/src/go/types/subst.go index d27f3645cc3..43a64d04bb5 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -396,8 +396,7 @@ func (subst *subster) typ(typ Type) Type { // create a new named type and populate caches to avoid endless recursion tname := NewTypeName(subst.pos, t.obj.pkg, t.obj.name, nil) - named := subst.check.newNamed(tname, t.underlying, t.methods) // method signatures are updated lazily - named.tparams = t.tparams // new type is still parameterized + named := subst.check.newNamed(tname, t, t.underlying, t.tparams, t.methods) // method signatures are updated lazily named.targs = newTargs if subst.check != nil { subst.check.typMap[h] = named @@ -407,7 +406,7 @@ func (subst *subster) typ(typ Type) Type { // do the substitution dump(">>> subst %s with %s (new: %s)", t.underlying, subst.smap, newTargs) named.underlying = subst.typOrNil(t.underlying) - named.orig = named.underlying // for cycle detection (Checker.validType) + named.fromRHS = named.underlying // for cycle detection (Checker.validType) return named diff --git a/src/go/types/type.go b/src/go/types/type.go index 2ea4d76d8b4..55b5c815405 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -642,12 +642,15 @@ func (c *Chan) Dir() ChanDir { return c.dir } // Elem returns the element type of channel c. func (c *Chan) Elem() Type { return c.elem } +// TODO(rfindley) Clean up Named struct below; specifically the fromRHS field (can we use underlying?). + // A Named represents a named (defined) type. type Named struct { check *Checker // for Named.under implementation; nilled once under has been called info typeInfo // for cycle detection obj *TypeName // corresponding declared object - orig Type // type (on RHS of declaration) this *Named type is derived of (for cycle reporting) + orig *Named // original, uninstantiated type + fromRHS Type // type (on RHS of declaration) this *Named type is derived of (for cycle reporting) underlying Type // possibly a *Named during setup; never a *Named once set up completely tparams []*TypeName // type parameters, or nil targs []Type // type arguments (after instantiation), or nil @@ -661,11 +664,14 @@ func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named { if _, ok := underlying.(*Named); ok { panic("types.NewNamed: underlying type must not be *Named") } - return (*Checker)(nil).newNamed(obj, underlying, methods) + return (*Checker)(nil).newNamed(obj, nil, underlying, nil, methods) } -func (check *Checker) newNamed(obj *TypeName, underlying Type, methods []*Func) *Named { - typ := &Named{check: check, obj: obj, orig: underlying, underlying: underlying, methods: methods} +func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams []*TypeName, methods []*Func) *Named { + typ := &Named{check: check, obj: obj, orig: orig, fromRHS: underlying, underlying: underlying, tparams: tparams, methods: methods} + if typ.orig == nil { + typ.orig = typ + } if obj.typ == nil { obj.typ = typ } @@ -692,6 +698,10 @@ func (check *Checker) newNamed(obj *TypeName, underlying Type, methods []*Func) // Obj returns the type name for the named type t. func (t *Named) Obj() *TypeName { return t.obj } +// _Orig returns the original generic type an instantiated type is derived from. +// If t is not an instantiated type, the result is t. +func (t *Named) _Orig() *Named { return t.orig } + // TODO(gri) Come up with a better representation and API to distinguish // between parameterized instantiated and non-instantiated types. @@ -699,10 +709,13 @@ func (t *Named) Obj() *TypeName { return t.obj } // The result is non-nil for an (originally) parameterized type even if it is instantiated. func (t *Named) _TParams() []*TypeName { return t.tparams } +// _SetTParams sets the type parameters of the named type t. +func (t *Named) _SetTParams(tparams []*TypeName) { t.tparams = tparams } + // _TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated. func (t *Named) _TArgs() []Type { return t.targs } -// _SetTArgs sets the type arguments of Named. +// SetTArgs sets the type arguments of the named type t. func (t *Named) _SetTArgs(args []Type) { t.targs = args } // NumMethods returns the number of explicit methods whose receiver is named type t. @@ -741,9 +754,9 @@ func nextID() uint64 { return uint64(atomic.AddUint32(&lastID, 1)) } // A _TypeParam represents a type parameter type. type _TypeParam struct { check *Checker // for lazy type bound completion - id uint64 // unique id + id uint64 // unique id, for debugging only obj *TypeName // corresponding type name - index int // parameter index + index int // type parameter index in source order, starting at 0 bound Type // *Named or *Interface; underlying type is always *Interface } From 2f26adc232988938cff003e15dae75757f76710a Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 3 Jun 2021 11:49:52 -0400 Subject: [PATCH 320/940] [dev.typeparams] go/types: re-use existing code for Interface.Complete This is a port of CL 321751 to go/types, adjusted to use token.Pos, and to exclude a missing position from a panic message (an unresolved comment on the original CL). Change-Id: I5814067aecb67aca9d73f2093fb6004b769924f3 Reviewed-on: https://go-review.googlesource.com/c/go/+/324756 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/interface.go | 48 +++++++++++++++++++++++++++---- src/go/types/type.go | 60 ++------------------------------------- 2 files changed, 44 insertions(+), 64 deletions(-) diff --git a/src/go/types/interface.go b/src/go/types/interface.go index 288e421cae1..fd3fe0ef91e 100644 --- a/src/go/types/interface.go +++ b/src/go/types/interface.go @@ -5,6 +5,7 @@ package types import ( + "fmt" "go/ast" "go/internal/typeparams" "go/token" @@ -142,8 +143,13 @@ func (check *Checker) completeInterface(pos token.Pos, ityp *Interface) { if check == nil { panic("internal error: incomplete interface") } + completeInterface(check, pos, ityp) +} - if trace { +func completeInterface(check *Checker, pos token.Pos, ityp *Interface) { + assert(ityp.allMethods == nil) + + if check != nil && trace { // Types don't generally have position information. // If we don't have a valid pos provided, try to use // one close enough. @@ -179,6 +185,7 @@ func (check *Checker) completeInterface(pos token.Pos, ityp *Interface) { // we can get rid of the mpos map below and simply use the cloned method's // position. + var todo []*Func var seen objset var methods []*Func mpos := make(map[*Func]token.Pos) // method specification or method embedding position, for good error messages @@ -188,6 +195,9 @@ func (check *Checker) completeInterface(pos token.Pos, ityp *Interface) { methods = append(methods, m) mpos[m] = pos case explicit: + if check == nil { + panic(fmt.Sprintf("%v: duplicate method %s", m.pos, m.name)) + } check.errorf(atPos(pos), _DuplicateDecl, "duplicate method %s", m.name) check.errorf(atPos(mpos[other.(*Func)]), _DuplicateDecl, "\tother declaration of %s", m.name) // secondary error, \t indented default: @@ -196,6 +206,11 @@ func (check *Checker) completeInterface(pos token.Pos, ityp *Interface) { // If we're pre-go1.14 (overlapping embeddings are not permitted), report that // error here as well (even though we could do it eagerly) because it's the same // error message. + if check == nil { + // check method signatures after all locally embedded interfaces are computed + todo = append(todo, m, other.(*Func)) + break + } check.later(func() { if !check.allowVersion(m.pkg, 1, 14) || !check.identical(m.typ, other.Type()) { check.errorf(atPos(pos), _DuplicateDecl, "duplicate method %s", m.name) @@ -212,9 +227,15 @@ func (check *Checker) completeInterface(pos token.Pos, ityp *Interface) { // collect types allTypes := ityp.types - posList := check.posMap[ityp] + var posList []token.Pos + if check != nil { + posList = check.posMap[ityp] + } for i, typ := range ityp.embeddeds { - pos := posList[i] // embedding position + var pos token.Pos // embedding position + if posList != nil { + pos = posList[i] + } utyp := under(typ) etyp := asInterface(utyp) if etyp == nil { @@ -225,18 +246,33 @@ func (check *Checker) completeInterface(pos token.Pos, ityp *Interface) { } else { format = "%s is not an interface" } - // TODO: correct error code. - check.errorf(atPos(pos), _InvalidIfaceEmbed, format, typ) + if check != nil { + // TODO: correct error code. + check.errorf(atPos(pos), _InvalidIfaceEmbed, format, typ) + } else { + panic(fmt.Sprintf(format, typ)) + } } continue } - check.completeInterface(pos, etyp) + if etyp.allMethods == nil { + completeInterface(check, pos, etyp) + } for _, m := range etyp.allMethods { addMethod(pos, m, false) // use embedding position pos rather than m.pos } allTypes = intersect(allTypes, etyp.allTypes) } + // process todo's (this only happens if check == nil) + for i := 0; i < len(todo); i += 2 { + m := todo[i] + other := todo[i+1] + if !Identical(m.typ, other.typ) { + panic(fmt.Sprintf("%v: duplicate method %s", m.pos, m.name)) + } + } + if methods != nil { sort.Sort(byUniqueMethodName(methods)) ityp.allMethods = methods diff --git a/src/go/types/type.go b/src/go/types/type.go index 55b5c815405..fff8541c426 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -5,7 +5,6 @@ package types import ( - "fmt" "go/token" "sync/atomic" ) @@ -538,64 +537,9 @@ func (t *Interface) isSatisfiedBy(typ Type) bool { // form other types. The interface must not contain duplicate methods or a // panic occurs. Complete returns the receiver. func (t *Interface) Complete() *Interface { - // TODO(gri) consolidate this method with Checker.completeInterface - if t.allMethods != nil { - return t + if t.allMethods == nil { + completeInterface(nil, token.NoPos, t) } - - t.allMethods = markComplete // avoid infinite recursion - - var todo []*Func - var methods []*Func - var seen objset - addMethod := func(m *Func, explicit bool) { - switch other := seen.insert(m); { - case other == nil: - methods = append(methods, m) - case explicit: - panic("duplicate method " + m.name) - default: - // check method signatures after all locally embedded interfaces are computed - todo = append(todo, m, other.(*Func)) - } - } - - for _, m := range t.methods { - addMethod(m, true) - } - - allTypes := t.types - - for _, typ := range t.embeddeds { - utyp := under(typ) - etyp := asInterface(utyp) - if etyp == nil { - if utyp != Typ[Invalid] { - panic(fmt.Sprintf("%s is not an interface", typ)) - } - continue - } - etyp.Complete() - for _, m := range etyp.allMethods { - addMethod(m, false) - } - allTypes = intersect(allTypes, etyp.allTypes) - } - - for i := 0; i < len(todo); i += 2 { - m := todo[i] - other := todo[i+1] - if !Identical(m.typ, other.typ) { - panic("duplicate method " + m.name) - } - } - - if methods != nil { - sortMethods(methods) - t.allMethods = methods - } - t.allTypes = allTypes - return t } From 7497e57a39b38894ee19b32a00fe5d057c05f842 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 3 Jun 2021 11:55:11 -0400 Subject: [PATCH 321/940] [dev.typeparams] go/types: simplify Interface accessors This is a straightforward port of CL 321850 to go/types. Change-Id: I719c19b8839390fdfa961255c6f1e79561cda6e6 Reviewed-on: https://go-review.googlesource.com/c/go/+/324757 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/type.go | 62 +++++++++----------------------------------- 1 file changed, 12 insertions(+), 50 deletions(-) diff --git a/src/go/types/type.go b/src/go/types/type.go index fff8541c426..4a394999058 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -421,79 +421,41 @@ func (t *Interface) EmbeddedType(i int) Type { return t.embeddeds[i] } // NumMethods returns the total number of methods of interface t. // The interface must have been completed. -func (t *Interface) NumMethods() int { t.assertCompleteness(); return len(t.allMethods) } - -func (t *Interface) assertCompleteness() { - if t.allMethods == nil { - panic("interface is incomplete") - } -} +func (t *Interface) NumMethods() int { t.Complete(); return len(t.allMethods) } // Method returns the i'th method of interface t for 0 <= i < t.NumMethods(). // The methods are ordered by their unique Id. // The interface must have been completed. -func (t *Interface) Method(i int) *Func { t.assertCompleteness(); return t.allMethods[i] } +func (t *Interface) Method(i int) *Func { t.Complete(); return t.allMethods[i] } // Empty reports whether t is the empty interface. func (t *Interface) Empty() bool { - if t.allMethods != nil { - // interface is complete - quick test - // A non-nil allTypes may still be empty and represents the bottom type. - return len(t.allMethods) == 0 && t.allTypes == nil - } - return !t.iterate(func(t *Interface) bool { - return len(t.methods) > 0 || t.types != nil - }, nil) + t.Complete() + // A non-nil allTypes may still have length 0 but represents the bottom type. + return len(t.allMethods) == 0 && t.allTypes == nil } // _HasTypeList reports whether interface t has a type list, possibly from an embedded type. func (t *Interface) _HasTypeList() bool { - if t.allMethods != nil { - // interface is complete - quick test - return t.allTypes != nil - } - - return t.iterate(func(t *Interface) bool { - return t.types != nil - }, nil) + t.Complete() + return t.allTypes != nil } // _IsComparable reports whether interface t is or embeds the predeclared interface "comparable". func (t *Interface) _IsComparable() bool { - if t.allMethods != nil { - // interface is complete - quick test - _, m := lookupMethod(t.allMethods, nil, "==") - return m != nil - } - - return t.iterate(func(t *Interface) bool { - _, m := lookupMethod(t.methods, nil, "==") - return m != nil - }, nil) + t.Complete() + _, m := lookupMethod(t.allMethods, nil, "==") + return m != nil } // _IsConstraint reports t.HasTypeList() || t.IsComparable(). func (t *Interface) _IsConstraint() bool { - if t.allMethods != nil { - // interface is complete - quick test - if t.allTypes != nil { - return true - } - _, m := lookupMethod(t.allMethods, nil, "==") - return m != nil - } - - return t.iterate(func(t *Interface) bool { - if t.types != nil { - return true - } - _, m := lookupMethod(t.methods, nil, "==") - return m != nil - }, nil) + return t._HasTypeList() || t._IsComparable() } // iterate calls f with t and then with any embedded interface of t, recursively, until f returns true. // iterate reports whether any call to f returned true. +// TODO(rfindley) This is now only used by infer.go - see if we can eliminate it. func (t *Interface) iterate(f func(*Interface) bool, seen map[*Interface]bool) bool { if f(t) { return true From 7c8a5be2d6f26caed84c6bae2a115872af5b1021 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 3 Jun 2021 12:14:16 -0400 Subject: [PATCH 322/940] [dev.typeparams] go/types: factor out constraint satisfaction check This is a port of CL 322070 to go/types, adjusted for the different error reporting API. Change-Id: I75eafe015b5b00554116527ea021e7a5f9e0343b Reviewed-on: https://go-review.googlesource.com/c/go/+/324759 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/subst.go | 157 ++++++++++++++++++++++-------------------- 1 file changed, 83 insertions(+), 74 deletions(-) diff --git a/src/go/types/subst.go b/src/go/types/subst.go index 43a64d04bb5..47b0c279db6 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -121,86 +121,14 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist // check bounds for i, tname := range tparams { - tpar := tname.typ.(*_TypeParam) - iface := tpar.Bound() - if iface.Empty() { - continue // no type bound - } - - targ := targs[i] - // best position for error reporting pos := pos if i < len(poslist) { pos = poslist[i] } - // The type parameter bound is parameterized with the same type parameters - // as the instantiated type; before we can use it for bounds checking we - // need to instantiate it with the type arguments with which we instantiate - // the parameterized type. - iface = check.subst(pos, iface, smap).(*Interface) - - // targ must implement iface (methods) - // - check only if we have methods - check.completeInterface(token.NoPos, iface) - if len(iface.allMethods) > 0 { - // If the type argument is a pointer to a type parameter, the type argument's - // method set is empty. - // TODO(gri) is this what we want? (spec question) - if base, isPtr := deref(targ); isPtr && asTypeParam(base) != nil { - check.errorf(atPos(pos), 0, "%s has no methods", targ) - break - } - if m, wrong := check.missingMethod(targ, iface, true); m != nil { - // TODO(gri) needs to print updated name to avoid major confusion in error message! - // (print warning for now) - // Old warning: - // check.softErrorf(pos, "%s does not satisfy %s (warning: name not updated) = %s (missing method %s)", targ, tpar.bound, iface, m) - if m.name == "==" { - // We don't want to report "missing method ==". - check.softErrorf(atPos(pos), 0, "%s does not satisfy comparable", targ) - } else if wrong != nil { - // TODO(gri) This can still report uninstantiated types which makes the error message - // more difficult to read then necessary. - // TODO(rFindley) should this use parentheses rather than ':' for qualification? - check.softErrorf(atPos(pos), _Todo, - "%s does not satisfy %s: wrong method signature\n\tgot %s\n\twant %s", - targ, tpar.bound, wrong, m, - ) - } else { - check.softErrorf(atPos(pos), 0, "%s does not satisfy %s (missing method %s)", targ, tpar.bound, m.name) - } - break - } - } - - // targ's underlying type must also be one of the interface types listed, if any - if iface.allTypes == nil { - continue // nothing to do - } - - // If targ is itself a type parameter, each of its possible types, but at least one, must be in the - // list of iface types (i.e., the targ type list must be a non-empty subset of the iface types). - if targ := asTypeParam(targ); targ != nil { - targBound := targ.Bound() - if targBound.allTypes == nil { - check.softErrorf(atPos(pos), _Todo, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ) - break - } - for _, t := range unpackType(targBound.allTypes) { - if !iface.isSatisfiedBy(t) { - // TODO(gri) match this error message with the one below (or vice versa) - check.softErrorf(atPos(pos), 0, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, t, iface.allTypes) - break - } - } - break - } - - // Otherwise, targ's type or underlying type must also be one of the interface types listed, if any. - if !iface.isSatisfiedBy(targ) { - check.softErrorf(atPos(pos), _Todo, "%s does not satisfy %s (%s or %s not found in %s)", targ, tpar.bound, targ, under(targ), iface.allTypes) + // stop checking bounds after the first failure + if !check.satisfies(pos, targs[i], tname.typ.(*_TypeParam), smap) { break } } @@ -208,6 +136,87 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist return check.subst(pos, typ, smap) } +// satisfies reports whether the type argument targ satisfies the constraint of type parameter +// parameter tpar (after any of its type parameters have been substituted through smap). +// A suitable error is reported if the result is false. +func (check *Checker) satisfies(pos token.Pos, targ Type, tpar *_TypeParam, smap *substMap) bool { + iface := tpar.Bound() + if iface.Empty() { + return true // no type bound + } + + // The type parameter bound is parameterized with the same type parameters + // as the instantiated type; before we can use it for bounds checking we + // need to instantiate it with the type arguments with which we instantiate + // the parameterized type. + iface = check.subst(pos, iface, smap).(*Interface) + + // targ must implement iface (methods) + // - check only if we have methods + check.completeInterface(token.NoPos, iface) + if len(iface.allMethods) > 0 { + // If the type argument is a pointer to a type parameter, the type argument's + // method set is empty. + // TODO(gri) is this what we want? (spec question) + if base, isPtr := deref(targ); isPtr && asTypeParam(base) != nil { + check.errorf(atPos(pos), 0, "%s has no methods", targ) + return false + } + if m, wrong := check.missingMethod(targ, iface, true); m != nil { + // TODO(gri) needs to print updated name to avoid major confusion in error message! + // (print warning for now) + // Old warning: + // check.softErrorf(pos, "%s does not satisfy %s (warning: name not updated) = %s (missing method %s)", targ, tpar.bound, iface, m) + if m.name == "==" { + // We don't want to report "missing method ==". + check.softErrorf(atPos(pos), 0, "%s does not satisfy comparable", targ) + } else if wrong != nil { + // TODO(gri) This can still report uninstantiated types which makes the error message + // more difficult to read then necessary. + // TODO(rFindley) should this use parentheses rather than ':' for qualification? + check.softErrorf(atPos(pos), _Todo, + "%s does not satisfy %s: wrong method signature\n\tgot %s\n\twant %s", + targ, tpar.bound, wrong, m, + ) + } else { + check.softErrorf(atPos(pos), 0, "%s does not satisfy %s (missing method %s)", targ, tpar.bound, m.name) + } + return false + } + } + + // targ's underlying type must also be one of the interface types listed, if any + if iface.allTypes == nil { + return true // nothing to do + } + + // If targ is itself a type parameter, each of its possible types, but at least one, must be in the + // list of iface types (i.e., the targ type list must be a non-empty subset of the iface types). + if targ := asTypeParam(targ); targ != nil { + targBound := targ.Bound() + if targBound.allTypes == nil { + check.softErrorf(atPos(pos), _Todo, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ) + return false + } + for _, t := range unpackType(targBound.allTypes) { + if !iface.isSatisfiedBy(t) { + // TODO(gri) match this error message with the one below (or vice versa) + check.softErrorf(atPos(pos), 0, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, t, iface.allTypes) + return false + } + } + return false + } + + // Otherwise, targ's type or underlying type must also be one of the interface types listed, if any. + if !iface.isSatisfiedBy(targ) { + check.softErrorf(atPos(pos), _Todo, "%s does not satisfy %s (%s not found in %s)", targ, tpar.bound, under(targ), iface.allTypes) + return false + } + + return true +} + // subst returns the type typ with its type parameters tpars replaced by // the corresponding type arguments targs, recursively. // subst is functional in the sense that it doesn't modify the incoming From 201d55e6376365dc5e8c2392e34fdf7ee8a4b63e Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Fri, 4 Jun 2021 18:17:49 -0700 Subject: [PATCH 323/940] [dev.typeparams] cmd/compile: create .dict Param in the package of the instantiated function The instantiated functions are created in the source package of the generic function, so all lookups of symbols should be relative to that package, so all symbols are consistently in the source package. Fixes #46575 Change-Id: Iba67b2ba8014a630c5d4e032c0f2f2fbaaedce65 Reviewed-on: https://go-review.googlesource.com/c/go/+/325529 Reviewed-by: Keith Randall Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/noder/stencil.go | 2 +- test/typeparam/mutualimp.dir/a.go | 11 +++++++++++ test/typeparam/mutualimp.dir/b.go | 12 ++++++++++++ test/typeparam/mutualimp.go | 7 +++++++ 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 test/typeparam/mutualimp.dir/a.go create mode 100644 test/typeparam/mutualimp.dir/b.go create mode 100644 test/typeparam/mutualimp.go diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 25a4bf775f1..8b5a91f6d11 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -558,7 +558,7 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*type oldt := nameNode.Type() // We also transform a generic method type to the corresponding // instantiated function type where the dictionary is the first parameter. - dictionarySym := types.LocalPkg.Lookup(".dict") + dictionarySym := newsym.Pkg.Lookup(".dict") dictionaryType := types.Types[types.TUINTPTR] dictionaryName := ir.NewNameAt(gf.Pos(), dictionarySym) typed(dictionaryType, dictionaryName) diff --git a/test/typeparam/mutualimp.dir/a.go b/test/typeparam/mutualimp.dir/a.go new file mode 100644 index 00000000000..56ca57cea5e --- /dev/null +++ b/test/typeparam/mutualimp.dir/a.go @@ -0,0 +1,11 @@ +// Copyright 2021 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 a + +type X int +func (x X) M() X { return x } + +func F[T interface{ M() U }, U interface{ M() T }]() {} +func G() { F[X, X]() } diff --git a/test/typeparam/mutualimp.dir/b.go b/test/typeparam/mutualimp.dir/b.go new file mode 100644 index 00000000000..83cc3af2835 --- /dev/null +++ b/test/typeparam/mutualimp.dir/b.go @@ -0,0 +1,12 @@ +// Copyright 2021 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 b + +import "./a" + +func H() { + a.F[a.X, a.X]() + a.G() +} diff --git a/test/typeparam/mutualimp.go b/test/typeparam/mutualimp.go new file mode 100644 index 00000000000..87b4ff46c1e --- /dev/null +++ b/test/typeparam/mutualimp.go @@ -0,0 +1,7 @@ +// compiledir -G=3 + +// Copyright 2021 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 ignored From bcb3927cb51af39f44d810aab809dff27c950697 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Fri, 4 Jun 2021 23:01:13 -0700 Subject: [PATCH 324/940] [dev.typeparams] cmd/compile: introduce IsTypeParam() helper better than Kind() == types.TTYPEPARAM Change-Id: I4f35a177cd0cda3be615a92b7b2af1b5a60a3bbc Reviewed-on: https://go-review.googlesource.com/c/go/+/325410 Trust: Keith Randall Trust: Dan Scales Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/noder/helpers.go | 2 +- src/cmd/compile/internal/typecheck/iexport.go | 8 ++++---- src/cmd/compile/internal/typecheck/iimport.go | 2 +- src/cmd/compile/internal/typecheck/subr.go | 2 +- src/cmd/compile/internal/types/type.go | 4 ++++ 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/cmd/compile/internal/noder/helpers.go b/src/cmd/compile/internal/noder/helpers.go index ea30a3bfa99..456df312a6d 100644 --- a/src/cmd/compile/internal/noder/helpers.go +++ b/src/cmd/compile/internal/noder/helpers.go @@ -63,7 +63,7 @@ func FixValue(typ *types.Type, val constant.Value) constant.Value { if !typ.IsUntyped() { val = typecheck.DefaultLit(ir.NewBasicLit(src.NoXPos, val), typ).Val() } - if typ.Kind() != types.TTYPEPARAM { + if !typ.IsTypeParam() { ir.AssertValidTypeForConst(typ, val) } return val diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index 6987bc99188..10d4bd6e7ee 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -522,7 +522,7 @@ func (p *iexporter) doDecl(n *ir.Name) { } case ir.OTYPE: - if n.Type().Kind() == types.TTYPEPARAM && n.Type().Underlying() == n.Type() { + if n.Type().IsTypeParam() && n.Type().Underlying() == n.Type() { // Even though it has local scope, a typeparam requires a // declaration via its package and unique name, because it // may be referenced within its type bound during its own @@ -898,7 +898,7 @@ func (w *exportWriter) doTyp(t *types.Type) { // The 't.Underlying() == t' check is to confirm this is a base typeparam // type, rather than a defined type with typeparam underlying type, like: // type orderedAbs[T any] T - if t.Kind() == types.TTYPEPARAM && t.Underlying() == t { + if t.IsTypeParam() && t.Underlying() == t { assert(base.Flag.G > 0) if s.Pkg == types.BuiltinPkg || s.Pkg == ir.Pkgs.Unsafe { base.Fatalf("builtin type missing from typIndex: %v", t) @@ -1042,7 +1042,7 @@ func (w *exportWriter) typeList(ts []*types.Type) { func (w *exportWriter) tparamList(fs []*types.Field) { w.uint64(uint64(len(fs))) for _, f := range fs { - if f.Type.Kind() != types.TTYPEPARAM { + if !f.Type.IsTypeParam() { base.Fatalf("unexpected non-typeparam") } w.typ(f.Type) @@ -1095,7 +1095,7 @@ func (w *exportWriter) value(typ *types.Type, v constant.Value) { var kind constant.Kind var valType *types.Type - if typ.Kind() == types.TTYPEPARAM { + if typ.IsTypeParam() { // A constant will have a TYPEPARAM type if it appears in a place // where it must match that typeparam type (e.g. in a binary // operation with a variable of that typeparam type). If so, then diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index cafb18d7a88..6d42875f496 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -415,7 +415,7 @@ func (p *importReader) value(typ *types.Type) constant.Value { var kind constant.Kind var valType *types.Type - if typ.Kind() == types.TTYPEPARAM { + if typ.IsTypeParam() { // If a constant had a typeparam type, then we wrote out its // actual constant kind as well. kind = constant.Kind(p.int64()) diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index 8ef49f91c83..e9a9a571269 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -984,7 +984,7 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type { return t } - if t.Kind() == types.TTYPEPARAM { + if t.IsTypeParam() { for i, tp := range ts.Tparams { if tp == t { return ts.Targs[i] diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index a3a6050c526..075009d6a3b 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -1487,6 +1487,10 @@ func (t *Type) IsUnion() bool { return t.kind == TUNION } +func (t *Type) IsTypeParam() bool { + return t.kind == TTYPEPARAM +} + // IsEmptyInterface reports whether t is an empty interface type. func (t *Type) IsEmptyInterface() bool { return t.IsInterface() && t.AllMethods().Len() == 0 From cf4b6dc48eba807e7d85fb6ab30cbbbdb143c552 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Fri, 4 Jun 2021 22:54:08 -0700 Subject: [PATCH 325/940] [dev.typeparams] cmd/compile: allow conversions from type parameter to interface When converting from a type param to an interface, allow it if the type bound implements that interface. Query: some conversions go through this path, some use another path? The test does var i interface{foo()int} = x but i := (interface{foo()int})(x) works at tip. Change-Id: I84d497e5228c0e1d1c9d76ffebaedce09dc45e8e Reviewed-on: https://go-review.googlesource.com/c/go/+/325409 Trust: Keith Randall Trust: Dan Scales Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/noder/transform.go | 5 +- src/cmd/compile/internal/typecheck/subr.go | 12 ++++- test/typeparam/ifaceconv.go | 58 +++++++++++++++++++++ 3 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 test/typeparam/ifaceconv.go diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go index a084f0b7be2..946d335f076 100644 --- a/src/cmd/compile/internal/noder/transform.go +++ b/src/cmd/compile/internal/noder/transform.go @@ -437,7 +437,10 @@ func assignconvfn(n ir.Node, t *types.Type) ir.Node { return n } - op, _ := typecheck.Assignop(n.Type(), t) + op, why := typecheck.Assignop(n.Type(), t) + if op == ir.OXXX { + base.Fatalf("found illegal assignment %+v -> %+v; %s", n.Type(), t, why) + } r := ir.NewConvExpr(base.Pos, op, t, n) r.SetTypecheck(1) diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index e9a9a571269..0e306eaea83 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -723,13 +723,23 @@ func ifacelookdot(s *types.Sym, t *types.Type, ignorecase bool) (m *types.Field, return m, followptr } +// implements reports whether t implements the interface iface. t can be +// an interface, a type parameter, or a concrete type. If implements returns +// false, it stores a method of iface that is not implemented in *m. If the +// method name matches but the type is wrong, it additionally stores the type +// of the method (on t) in *samename. func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool { t0 := t if t == nil { return false } - if t.IsInterface() { + if t.IsInterface() || t.IsTypeParam() { + if t.IsTypeParam() { + // A typeparam satisfies an interface if its type bound + // has all the methods of that interface. + t = t.Bound() + } i := 0 tms := t.AllMethods().Slice() for _, im := range iface.AllMethods().Slice() { diff --git a/test/typeparam/ifaceconv.go b/test/typeparam/ifaceconv.go new file mode 100644 index 00000000000..0b0776815c9 --- /dev/null +++ b/test/typeparam/ifaceconv.go @@ -0,0 +1,58 @@ +// run -gcflags=-G=3 + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test that we can convert type parameters to both empty +// and nonempty interfaces, and named and nonnamed versions +// thereof. + +package main + +import "fmt" + +type E interface{} + +func f[T any](x T) interface{} { + var i interface{} = x + return i +} +func g[T any](x T) E { + var i E = x + return i +} + +type C interface { + foo() int +} + +type myInt int + +func (x myInt) foo() int { + return int(x+1) +} + +func h[T C](x T) interface{foo() int} { + var i interface{foo()int} = x + return i +} +func i[T C](x T) C { + var i C = x + return i +} + +func main() { + if got, want := f[int](7), 7; got != want { + panic(fmt.Sprintf("got %d want %d", got, want)) + } + if got, want := g[int](7), 7; got != want { + panic(fmt.Sprintf("got %d want %d", got, want)) + } + if got, want := h[myInt](7).foo(), 8; got != want { + panic(fmt.Sprintf("got %d want %d", got, want)) + } + if got, want := i[myInt](7).foo(), 8; got != want { + panic(fmt.Sprintf("got %d want %d", got, want)) + } +} From ccfb0ce8df980599750db4fa56a8ab16202f1ba6 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Fri, 4 Jun 2021 17:19:09 -0700 Subject: [PATCH 326/940] [dev.typeparams] cmd/compile: convert generic values to interface type using dictionary When converting a variable of generic type to an interface, use the entry in the dictionary for the type field instead of using the compile-time type (which we only have when fully stenciling). Note: this isn't all the conversions. Conversions often get processed in the ir.OCALL case. Those aren't handled yet. Change-Id: I9a6a4c572e3c54a8e8efad98365184dbb94c4487 Reviewed-on: https://go-review.googlesource.com/c/go/+/325330 Trust: Keith Randall Trust: Dan Scales Reviewed-by: Dan Scales --- src/cmd/compile/internal/escape/escape.go | 7 +++ src/cmd/compile/internal/noder/stencil.go | 71 +++++++++++++++++++++-- 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/src/cmd/compile/internal/escape/escape.go b/src/cmd/compile/internal/escape/escape.go index 3ac7ff1ebe1..842b0f4a7e0 100644 --- a/src/cmd/compile/internal/escape/escape.go +++ b/src/cmd/compile/internal/escape/escape.go @@ -669,6 +669,13 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) { k = e.spill(k, n) } e.expr(k.note(n, "interface-converted"), n.X) + case ir.OEFACE: + n := n.(*ir.BinaryExpr) + // Note: n.X is not needed because it can never point to memory that might escape. + e.expr(k, n.Y) + case ir.OIDATA: + n := n.(*ir.UnaryExpr) + e.expr(k, n.X) case ir.OSLICE2ARRPTR: // the slice pointer flows directly to the result n := n.(*ir.ConvExpr) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 8b5a91f6d11..3e3de1908ec 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -13,6 +13,7 @@ import ( "cmd/compile/internal/reflectdata" "cmd/compile/internal/typecheck" "cmd/compile/internal/types" + "cmd/internal/src" "fmt" "go/constant" ) @@ -496,10 +497,11 @@ func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth // Struct containing info needed for doing the substitution as we create the // instantiation of a generic function with specified type arguments. type subster struct { - g *irgen - isMethod bool // If a method is being instantiated - newf *ir.Func // Func node for the new stenciled function - ts typecheck.Tsubster + g *irgen + isMethod bool // If a method is being instantiated + newf *ir.Func // Func node for the new stenciled function + ts typecheck.Tsubster + dictionary *ir.Name // Name of dictionary variable } // genericSubst returns a new function with name newsym. The function is an @@ -573,6 +575,7 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*type } dictionaryArg := types.NewField(gf.Pos(), dictionarySym, dictionaryType) dictionaryArg.Nname = dictionaryName + subst.dictionary = dictionaryName var args []*types.Field args = append(args, dictionaryArg) args = append(args, oldt.Recvs().FieldSlice()...) @@ -656,6 +659,38 @@ func (g *irgen) checkDictionary(name *ir.Name, targs []*types.Type) (code []ir.N return } +// getDictionaryType returns a *runtime._type from the dictionary corresponding to the input type. +// The input type must be a type parameter (TODO: or a local derived type). +func (subst *subster) getDictionaryType(pos src.XPos, t *types.Type) ir.Node { + tparams := subst.ts.Tparams + var i = 0 + for i = range tparams { + if t == tparams[i] { + break + } + } + if i == len(tparams) { + base.Fatalf(fmt.Sprintf("couldn't find type param %+v", t)) + } + + // Convert dictionary to *[N]uintptr + // All entries in the dictionary are pointers. They all point to static data, though, so we + // treat them as uintptrs so the GC doesn't need to keep track of them. + d := ir.NewConvExpr(pos, ir.OCONVNOP, types.Types[types.TUNSAFEPTR], subst.dictionary) + d.SetTypecheck(1) + d = ir.NewConvExpr(pos, ir.OCONVNOP, types.NewArray(types.Types[types.TUINTPTR], int64(len(tparams))).PtrTo(), d) + d.SetTypecheck(1) + + // Load entry i out of the dictionary. + deref := ir.NewStarExpr(pos, d) + typed(d.Type().Elem(), deref) + idx := ir.NewConstExpr(constant.MakeUint64(uint64(i)), subst.dictionary) // TODO: what to set orig to? + typed(types.Types[types.TUINTPTR], idx) + r := ir.NewIndexExpr(pos, deref, idx) + typed(types.Types[types.TUINT8].PtrTo(), r) // standard typing of a *runtime._type in the compiler is *byte + return r +} + // node is like DeepCopy(), but substitutes ONAME nodes based on subst.ts.vars, and // also descends into closures. It substitutes type arguments for type parameters // in all the new nodes. @@ -859,6 +894,34 @@ func (subst *subster) node(n ir.Node) ir.Node { ir.CurFunc = saveNewf subst.g.target.Decls = append(subst.g.target.Decls, newfn) + + case ir.OCONVIFACE: + x := x.(*ir.ConvExpr) + // TODO: handle converting from derived types. For now, just from naked + // type parameters. + if x.X.Type().IsTypeParam() { + // Load the actual runtime._type of the type parameter from the dictionary. + rt := subst.getDictionaryType(m.Pos(), x.X.Type()) + + // At this point, m is an interface type with a data word we want. + // But the type word represents a gcshape type, which we don't want. + // Replace with the instantiated type loaded from the dictionary. + m = ir.NewUnaryExpr(m.Pos(), ir.OIDATA, m) + typed(types.Types[types.TUNSAFEPTR], m) + m = ir.NewBinaryExpr(m.Pos(), ir.OEFACE, rt, m) + if !x.Type().IsEmptyInterface() { + // We just built an empty interface{}. Type it as such, + // then assert it to the required non-empty interface. + typed(types.NewInterface(types.LocalPkg, nil), m) + m = ir.NewTypeAssertExpr(m.Pos(), m, nil) + } + typed(x.Type(), m) + // TODO: we're throwing away the type word of the original version + // of m here (it would be OITAB(m)), which probably took some + // work to generate. Can we avoid generating it at all? + // (The linker will throw them away if not needed, so it would just + // save toolchain work, not binary size.) + } } return m } From 909dd5e010c99d48f1dc72d7da61fd8d3fd8f030 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 7 Jun 2021 10:51:33 -0700 Subject: [PATCH 327/940] strconv: ParseFloat: always return ErrSyntax for bad syntax Previously we would sometimes return ErrRange if the parseable part of the floating point number was out of range. Fixes #46628 Change-Id: I15bbbb1e2a56fa27c19fe25ab5554d988cbfd9d2 Reviewed-on: https://go-review.googlesource.com/c/go/+/325750 Trust: Ian Lance Taylor Trust: Robert Griesemer Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/strconv/atof.go | 2 +- src/strconv/atof_test.go | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/strconv/atof.go b/src/strconv/atof.go index 9010a66ca89..57556c70475 100644 --- a/src/strconv/atof.go +++ b/src/strconv/atof.go @@ -689,7 +689,7 @@ func atof64(s string) (f float64, n int, err error) { // as their respective special floating point values. It ignores case when matching. func ParseFloat(s string, bitSize int) (float64, error) { f, n, err := parseFloatPrefix(s, bitSize) - if err == nil && n != len(s) { + if n != len(s) && (err == nil || err.(*NumError).Err != ErrSyntax) { return 0, syntaxError(fnParseFloat, s) } return f, err diff --git a/src/strconv/atof_test.go b/src/strconv/atof_test.go index 3c058b9be5a..aa587a473cd 100644 --- a/src/strconv/atof_test.go +++ b/src/strconv/atof_test.go @@ -342,6 +342,9 @@ var atoftests = []atofTest{ {"0x12.345p-_12", "0", ErrSyntax}, {"0x12.345p+1__2", "0", ErrSyntax}, {"0x12.345p+12_", "0", ErrSyntax}, + + {"1e100x", "0", ErrSyntax}, + {"1e1000x", "0", ErrSyntax}, } var atof32tests = []atofTest{ From dc8b55895166c808b02e93ef4a778c6648c10bf3 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 3 Jun 2021 14:15:12 -0700 Subject: [PATCH 328/940] cmd/dist: pass -Wno-lto-type-mismatch in swig_callback_lto Fixes #46557 Change-Id: I95200ddd60e2879db15dd7353c2152b515c89020 Reviewed-on: https://go-review.googlesource.com/c/go/+/324909 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Damien Neil --- src/cmd/dist/test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index bc49c6d8040..1ed2c0f631e 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -737,9 +737,9 @@ func (t *tester) registerTests() { fn: func(dt *distTest) error { cmd := t.addCmd(dt, "misc/swig/callback", t.goTest()) cmd.Env = append(os.Environ(), - "CGO_CFLAGS=-flto", - "CGO_CXXFLAGS=-flto", - "CGO_LDFLAGS=-flto", + "CGO_CFLAGS=-flto -Wno-lto-type-mismatch", + "CGO_CXXFLAGS=-flto -Wno-lto-type-mismatch", + "CGO_LDFLAGS=-flto -Wno-lto-type-mismatch", ) return nil }, From 74d46381b2003f7d77bbe6eb4a8a31cb6f753a09 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Fri, 4 Jun 2021 15:22:55 -0700 Subject: [PATCH 329/940] [dev.typeparams] cmd/compile: do extra markObjects during iexport to deal with generics markInlBody/markObject/markType don't fully work as they stand for generic functions/methods, since markInlBody can't understand method calls on generic types. Those method calls will be resolved to concrete methods in a full instantiation, but markInlBody on a generic function/method can't understand those method calls. So, we won't necessarily cause export of the appropriate extra method/function bodies needed for inlining in an instantiated function. One way to do this is just to make sure that we call markType on all generic types that are exported (whether explicitly exported via a capitalized name or unexported types that are referenced by a generic function body). That way, we will call markInlBody on all possible generic methods that might be called. Fixes the current problem for i386-softfloat builds on dev.typeparams. Change-Id: I2d3625d26042296731bd3c44ba1938aa194d527e Reviewed-on: https://go-review.googlesource.com/c/go/+/325329 Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky Trust: Dan Scales --- src/cmd/compile/internal/typecheck/crawler.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/typecheck/crawler.go b/src/cmd/compile/internal/typecheck/crawler.go index 48fc61dbfd9..c78a604a8d2 100644 --- a/src/cmd/compile/internal/typecheck/crawler.go +++ b/src/cmd/compile/internal/typecheck/crawler.go @@ -146,7 +146,9 @@ func (p *crawler) markInlBody(n *ir.Name) { case ir.PEXTERN: Export(n) } - + p.checkGenericType(n.Type()) + case ir.OTYPE: + p.checkGenericType(n.Type()) case ir.OCALLPART: // Okay, because we don't yet inline indirect // calls to method values. @@ -162,3 +164,16 @@ func (p *crawler) markInlBody(n *ir.Name) { // because after inlining they might be callable. ir.VisitList(fn.Inl.Body, doFlood) } + +// checkGenerictype ensures that we call markType() on any base generic type that +// is written to the export file (even if not explicitly marked +// for export), so its methods will be available for inlining if needed. +func (p *crawler) checkGenericType(t *types.Type) { + if t != nil && t.HasTParam() { + if t.OrigSym != nil { + // Convert to the base generic type. + t = t.OrigSym.Def.Type() + } + p.markType(t) + } +} From 39c39ae52f0f35085be8ca1e004dee509abc21de Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 7 Jun 2021 14:28:14 -0700 Subject: [PATCH 330/940] doc: document Go 1.17 language changes Fixes #46020. Change-Id: Iadf9a0ac4a8863e17155d6ba1af2cc497634a634 Reviewed-on: https://go-review.googlesource.com/c/go/+/325870 Trust: Matthew Dempsky Reviewed-by: Ian Lance Taylor Reviewed-by: Dmitri Shuralyov --- doc/go1.17.html | 42 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 7438d894fe3..c1978ff1c15 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -25,12 +25,46 @@ Do not send CLs removing the interior tags from such phrases.

Changes to the language

-

- TODO: https://golang.org/cl/216424: allow conversion from slice to array ptr +

+ Go 1.17 includes three small enhancements to the language.

-

- TODO: https://golang.org/cl/312212: add unsafe.Add and unsafe.Slice +

    +
  • + Conversions + from slice to array pointer: An expression s of + type []T may now be converted to array pointer type + *[N]T. If a is the result of such a + conversion, then corresponding indices that are in range refer to + the same underlying elements: &a[i] == &s[i] + for 0 <= i < N. The conversion panics if + len(s) is less than N. +
  • + +
  • + unsafe.Add: + unsafe.Add(ptr, len) adds len + to ptr and returns the updated pointer + unsafe.Pointer(uintptr(ptr) + uintptr(len)). +
  • + +
  • + unsafe.Slice: + For expression ptr of type *T, + unsafe.Slice(ptr, len) returns a slice of + type []T whose underlying array starts + at ptr and whose length and capacity + are len. +
  • +
+ +

+ These enhancements were added to simplify writing code that conforms + to unsafe.Pointer's safety + rules, but the rules remain unchanged. In particular, existing + programs that correctly use unsafe.Pointer remain + valid, and new programs must still follow the rules when + using unsafe.Add or unsafe.Slice.

Ports

From 0c40cb4a0736df4514c5e5f35fdbb87c0543fe6f Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 4 Jun 2021 21:38:40 -0700 Subject: [PATCH 331/940] [dev.typeparams] cmd/compile/internal/types2: provide valid signature in errors involving method expressions This is an adjusted port of a similar fix in https://golang.org/cl/324733. Fixes #46583. Change-Id: Ica1410e4de561e64e58b753e3da04b32156cbaf6 Reviewed-on: https://go-review.googlesource.com/c/go/+/325369 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/call.go | 20 +++++++++++-- .../types2/testdata/fixedbugs/issue46583.src | 28 +++++++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 src/cmd/compile/internal/types2/testdata/fixedbugs/issue46583.src diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index f0f769ec705..8c717cd1e58 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -582,13 +582,27 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) { goto Error } - // the receiver type becomes the type of the first function - // argument of the method expression's function type + // The receiver type becomes the type of the first function + // argument of the method expression's function type. var params []*Var if sig.params != nil { params = sig.params.vars } - params = append([]*Var{NewVar(sig.recv.pos, sig.recv.pkg, sig.recv.name, x.typ)}, params...) + // Be consistent about named/unnamed parameters. This is not needed + // for type-checking, but the newly constructed signature may appear + // in an error message and then have mixed named/unnamed parameters. + // (An alternative would be to not print parameter names in errors, + // but it's useful to see them; this is cheap and method expressions + // are rare.) + name := "" + if len(params) > 0 && params[0].name != "" { + // name needed + name = sig.recv.name + if name == "" { + name = "_" + } + } + params = append([]*Var{NewVar(sig.recv.pos, sig.recv.pkg, name, x.typ)}, params...) x.mode = value x.typ = &Signature{ tparams: sig.tparams, diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue46583.src b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue46583.src new file mode 100644 index 00000000000..da1f1ffbbaf --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue46583.src @@ -0,0 +1,28 @@ +// Copyright 2021 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 + +type T1 struct{} +func (t T1) m(int) {} +var f1 func(T1) + +type T2 struct{} +func (t T2) m(x int) {} +var f2 func(T2) + +type T3 struct{} +func (T3) m(int) {} +var f3 func(T3) + +type T4 struct{} +func (T4) m(x int) {} +var f4 func(T4) + +func _() { + f1 = T1 /* ERROR func\(T1, int\) */ .m + f2 = T2 /* ERROR func\(t T2, x int\) */ .m + f3 = T3 /* ERROR func\(T3, int\) */ .m + f4 = T4 /* ERROR func\(_ T4, x int\) */ .m +} From c20bcb64882d1134770683d663ee9f82fea715e6 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 7 Jun 2021 16:24:40 -0700 Subject: [PATCH 332/940] runtime: remove out-of-date comments about frame skipping skipPleaseUseCallersFrames was removed in CL 152537. Change-Id: Ide47feec85a33a6fb6882e16baf9e21492521640 Reviewed-on: https://go-review.googlesource.com/c/go/+/325949 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/runtime/traceback.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index 89780edc1ff..814c3236345 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -56,8 +56,6 @@ func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v uns } } -const sizeofSkipFunction = 256 - // Generic traceback. Handles runtime stack prints (pcbuf == nil), // the runtime.Callers function (pcbuf != nil), as well as the garbage // collector (callback != nil). A little clunky to merge these, but avoids @@ -65,9 +63,7 @@ const sizeofSkipFunction = 256 // // The skip argument is only valid with pcbuf != nil and counts the number // of logical frames to skip rather than physical frames (with inlining, a -// PC in pcbuf can represent multiple calls). If a PC is partially skipped -// and max > 1, pcbuf[1] will be runtime.skipPleaseUseCallersFrames+N where -// N indicates the number of logical frames to skip in pcbuf[0]. +// PC in pcbuf can represent multiple calls). func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max int, callback func(*stkframe, unsafe.Pointer) bool, v unsafe.Pointer, flags uint) int { if skip > 0 && callback != nil { throw("gentraceback callback cannot be used with non-zero skip") From 2169deb35247a80794519589e7cd845c6ebf4e5a Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Sun, 30 May 2021 15:35:06 +0700 Subject: [PATCH 333/940] cmd/compile: use t.AllMethods when sorting typesByString For interface types, t.Methods contains only unexpanded method set, i.e exclusive of interface embedding. Thus, we can't use it to detect an interface contains embedding empty interface, like in: type EI interface{} func f() interface{ EI } { return nil } At the time we generate runtime types, we want to check against the full method set of interface instead. Fixes #46386 Change-Id: Idff53ad39276be6632eb5932b76e855c15cbdd2e Reviewed-on: https://go-review.googlesource.com/c/go/+/323649 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- .../compile/internal/reflectdata/reflect.go | 4 +-- test/fixedbugs/issue46386.go | 32 +++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 test/fixedbugs/issue46386.go diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index b3688fca673..e07294be0f9 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -1475,8 +1475,8 @@ func (a typesByString) Less(i, j int) bool { // will be equal for the above checks, but different in DWARF output. // Sort by source position to ensure deterministic order. // See issues 27013 and 30202. - if a[i].t.Kind() == types.TINTER && a[i].t.Methods().Len() > 0 { - return a[i].t.Methods().Index(0).Pos.Before(a[j].t.Methods().Index(0).Pos) + if a[i].t.Kind() == types.TINTER && a[i].t.AllMethods().Len() > 0 { + return a[i].t.AllMethods().Index(0).Pos.Before(a[j].t.AllMethods().Index(0).Pos) } return false } diff --git a/test/fixedbugs/issue46386.go b/test/fixedbugs/issue46386.go new file mode 100644 index 00000000000..89dea8abf3b --- /dev/null +++ b/test/fixedbugs/issue46386.go @@ -0,0 +1,32 @@ +// compile -p=main + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type I interface { + M() interface{} +} + +type S1 struct{} + +func (S1) M() interface{} { + return nil +} + +type EI interface{} + +type S struct{} + +func (S) M(as interface{ I }) {} + +func f() interface{ EI } { + return &S1{} +} + +func main() { + var i interface{ I } + (&S{}).M(i) +} From e58bddde706c8814f82ec4ef404fc7ff36d88469 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Mon, 7 Jun 2021 18:22:14 -0400 Subject: [PATCH 334/940] [dev.typeparams] internal/goexperiment: regenerate generated files Rerun the generator. exp_regabi_{on,off}.go are gone, as "regabi" itself is not a goexperiment that we test at run time (the sub-experiments are). Change-Id: Ic1f31b4ef2769a143f768e1b3dc7221041aafca9 Reviewed-on: https://go-review.googlesource.com/c/go/+/325912 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/internal/goexperiment/exp_regabi_off.go | 9 --------- src/internal/goexperiment/exp_regabi_on.go | 9 --------- 2 files changed, 18 deletions(-) delete mode 100644 src/internal/goexperiment/exp_regabi_off.go delete mode 100644 src/internal/goexperiment/exp_regabi_on.go diff --git a/src/internal/goexperiment/exp_regabi_off.go b/src/internal/goexperiment/exp_regabi_off.go deleted file mode 100644 index 5d8823843d9..00000000000 --- a/src/internal/goexperiment/exp_regabi_off.go +++ /dev/null @@ -1,9 +0,0 @@ -// Code generated by mkconsts.go. DO NOT EDIT. - -//go:build !goexperiment.regabi -// +build !goexperiment.regabi - -package goexperiment - -const Regabi = false -const RegabiInt = 0 diff --git a/src/internal/goexperiment/exp_regabi_on.go b/src/internal/goexperiment/exp_regabi_on.go deleted file mode 100644 index c08d58e9b2a..00000000000 --- a/src/internal/goexperiment/exp_regabi_on.go +++ /dev/null @@ -1,9 +0,0 @@ -// Code generated by mkconsts.go. DO NOT EDIT. - -//go:build goexperiment.regabi -// +build goexperiment.regabi - -package goexperiment - -const Regabi = true -const RegabiInt = 1 From a9de78ac88ff668bbe8c0dc5fdc9dc864ae60447 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Fri, 4 Jun 2021 13:53:18 -0400 Subject: [PATCH 335/940] [dev.typeparams] cmd/compile, runtime: always enable defer/go wrapping Hardwire regabidefers to true. Remove it from GOEXPERIMENTs. Fallback paths are not cleaned up in this CL. That will be done in later CLs. Change-Id: Iec1112a1e55d5f6ef70232a5ff6e702f649071c4 Reviewed-on: https://go-review.googlesource.com/c/go/+/325913 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek Reviewed-by: Than McIntosh --- src/cmd/compile/internal/ssagen/ssa.go | 4 ++-- src/cmd/compile/internal/walk/order.go | 5 +---- src/internal/buildcfg/exp.go | 6 ++---- .../goexperiment/exp_regabidefer_off.go | 9 --------- .../goexperiment/exp_regabidefer_on.go | 9 --------- src/internal/goexperiment/flags.go | 3 --- src/runtime/panic.go | 19 +++++++++---------- src/runtime/proc.go | 3 +-- test/live.go | 2 +- test/live_regabi.go | 2 +- 10 files changed, 17 insertions(+), 45 deletions(-) delete mode 100644 src/internal/goexperiment/exp_regabidefer_off.go delete mode 100644 src/internal/goexperiment/exp_regabidefer_on.go diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index f59220ab8e4..106ce8d6c51 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -4696,7 +4696,7 @@ func (s *state) openDeferRecord(n *ir.CallExpr) { var args []*ssa.Value var argNodes []*ir.Name - if buildcfg.Experiment.RegabiDefer && (len(n.Args) != 0 || n.Op() == ir.OCALLINTER || n.X.Type().NumResults() != 0) { + if len(n.Args) != 0 || n.Op() == ir.OCALLINTER || n.X.Type().NumResults() != 0 { s.Fatalf("defer call with arguments or results: %v", n) } @@ -4951,7 +4951,7 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val } } - if buildcfg.Experiment.RegabiDefer && k != callNormal && (len(n.Args) != 0 || n.Op() == ir.OCALLINTER || n.X.Type().NumResults() != 0) { + if k != callNormal && (len(n.Args) != 0 || n.Op() == ir.OCALLINTER || n.X.Type().NumResults() != 0) { s.Fatalf("go/defer call with arguments: %v", n) } diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go index 19d9551566e..d1fd3a9b732 100644 --- a/src/cmd/compile/internal/walk/order.go +++ b/src/cmd/compile/internal/walk/order.go @@ -7,7 +7,6 @@ package walk import ( "fmt" "go/constant" - "internal/buildcfg" "cmd/compile/internal/base" "cmd/compile/internal/escape" @@ -790,9 +789,7 @@ func (o *orderState) stmt(n ir.Node) { n.Call = walkRecover(n.Call.(*ir.CallExpr), &init) o.stmtList(init) } - if buildcfg.Experiment.RegabiDefer { - o.wrapGoDefer(n) - } + o.wrapGoDefer(n) o.out = append(o.out, n) o.cleanTemp(t) diff --git a/src/internal/buildcfg/exp.go b/src/internal/buildcfg/exp.go index 38a20456391..9402da2ebff 100644 --- a/src/internal/buildcfg/exp.go +++ b/src/internal/buildcfg/exp.go @@ -30,7 +30,6 @@ var experimentBaseline = goexperiment.Flags{ RegabiWrappers: regabiSupported, RegabiG: regabiSupported, RegabiReflect: regabiSupported, - RegabiDefer: true, RegabiArgs: regabiSupported, } @@ -70,7 +69,6 @@ func parseExperiments() goexperiment.Flags { flags.RegabiWrappers = v flags.RegabiG = v flags.RegabiReflect = v - flags.RegabiDefer = v flags.RegabiArgs = v } @@ -110,8 +108,8 @@ func parseExperiments() goexperiment.Flags { if flags.RegabiG && !flags.RegabiWrappers { Error = fmt.Errorf("GOEXPERIMENT regabig requires regabiwrappers") } - if flags.RegabiArgs && !(flags.RegabiWrappers && flags.RegabiG && flags.RegabiReflect && flags.RegabiDefer) { - Error = fmt.Errorf("GOEXPERIMENT regabiargs requires regabiwrappers,regabig,regabireflect,regabidefer") + if flags.RegabiArgs && !(flags.RegabiWrappers && flags.RegabiG && flags.RegabiReflect) { + Error = fmt.Errorf("GOEXPERIMENT regabiargs requires regabiwrappers,regabig,regabireflect") } return flags } diff --git a/src/internal/goexperiment/exp_regabidefer_off.go b/src/internal/goexperiment/exp_regabidefer_off.go deleted file mode 100644 index b47c0c2cf55..00000000000 --- a/src/internal/goexperiment/exp_regabidefer_off.go +++ /dev/null @@ -1,9 +0,0 @@ -// Code generated by mkconsts.go. DO NOT EDIT. - -//go:build !goexperiment.regabidefer -// +build !goexperiment.regabidefer - -package goexperiment - -const RegabiDefer = false -const RegabiDeferInt = 0 diff --git a/src/internal/goexperiment/exp_regabidefer_on.go b/src/internal/goexperiment/exp_regabidefer_on.go deleted file mode 100644 index bbf2f6c69be..00000000000 --- a/src/internal/goexperiment/exp_regabidefer_on.go +++ /dev/null @@ -1,9 +0,0 @@ -// Code generated by mkconsts.go. DO NOT EDIT. - -//go:build goexperiment.regabidefer -// +build goexperiment.regabidefer - -package goexperiment - -const RegabiDefer = true -const RegabiDeferInt = 1 diff --git a/src/internal/goexperiment/flags.go b/src/internal/goexperiment/flags.go index cd4c1788184..c20dbcd9f5e 100644 --- a/src/internal/goexperiment/flags.go +++ b/src/internal/goexperiment/flags.go @@ -78,9 +78,6 @@ type Flags struct { // reflect and runtime (which are disabled by default) so it // can be used in targeted tests. RegabiReflect bool - // RegabiDefer enables desugaring defer and go calls - // into argument-less closures. - RegabiDefer bool // RegabiArgs enables register arguments/results in all // compiled Go functions. // diff --git a/src/runtime/panic.go b/src/runtime/panic.go index f6c38aafcc8..e73d59c1366 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -6,7 +6,6 @@ package runtime import ( "internal/abi" - "internal/goexperiment" "runtime/internal/atomic" "runtime/internal/sys" "unsafe" @@ -236,7 +235,7 @@ func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn throw("defer on system stack") } - if goexperiment.RegabiDefer && siz != 0 { + if true && siz != 0 { // TODO: Make deferproc just take a func(). throw("defer with non-empty frame") } @@ -293,7 +292,7 @@ func deferprocStack(d *_defer) { // go code on the system stack can't defer throw("defer on system stack") } - if goexperiment.RegabiDefer && d.siz != 0 { + if true && d.siz != 0 { throw("defer with non-empty frame") } // siz and fn are already set. @@ -395,7 +394,7 @@ func deferArgs(d *_defer) unsafe.Pointer { // that experiment, we should change the type of d.fn. //go:nosplit func deferFunc(d *_defer) func() { - if !goexperiment.RegabiDefer { + if false { throw("requires GOEXPERIMENT=regabidefer") } var fn func() @@ -655,7 +654,7 @@ func Goexit() { addOneOpenDeferFrame(gp, 0, nil) } } else { - if goexperiment.RegabiDefer { + if true { // Save the pc/sp in deferCallSave(), so we can "recover" back to this // loop if necessary. deferCallSave(&p, deferFunc(d)) @@ -857,7 +856,7 @@ func runOpenDeferFrame(gp *g, d *_defer) bool { argWidth, fd = readvarintUnsafe(fd) closureOffset, fd = readvarintUnsafe(fd) nArgs, fd = readvarintUnsafe(fd) - if goexperiment.RegabiDefer && argWidth != 0 { + if true && argWidth != 0 { throw("defer with non-empty frame") } if deferBits&(1< Date: Mon, 7 Jun 2021 17:04:32 -0400 Subject: [PATCH 336/940] doc/go1.17: add a release note for the '-compat' flag to 'go mod tidy' Updates #46141 Change-Id: I7a6a84f816e3db19bb492f862366a29dc46ed2ee Reviewed-on: https://go-review.googlesource.com/c/go/+/325910 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Michael Matloob --- doc/go1.17.html | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index c1978ff1c15..ba6b8baf190 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -137,8 +137,9 @@ Do not send CLs removing the interior tags from such phrases.

-

To facilitate the upgrade to lazy loading, - the go mod tidy subcommand now supports +

+ To facilitate the upgrade to lazy loading, the + go mod tidy subcommand now supports a -go flag to set or change the go version in the go.mod file. To enable lazy loading for an existing module without changing the selected versions of its dependencies, run: @@ -149,8 +150,32 @@ Do not send CLs removing the interior tags from such phrases.

- TODO: Describe the -compat flag - for go mod tidy. + By default, go mod tidy verifies that + the selected versions of dependencies relevant to the main module are the same + versions that would be used by the prior Go release (Go 1.16 for a module that + spsecifies go 1.17), and preserves + the go.sum entries needed by that release even for dependencies + that are not normally needed by other commands. +

+ +

+ The -compat flag allows that version to be overridden to support + older (or only newer) versions, up to the version specified by + the go directive in the go.mod file. To tidy + a go 1.17 module for Go 1.17 only, without saving + checksums for (or checking for consistency with) Go 1.16: +

+ +
+  go mod tidy -compat=1.17
+
+ +

+ Note that even if the main module is tidied with -compat=1.17, + users who require the module from a + go 1.16 or earlier module will still be able to + use it, provided that the packages use only compatible language and library + features.

Module deprecation comments

From 949f00cebe9a40c7454bc42acaa77fdb8bf6c4e6 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 7 Jun 2021 10:20:38 -0400 Subject: [PATCH 337/940] doc/go1.17: add release notes for crypto packages For #44513 Change-Id: I459b3a4f9936eaa2c09888177f91176140d04280 Reviewed-on: https://go-review.googlesource.com/c/go/+/325649 Trust: Filippo Valsorda Trust: Katie Hockman Reviewed-by: Roland Shoemaker Reviewed-by: Katie Hockman --- doc/go1.17.html | 136 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 108 insertions(+), 28 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index ba6b8baf190..c1b3b3cef46 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -338,30 +338,6 @@ Do not send CLs removing the interior tags from such phrases. TODO: complete the Core library section

-

crypto/tls

- -

- (*Conn).HandshakeContext was added to - allow the user to control cancellation of an in-progress TLS Handshake. - The context provided is propagated into the - ClientHelloInfo - and CertificateRequestInfo - structs and accessible through the new - (*ClientHelloInfo).Context - and - - (*CertificateRequestInfo).Context - methods respectively. Canceling the context after the handshake has finished - has no effect. -

- -

- When Config.NextProtos is set, servers now - enforce that there is an overlap between the configured protocols and the protocols - advertised by the client, if any. If there is no overlap the connection is closed - with the no_application_protocol alert, as required by RFC 7301. -

-

Cgo

@@ -424,13 +400,117 @@ Do not send CLs removing the interior tags from such phrases.

-
crypto/rsa
+
crypto/ed25519
-

- TODO: https://golang.org/cl/302230: fix salt length calculation with PSSSaltLengthAuto +

+ The crypto/ed25519 package has been rewritten, and all + operations are now approximately twice as fast on amd64 and arm64. + The observable behavior has not otherwise changed.

-
+
+ +
crypto/elliptic
+
+

+ CurveParams + methods now automatically invoke faster and safer dedicated + implementations for known curves (P-224, P-256, and P-521) when + available. Note that this is a best-effort approach and applications + should avoid using the generic, not constant-time CurveParams + methods and instead use dedicated + Curve implementations + such as P256. +

+ +

+ The P521 curve + implementation has been rewritten using code generated by the + fiat-crypto project, + which is based on a formally-verified model of the arithmetic + operations. It is now constant-time and three times faster on amd64 and + arm64. The observable behavior has not otherwise changed. +

+
+
+ +
crypto/rand
+
+

+ The crypto/rand package now uses the getentropy + syscall on macOS and the getrandom syscall on Solaris, + Illumos, and DragonFlyBSD. +

+
+
+ +
crypto/tls
+
+

+ The new Conn.HandshakeContext + method allows the user to control cancellation of an in-progress TLS + handshake. The provided context is accessible from various callbacks through the new + ClientHelloInfo.Context and + CertificateRequestInfo.Context + methods. Canceling the context after the handshake has finished has no effect. +

+ +

+ When Config.NextProtos + is set, servers now enforce that there is an overlap between the + configured protocols and the protocols advertised by the client, if any. + If there is no overlap the connection is closed with the + no_application_protocol alert, as required by RFC 7301. +

+ +

+ Cipher suite ordering is now handled entirely by the + crypto/tls package. Currently, cipher suites are sorted based + on their security, performance, and hardware support taking into account + both the local and peer's hardware. The order of the + Config.CipherSuites + field is now ignored, as well as the + Config.PreferServerCipherSuites + field. Note that Config.CipherSuites still allows + applications to choose what TLS 1.0–1.2 cipher suites to enable. +

+ +

+ The 3DES cipher suites have been moved to + InsecureCipherSuites + due to fundamental block size-related + weakness. They are still enabled by default but only as a last resort, + thanks to the cipher suite ordering change above. +

+
+
+ +
crypto/x509
+
+

+ CreateCertificate + now returns an error if the provided private key doesn't match the + parent's public key, if any. The resulting certificate would have failed + to verify. +

+ +

+ The temporary GODEBUG=x509ignoreCN=0 flag has been removed. +

+ +

+ ParseCertificate + has been rewritten, and now consumes ~70% fewer resources. The observable + behavior has not otherwise changed, except for error messages. +

+ +

+ On BSD systems, /etc/ssl/certs is now searched for trusted + roots. This adds support for the new system trusted certificate store in + FreeBSD 12.2+. +

+
+
database/sql
From 9498b0155d4c38c018d00b83afaedaabbdbb9e85 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Mon, 7 Jun 2021 23:04:16 -0400 Subject: [PATCH 338/940] cmd/go: in Go 1.17+ modules, add indirect go.mod dependencies separately from direct ones Fixes #45965 Change-Id: If5c0d7b29e9f81be0763f3fa68051d4ef5419990 Reviewed-on: https://go-review.googlesource.com/c/go/+/325922 Trust: Bryan C. Mills Reviewed-by: Michael Matloob --- doc/go1.17.html | 8 + src/cmd/go.mod | 2 +- src/cmd/go.sum | 4 +- src/cmd/go/internal/modload/init.go | 6 +- src/cmd/go/internal/modload/modfile.go | 5 + .../script/mod_go_version_missing.txt | 7 +- .../script/mod_lazy_import_allmod.txt | 3 +- .../testdata/script/mod_lazy_new_import.txt | 10 +- .../script/mod_lazy_test_of_test_dep.txt | 7 +- src/cmd/go/testdata/script/mod_retention.txt | 3 +- .../testdata/script/mod_tidy_convergence.txt | 18 +- .../go/testdata/script/mod_tidy_version.txt | 22 +- .../vendor/golang.org/x/mod/modfile/read.go | 7 +- .../vendor/golang.org/x/mod/modfile/rule.go | 422 +++++++++++++----- src/cmd/vendor/modules.txt | 2 +- 15 files changed, 382 insertions(+), 144 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index c1b3b3cef46..8b0fcea29d1 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -137,6 +137,14 @@ Do not send CLs removing the interior tags from such phrases.

+

+ Because the number of additional explicit requirements in the go.mod file may + be substantial, in a Go 1.17 module the newly-added requirements + on indirect dependencies are maintained in a + separate require block from the block containing direct + dependencies. +

+

To facilitate the upgrade to lazy loading, the go mod tidy subcommand now supports diff --git a/src/cmd/go.mod b/src/cmd/go.mod index 1aa0320d078..cd03968eedc 100644 --- a/src/cmd/go.mod +++ b/src/cmd/go.mod @@ -7,7 +7,7 @@ require ( github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 // indirect golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e // indirect - golang.org/x/mod v0.4.3-0.20210512182355-6088ed88cecd + golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 // indirect golang.org/x/term v0.0.0-20210503060354-a79de5458b56 golang.org/x/tools v0.1.2-0.20210519160823-49064d2332f9 diff --git a/src/cmd/go.sum b/src/cmd/go.sum index eeb625fcf8a..d728acaec99 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -13,8 +13,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI= golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.3-0.20210512182355-6088ed88cecd h1:CuRnpyMrCCBulv0d/y0CswR4K0vGydgE3DZ2wYPIOo8= -golang.org/x/mod v0.4.3-0.20210512182355-6088ed88cecd/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a h1:e8qnjKz4EE6OjRki9wTadWSIogINvq10sMcuBRORxMY= +golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go index ea404b9f78f..eb9cfe629b3 100644 --- a/src/cmd/go/internal/modload/init.go +++ b/src/cmd/go/internal/modload/init.go @@ -999,10 +999,14 @@ func commitRequirements(ctx context.Context, goVersion string, rs *Requirements) Indirect: !rs.direct[m.Path], }) } - modFile.SetRequire(list) if goVersion != "" { modFile.AddGoStmt(goVersion) } + if semver.Compare("v"+modFileGoVersion(), separateIndirectVersionV) < 0 { + modFile.SetRequire(list) + } else { + modFile.SetRequireSeparateIndirect(list) + } modFile.Cleanup() dirty := index.modFileIsDirty(modFile) diff --git a/src/cmd/go/internal/modload/modfile.go b/src/cmd/go/internal/modload/modfile.go index a9c3a91d35d..1145ac4ba59 100644 --- a/src/cmd/go/internal/modload/modfile.go +++ b/src/cmd/go/internal/modload/modfile.go @@ -35,6 +35,11 @@ const ( // module's go.mod file is expected to list explicit requirements on every // module that provides any package transitively imported by that module. lazyLoadingVersionV = "v1.17" + + // separateIndirectVersionV is the Go version (plus leading "v") at which + // "// indirect" dependencies are added in a block separate from the direct + // ones. See https://golang.org/issue/45965. + separateIndirectVersionV = "v1.17" ) const ( diff --git a/src/cmd/go/testdata/script/mod_go_version_missing.txt b/src/cmd/go/testdata/script/mod_go_version_missing.txt index aca36a04506..d704816729b 100644 --- a/src/cmd/go/testdata/script/mod_go_version_missing.txt +++ b/src/cmd/go/testdata/script/mod_go_version_missing.txt @@ -73,10 +73,9 @@ module example.com/m go $goversion -require ( - example.com/dep v0.1.0 - example.com/testdep v0.1.0 // indirect -) +require example.com/dep v0.1.0 + +require example.com/testdep v0.1.0 // indirect replace ( example.com/dep v0.1.0 => ./dep diff --git a/src/cmd/go/testdata/script/mod_lazy_import_allmod.txt b/src/cmd/go/testdata/script/mod_lazy_import_allmod.txt index 3dc1515df26..97718c4513b 100644 --- a/src/cmd/go/testdata/script/mod_lazy_import_allmod.txt +++ b/src/cmd/go/testdata/script/mod_lazy_import_allmod.txt @@ -139,9 +139,10 @@ go 1.17 require ( a v0.1.0 b v0.1.0 - c v0.1.0 // indirect ) +require c v0.1.0 // indirect + replace ( a v0.1.0 => ./a1 b v0.1.0 => ./b1 diff --git a/src/cmd/go/testdata/script/mod_lazy_new_import.txt b/src/cmd/go/testdata/script/mod_lazy_new_import.txt index 86b14b64b6f..4272a52de1c 100644 --- a/src/cmd/go/testdata/script/mod_lazy_new_import.txt +++ b/src/cmd/go/testdata/script/mod_lazy_new_import.txt @@ -78,10 +78,9 @@ module example.com/lazy go 1.17 -require ( - example.com/a v0.1.0 - example.com/b v0.1.0 // indirect -) +require example.com/a v0.1.0 + +require example.com/b v0.1.0 // indirect replace ( example.com/a v0.1.0 => ./a @@ -94,8 +93,9 @@ module example.com/lazy go 1.17 +require example.com/a v0.1.0 + require ( - example.com/a v0.1.0 example.com/b v0.1.0 // indirect example.com/c v0.1.0 // indirect ) diff --git a/src/cmd/go/testdata/script/mod_lazy_test_of_test_dep.txt b/src/cmd/go/testdata/script/mod_lazy_test_of_test_dep.txt index 722712d1f2c..68a5b6dca2a 100644 --- a/src/cmd/go/testdata/script/mod_lazy_test_of_test_dep.txt +++ b/src/cmd/go/testdata/script/mod_lazy_test_of_test_dep.txt @@ -148,10 +148,9 @@ module example.com/lazy go 1.17 -require ( - example.com/a v0.1.0 - example.com/b v0.1.0 // indirect -) +require example.com/a v0.1.0 + +require example.com/b v0.1.0 // indirect replace ( example.com/a v0.1.0 => ./a diff --git a/src/cmd/go/testdata/script/mod_retention.txt b/src/cmd/go/testdata/script/mod_retention.txt index 0e639db551d..7a371b18068 100644 --- a/src/cmd/go/testdata/script/mod_retention.txt +++ b/src/cmd/go/testdata/script/mod_retention.txt @@ -140,8 +140,9 @@ module m go $goversion require ( - golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect rsc.io/quote v1.5.2 rsc.io/sampler v1.3.0 // indirect rsc.io/testonly v1.0.0 // indirect ) + +require golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect diff --git a/src/cmd/go/testdata/script/mod_tidy_convergence.txt b/src/cmd/go/testdata/script/mod_tidy_convergence.txt index 22c8fc66c57..09c46f764bf 100644 --- a/src/cmd/go/testdata/script/mod_tidy_convergence.txt +++ b/src/cmd/go/testdata/script/mod_tidy_convergence.txt @@ -90,7 +90,6 @@ cmp go.mod go.mod.postget cp go.mod.orig go.mod go mod edit -go=1.17 go.mod go mod edit -go=1.17 go.mod.tidye -go mod edit -go=1.17 go.mod.postget go mod tidy -e cmp go.mod go.mod.tidye @@ -99,7 +98,7 @@ stderr '^example\.net/m imports\n\texample\.net/x: package example\.net/x provid go get -d example.net/x@v0.1.0 example.net/y@v0.1.0 go mod tidy -cmp go.mod go.mod.postget +cmp go.mod go.mod.postget-117 -- go.mod -- @@ -144,6 +143,21 @@ require ( example.net/x v0.1.0 example.net/y v0.1.0 // indirect ) +-- go.mod.postget-117 -- +module example.net/m + +go 1.17 + +replace ( + example.net/x v0.1.0 => ./x1 + example.net/x v0.2.0-pre => ./x2-pre + example.net/y v0.1.0 => ./y1 + example.net/y v0.2.0 => ./y2 +) + +require example.net/x v0.1.0 + +require example.net/y v0.1.0 // indirect -- m.go -- package m diff --git a/src/cmd/go/testdata/script/mod_tidy_version.txt b/src/cmd/go/testdata/script/mod_tidy_version.txt index eaa6ee7b0db..3bc97bcb1e7 100644 --- a/src/cmd/go/testdata/script/mod_tidy_version.txt +++ b/src/cmd/go/testdata/script/mod_tidy_version.txt @@ -92,8 +92,9 @@ cmpenv go.mod go.mod.latest -- go.mod -- module example.com/m +require example.net/a v0.1.0 + require ( - example.net/a v0.1.0 example.net/c v0.1.0 // indirect example.net/d v0.1.0 // indirect ) @@ -118,8 +119,9 @@ module example.com/m go 1.15 +require example.net/a v0.1.0 + require ( - example.net/a v0.1.0 example.net/c v0.1.0 // indirect example.net/d v0.1.0 // indirect ) @@ -139,8 +141,9 @@ module example.com/m go 1.15 +require example.net/a v0.1.0 + require ( - example.net/a v0.1.0 example.net/c v0.1.0 // indirect example.net/d v0.2.0 // indirect ) @@ -160,10 +163,9 @@ module example.com/m go 1.16 -require ( - example.net/a v0.1.0 - example.net/c v0.1.0 // indirect -) +require example.net/a v0.1.0 + +require example.net/c v0.1.0 // indirect replace ( example.net/a v0.1.0 => ./a @@ -180,8 +182,9 @@ module example.com/m go 1.17 +require example.net/a v0.1.0 + require ( - example.net/a v0.1.0 example.net/b v0.1.0 // indirect example.net/c v0.1.0 // indirect ) @@ -201,8 +204,9 @@ module example.com/m go $goversion +require example.net/a v0.1.0 + require ( - example.net/a v0.1.0 example.net/b v0.1.0 // indirect example.net/c v0.1.0 // indirect ) diff --git a/src/cmd/vendor/golang.org/x/mod/modfile/read.go b/src/cmd/vendor/golang.org/x/mod/modfile/read.go index 2a961ca81c2..956f30cbb39 100644 --- a/src/cmd/vendor/golang.org/x/mod/modfile/read.go +++ b/src/cmd/vendor/golang.org/x/mod/modfile/read.go @@ -194,12 +194,15 @@ func (x *FileSyntax) updateLine(line *Line, tokens ...string) { line.Token = tokens } -func (x *FileSyntax) removeLine(line *Line) { +// markRemoved modifies line so that it (and its end-of-line comment, if any) +// will be dropped by (*FileSyntax).Cleanup. +func (line *Line) markRemoved() { line.Token = nil + line.Comments.Suffix = nil } // Cleanup cleans up the file syntax x after any edit operations. -// To avoid quadratic behavior, removeLine marks the line as dead +// To avoid quadratic behavior, (*Line).markRemoved marks the line as dead // by setting line.Token = nil but does not remove it from the slice // in which it appears. After edits have all been indicated, // calling Cleanup cleans out the dead lines. diff --git a/src/cmd/vendor/golang.org/x/mod/modfile/rule.go b/src/cmd/vendor/golang.org/x/mod/modfile/rule.go index 7299e15500a..78f83fa7144 100644 --- a/src/cmd/vendor/golang.org/x/mod/modfile/rule.go +++ b/src/cmd/vendor/golang.org/x/mod/modfile/rule.go @@ -58,13 +58,6 @@ type Go struct { Syntax *Line } -// A Require is a single require statement. -type Require struct { - Mod module.Version - Indirect bool // has "// indirect" comment - Syntax *Line -} - // An Exclude is a single exclude statement. type Exclude struct { Mod module.Version @@ -93,6 +86,93 @@ type VersionInterval struct { Low, High string } +// A Require is a single require statement. +type Require struct { + Mod module.Version + Indirect bool // has "// indirect" comment + Syntax *Line +} + +func (r *Require) markRemoved() { + r.Syntax.markRemoved() + *r = Require{} +} + +func (r *Require) setVersion(v string) { + r.Mod.Version = v + + if line := r.Syntax; len(line.Token) > 0 { + if line.InBlock { + // If the line is preceded by an empty line, remove it; see + // https://golang.org/issue/33779. + if len(line.Comments.Before) == 1 && len(line.Comments.Before[0].Token) == 0 { + line.Comments.Before = line.Comments.Before[:0] + } + if len(line.Token) >= 2 { // example.com v1.2.3 + line.Token[1] = v + } + } else { + if len(line.Token) >= 3 { // require example.com v1.2.3 + line.Token[2] = v + } + } + } +} + +// setIndirect sets line to have (or not have) a "// indirect" comment. +func (r *Require) setIndirect(indirect bool) { + r.Indirect = indirect + line := r.Syntax + if isIndirect(line) == indirect { + return + } + if indirect { + // Adding comment. + if len(line.Suffix) == 0 { + // New comment. + line.Suffix = []Comment{{Token: "// indirect", Suffix: true}} + return + } + + com := &line.Suffix[0] + text := strings.TrimSpace(strings.TrimPrefix(com.Token, string(slashSlash))) + if text == "" { + // Empty comment. + com.Token = "// indirect" + return + } + + // Insert at beginning of existing comment. + com.Token = "// indirect; " + text + return + } + + // Removing comment. + f := strings.TrimSpace(strings.TrimPrefix(line.Suffix[0].Token, string(slashSlash))) + if f == "indirect" { + // Remove whole comment. + line.Suffix = nil + return + } + + // Remove comment prefix. + com := &line.Suffix[0] + i := strings.Index(com.Token, "indirect;") + com.Token = "//" + com.Token[i+len("indirect;"):] +} + +// isIndirect reports whether line has a "// indirect" comment, +// meaning it is in go.mod only for its effect on indirect dependencies, +// so that it can be dropped entirely once the effective version of the +// indirect dependency reaches the given minimum version. +func isIndirect(line *Line) bool { + if len(line.Suffix) == 0 { + return false + } + f := strings.Fields(strings.TrimPrefix(line.Suffix[0].Token, string(slashSlash))) + return (len(f) == 1 && f[0] == "indirect" || len(f) > 1 && f[0] == "indirect;") +} + func (f *File) AddModuleStmt(path string) error { if f.Syntax == nil { f.Syntax = new(FileSyntax) @@ -476,58 +556,6 @@ func (f *File) fixRetract(fix VersionFixer, errs *ErrorList) { } } -// isIndirect reports whether line has a "// indirect" comment, -// meaning it is in go.mod only for its effect on indirect dependencies, -// so that it can be dropped entirely once the effective version of the -// indirect dependency reaches the given minimum version. -func isIndirect(line *Line) bool { - if len(line.Suffix) == 0 { - return false - } - f := strings.Fields(strings.TrimPrefix(line.Suffix[0].Token, string(slashSlash))) - return (len(f) == 1 && f[0] == "indirect" || len(f) > 1 && f[0] == "indirect;") -} - -// setIndirect sets line to have (or not have) a "// indirect" comment. -func setIndirect(line *Line, indirect bool) { - if isIndirect(line) == indirect { - return - } - if indirect { - // Adding comment. - if len(line.Suffix) == 0 { - // New comment. - line.Suffix = []Comment{{Token: "// indirect", Suffix: true}} - return - } - - com := &line.Suffix[0] - text := strings.TrimSpace(strings.TrimPrefix(com.Token, string(slashSlash))) - if text == "" { - // Empty comment. - com.Token = "// indirect" - return - } - - // Insert at beginning of existing comment. - com.Token = "// indirect; " + text - return - } - - // Removing comment. - f := strings.TrimSpace(strings.TrimPrefix(line.Suffix[0].Token, string(slashSlash))) - if f == "indirect" { - // Remove whole comment. - line.Suffix = nil - return - } - - // Remove comment prefix. - com := &line.Suffix[0] - i := strings.Index(com.Token, "indirect;") - com.Token = "//" + com.Token[i+len("indirect;"):] -} - // IsDirectoryPath reports whether the given path should be interpreted // as a directory path. Just like on the go command line, relative paths // and rooted paths are directory paths; the rest are module paths. @@ -835,6 +863,12 @@ func (f *File) AddGoStmt(version string) error { return nil } +// AddRequire sets the first require line for path to version vers, +// preserving any existing comments for that line and removing all +// other lines for path. +// +// If no line currently exists for path, AddRequire adds a new line +// at the end of the last require block. func (f *File) AddRequire(path, vers string) error { need := true for _, r := range f.Require { @@ -844,7 +878,7 @@ func (f *File) AddRequire(path, vers string) error { f.Syntax.updateLine(r.Syntax, "require", AutoQuote(path), vers) need = false } else { - f.Syntax.removeLine(r.Syntax) + r.Syntax.markRemoved() *r = Require{} } } @@ -856,69 +890,235 @@ func (f *File) AddRequire(path, vers string) error { return nil } +// AddNewRequire adds a new require line for path at version vers at the end of +// the last require block, regardless of any existing require lines for path. func (f *File) AddNewRequire(path, vers string, indirect bool) { line := f.Syntax.addLine(nil, "require", AutoQuote(path), vers) - setIndirect(line, indirect) - f.Require = append(f.Require, &Require{module.Version{Path: path, Version: vers}, indirect, line}) + r := &Require{ + Mod: module.Version{Path: path, Version: vers}, + Syntax: line, + } + r.setIndirect(indirect) + f.Require = append(f.Require, r) } +// SetRequire updates the requirements of f to contain exactly req, preserving +// the existing block structure and line comment contents (except for 'indirect' +// markings) for the first requirement on each named module path. +// +// The Syntax field is ignored for the requirements in req. +// +// Any requirements not already present in the file are added to the block +// containing the last require line. +// +// The requirements in req must specify at most one distinct version for each +// module path. +// +// If any existing requirements may be removed, the caller should call Cleanup +// after all edits are complete. func (f *File) SetRequire(req []*Require) { - need := make(map[string]string) - indirect := make(map[string]bool) + type elem struct { + version string + indirect bool + } + need := make(map[string]elem) for _, r := range req { - need[r.Mod.Path] = r.Mod.Version - indirect[r.Mod.Path] = r.Indirect - } - - for _, r := range f.Require { - if v, ok := need[r.Mod.Path]; ok { - r.Mod.Version = v - r.Indirect = indirect[r.Mod.Path] - } else { - *r = Require{} + if prev, dup := need[r.Mod.Path]; dup && prev.version != r.Mod.Version { + panic(fmt.Errorf("SetRequire called with conflicting versions for path %s (%s and %s)", r.Mod.Path, prev.version, r.Mod.Version)) } + need[r.Mod.Path] = elem{r.Mod.Version, r.Indirect} } - var newStmts []Expr + // Update or delete the existing Require entries to preserve + // only the first for each module path in req. + for _, r := range f.Require { + e, ok := need[r.Mod.Path] + if ok { + r.setVersion(e.version) + r.setIndirect(e.indirect) + } else { + r.markRemoved() + } + delete(need, r.Mod.Path) + } + + // Add new entries in the last block of the file for any paths that weren't + // already present. + // + // This step is nondeterministic, but the final result will be deterministic + // because we will sort the block. + for path, e := range need { + f.AddNewRequire(path, e.version, e.indirect) + } + + f.SortBlocks() +} + +// SetRequireSeparateIndirect updates the requirements of f to contain the given +// requirements. Comment contents (except for 'indirect' markings) are retained +// from the first existing requirement for each module path, and block structure +// is maintained as long as the indirect markings match. +// +// Any requirements on paths not already present in the file are added. Direct +// requirements are added to the last block containing *any* other direct +// requirement. Indirect requirements are added to the last block containing +// *only* other indirect requirements. If no suitable block exists, a new one is +// added, with the last block containing a direct dependency (if any) +// immediately before the first block containing only indirect dependencies. +// +// The Syntax field is ignored for requirements in the given blocks. +func (f *File) SetRequireSeparateIndirect(req []*Require) { + type modKey struct { + path string + indirect bool + } + need := make(map[modKey]string) + for _, r := range req { + need[modKey{r.Mod.Path, r.Indirect}] = r.Mod.Version + } + + comments := make(map[string]Comments) + for _, r := range f.Require { + v, ok := need[modKey{r.Mod.Path, r.Indirect}] + if !ok { + if _, ok := need[modKey{r.Mod.Path, !r.Indirect}]; ok { + if _, dup := comments[r.Mod.Path]; !dup { + comments[r.Mod.Path] = r.Syntax.Comments + } + } + r.markRemoved() + continue + } + r.setVersion(v) + delete(need, modKey{r.Mod.Path, r.Indirect}) + } + + var ( + lastDirectOrMixedBlock Expr + firstIndirectOnlyBlock Expr + lastIndirectOnlyBlock Expr + ) for _, stmt := range f.Syntax.Stmt { switch stmt := stmt.(type) { - case *LineBlock: - if len(stmt.Token) > 0 && stmt.Token[0] == "require" { - var newLines []*Line - for _, line := range stmt.Line { - if p, err := parseString(&line.Token[0]); err == nil && need[p] != "" { - if len(line.Comments.Before) == 1 && len(line.Comments.Before[0].Token) == 0 { - line.Comments.Before = line.Comments.Before[:0] - } - line.Token[1] = need[p] - delete(need, p) - setIndirect(line, indirect[p]) - newLines = append(newLines, line) - } - } - if len(newLines) == 0 { - continue // drop stmt - } - stmt.Line = newLines - } - case *Line: - if len(stmt.Token) > 0 && stmt.Token[0] == "require" { - if p, err := parseString(&stmt.Token[1]); err == nil && need[p] != "" { - stmt.Token[2] = need[p] - delete(need, p) - setIndirect(stmt, indirect[p]) - } else { - continue // drop stmt + if len(stmt.Token) == 0 || stmt.Token[0] != "require" { + continue + } + if isIndirect(stmt) { + lastIndirectOnlyBlock = stmt + } else { + lastDirectOrMixedBlock = stmt + } + case *LineBlock: + if len(stmt.Token) == 0 || stmt.Token[0] != "require" { + continue + } + indirectOnly := true + for _, line := range stmt.Line { + if len(line.Token) == 0 { + continue + } + if !isIndirect(line) { + indirectOnly = false + break + } + } + if indirectOnly { + lastIndirectOnlyBlock = stmt + if firstIndirectOnlyBlock == nil { + firstIndirectOnlyBlock = stmt + } + } else { + lastDirectOrMixedBlock = stmt + } + } + } + + isOrContainsStmt := func(stmt Expr, target Expr) bool { + if stmt == target { + return true + } + if stmt, ok := stmt.(*LineBlock); ok { + if target, ok := target.(*Line); ok { + for _, line := range stmt.Line { + if line == target { + return true + } } } } - newStmts = append(newStmts, stmt) + return false } - f.Syntax.Stmt = newStmts - for path, vers := range need { - f.AddNewRequire(path, vers, indirect[path]) + addRequire := func(path, vers string, indirect bool, comments Comments) { + var line *Line + if indirect { + if lastIndirectOnlyBlock != nil { + line = f.Syntax.addLine(lastIndirectOnlyBlock, "require", path, vers) + } else { + // Add a new require block after the last direct-only or mixed "require" + // block (if any). + // + // (f.Syntax.addLine would add the line to an existing "require" block if + // present, but here the existing "require" blocks are all direct-only, so + // we know we need to add a new block instead.) + line = &Line{Token: []string{"require", path, vers}} + lastIndirectOnlyBlock = line + firstIndirectOnlyBlock = line // only block implies first block + if lastDirectOrMixedBlock == nil { + f.Syntax.Stmt = append(f.Syntax.Stmt, line) + } else { + for i, stmt := range f.Syntax.Stmt { + if isOrContainsStmt(stmt, lastDirectOrMixedBlock) { + f.Syntax.Stmt = append(f.Syntax.Stmt, nil) // increase size + copy(f.Syntax.Stmt[i+2:], f.Syntax.Stmt[i+1:]) // shuffle elements up + f.Syntax.Stmt[i+1] = line + break + } + } + } + } + } else { + if lastDirectOrMixedBlock != nil { + line = f.Syntax.addLine(lastDirectOrMixedBlock, "require", path, vers) + } else { + // Add a new require block before the first indirect block (if any). + // + // That way if the file initially contains only indirect lines, + // the direct lines still appear before it: we preserve existing + // structure, but only to the extent that that structure already + // reflects the direct/indirect split. + line = &Line{Token: []string{"require", path, vers}} + lastDirectOrMixedBlock = line + if firstIndirectOnlyBlock == nil { + f.Syntax.Stmt = append(f.Syntax.Stmt, line) + } else { + for i, stmt := range f.Syntax.Stmt { + if isOrContainsStmt(stmt, firstIndirectOnlyBlock) { + f.Syntax.Stmt = append(f.Syntax.Stmt, nil) // increase size + copy(f.Syntax.Stmt[i+1:], f.Syntax.Stmt[i:]) // shuffle elements up + f.Syntax.Stmt[i] = line + break + } + } + } + } + } + + line.Comments.Before = commentsAdd(line.Comments.Before, comments.Before) + line.Comments.Suffix = commentsAdd(line.Comments.Suffix, comments.Suffix) + + r := &Require{ + Mod: module.Version{Path: path, Version: vers}, + Indirect: indirect, + Syntax: line, + } + r.setIndirect(indirect) + f.Require = append(f.Require, r) + } + + for k, vers := range need { + addRequire(k.path, vers, k.indirect, comments[k.path]) } f.SortBlocks() } @@ -926,7 +1126,7 @@ func (f *File) SetRequire(req []*Require) { func (f *File) DropRequire(path string) error { for _, r := range f.Require { if r.Mod.Path == path { - f.Syntax.removeLine(r.Syntax) + r.Syntax.markRemoved() *r = Require{} } } @@ -957,7 +1157,7 @@ func (f *File) AddExclude(path, vers string) error { func (f *File) DropExclude(path, vers string) error { for _, x := range f.Exclude { if x.Mod.Path == path && x.Mod.Version == vers { - f.Syntax.removeLine(x.Syntax) + x.Syntax.markRemoved() *x = Exclude{} } } @@ -988,7 +1188,7 @@ func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) error { continue } // Already added; delete other replacements for same. - f.Syntax.removeLine(r.Syntax) + r.Syntax.markRemoved() *r = Replace{} } if r.Old.Path == oldPath { @@ -1004,7 +1204,7 @@ func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) error { func (f *File) DropReplace(oldPath, oldVers string) error { for _, r := range f.Replace { if r.Old.Path == oldPath && r.Old.Version == oldVers { - f.Syntax.removeLine(r.Syntax) + r.Syntax.markRemoved() *r = Replace{} } } @@ -1045,7 +1245,7 @@ func (f *File) AddRetract(vi VersionInterval, rationale string) error { func (f *File) DropRetract(vi VersionInterval) error { for _, r := range f.Retract { if r.VersionInterval == vi { - f.Syntax.removeLine(r.Syntax) + r.Syntax.markRemoved() *r = Retract{} } } diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt index 9a1723d32c7..34dbdaf5dd3 100644 --- a/src/cmd/vendor/modules.txt +++ b/src/cmd/vendor/modules.txt @@ -28,7 +28,7 @@ golang.org/x/arch/x86/x86asm ## explicit; go 1.17 golang.org/x/crypto/ed25519 golang.org/x/crypto/ed25519/internal/edwards25519 -# golang.org/x/mod v0.4.3-0.20210512182355-6088ed88cecd +# golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a ## explicit; go 1.17 golang.org/x/mod/internal/lazyregexp golang.org/x/mod/modfile From 5b350505da37a37ebfedbc4114777107867a4181 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Fri, 4 Jun 2021 16:32:03 -0400 Subject: [PATCH 339/940] [dev.typeparams] cmd/compile: remove variadic defer calls Now that defer wrapping is used, deferred function is always argumentless. Remove the code handling arguments. This CL is mostly removing the fallback code path. There are more cleanups to be done, in later CLs. Change-Id: If6c729d3055c7a507cb1f1a000f5bbd3ad7ff235 Reviewed-on: https://go-review.googlesource.com/c/go/+/325914 Trust: Cherry Mui Reviewed-by: Than McIntosh --- src/cmd/compile/internal/ssagen/ssa.go | 178 ++++--------------------- 1 file changed, 29 insertions(+), 149 deletions(-) diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 106ce8d6c51..64793468458 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -359,31 +359,8 @@ func (s *state) emitOpenDeferInfo() { r := s.openDefers[i] off = dvarint(x, off, r.n.X.Type().ArgWidth()) off = dvarint(x, off, -r.closureNode.FrameOffset()) - numArgs := len(r.argNodes) - if r.rcvrNode != nil { - // If there's an interface receiver, treat/place it as the first - // arg. (If there is a method receiver, it's already included as - // first arg in r.argNodes.) - numArgs++ - } + numArgs := 0 off = dvarint(x, off, int64(numArgs)) - argAdjust := 0 // presence of receiver offsets the parameter count. - if r.rcvrNode != nil { - off = dvarint(x, off, -okOffset(r.rcvrNode.FrameOffset())) - off = dvarint(x, off, s.config.PtrSize) - off = dvarint(x, off, 0) // This is okay because defer records use ABI0 (for now) - argAdjust++ - } - - // TODO(register args) assume abi0 for this? - ab := s.f.ABI0 - pri := ab.ABIAnalyzeFuncType(r.n.X.Type().FuncType()) - for j, arg := range r.argNodes { - f := getParam(r.n, j) - off = dvarint(x, off, -okOffset(arg.FrameOffset())) - off = dvarint(x, off, f.Type.Size()) - off = dvarint(x, off, okOffset(pri.InParam(j+argAdjust).FrameOffset(pri))) - } } } @@ -864,16 +841,6 @@ type openDeferInfo struct { // function, method, or interface call, to store a closure that panic // processing can use for this defer. closureNode *ir.Name - // If defer call is interface call, the address of the argtmp where the - // receiver is stored - rcvr *ssa.Value - // The node representing the argtmp where the receiver is stored - rcvrNode *ir.Name - // The addresses of the argtmps where the evaluated arguments of the defer - // function call are stored. - argVals []*ssa.Value - // The nodes representing the argtmps where the args of the defer are stored - argNodes []*ir.Name } type state struct { @@ -4686,17 +4653,14 @@ func (s *state) intrinsicArgs(n *ir.CallExpr) []*ssa.Value { return args } -// openDeferRecord adds code to evaluate and store the args for an open-code defer +// openDeferRecord adds code to evaluate and store the function for an open-code defer // call, and records info about the defer, so we can generate proper code on the // exit paths. n is the sub-node of the defer node that is the actual function -// call. We will also record funcdata information on where the args are stored +// call. We will also record funcdata information on where the function is stored // (as well as the deferBits variable), and this will enable us to run the proper // defer calls during panics. func (s *state) openDeferRecord(n *ir.CallExpr) { - var args []*ssa.Value - var argNodes []*ir.Name - - if len(n.Args) != 0 || n.Op() == ir.OCALLINTER || n.X.Type().NumResults() != 0 { + if len(n.Args) != 0 || n.Op() != ir.OCALLFUNC || n.X.Type().NumResults() != 0 { s.Fatalf("defer call with arguments or results: %v", n) } @@ -4704,48 +4668,20 @@ func (s *state) openDeferRecord(n *ir.CallExpr) { n: n, } fn := n.X - if n.Op() == ir.OCALLFUNC { - // We must always store the function value in a stack slot for the - // runtime panic code to use. But in the defer exit code, we will - // call the function directly if it is a static function. - closureVal := s.expr(fn) - closure := s.openDeferSave(nil, fn.Type(), closureVal) - opendefer.closureNode = closure.Aux.(*ir.Name) - if !(fn.Op() == ir.ONAME && fn.(*ir.Name).Class == ir.PFUNC) { - opendefer.closure = closure - } - } else if n.Op() == ir.OCALLMETH { - base.Fatalf("OCALLMETH missed by walkCall") - } else { - if fn.Op() != ir.ODOTINTER { - base.Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op()) - } - fn := fn.(*ir.SelectorExpr) - closure, rcvr := s.getClosureAndRcvr(fn) - opendefer.closure = s.openDeferSave(nil, closure.Type, closure) - // Important to get the receiver type correct, so it is recognized - // as a pointer for GC purposes. - opendefer.rcvr = s.openDeferSave(nil, fn.Type().Recv().Type, rcvr) - opendefer.closureNode = opendefer.closure.Aux.(*ir.Name) - opendefer.rcvrNode = opendefer.rcvr.Aux.(*ir.Name) + // We must always store the function value in a stack slot for the + // runtime panic code to use. But in the defer exit code, we will + // call the function directly if it is a static function. + closureVal := s.expr(fn) + closure := s.openDeferSave(nil, fn.Type(), closureVal) + opendefer.closureNode = closure.Aux.(*ir.Name) + if !(fn.Op() == ir.ONAME && fn.(*ir.Name).Class == ir.PFUNC) { + opendefer.closure = closure } - for _, argn := range n.Args { - var v *ssa.Value - if TypeOK(argn.Type()) { - v = s.openDeferSave(nil, argn.Type(), s.expr(argn)) - } else { - v = s.openDeferSave(argn, argn.Type(), nil) - } - args = append(args, v) - argNodes = append(argNodes, v.Aux.(*ir.Name)) - } - opendefer.argVals = args - opendefer.argNodes = argNodes index := len(s.openDefers) s.openDefers = append(s.openDefers, opendefer) // Update deferBits only after evaluation and storage to stack of - // args/receiver/interface is successful. + // the function is successful. bitvalue := s.constInt8(types.Types[types.TUINT8], 1< Date: Mon, 7 Jun 2021 13:43:55 -0400 Subject: [PATCH 340/940] doc/go1.17: resolve TODO for cmd/cover Updates #32211 Change-Id: Ie38e831fcf557534023afd552d9394fe9e055caa Reviewed-on: https://go-review.googlesource.com/c/go/+/325909 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Dmitri Shuralyov Reviewed-by: Emmanuel Odeke --- doc/go1.17.html | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 8b0fcea29d1..ac315d47279 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -277,10 +277,6 @@ Do not send CLs removing the interior tags from such phrases. mod download all.

-

- TODO: https://golang.org/cl/249759: cmd/cover: replace code using optimized golang.org/x/tools/cover -

-

Vet

@@ -291,6 +287,14 @@ Do not send CLs removing the interior tags from such phrases. TODO: complete the Vet section

+

Cover

+ +

+ The cover tool now uses an optimized parser + from golang.org/x/tools/cover, which may be noticeably faster + when parsing large coverage profiles. +

+

Compiler

From 12b37b713fddcee366d286a858c452f3bfdfa794 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Fri, 4 Jun 2021 17:04:46 -0400 Subject: [PATCH 341/940] [dev.typeparams] runtime: remove variadic defer/go calls Now that defer/go wrapping is used, deferred/go'd functions are always argumentless. Remove the code handling arguments. This CL is mostly removing the fallback code path. There are more cleanups to be done, in later CLs. Change-Id: I87bfd3fb2d759fbeb6487b8125c0f6992863d6e5 Reviewed-on: https://go-review.googlesource.com/c/go/+/325915 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/cmd/compile/internal/test/inl_test.go | 1 - src/cmd/internal/objabi/funcid.go | 1 - src/runtime/panic.go | 113 ++-------------------- src/runtime/proc.go | 34 +------ src/runtime/traceback.go | 9 +- 5 files changed, 16 insertions(+), 142 deletions(-) diff --git a/src/cmd/compile/internal/test/inl_test.go b/src/cmd/compile/internal/test/inl_test.go index ad4e4fee976..5b0db833010 100644 --- a/src/cmd/compile/internal/test/inl_test.go +++ b/src/cmd/compile/internal/test/inl_test.go @@ -42,7 +42,6 @@ func TestIntendedInlining(t *testing.T) { "bucketMask", "bucketShift", "chanbuf", - "deferArgs", "deferclass", "evacuated", "fastlog2", diff --git a/src/cmd/internal/objabi/funcid.go b/src/cmd/internal/objabi/funcid.go index 93ebd7be943..d881cdd0618 100644 --- a/src/cmd/internal/objabi/funcid.go +++ b/src/cmd/internal/objabi/funcid.go @@ -74,7 +74,6 @@ var funcIDs = map[string]FuncID{ // Don't show in call stack but otherwise not special. "deferreturn": FuncID_wrapper, "runOpenDeferFrame": FuncID_wrapper, - "reflectcallSave": FuncID_wrapper, "deferCallSave": FuncID_wrapper, } diff --git a/src/runtime/panic.go b/src/runtime/panic.go index e73d59c1366..8a296a3c17f 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -5,7 +5,6 @@ package runtime import ( - "internal/abi" "runtime/internal/atomic" "runtime/internal/sys" "unsafe" @@ -235,7 +234,7 @@ func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn throw("defer on system stack") } - if true && siz != 0 { + if siz != 0 { // TODO: Make deferproc just take a func(). throw("defer with non-empty frame") } @@ -246,10 +245,9 @@ func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn // to somewhere safe. The memmove below does that. // Until the copy completes, we can only call nosplit routines. sp := getcallersp() - argp := uintptr(unsafe.Pointer(&fn)) + unsafe.Sizeof(fn) callerpc := getcallerpc() - d := newdefer(siz) + d := newdefer(0) if d._panic != nil { throw("deferproc: d.panic != nil after newdefer") } @@ -258,14 +256,6 @@ func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn d.fn = fn d.pc = callerpc d.sp = sp - switch siz { - case 0: - // Do nothing. - case sys.PtrSize: - *(*uintptr)(deferArgs(d)) = *(*uintptr)(unsafe.Pointer(argp)) - default: - memmove(deferArgs(d), unsafe.Pointer(argp), uintptr(siz)) - } // deferproc returns 0 normally. // a deferred func that stops a panic @@ -292,7 +282,7 @@ func deferprocStack(d *_defer) { // go code on the system stack can't defer throw("defer on system stack") } - if true && d.siz != 0 { + if d.siz != 0 { throw("defer with non-empty frame") } // siz and fn are already set. @@ -378,25 +368,11 @@ func testdefersizes() { } } -// The arguments associated with a deferred call are stored -// immediately after the _defer header in memory. -//go:nosplit -func deferArgs(d *_defer) unsafe.Pointer { - if d.siz == 0 { - // Avoid pointer past the defer allocation. - return nil - } - return add(unsafe.Pointer(d), unsafe.Sizeof(*d)) -} - // deferFunc returns d's deferred function. This is temporary while we // support both modes of GOEXPERIMENT=regabidefer. Once we commit to // that experiment, we should change the type of d.fn. //go:nosplit func deferFunc(d *_defer) func() { - if false { - throw("requires GOEXPERIMENT=regabidefer") - } var fn func() *(**funcval)(unsafe.Pointer(&fn)) = d.fn return fn @@ -575,14 +551,6 @@ func deferreturn() { // of the arguments until the jmpdefer can flip the PC over to // fn. argp := getcallersp() + sys.MinFrameSize - switch d.siz { - case 0: - // Do nothing. - case sys.PtrSize: - *(*uintptr)(unsafe.Pointer(argp)) = *(*uintptr)(deferArgs(d)) - default: - memmove(unsafe.Pointer(argp), deferArgs(d), uintptr(d.siz)) - } fn := d.fn d.fn = nil gp._defer = d.link @@ -654,15 +622,9 @@ func Goexit() { addOneOpenDeferFrame(gp, 0, nil) } } else { - if true { - // Save the pc/sp in deferCallSave(), so we can "recover" back to this - // loop if necessary. - deferCallSave(&p, deferFunc(d)) - } else { - // Save the pc/sp in reflectcallSave(), so we can "recover" back to this - // loop if necessary. - reflectcallSave(&p, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz)) - } + // Save the pc/sp in deferCallSave(), so we can "recover" back to this + // loop if necessary. + deferCallSave(&p, deferFunc(d)) } if p.aborted { // We had a recursive panic in the defer d we started, and @@ -856,7 +818,7 @@ func runOpenDeferFrame(gp *g, d *_defer) bool { argWidth, fd = readvarintUnsafe(fd) closureOffset, fd = readvarintUnsafe(fd) nArgs, fd = readvarintUnsafe(fd) - if true && argWidth != 0 { + if argWidth != 0 || nArgs != 0 { throw("defer with non-empty frame") } if deferBits&(1<= _StackMin-4*sys.PtrSize-sys.PtrSize { - throw("newproc: function arguments too large for new goroutine") - } _p_ := _g_.m.p.ptr() newg := gfget(_p_) @@ -4299,8 +4289,8 @@ func newproc1(fn *funcval, argp unsafe.Pointer, narg int32, callergp *g, callerp throw("newproc1: new g is not Gdead") } - totalSize := 4*sys.PtrSize + uintptr(siz) + sys.MinFrameSize // extra space in case of reads slightly beyond frame - totalSize += -totalSize & (sys.StackAlign - 1) // align to StackAlign + totalSize := uintptr(4*sys.PtrSize + sys.MinFrameSize) // extra space in case of reads slightly beyond frame + totalSize = alignUp(totalSize, sys.StackAlign) sp := newg.stack.hi - totalSize spArg := sp if usesLR { @@ -4309,24 +4299,6 @@ func newproc1(fn *funcval, argp unsafe.Pointer, narg int32, callergp *g, callerp prepGoExitFrame(sp) spArg += sys.MinFrameSize } - if narg > 0 { - memmove(unsafe.Pointer(spArg), argp, uintptr(narg)) - // This is a stack-to-stack copy. If write barriers - // are enabled and the source stack is grey (the - // destination is always black), then perform a - // barrier copy. We do this *after* the memmove - // because the destination stack may have garbage on - // it. - if writeBarrier.needed && !_g_.m.curg.gcscandone { - f := findfunc(fn.fn) - stkmap := (*stackmap)(funcdata(f, _FUNCDATA_ArgsPointerMaps)) - if stkmap.nbit > 0 { - // We're in the prologue, so it's always stack map index 0. - bv := stackmapdata(stkmap, 0) - bulkBarrierBitmap(spArg, spArg, uintptr(bv.n)*sys.PtrSize, 0, bv.bytedata) - } - } - } memclrNoHeapPointers(unsafe.Pointer(&newg.sched), unsafe.Sizeof(newg.sched)) newg.sched.sp = sp diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index 89780edc1ff..2564273a53b 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -42,12 +42,9 @@ func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v uns throw("unknown pc") } frame.fn = f - frame.argp = uintptr(deferArgs(d)) - var ok bool - frame.arglen, frame.argmap, ok = getArgInfoFast(f, true) - if !ok { - frame.arglen, frame.argmap = getArgInfo(&frame, f, true, fn) - } + frame.argp = 0 + frame.arglen = 0 + frame.argmap = nil } frame.continpc = frame.pc if !callback((*stkframe)(noescape(unsafe.Pointer(&frame))), v) { From 00d01b57866d4b052c3b75706bbc8601167ead7c Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Fri, 4 Jun 2021 17:18:09 -0400 Subject: [PATCH 342/940] [dev.typeparams] runtime: remove tracebackdefers tracebackdefers is used for scanning/copying deferred functions' arguments. Now that deferred functions are always argumentless, it does nothing. Remove. Change-Id: I55bedabe5584ea41a12cdb03d55ec9692a5aacd9 Reviewed-on: https://go-review.googlesource.com/c/go/+/325916 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/runtime/mgcmark.go | 7 ++----- src/runtime/stack.go | 5 ----- src/runtime/traceback.go | 32 -------------------------------- 3 files changed, 2 insertions(+), 42 deletions(-) diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go index 1fd0732d62d..eb70ae9f493 100644 --- a/src/runtime/mgcmark.go +++ b/src/runtime/mgcmark.go @@ -750,14 +750,11 @@ func scanstack(gp *g, gcw *gcWork) { // Find additional pointers that point into the stack from the heap. // Currently this includes defers and panics. See also function copystack. - // Find and trace all defer arguments. - tracebackdefers(gp, scanframe, nil) - // Find and trace other pointers in defer records. for d := gp._defer; d != nil; d = d.link { if d.fn != nil { - // tracebackdefers above does not scan the func value, which could - // be a stack allocated closure. See issue 30453. + // Scan the func value, which could be a stack allocated closure. + // See issue 30453. scanblock(uintptr(unsafe.Pointer(&d.fn)), sys.PtrSize, &oneptrmask[0], gcw, &state) } if d.link != nil { diff --git a/src/runtime/stack.go b/src/runtime/stack.go index a1182b00bdc..b5545ac796d 100644 --- a/src/runtime/stack.go +++ b/src/runtime/stack.go @@ -753,11 +753,6 @@ func adjustdefers(gp *g, adjinfo *adjustinfo) { adjustpointer(adjinfo, unsafe.Pointer(&d.varp)) adjustpointer(adjinfo, unsafe.Pointer(&d.fd)) } - - // Adjust defer argument blocks the same way we adjust active stack frames. - // Note: this code is after the loop above, so that if a defer record is - // stack allocated, we work on the copy in the new stack. - tracebackdefers(gp, adjustframe, noescape(unsafe.Pointer(adjinfo))) } func adjustpanics(gp *g, adjinfo *adjustinfo) { diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index 2564273a53b..3fc9d07fc5a 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -21,38 +21,6 @@ import ( const usesLR = sys.MinFrameSize > 0 -// Traceback over the deferred function calls. -// Report them like calls that have been invoked but not started executing yet. -func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v unsafe.Pointer) { - var frame stkframe - for d := gp._defer; d != nil; d = d.link { - fn := d.fn - if fn == nil { - // Defer of nil function. Args don't matter. - frame.pc = 0 - frame.fn = funcInfo{} - frame.argp = 0 - frame.arglen = 0 - frame.argmap = nil - } else { - frame.pc = fn.fn - f := findfunc(frame.pc) - if !f.valid() { - print("runtime: unknown pc in defer ", hex(frame.pc), "\n") - throw("unknown pc") - } - frame.fn = f - frame.argp = 0 - frame.arglen = 0 - frame.argmap = nil - } - frame.continpc = frame.pc - if !callback((*stkframe)(noescape(unsafe.Pointer(&frame))), v) { - return - } - } -} - const sizeofSkipFunction = 256 // Generic traceback. Handles runtime stack prints (pcbuf == nil), From 9afe071c605c65302066fa8ece7bdecd00730f8b Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Mon, 7 Jun 2021 17:11:32 -0400 Subject: [PATCH 343/940] doc/go1.17: remove TODO for Tools section Change-Id: I6cd7376bd051222a830cbf18cf7e887072b61f3b Reviewed-on: https://go-review.googlesource.com/c/go/+/325911 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Dmitri Shuralyov --- doc/go1.17.html | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index ac315d47279..42f3631b923 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -116,10 +116,6 @@ Do not send CLs removing the interior tags from such phrases.

Tools

-

- TODO: complete the Tools section -

-

Go command

Lazy module loading

From 689f4c7415acc8a135440574a483e0eeabba8b87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?= Date: Thu, 3 Jun 2021 15:33:08 +0200 Subject: [PATCH 344/940] doc/go1.17: mention block profile bias fix Change-Id: I76fd872b2d74704396f0683ffa9cec40b7027247 Reviewed-on: https://go-review.googlesource.com/c/go/+/324471 Reviewed-by: Heschi Kreinick Trust: Dmitri Shuralyov --- doc/go1.17.html | 10 ++++++++++ src/runtime/pprof/pprof_test.go | 22 ++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/doc/go1.17.html b/doc/go1.17.html index 42f3631b923..1701508ea9a 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -725,6 +725,16 @@ Do not send CLs removing the interior tags from such phrases.
+ +
runtime/pprof
+
+

+ Block profiles are no longer biased to favor infrequent long events over + frequent short events. +

+
+
+
strconv

diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go index 7cbb4fc7ae4..e139ee787d6 100644 --- a/src/runtime/pprof/pprof_test.go +++ b/src/runtime/pprof/pprof_test.go @@ -106,6 +106,28 @@ func TestCPUProfileMultithreaded(t *testing.T) { }) } +func TestCPUProfileThreadBias(t *testing.T) { + cpuHogA := func(dur time.Duration) { + cpuHogger(cpuHog1, &salt2, dur) + } + + defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2)) + prof := testCPUProfile(t, stackContains, []string{"runtime/pprof.cpuHog1", "runtime/pprof.cpuHog2"}, avoidFunctions(), func(dur time.Duration) { + //c := make(chan int) + //go func() { + //cpuHogger(cpuHog1, &salt1, dur) + //c <- 1 + //}() + cpuHogA(dur) + //<-c + }) + fmt.Printf("%#v\n", prof) +} + +func cpuHogA(dur time.Duration) { + cpuHogger(cpuHog1, &salt2, dur) +} + // containsInlinedCall reports whether the function body for the function f is // known to contain an inlined function call within the first maxBytes bytes. func containsInlinedCall(f interface{}, maxBytes int) bool { From da4a64014140adf83fb1434367ff68067249c267 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 26 May 2021 12:14:19 -0400 Subject: [PATCH 345/940] doc/go1.17: revise OpenBSD release notes Updates #44513. Change-Id: I64077859fa3061fee8327599875ad3870d603a81 Reviewed-on: https://go-review.googlesource.com/c/go/+/322856 Trust: Cherry Mui Reviewed-by: Dmitri Shuralyov Reviewed-by: Heschi Kreinick --- doc/go1.17.html | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 1701508ea9a..3a1b43a4e51 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -95,11 +95,13 @@ Do not send CLs removing the interior tags from such phrases. In Go 1.16, on the 64-bit x86 and 64-bit ARM architectures on OpenBSD (the openbsd/amd64 and openbsd/arm64 ports) system calls are made through libc, instead - of directly using the machine instructions. In Go 1.17, this is - also done on the 32-bit x86 and 32-bit ARM architectures on OpenBSD + of directly using machine instructions. In Go 1.17, this is also + done on the 32-bit x86 and 32-bit ARM architectures on OpenBSD (the openbsd/386 and openbsd/arm ports). This ensures forward-compatibility with future versions of - OpenBSD. + OpenBSD, in particular, with OpenBSD 6.9 onwards, which requires + system calls to be made through libc for non-static + Go binaries.

ARM64

From d3e3d03666bbd8784007bbb78a75864aac786967 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Mon, 7 Jun 2021 10:21:29 -0700 Subject: [PATCH 346/940] net: reject leading zeros in IP address parsers In both net.ParseIP and net.ParseCIDR reject leading zeros in the dot-decimal notation of IPv4 addresses. Fixes #30999 Fixes #43389 Change-Id: I2b6a31fe84db89ac828cf5ed03eaa586ee96ab68 Reviewed-on: https://go-review.googlesource.com/c/go/+/325829 Trust: Roland Shoemaker Trust: Katie Hockman Run-TryBot: Roland Shoemaker Reviewed-by: Filippo Valsorda Reviewed-by: Katie Hockman TryBot-Result: Go Bot --- doc/go1.17.html | 10 ++++++++++ src/net/hosts_test.go | 4 ++-- src/net/ip.go | 4 ++++ src/net/ip_test.go | 8 ++++++-- src/net/testdata/ipv4-hosts | 8 ++------ 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 3a1b43a4e51..56f88e67245 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -639,6 +639,16 @@ Do not send CLs removing the interior tags from such phrases. ParseError error type now implement the net.Error interface.

+ +

+ The ParseIP and ParseCIDR + functions now reject IPv4 addresses which contain decimal components with leading zeros. + + These components were always interpreted as decimal, but some operating systems treat them as octal. + This mismatch could hypothetically lead to security issues if a Go application was used to validate IP addresses + which were then used in their original form with non-Go applications which interpreted components as octal. Generally, + it is advisable to always re-encoded values after validation, which avoids this class of parser misalignment issues. +

diff --git a/src/net/hosts_test.go b/src/net/hosts_test.go index f850e2fccfd..19c43999f92 100644 --- a/src/net/hosts_test.go +++ b/src/net/hosts_test.go @@ -36,7 +36,7 @@ var lookupStaticHostTests = []struct { }, }, { - "testdata/ipv4-hosts", // see golang.org/issue/8996 + "testdata/ipv4-hosts", []staticHostEntry{ {"localhost", []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}}, {"localhost.localdomain", []string{"127.0.0.3"}}, @@ -102,7 +102,7 @@ var lookupStaticAddrTests = []struct { }, }, { - "testdata/ipv4-hosts", // see golang.org/issue/8996 + "testdata/ipv4-hosts", []staticHostEntry{ {"127.0.0.1", []string{"localhost"}}, {"127.0.0.2", []string{"localhost"}}, diff --git a/src/net/ip.go b/src/net/ip.go index 04772697618..38e1aa2247f 100644 --- a/src/net/ip.go +++ b/src/net/ip.go @@ -574,6 +574,10 @@ func parseIPv4(s string) IP { if !ok || n > 0xFF { return nil } + if c > 1 && s[0] == '0' { + // Reject non-zero components with leading zeroes. + return nil + } s = s[c:] p[i] = byte(n) } diff --git a/src/net/ip_test.go b/src/net/ip_test.go index 3af5e41ceb4..5bbda6024dc 100644 --- a/src/net/ip_test.go +++ b/src/net/ip_test.go @@ -21,9 +21,7 @@ var parseIPTests = []struct { }{ {"127.0.1.2", IPv4(127, 0, 1, 2)}, {"127.0.0.1", IPv4(127, 0, 0, 1)}, - {"127.001.002.003", IPv4(127, 1, 2, 3)}, {"::ffff:127.1.2.3", IPv4(127, 1, 2, 3)}, - {"::ffff:127.001.002.003", IPv4(127, 1, 2, 3)}, {"::ffff:7f01:0203", IPv4(127, 1, 2, 3)}, {"0:0:0:0:0000:ffff:127.1.2.3", IPv4(127, 1, 2, 3)}, {"0:0:0:0:000000:ffff:127.1.2.3", IPv4(127, 1, 2, 3)}, @@ -43,6 +41,11 @@ var parseIPTests = []struct { {"fe80::1%911", nil}, {"", nil}, {"a1:a2:a3:a4::b1:b2:b3:b4", nil}, // Issue 6628 + {"127.001.002.003", nil}, + {"::ffff:127.001.002.003", nil}, + {"123.000.000.000", nil}, + {"1.2..4", nil}, + {"0123.0.0.1", nil}, } func TestParseIP(t *testing.T) { @@ -358,6 +361,7 @@ var parseCIDRTests = []struct { {"0.0.-2.0/32", nil, nil, &ParseError{Type: "CIDR address", Text: "0.0.-2.0/32"}}, {"0.0.0.-3/32", nil, nil, &ParseError{Type: "CIDR address", Text: "0.0.0.-3/32"}}, {"0.0.0.0/-0", nil, nil, &ParseError{Type: "CIDR address", Text: "0.0.0.0/-0"}}, + {"127.000.000.001/32", nil, nil, &ParseError{Type: "CIDR address", Text: "127.000.000.001/32"}}, {"", nil, nil, &ParseError{Type: "CIDR address", Text: ""}}, } diff --git a/src/net/testdata/ipv4-hosts b/src/net/testdata/ipv4-hosts index 5208bb44ac8..6b99675dfc8 100644 --- a/src/net/testdata/ipv4-hosts +++ b/src/net/testdata/ipv4-hosts @@ -1,12 +1,8 @@ # See https://tools.ietf.org/html/rfc1123. -# -# The literal IPv4 address parser in the net package is a relaxed -# one. It may accept a literal IPv4 address in dotted-decimal notation -# with leading zeros such as "001.2.003.4". # internet address and host name 127.0.0.1 localhost # inline comment separated by tab -127.000.000.002 localhost # inline comment separated by space +127.0.0.2 localhost # inline comment separated by space # internet address, host name and aliases -127.000.000.003 localhost localhost.localdomain +127.0.0.3 localhost localhost.localdomain From cb80937bf6b728fa56ee315d2c079f07c2f9f2a1 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 8 Jun 2021 20:38:30 +0000 Subject: [PATCH 347/940] Revert "doc/go1.17: mention block profile bias fix" This reverts CL 324471 (commit 689f4c7415acc8a135440574a483e0eeabba8b87). Reason for revert: break ~all builders. And it is not a doc-only change. Change-Id: Iadbdda34d2ca476a9f5e6c2d3a28592ed7ccb067 Reviewed-on: https://go-review.googlesource.com/c/go/+/326170 Trust: Cherry Mui Run-TryBot: Cherry Mui Reviewed-by: Heschi Kreinick --- doc/go1.17.html | 10 ---------- src/runtime/pprof/pprof_test.go | 22 ---------------------- 2 files changed, 32 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 56f88e67245..1e153377d6e 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -737,16 +737,6 @@ Do not send CLs removing the interior tags from such phrases. - -
runtime/pprof
-
-

- Block profiles are no longer biased to favor infrequent long events over - frequent short events. -

-
-
-
strconv

diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go index e139ee787d6..7cbb4fc7ae4 100644 --- a/src/runtime/pprof/pprof_test.go +++ b/src/runtime/pprof/pprof_test.go @@ -106,28 +106,6 @@ func TestCPUProfileMultithreaded(t *testing.T) { }) } -func TestCPUProfileThreadBias(t *testing.T) { - cpuHogA := func(dur time.Duration) { - cpuHogger(cpuHog1, &salt2, dur) - } - - defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2)) - prof := testCPUProfile(t, stackContains, []string{"runtime/pprof.cpuHog1", "runtime/pprof.cpuHog2"}, avoidFunctions(), func(dur time.Duration) { - //c := make(chan int) - //go func() { - //cpuHogger(cpuHog1, &salt1, dur) - //c <- 1 - //}() - cpuHogA(dur) - //<-c - }) - fmt.Printf("%#v\n", prof) -} - -func cpuHogA(dur time.Duration) { - cpuHogger(cpuHog1, &salt2, dur) -} - // containsInlinedCall reports whether the function body for the function f is // known to contain an inlined function call within the first maxBytes bytes. func containsInlinedCall(f interface{}, maxBytes int) bool { From 6551763a60ce25d171feaa69089a7f1ca60f43b6 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 8 Jun 2021 16:42:02 -0400 Subject: [PATCH 348/940] doc/go1.17: mention block profile bias fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Re-apply the doc part of CL 324471, originally written by Felix Geisendörfer. Change-Id: I831bead9a385bc5a5eed3058649a25ef17373bc6 Reviewed-on: https://go-review.googlesource.com/c/go/+/326171 Trust: Cherry Mui Reviewed-by: Dmitri Shuralyov --- doc/go1.17.html | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/go1.17.html b/doc/go1.17.html index 1e153377d6e..eb7932cd675 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -737,6 +737,15 @@ Do not send CLs removing the interior tags from such phrases.

+
runtime/pprof
+
+

+ Block profiles are no longer biased to favor infrequent long events over + frequent short events. +

+
+
+
strconv

From 8e5304f7298a0eef48e4796017c51b4d9aeb52b5 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Fri, 4 Jun 2021 18:11:59 -0400 Subject: [PATCH 349/940] [dev.typeparams] cmd/compile, runtime: remove the siz argument of newproc/deferproc newproc/deferproc takes a siz argument for the go'd/deferred function's argument size. Now it is always zero. Remove the argument. Change-Id: If1bb8d427e34015ccec0ba10dbccaae96757fa8c Reviewed-on: https://go-review.googlesource.com/c/go/+/325917 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/cmd/compile/internal/ssagen/ssa.go | 11 ++++------- src/runtime/asm_386.s | 2 -- src/runtime/asm_amd64.s | 2 -- src/runtime/asm_arm.s | 7 +++---- src/runtime/asm_arm64.s | 11 ++++------- src/runtime/asm_mips64x.s | 7 +++---- src/runtime/asm_mipsx.s | 7 +++---- src/runtime/asm_ppc64x.s | 3 +-- src/runtime/asm_riscv64.s | 7 +++---- src/runtime/asm_s390x.s | 7 +++---- src/runtime/asm_wasm.s | 3 +-- src/runtime/debugcall.go | 2 +- src/runtime/panic.go | 9 ++------- src/runtime/proc.go | 27 +++++++++++--------------- 14 files changed, 39 insertions(+), 66 deletions(-) diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 64793468458..27f0ee685bc 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -4972,14 +4972,11 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val argStart := base.Ctxt.FixedFrameSize() // Defer/go args. if k != callNormal { - // Write argsize and closure (args to newproc/deferproc). - argsize := s.constInt32(types.Types[types.TUINT32], int32(stksize)) - ACArgs = append(ACArgs, types.Types[types.TUINT32]) // not argExtra - callArgs = append(callArgs, argsize) - ACArgs = append(ACArgs, types.Types[types.TUINTPTR]) + // Write closure (arg to newproc/deferproc). + ACArgs = append(ACArgs, types.Types[types.TUINTPTR]) // not argExtra callArgs = append(callArgs, closure) - stksize += 2 * int64(types.PtrSize) - argStart += 2 * int64(types.PtrSize) + stksize += int64(types.PtrSize) + argStart += int64(types.PtrSize) } // Set receiver (for interface calls). diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s index ec5ea58028b..dd2ea458cc5 100644 --- a/src/runtime/asm_386.s +++ b/src/runtime/asm_386.s @@ -244,10 +244,8 @@ ok: // create a new goroutine to start program PUSHL $runtime·mainPC(SB) // entry - PUSHL $0 // arg size CALL runtime·newproc(SB) POPL AX - POPL AX // start this M CALL runtime·mstart(SB) diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index 96f0d3fefce..f8f5fc62e6c 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -214,10 +214,8 @@ ok: // create a new goroutine to start program MOVQ $runtime·mainPC(SB), AX // entry PUSHQ AX - PUSHQ $0 // arg size CALL runtime·newproc(SB) POPQ AX - POPQ AX // start this M CALL runtime·mstart(SB) diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index 872e56aeb49..5c2bc00fe81 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -168,14 +168,13 @@ TEXT runtime·rt0_go(SB),NOSPLIT|NOFRAME|TOPFRAME,$0 BL runtime·schedinit(SB) // create a new goroutine to start program - SUB $12, R13 + SUB $8, R13 MOVW $runtime·mainPC(SB), R0 - MOVW R0, 8(R13) // arg 2: fn + MOVW R0, 4(R13) // arg 1: fn MOVW $0, R0 - MOVW R0, 4(R13) // arg 1: siz MOVW R0, 0(R13) // dummy LR BL runtime·newproc(SB) - ADD $12, R13 // pop args and LR + ADD $8, R13 // pop args and LR // start this M BL runtime·mstart(SB) diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s index be4313d35d5..e7c5fa32252 100644 --- a/src/runtime/asm_arm64.s +++ b/src/runtime/asm_arm64.s @@ -87,14 +87,11 @@ nocgo: // create a new goroutine to start program MOVD $runtime·mainPC(SB), R0 // entry - MOVD RSP, R7 - MOVD.W $0, -8(R7) - MOVD.W R0, -8(R7) - MOVD.W $0, -8(R7) - MOVD.W $0, -8(R7) - MOVD R7, RSP + SUB $16, RSP + MOVD R0, 8(RSP) // arg + MOVD $0, 0(RSP) // dummy LR BL runtime·newproc(SB) - ADD $32, RSP + ADD $16, RSP // start this M BL runtime·mstart(SB) diff --git a/src/runtime/asm_mips64x.s b/src/runtime/asm_mips64x.s index d4d22801055..f3ac453d998 100644 --- a/src/runtime/asm_mips64x.s +++ b/src/runtime/asm_mips64x.s @@ -63,12 +63,11 @@ nocgo: // create a new goroutine to start program MOVV $runtime·mainPC(SB), R1 // entry - ADDV $-24, R29 - MOVV R1, 16(R29) - MOVV R0, 8(R29) + ADDV $-16, R29 + MOVV R1, 8(R29) MOVV R0, 0(R29) JAL runtime·newproc(SB) - ADDV $24, R29 + ADDV $16, R29 // start this M JAL runtime·mstart(SB) diff --git a/src/runtime/asm_mipsx.s b/src/runtime/asm_mipsx.s index ea7edf20cf9..4dc165849e2 100644 --- a/src/runtime/asm_mipsx.s +++ b/src/runtime/asm_mipsx.s @@ -64,12 +64,11 @@ nocgo: // create a new goroutine to start program MOVW $runtime·mainPC(SB), R1 // entry - ADDU $-12, R29 - MOVW R1, 8(R29) - MOVW R0, 4(R29) + ADDU $-8, R29 + MOVW R1, 4(R29) MOVW R0, 0(R29) JAL runtime·newproc(SB) - ADDU $12, R29 + ADDU $8, R29 // start this M JAL runtime·mstart(SB) diff --git a/src/runtime/asm_ppc64x.s b/src/runtime/asm_ppc64x.s index 942cc14f17d..a789d041e43 100644 --- a/src/runtime/asm_ppc64x.s +++ b/src/runtime/asm_ppc64x.s @@ -94,9 +94,8 @@ nocgo: MOVDU R0, -8(R1) MOVDU R0, -8(R1) MOVDU R0, -8(R1) - MOVDU R0, -8(R1) BL runtime·newproc(SB) - ADD $(16+FIXED_FRAME), R1 + ADD $(8+FIXED_FRAME), R1 // start this M BL runtime·mstart(SB) diff --git a/src/runtime/asm_riscv64.s b/src/runtime/asm_riscv64.s index ef7af4e10d8..69ab88f1d2c 100644 --- a/src/runtime/asm_riscv64.s +++ b/src/runtime/asm_riscv64.s @@ -57,12 +57,11 @@ nocgo: // create a new goroutine to start program MOV $runtime·mainPC(SB), T0 // entry - ADD $-24, X2 - MOV T0, 16(X2) - MOV ZERO, 8(X2) + ADD $-16, X2 + MOV T0, 8(X2) MOV ZERO, 0(X2) CALL runtime·newproc(SB) - ADD $24, X2 + ADD $16, X2 // start this M CALL runtime·mstart(SB) diff --git a/src/runtime/asm_s390x.s b/src/runtime/asm_s390x.s index fb382716303..534cb6112c6 100644 --- a/src/runtime/asm_s390x.s +++ b/src/runtime/asm_s390x.s @@ -147,12 +147,11 @@ nocgo: // create a new goroutine to start program MOVD $runtime·mainPC(SB), R2 // entry - SUB $24, R15 - MOVD R2, 16(R15) - MOVD $0, 8(R15) + SUB $16, R15 + MOVD R2, 8(R15) MOVD $0, 0(R15) BL runtime·newproc(SB) - ADD $24, R15 + ADD $16, R15 // start this M BL runtime·mstart(SB) diff --git a/src/runtime/asm_wasm.s b/src/runtime/asm_wasm.s index 33c335ba5af..53c271aa708 100644 --- a/src/runtime/asm_wasm.s +++ b/src/runtime/asm_wasm.s @@ -18,8 +18,7 @@ TEXT runtime·rt0_go(SB), NOSPLIT|NOFRAME|TOPFRAME, $0 CALLNORESUME runtime·args(SB) CALLNORESUME runtime·osinit(SB) CALLNORESUME runtime·schedinit(SB) - MOVD $0, 0(SP) - MOVD $runtime·mainPC(SB), 8(SP) + MOVD $runtime·mainPC(SB), 0(SP) CALLNORESUME runtime·newproc(SB) CALL runtime·mstart(SB) // WebAssembly stack will unwind when switching to another goroutine UNDEF diff --git a/src/runtime/debugcall.go b/src/runtime/debugcall.go index faddf59eed6..ad66a18c26c 100644 --- a/src/runtime/debugcall.go +++ b/src/runtime/debugcall.go @@ -112,7 +112,7 @@ func debugCallWrap(dispatch uintptr) { // closure and start the goroutine with that closure, but the compiler disallows // implicit closure allocation in the runtime. fn := debugCallWrap1 - newg := newproc1(*(**funcval)(unsafe.Pointer(&fn)), nil, 0, gp, callerpc) + newg := newproc1(*(**funcval)(unsafe.Pointer(&fn)), gp, callerpc) args := &debugCallWrapArgs{ dispatch: dispatch, callingG: gp, diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 8a296a3c17f..46e43382cdf 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -224,21 +224,16 @@ func panicmemAddr(addr uintptr) { panic(errorAddressString{msg: "invalid memory address or nil pointer dereference", addr: addr}) } -// Create a new deferred function fn with siz bytes of arguments. +// Create a new deferred function fn, which has no arguments and results. // The compiler turns a defer statement into a call to this. //go:nosplit -func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn +func deferproc(fn *funcval) { // TODO: Make deferproc just take a func(). gp := getg() if gp.m.curg != gp { // go code on the system stack can't defer throw("defer on system stack") } - if siz != 0 { - // TODO: Make deferproc just take a func(). - throw("defer with non-empty frame") - } - // the arguments of fn are in a perilous state. The stack map // for deferproc does not describe them. So we can't let garbage // collection or stack copying trigger until we've copied them out diff --git a/src/runtime/proc.go b/src/runtime/proc.go index be18bbc090c..5d2511b83cf 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -4217,7 +4217,7 @@ func malg(stacksize int32) *g { return newg } -// Create a new g running fn with siz bytes of arguments. +// Create a new g running fn. // Put it on the queue of g's waiting to run. // The compiler turns a go statement into a call to this. // @@ -4232,12 +4232,11 @@ func malg(stacksize int32) *g { // be able to adjust them and stack splits won't be able to copy them. // //go:nosplit -func newproc(siz int32, fn *funcval) { - argp := add(unsafe.Pointer(&fn), sys.PtrSize) +func newproc(fn *funcval) { gp := getg() pc := getcallerpc() systemstack(func() { - newg := newproc1(fn, argp, siz, gp, pc) + newg := newproc1(fn, gp, pc) _p_ := getg().m.p.ptr() runqput(_p_, newg, true) @@ -4248,23 +4247,19 @@ func newproc(siz int32, fn *funcval) { }) } -// Create a new g in state _Grunnable, starting at fn, with narg bytes -// of arguments starting at argp. callerpc is the address of the go -// statement that created this. The caller is responsible for adding -// the new g to the scheduler. +// Create a new g in state _Grunnable, starting at fn. callerpc is the +// address of the go statement that created this. The caller is responsible +// for adding the new g to the scheduler. // // This must run on the system stack because it's the continuation of // newproc, which cannot split the stack. // //go:systemstack -func newproc1(fn *funcval, argp unsafe.Pointer, narg int32, callergp *g, callerpc uintptr) *g { - if narg != 0 { - // TODO: When we commit to GOEXPERIMENT=regabidefer, - // rewrite the comments for newproc and newproc1. - // newproc will no longer have a funny stack layout or - // need to be nosplit. - throw("go with non-empty frame") - } +func newproc1(fn *funcval, callergp *g, callerpc uintptr) *g { + // TODO: When we commit to GOEXPERIMENT=regabidefer, + // rewrite the comments for newproc and newproc1. + // newproc will no longer have a funny stack layout or + // need to be nosplit. _g_ := getg() From 83da32749ce86d7ecbe9078d524788fbecb4f39c Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Fri, 4 Jun 2021 18:30:51 -0400 Subject: [PATCH 350/940] [dev.typeparams] runtime: make deferproc take a func() argument Previously it takes a *funcval, as it can be any function types. Now it must be func(). Make it so. Change-Id: I04273047b024386f55dbbd5fbda4767cbee7ac93 Reviewed-on: https://go-review.googlesource.com/c/go/+/325918 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/runtime/heapdump.go | 7 ++++--- src/runtime/panic.go | 25 ++++++++----------------- src/runtime/runtime2.go | 8 ++++---- src/runtime/stubs.go | 2 +- 4 files changed, 17 insertions(+), 25 deletions(-) diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go index 934e55f4952..47e4b6b0d1d 100644 --- a/src/runtime/heapdump.go +++ b/src/runtime/heapdump.go @@ -381,12 +381,13 @@ func dumpgoroutine(gp *g) { dumpint(uint64(uintptr(unsafe.Pointer(gp)))) dumpint(uint64(d.sp)) dumpint(uint64(d.pc)) - dumpint(uint64(uintptr(unsafe.Pointer(d.fn)))) - if d.fn == nil { + fn := *(**funcval)(unsafe.Pointer(&d.fn)) + dumpint(uint64(uintptr(unsafe.Pointer(fn)))) + if fn == nil { // d.fn can be nil for open-coded defers dumpint(uint64(0)) } else { - dumpint(uint64(uintptr(unsafe.Pointer(d.fn.fn)))) + dumpint(uint64(uintptr(unsafe.Pointer(fn.fn)))) } dumpint(uint64(uintptr(unsafe.Pointer(d.link)))) } diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 46e43382cdf..dc3f6956eb9 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -227,7 +227,7 @@ func panicmemAddr(addr uintptr) { // Create a new deferred function fn, which has no arguments and results. // The compiler turns a defer statement into a call to this. //go:nosplit -func deferproc(fn *funcval) { // TODO: Make deferproc just take a func(). +func deferproc(fn func()) { gp := getg() if gp.m.curg != gp { // go code on the system stack can't defer @@ -363,16 +363,6 @@ func testdefersizes() { } } -// deferFunc returns d's deferred function. This is temporary while we -// support both modes of GOEXPERIMENT=regabidefer. Once we commit to -// that experiment, we should change the type of d.fn. -//go:nosplit -func deferFunc(d *_defer) func() { - var fn func() - *(**funcval)(unsafe.Pointer(&fn)) = d.fn - return fn -} - var deferType *_type // type of _defer struct func init() { @@ -555,7 +545,9 @@ func deferreturn() { // called with a callback on an LR architecture and jmpdefer is on the // stack, because the stack trace can be incorrect in that case - see // issue #8153). - _ = fn.fn + if fn == nil { + fn() + } jmpdefer(fn, argp) } @@ -619,7 +611,7 @@ func Goexit() { } else { // Save the pc/sp in deferCallSave(), so we can "recover" back to this // loop if necessary. - deferCallSave(&p, deferFunc(d)) + deferCallSave(&p, d.fn) } if p.aborted { // We had a recursive panic in the defer d we started, and @@ -824,12 +816,12 @@ func runOpenDeferFrame(gp *g, d *_defer) bool { } continue } - closure := *(**funcval)(unsafe.Pointer(d.varp - uintptr(closureOffset))) + closure := *(*func())(unsafe.Pointer(d.varp - uintptr(closureOffset))) d.fn = closure deferBits = deferBits &^ (1 << i) *(*uint8)(unsafe.Pointer(d.varp - uintptr(deferBitsOffset))) = deferBits p := d._panic - deferCallSave(p, deferFunc(d)) + deferCallSave(p, d.fn) if p != nil && p.aborted { break } @@ -950,8 +942,7 @@ func gopanic(e interface{}) { } } else { p.argp = unsafe.Pointer(getargp()) - fn := deferFunc(d) - fn() + d.fn() } p.argp = nil diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index 0e0eb0b7285..8b2998f29aa 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -954,10 +954,10 @@ type _defer struct { // defers. We have only one defer record for the entire frame (which may // currently have 0, 1, or more defers active). openDefer bool - sp uintptr // sp at time of defer - pc uintptr // pc at time of defer - fn *funcval // can be nil for open-coded defers - _panic *_panic // panic that is running defer + sp uintptr // sp at time of defer + pc uintptr // pc at time of defer + fn func() // can be nil for open-coded defers + _panic *_panic // panic that is running defer link *_defer // If openDefer is true, the fields below record values about the stack diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index 16d75832029..b94acdea1f6 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -177,7 +177,7 @@ func cgocallback(fn, frame, ctxt uintptr) func gogo(buf *gobuf) //go:noescape -func jmpdefer(fv *funcval, argp uintptr) +func jmpdefer(fv func(), argp uintptr) func asminit() func setg(gg *g) func breakpoint() From b80a4c56f015ed51a94da6bd7bcf5bf4b0b08a27 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Fri, 4 Jun 2021 20:07:50 -0400 Subject: [PATCH 351/940] [dev.typeparams] runtime: allow deferproc split stack deferproc was not allowed to split stack because it had a special stack layout, where the go'd function's arguments were passed on stack but not included in the signature (therefore the stack map). Now it no longer has argument, so it does not need to be nosplit. Change-Id: I6d4b5302bd6fea6642bb4202984d86e3ebbc9054 Reviewed-on: https://go-review.googlesource.com/c/go/+/325920 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/runtime/panic.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/runtime/panic.go b/src/runtime/panic.go index dc3f6956eb9..5f35abc43b9 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -226,7 +226,6 @@ func panicmemAddr(addr uintptr) { // Create a new deferred function fn, which has no arguments and results. // The compiler turns a defer statement into a call to this. -//go:nosplit func deferproc(fn func()) { gp := getg() if gp.m.curg != gp { @@ -234,11 +233,6 @@ func deferproc(fn func()) { throw("defer on system stack") } - // the arguments of fn are in a perilous state. The stack map - // for deferproc does not describe them. So we can't let garbage - // collection or stack copying trigger until we've copied them out - // to somewhere safe. The memmove below does that. - // Until the copy completes, we can only call nosplit routines. sp := getcallersp() callerpc := getcallerpc() From 74b0b2772ab361884c0e00caf16aa158a7b51e36 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Mon, 7 Jun 2021 18:18:00 -0400 Subject: [PATCH 352/940] [dev.typeparams] cmd/compile, runtime: remove _defer.siz field As deferred function now always has zero arguments, _defer.siz is always 0 and can be removed. Change-Id: Ibb89f65b2f9d2ba4aeabe50438cc3d4b6a88320b Reviewed-on: https://go-review.googlesource.com/c/go/+/325921 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/cmd/compile/internal/ssagen/ssa.go | 33 +++++++++++--------------- src/runtime/panic.go | 11 +++------ src/runtime/runtime2.go | 5 ++-- 3 files changed, 19 insertions(+), 30 deletions(-) diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 27f0ee685bc..613a5b62119 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -4940,24 +4940,20 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val addr := s.addr(d) // Must match deferstruct() below and src/runtime/runtime2.go:_defer. - // 0: siz - s.store(types.Types[types.TUINT32], - s.newValue1I(ssa.OpOffPtr, types.Types[types.TUINT32].PtrTo(), t.FieldOff(0), addr), - s.constInt32(types.Types[types.TUINT32], 0)) - // 1: started, set in deferprocStack - // 2: heap, set in deferprocStack - // 3: openDefer - // 4: sp, set in deferprocStack - // 5: pc, set in deferprocStack - // 6: fn + // 0: started, set in deferprocStack + // 1: heap, set in deferprocStack + // 2: openDefer + // 3: sp, set in deferprocStack + // 4: pc, set in deferprocStack + // 5: fn s.store(closure.Type, - s.newValue1I(ssa.OpOffPtr, closure.Type.PtrTo(), t.FieldOff(6), addr), + s.newValue1I(ssa.OpOffPtr, closure.Type.PtrTo(), t.FieldOff(5), addr), closure) - // 7: panic, set in deferprocStack - // 8: link, set in deferprocStack - // 9: framepc - // 10: varp - // 11: fd + // 6: panic, set in deferprocStack + // 7: link, set in deferprocStack + // 8: fd + // 9: varp + // 10: framepc // Call runtime.deferprocStack with pointer to _defer record. ACArgs = append(ACArgs, types.Types[types.TUINTPTR]) @@ -7583,7 +7579,6 @@ func deferstruct() *types.Type { // These fields must match the ones in runtime/runtime2.go:_defer and // (*state).call above. fields := []*types.Field{ - makefield("siz", types.Types[types.TUINT32]), makefield("started", types.Types[types.TBOOL]), makefield("heap", types.Types[types.TBOOL]), makefield("openDefer", types.Types[types.TBOOL]), @@ -7595,9 +7590,9 @@ func deferstruct() *types.Type { makefield("fn", types.Types[types.TUINTPTR]), makefield("_panic", types.Types[types.TUINTPTR]), makefield("link", types.Types[types.TUINTPTR]), - makefield("framepc", types.Types[types.TUINTPTR]), - makefield("varp", types.Types[types.TUINTPTR]), makefield("fd", types.Types[types.TUINTPTR]), + makefield("varp", types.Types[types.TUINTPTR]), + makefield("framepc", types.Types[types.TUINTPTR]), } // build struct holding the above fields diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 5f35abc43b9..f6d72995b3f 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -258,7 +258,7 @@ func deferproc(fn func()) { } // deferprocStack queues a new deferred function with a defer record on the stack. -// The defer record must have its siz and fn fields initialized. +// The defer record must have its fn field initialized. // All other fields can contain junk. // The defer record must be immediately followed in memory by // the arguments of the defer. @@ -271,10 +271,7 @@ func deferprocStack(d *_defer) { // go code on the system stack can't defer throw("defer on system stack") } - if d.siz != 0 { - throw("defer with non-empty frame") - } - // siz and fn are already set. + // fn is already set. // The other fields are junk on entry to deferprocStack and // are initialized here. d.started = false @@ -406,7 +403,6 @@ func newdefer(siz int32) *_defer { d = (*_defer)(mallocgc(total, deferType, true)) }) } - d.siz = siz d.heap = true return d } @@ -428,7 +424,7 @@ func freedefer(d *_defer) { if !d.heap { return } - sc := deferclass(uintptr(d.siz)) + sc := deferclass(0) if sc >= uintptr(len(p{}.deferpool)) { return } @@ -461,7 +457,6 @@ func freedefer(d *_defer) { // These lines used to be simply `*d = _defer{}` but that // started causing a nosplit stack overflow via typedmemmove. - d.siz = 0 d.started = false d.openDefer = false d.sp = 0 diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index 8b2998f29aa..cf4b0bff430 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -940,14 +940,13 @@ func extendRandom(r []byte, n int) { // A _defer holds an entry on the list of deferred calls. // If you add a field here, add code to clear it in freedefer and deferProcStack -// This struct must match the code in cmd/compile/internal/gc/reflect.go:deferstruct -// and cmd/compile/internal/gc/ssa.go:(*state).call. +// This struct must match the code in cmd/compile/internal/ssagen/ssa.go:deferstruct +// and cmd/compile/internal/ssagen/ssa.go:(*state).call. // Some defers will be allocated on the stack and some on the heap. // All defers are logically part of the stack, so write barriers to // initialize them are not required. All defers must be manually scanned, // and for heap defers, marked. type _defer struct { - siz int32 // includes both arguments and results started bool heap bool // openDefer indicates that this _defer is for a frame with open-coded From 63dcab2e91cfa40ae6dc1f0455b1f3c2801a00ec Mon Sep 17 00:00:00 2001 From: Tim King Date: Tue, 25 May 2021 19:23:02 -0700 Subject: [PATCH 353/940] doc/go1.17: mention new vet checks sigchanyzer and stdmethods. These vet checks were added in CL 299532 and CL 321389. Also adds a TODO for buildtags. Change-Id: I516dc77729f6d2dc147318260fe452831b115dfa Reviewed-on: https://go-review.googlesource.com/c/go/+/322769 Trust: Tim King Run-TryBot: Tim King TryBot-Result: Go Bot Reviewed-by: Dmitri Shuralyov --- doc/go1.17.html | 49 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index eb7932cd675..cc3bcdf1801 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -277,14 +277,55 @@ Do not send CLs removing the interior tags from such phrases.

Vet

-

- TODO: https://golang.org/cl/299532: cmd/vet: bring in sigchanyzer to report unbuffered channels to signal.Notify +

New warning within buildtags

+ +

+ TODO(rsc): Describe changes to buildtags https://golang.org/cl/240609

-

- TODO: complete the Vet section +

New warning for calling signal.Notify on unbuffered channels

+ +

+ The vet tool now warns about calls to signal.Notify + with incoming signals being sent to an unbuffered channel. Using an unbuffered channel + risks missing signals sent on them as signal.Notify does not block when + sending to a channel. For example:

+
+c := make(chan os.Signal)
+// signals are sent on c before the channel is read from.
+// This signal may be dropped as c is unbuffered.
+signal.Notify(c, os.Interrupt)
+
+ +

+ Users of signal.Notify should use channels with sufficient buffer space to keep up with the + expected signal rate. +

+ +

New warnings for Is, As and Unwrap methods

+ +

+ The vet tool now warns about methods named As, Is or Unwrap + on types implementing the error interface that have a different signature than the + one expected by the errors package. The errors.{As,Is,Unwrap} functions + expect such methods to implement either Is(error) bool, + As(interface{}) bool, or Unwrap() error + respectively. The functions errors.{As,Is,Unwrap} will ignore methods with the same + names but a different signature. For example: +

+ +
+type MyError struct { hint string }
+func (m MyError) Error() string { ... } // MyError implements error.
+func (MyError) Is(target interface{}) bool { ... } // target is interface{} instead of error.
+func Foo() bool {
+	x, y := MyError{"A"}, MyError{"B"}
+	return errors.Is(x, y) // returns false as x != y and MyError does not have an `Is(error) bool` function.
+}
+
+

Cover

From bcecae2af6ee43abebf84411385d538ec4e7d0ea Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 8 Jun 2021 12:42:02 -0700 Subject: [PATCH 354/940] doc/go1.17: mention new possibility of type conversion panicking For #44513 For #46020 Change-Id: I07c7a4268465c536d1866cc6bb1fad76b2b88b15 Reviewed-on: https://go-review.googlesource.com/c/go/+/326149 Trust: Ian Lance Taylor Reviewed-by: Matthew Dempsky --- doc/go1.17.html | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/go1.17.html b/doc/go1.17.html index cc3bcdf1801..011377a84e7 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -67,6 +67,14 @@ Do not send CLs removing the interior tags from such phrases. using unsafe.Add or unsafe.Slice.

+ +

+ Note that the new conversion from slice to array pointer is the + first case in which a type conversion can panic at run time. + Analysis tools that assume type conversions can never panic + should be updated to consider this possibility. +

+

Ports

Darwin

From c0a86c10f174dd1679974b48a085273d02803121 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 8 Jun 2021 16:55:36 -0400 Subject: [PATCH 355/940] [dev.typeparams] cmd/compile: simplify openDeferSave Now it is only used to save the deferred the function (closure), which must be a function type. Simplify the code. Change-Id: Id4b8f2760fbf39a95883df2327f97378e7edab88 Reviewed-on: https://go-review.googlesource.com/c/go/+/326060 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- src/cmd/compile/internal/ssagen/ssa.go | 76 +++++++++++--------------- 1 file changed, 33 insertions(+), 43 deletions(-) diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 613a5b62119..68a06ab4f5f 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -4672,7 +4672,7 @@ func (s *state) openDeferRecord(n *ir.CallExpr) { // runtime panic code to use. But in the defer exit code, we will // call the function directly if it is a static function. closureVal := s.expr(fn) - closure := s.openDeferSave(nil, fn.Type(), closureVal) + closure := s.openDeferSave(fn.Type(), closureVal) opendefer.closureNode = closure.Aux.(*ir.Name) if !(fn.Op() == ir.ONAME && fn.(*ir.Name).Class == ir.PFUNC) { opendefer.closure = closure @@ -4690,57 +4690,47 @@ func (s *state) openDeferRecord(n *ir.CallExpr) { // openDeferSave generates SSA nodes to store a value (with type t) for an // open-coded defer at an explicit autotmp location on the stack, so it can be -// reloaded and used for the appropriate call on exit. If type t is SSAable, then -// val must be non-nil (and n should be nil) and val is the value to be stored. If -// type t is non-SSAable, then n must be non-nil (and val should be nil) and n is -// evaluated (via s.addr() below) to get the value that is to be stored. The -// function returns an SSA value representing a pointer to the autotmp location. -func (s *state) openDeferSave(n ir.Node, t *types.Type, val *ssa.Value) *ssa.Value { - canSSA := TypeOK(t) - var pos src.XPos - if canSSA { - pos = val.Pos - } else { - pos = n.Pos() +// reloaded and used for the appropriate call on exit. Type t must be a function type +// (therefore SSAable). val is the value to be stored. The function returns an SSA +// value representing a pointer to the autotmp location. +func (s *state) openDeferSave(t *types.Type, val *ssa.Value) *ssa.Value { + if !TypeOK(t) { + s.Fatalf("openDeferSave of non-SSA-able type %v val=%v", t, val) } - argTemp := typecheck.TempAt(pos.WithNotStmt(), s.curfn, t) - argTemp.SetOpenDeferSlot(true) - var addrArgTemp *ssa.Value - // Use OpVarLive to make sure stack slots for the args, etc. are not - // removed by dead-store elimination + if !t.HasPointers() { + s.Fatalf("openDeferSave of pointerless type %v val=%v", t, val) + } + pos := val.Pos + temp := typecheck.TempAt(pos.WithNotStmt(), s.curfn, t) + temp.SetOpenDeferSlot(true) + var addrTemp *ssa.Value + // Use OpVarLive to make sure stack slot for the closure is not removed by + // dead-store elimination if s.curBlock.ID != s.f.Entry.ID { - // Force the argtmp storing this defer function/receiver/arg to be - // declared in the entry block, so that it will be live for the - // defer exit code (which will actually access it only if the - // associated defer call has been activated). - s.defvars[s.f.Entry.ID][memVar] = s.f.Entry.NewValue1A(src.NoXPos, ssa.OpVarDef, types.TypeMem, argTemp, s.defvars[s.f.Entry.ID][memVar]) - s.defvars[s.f.Entry.ID][memVar] = s.f.Entry.NewValue1A(src.NoXPos, ssa.OpVarLive, types.TypeMem, argTemp, s.defvars[s.f.Entry.ID][memVar]) - addrArgTemp = s.f.Entry.NewValue2A(src.NoXPos, ssa.OpLocalAddr, types.NewPtr(argTemp.Type()), argTemp, s.sp, s.defvars[s.f.Entry.ID][memVar]) + // Force the tmp storing this defer function to be declared in the entry + // block, so that it will be live for the defer exit code (which will + // actually access it only if the associated defer call has been activated). + s.defvars[s.f.Entry.ID][memVar] = s.f.Entry.NewValue1A(src.NoXPos, ssa.OpVarDef, types.TypeMem, temp, s.defvars[s.f.Entry.ID][memVar]) + s.defvars[s.f.Entry.ID][memVar] = s.f.Entry.NewValue1A(src.NoXPos, ssa.OpVarLive, types.TypeMem, temp, s.defvars[s.f.Entry.ID][memVar]) + addrTemp = s.f.Entry.NewValue2A(src.NoXPos, ssa.OpLocalAddr, types.NewPtr(temp.Type()), temp, s.sp, s.defvars[s.f.Entry.ID][memVar]) } else { // Special case if we're still in the entry block. We can't use // the above code, since s.defvars[s.f.Entry.ID] isn't defined // until we end the entry block with s.endBlock(). - s.vars[memVar] = s.newValue1Apos(ssa.OpVarDef, types.TypeMem, argTemp, s.mem(), false) - s.vars[memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, argTemp, s.mem(), false) - addrArgTemp = s.newValue2Apos(ssa.OpLocalAddr, types.NewPtr(argTemp.Type()), argTemp, s.sp, s.mem(), false) - } - if t.HasPointers() { - // Since we may use this argTemp during exit depending on the - // deferBits, we must define it unconditionally on entry. - // Therefore, we must make sure it is zeroed out in the entry - // block if it contains pointers, else GC may wrongly follow an - // uninitialized pointer value. - argTemp.SetNeedzero(true) - } - if !canSSA { - a := s.addr(n) - s.move(t, addrArgTemp, a) - return addrArgTemp + s.vars[memVar] = s.newValue1Apos(ssa.OpVarDef, types.TypeMem, temp, s.mem(), false) + s.vars[memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, temp, s.mem(), false) + addrTemp = s.newValue2Apos(ssa.OpLocalAddr, types.NewPtr(temp.Type()), temp, s.sp, s.mem(), false) } + // Since we may use this temp during exit depending on the + // deferBits, we must define it unconditionally on entry. + // Therefore, we must make sure it is zeroed out in the entry + // block if it contains pointers, else GC may wrongly follow an + // uninitialized pointer value. + temp.SetNeedzero(true) // We are storing to the stack, hence we can avoid the full checks in // storeType() (no write barrier) and do a simple store(). - s.store(t, addrArgTemp, val) - return addrArgTemp + s.store(t, addrTemp, val) + return addrTemp } // openDeferExit generates SSA for processing all the open coded defers at exit. From b20747334a4a3dee51759369a098ef2a0c9dbcff Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 8 Jun 2021 18:07:16 -0400 Subject: [PATCH 356/940] [dev.typeparams] cmd/compile, runtime: simplify opendefer metadata Now that deferred functions are always argumentless, we don't need the metadata for the frame size, number of arguments, and the information about each argument. Change-Id: I99e75248a22bda6efbdf2012a2f35beca4c18fd7 Reviewed-on: https://go-review.googlesource.com/c/go/+/326061 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- src/cmd/compile/internal/ssagen/ssa.go | 22 ---------------------- src/runtime/panic.go | 17 ++--------------- 2 files changed, 2 insertions(+), 37 deletions(-) diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 68a06ab4f5f..0fbb39cfbb0 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -324,43 +324,21 @@ func dvarint(x *obj.LSym, off int, v int64) int { // for stack variables are specified as the number of bytes below varp (pointer to the // top of the local variables) for their starting address. The format is: // -// - Max total argument size among all the defers // - Offset of the deferBits variable // - Number of defers in the function // - Information about each defer call, in reverse order of appearance in the function: -// - Total argument size of the call // - Offset of the closure value to call -// - Number of arguments (including interface receiver or method receiver as first arg) -// - Information about each argument -// - Offset of the stored defer argument in this function's frame -// - Size of the argument -// - Offset of where argument should be placed in the args frame when making call func (s *state) emitOpenDeferInfo() { x := base.Ctxt.Lookup(s.curfn.LSym.Name + ".opendefer") s.curfn.LSym.Func().OpenCodedDeferInfo = x off := 0 - - // Compute maxargsize (max size of arguments for all defers) - // first, so we can output it first to the funcdata - var maxargsize int64 - for i := len(s.openDefers) - 1; i >= 0; i-- { - r := s.openDefers[i] - argsize := r.n.X.Type().ArgWidth() // TODO register args: but maybe use of abi0 will make this easy - if argsize > maxargsize { - maxargsize = argsize - } - } - off = dvarint(x, off, maxargsize) off = dvarint(x, off, -s.deferBitsTemp.FrameOffset()) off = dvarint(x, off, int64(len(s.openDefers))) // Write in reverse-order, for ease of running in that order at runtime for i := len(s.openDefers) - 1; i >= 0; i-- { r := s.openDefers[i] - off = dvarint(x, off, r.n.X.Type().ArgWidth()) off = dvarint(x, off, -r.closureNode.FrameOffset()) - numArgs := 0 - off = dvarint(x, off, int64(numArgs)) } } diff --git a/src/runtime/panic.go b/src/runtime/panic.go index f6d72995b3f..39013163b6e 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -720,8 +720,7 @@ func addOneOpenDeferFrame(gp *g, pc uintptr, sp unsafe.Pointer) { throw("missing deferreturn") } - maxargsize, _ := readvarintUnsafe(fd) - d1 := newdefer(int32(maxargsize)) + d1 := newdefer(0) d1.openDefer = true d1._panic = nil // These are the pc/sp to set after we've @@ -782,27 +781,15 @@ func runOpenDeferFrame(gp *g, d *_defer) bool { done := true fd := d.fd - // Skip the maxargsize - _, fd = readvarintUnsafe(fd) deferBitsOffset, fd := readvarintUnsafe(fd) nDefers, fd := readvarintUnsafe(fd) deferBits := *(*uint8)(unsafe.Pointer(d.varp - uintptr(deferBitsOffset))) for i := int(nDefers) - 1; i >= 0; i-- { // read the funcdata info for this defer - var argWidth, closureOffset, nArgs uint32 - argWidth, fd = readvarintUnsafe(fd) + var closureOffset uint32 closureOffset, fd = readvarintUnsafe(fd) - nArgs, fd = readvarintUnsafe(fd) - if argWidth != 0 || nArgs != 0 { - throw("defer with non-empty frame") - } if deferBits&(1< Date: Tue, 8 Jun 2021 19:45:41 -0400 Subject: [PATCH 357/940] cmd/link: fix bug in -strictdups checking of BSS symbols The linker's -strictdups debugging option was not properly checking for cases where you have two dupok BSS symbols with different length (the check examined data length and content, but not symbol size). Updates #46653. Change-Id: I3844f25ef76dd6e4a84ffd5caed5d19a1b1a57c9 Reviewed-on: https://go-review.googlesource.com/c/go/+/326210 Trust: Than McIntosh Run-TryBot: Than McIntosh TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/cmd/link/internal/loader/loader.go | 12 +++++-- src/cmd/link/link_test.go | 43 +++++++++++++++++++------- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go index 1b71a66c6f5..efca824d981 100644 --- a/src/cmd/link/internal/loader/loader.go +++ b/src/cmd/link/internal/loader/loader.go @@ -699,12 +699,18 @@ func (l *Loader) checkdup(name string, r *oReader, li uint32, dup Sym) { p := r.Data(li) rdup, ldup := l.toLocal(dup) pdup := rdup.Data(ldup) - if bytes.Equal(p, pdup) { - return - } reason := "same length but different contents" if len(p) != len(pdup) { reason = fmt.Sprintf("new length %d != old length %d", len(p), len(pdup)) + } else if bytes.Equal(p, pdup) { + // For BSS symbols, we need to check size as well, see issue 46653. + szdup := l.SymSize(dup) + sz := int64(r.Sym(li).Siz()) + if szdup == sz { + return + } + reason = fmt.Sprintf("different sizes: new size %d != old size %d", + sz, szdup) } fmt.Fprintf(os.Stderr, "cmd/link: while reading object for '%v': duplicate symbol '%s', previous def at '%v', with mismatched payload: %s\n", r.unit.Lib, name, rdup.unit.Lib, reason) diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go index 4d6bc76aca8..7230054bedd 100644 --- a/src/cmd/link/link_test.go +++ b/src/cmd/link/link_test.go @@ -470,10 +470,30 @@ TEXT ·f(SB), NOSPLIT|DUPOK, $0-0 JMP 0(PC) ` +const testStrictDupAsmSrc3 = ` +#include "textflag.h" +GLOBL ·rcon(SB), RODATA|DUPOK, $64 +` + +const testStrictDupAsmSrc4 = ` +#include "textflag.h" +GLOBL ·rcon(SB), RODATA|DUPOK, $32 +` + func TestStrictDup(t *testing.T) { // Check that -strictdups flag works. testenv.MustHaveGoBuild(t) + asmfiles := []struct { + fname string + payload string + }{ + {"a", testStrictDupAsmSrc1}, + {"b", testStrictDupAsmSrc2}, + {"c", testStrictDupAsmSrc3}, + {"d", testStrictDupAsmSrc4}, + } + t.Parallel() tmpdir := t.TempDir() @@ -483,15 +503,12 @@ func TestStrictDup(t *testing.T) { if err != nil { t.Fatal(err) } - src = filepath.Join(tmpdir, "a.s") - err = ioutil.WriteFile(src, []byte(testStrictDupAsmSrc1), 0666) - if err != nil { - t.Fatal(err) - } - src = filepath.Join(tmpdir, "b.s") - err = ioutil.WriteFile(src, []byte(testStrictDupAsmSrc2), 0666) - if err != nil { - t.Fatal(err) + for _, af := range asmfiles { + src = filepath.Join(tmpdir, af.fname+".s") + err = ioutil.WriteFile(src, []byte(af.payload), 0666) + if err != nil { + t.Fatal(err) + } } src = filepath.Join(tmpdir, "go.mod") err = ioutil.WriteFile(src, []byte("module teststrictdup\n"), 0666) @@ -503,7 +520,7 @@ func TestStrictDup(t *testing.T) { cmd.Dir = tmpdir out, err := cmd.CombinedOutput() if err != nil { - t.Errorf("linking with -strictdups=1 failed: %v", err) + t.Errorf("linking with -strictdups=1 failed: %v\n%s", err, string(out)) } if !bytes.Contains(out, []byte("mismatched payload")) { t.Errorf("unexpected output:\n%s", out) @@ -515,7 +532,11 @@ func TestStrictDup(t *testing.T) { if err == nil { t.Errorf("linking with -strictdups=2 did not fail") } - if !bytes.Contains(out, []byte("mismatched payload")) { + // NB: on amd64 we get the 'new length' error, on arm64 the 'different + // contents' error. + if !(bytes.Contains(out, []byte("mismatched payload: new length")) || + bytes.Contains(out, []byte("mismatched payload: same length but different contents"))) || + !bytes.Contains(out, []byte("mismatched payload: different sizes")) { t.Errorf("unexpected output:\n%s", out) } } From aa5540cd82170f82c6fe11511e12de96aa58cbc1 Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Tue, 8 Jun 2021 20:09:49 -0400 Subject: [PATCH 358/940] cmd/compile: make map.zero symbol content-addressable The compiler machinery that generates "map.zero" symbols marks them as RODATA and DUPOK, which is problematic when a given application has multiple map zero symbols (from different packages) with varying sizes: the dupok path in the loader assumes that if two symbols have the same name, it is safe to pick any of the versions. In the case of map.zero, the link needs to select the largest symbol, not an arbitrary sym. To fix this problem, mark map.zero symbols as content-addressable, since the loader's content addressability processing path already supports selection of the larger symbol in cases where there are dups. Fixes #46653. Change-Id: Iabd2feef01d448670ba795c7eaddc48c191ea276 Reviewed-on: https://go-review.googlesource.com/c/go/+/326211 Trust: Than McIntosh Run-TryBot: Than McIntosh TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/cmd/compile/internal/gc/obj.go | 1 + test/fixedbugs/issue46653.dir/bad/bad.go | 64 ++++++++++++++++++++++++ test/fixedbugs/issue46653.dir/main.go | 27 ++++++++++ test/fixedbugs/issue46653.go | 10 ++++ 4 files changed, 102 insertions(+) create mode 100644 test/fixedbugs/issue46653.dir/bad/bad.go create mode 100644 test/fixedbugs/issue46653.dir/main.go create mode 100644 test/fixedbugs/issue46653.go diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go index 0b10cb8a9e1..55a0ab7da79 100644 --- a/src/cmd/compile/internal/gc/obj.go +++ b/src/cmd/compile/internal/gc/obj.go @@ -148,6 +148,7 @@ func dumpdata() { if reflectdata.ZeroSize > 0 { zero := base.PkgLinksym("go.map", "zero", obj.ABI0) objw.Global(zero, int32(reflectdata.ZeroSize), obj.DUPOK|obj.RODATA) + zero.Set(obj.AttrContentAddressable, true) } staticdata.WriteFuncSyms() diff --git a/test/fixedbugs/issue46653.dir/bad/bad.go b/test/fixedbugs/issue46653.dir/bad/bad.go new file mode 100644 index 00000000000..c1611b8347a --- /dev/null +++ b/test/fixedbugs/issue46653.dir/bad/bad.go @@ -0,0 +1,64 @@ +// Copyright 2021 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 a + +func Bad() { + m := make(map[int64]A) + a := m[0] + if len(a.B.C1.D2.E2.F1) != 0 || + len(a.B.C1.D2.E2.F2) != 0 || + len(a.B.C1.D2.E2.F3) != 0 || + len(a.B.C1.D2.E2.F4) != 0 || + len(a.B.C1.D2.E2.F5) != 0 || + len(a.B.C1.D2.E2.F6) != 0 || + len(a.B.C1.D2.E2.F7) != 0 || + len(a.B.C1.D2.E2.F8) != 0 || + len(a.B.C1.D2.E2.F9) != 0 || + len(a.B.C1.D2.E2.F10) != 0 || + len(a.B.C1.D2.E2.F11) != 0 || + len(a.B.C1.D2.E2.F16) != 0 { + panic("bad") + } +} + +type A struct { + B +} + +type B struct { + C1 C + C2 C +} + +type C struct { + D1 D + D2 D +} + +type D struct { + E1 E + E2 E + E3 E + E4 E +} + +type E struct { + F1 string + F2 string + F3 string + F4 string + F5 string + F6 string + F7 string + F8 string + F9 string + F10 string + F11 string + F12 string + F13 string + F14 string + F15 string + F16 string +} diff --git a/test/fixedbugs/issue46653.dir/main.go b/test/fixedbugs/issue46653.dir/main.go new file mode 100644 index 00000000000..e2a96e54ec5 --- /dev/null +++ b/test/fixedbugs/issue46653.dir/main.go @@ -0,0 +1,27 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + bad "issue46653.dir/bad" +) + +func main() { + bad.Bad() +} + +func neverCalled() L { + m := make(map[string]L) + return m[""] +} + +type L struct { + A Data + B Data +} + +type Data struct { + F1 [22][]string +} diff --git a/test/fixedbugs/issue46653.go b/test/fixedbugs/issue46653.go new file mode 100644 index 00000000000..e6283b1de50 --- /dev/null +++ b/test/fixedbugs/issue46653.go @@ -0,0 +1,10 @@ +// runindir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test to verify compiler and linker handling of multiple +// competing map.zero symbol definitions. + +package ignored From 139e935d3cc8d38c9adc7ff7de8a87c28fe339c6 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 13 May 2021 10:46:58 -0400 Subject: [PATCH 359/940] math/big: comment division The comments in the code refer to Knuth and to Burnikel and Ziegler, but Knuth's presentation is inscrutable, and our recursive division code does not bear much resemblance to Burnikel and Ziegler's paper (which is fine, ours is nicer). Add a standalone explanation of division instead of referring to difficult or not-directly-used references. Change-Id: Ic1b35dc167fb29a69ee00e0b4a768ac9cc9e1324 Reviewed-on: https://go-review.googlesource.com/c/go/+/321078 Trust: Russ Cox Trust: Katie Hockman Run-TryBot: Russ Cox Reviewed-by: Katie Hockman Reviewed-by: Filippo Valsorda --- src/math/big/natdiv.go | 684 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 611 insertions(+), 73 deletions(-) diff --git a/src/math/big/natdiv.go b/src/math/big/natdiv.go index 1330990c2cd..882bb6d3bac 100644 --- a/src/math/big/natdiv.go +++ b/src/math/big/natdiv.go @@ -2,10 +2,506 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +/* + +Multi-precision division. Here be dragons. + +Given u and v, where u is n+m digits, and v is n digits (with no leading zeros), +the goal is to return quo, rem such that u = quo*v + rem, where 0 ≤ rem < v. +That is, quo = ⌊u/v⌋ where ⌊x⌋ denotes the floor (truncation to integer) of x, +and rem = u - quo·v. + + +Long Division + +Division in a computer proceeds the same as long division in elementary school, +but computers are not as good as schoolchildren at following vague directions, +so we have to be much more precise about the actual steps and what can happen. + +We work from most to least significant digit of the quotient, doing: + + • Guess a digit q, the number of v to subtract from the current + section of u to zero out the topmost digit. + • Check the guess by multiplying q·v and comparing it against + the current section of u, adjusting the guess as needed. + • Subtract q·v from the current section of u. + • Add q to the corresponding section of the result quo. + +When all digits have been processed, the final remainder is left in u +and returned as rem. + +For example, here is a sketch of dividing 5 digits by 3 digits (n=3, m=2). + + q₂ q₁ q₀ + _________________ + v₂ v₁ v₀ ) u₄ u₃ u₂ u₁ u₀ + ↓ ↓ ↓ | | + [u₄ u₃ u₂]| | + - [ q₂·v ]| | + ----------- ↓ | + [ rem | u₁]| + - [ q₁·v ]| + ----------- ↓ + [ rem | u₀] + - [ q₀·v ] + ------------ + [ rem ] + +Instead of creating new storage for the remainders and copying digits from u +as indicated by the arrows, we use u's storage directly as both the source +and destination of the subtractions, so that the remainders overwrite +successive overlapping sections of u as the division proceeds, using a slice +of u to identify the current section. This avoids all the copying as well as +shifting of remainders. + +Division of u with n+m digits by v with n digits (in base B) can in general +produce at most m+1 digits, because: + + • u < B^(n+m) [B^(n+m) has n+m+1 digits] + • v ≥ B^(n-1) [B^(n-1) is the smallest n-digit number] + • u/v < B^(n+m) / B^(n-1) [divide bounds for u, v] + • u/v < B^(m+1) [simplify] + +The first step is special: it takes the top n digits of u and divides them by +the n digits of v, producing the first quotient digit and an n-digit remainder. +In the example, q₂ = ⌊u₄u₃u₂ / v⌋. + +The first step divides n digits by n digits to ensure that it produces only a +single digit. + +Each subsequent step appends the next digit from u to the remainder and divides +those n+1 digits by the n digits of v, producing another quotient digit and a +new n-digit remainder. + +Subsequent steps divide n+1 digits by n digits, an operation that in general +might produce two digits. However, as used in the algorithm, that division is +guaranteed to produce only a single digit. The dividend is of the form +rem·B + d, where rem is a remainder from the previous step and d is a single +digit, so: + + • rem ≤ v - 1 [rem is a remainder from dividing by v] + • rem·B ≤ v·B - B [multiply by B] + • d ≤ B - 1 [d is a single digit] + • rem·B + d ≤ v·B - 1 [add] + • rem·B + d < v·B [change ≤ to <] + • (rem·B + d)/v < B [divide by v] + + +Guess and Check + +At each step we need to divide n+1 digits by n digits, but this is for the +implementation of division by n digits, so we can't just invoke a division +routine: we _are_ the division routine. Instead, we guess at the answer and +then check it using multiplication. If the guess is wrong, we correct it. + +How can this guessing possibly be efficient? It turns out that the following +statement (let's call it the Good Guess Guarantee) is true. + +If + + • q = ⌊u/v⌋ where u is n+1 digits and v is n digits, + • q < B, and + • the topmost digit of v = vₙ₋₁ ≥ B/2, + +then q̂ = ⌊uₙuₙ₋₁ / vₙ₋₁⌋ satisfies q ≤ q̂ ≤ q+2. (Proof below.) + +That is, if we know the answer has only a single digit and we guess an answer +by ignoring the bottom n-1 digits of u and v, using a 2-by-1-digit division, +then that guess is at least as large as the correct answer. It is also not +too much larger: it is off by at most two from the correct answer. + +Note that in the first step of the overall division, which is an n-by-n-digit +division, the 2-by-1 guess uses an implicit uₙ = 0. + +Note that using a 2-by-1-digit division here does not mean calling ourselves +recursively. Instead, we use an efficient direct hardware implementation of +that operation. + +Note that because q is u/v rounded down, q·v must not exceed u: u ≥ q·v. +If a guess q̂ is too big, it will not satisfy this test. Viewed a different way, +the remainder r̂ for a given q̂ is u - q̂·v, which must be positive. If it is +negative, then the guess q̂ is too big. + +This gives us a way to compute q. First compute q̂ with 2-by-1-digit division. +Then, while u < q̂·v, decrement q̂; this loop executes at most twice, because +q̂ ≤ q+2. + + +Scaling Inputs + +The Good Guess Guarantee requires that the top digit of v (vₙ₋₁) be at least B/2. +For example in base 10, ⌊172/19⌋ = 9, but ⌊18/1⌋ = 18: the guess is wildly off +because the first digit 1 is smaller than B/2 = 5. + +We can ensure that v has a large top digit by multiplying both u and v by the +right amount. Continuing the example, if we multiply both 172 and 19 by 3, we +now have ⌊516/57⌋, the leading digit of v is now ≥ 5, and sure enough +⌊51/5⌋ = 10 is much closer to the correct answer 9. It would be easier here +to multiply by 4, because that can be done with a shift. Specifically, we can +always count the number of leading zeros i in the first digit of v and then +shift both u and v left by i bits. + +Having scaled u and v, the value ⌊u/v⌋ is unchanged, but the remainder will +be scaled: 172 mod 19 is 1, but 516 mod 57 is 3. We have to divide the remainder +by the scaling factor (shifting right i bits) when we finish. + +Note that these shifts happen before and after the entire division algorithm, +not at each step in the per-digit iteration. + +Note the effect of scaling inputs on the size of the possible quotient. +In the scaled u/v, u can gain a digit from scaling; v never does, because we +pick the scaling factor to make v's top digit larger but without overflowing. +If u and v have n+m and n digits after scaling, then: + + • u < B^(n+m) [B^(n+m) has n+m+1 digits] + • v ≥ B^n / 2 [vₙ₋₁ ≥ B/2, so vₙ₋₁·B^(n-1) ≥ B^n/2] + • u/v < B^(n+m) / (B^n / 2) [divide bounds for u, v] + • u/v < 2 B^m [simplify] + +The quotient can still have m+1 significant digits, but if so the top digit +must be a 1. This provides a different way to handle the first digit of the +result: compare the top n digits of u against v and fill in either a 0 or a 1. + + +Refining Guesses + +Before we check whether u < q̂·v, we can adjust our guess to change it from +q̂ = ⌊uₙuₙ₋₁ / vₙ₋₁⌋ into the refined guess ⌊uₙuₙ₋₁uₙ₋₂ / vₙ₋₁vₙ₋₂⌋. +Although not mentioned above, the Good Guess Guarantee also promises that this +3-by-2-digit division guess is more precise and at most one away from the real +answer q. The improvement from the 2-by-1 to the 3-by-2 guess can also be done +without n-digit math. + +If we have a guess q̂ = ⌊uₙuₙ₋₁ / vₙ₋₁⌋ and we want to see if it also equal to +⌊uₙuₙ₋₁uₙ₋₂ / vₙ₋₁vₙ₋₂⌋, we can use the same check we would for the full division: +if uₙuₙ₋₁uₙ₋₂ < q̂·vₙ₋₁vₙ₋₂, then the guess is too large and should be reduced. + +Checking uₙuₙ₋₁uₙ₋₂ < q̂·vₙ₋₁vₙ₋₂ is the same as uₙuₙ₋₁uₙ₋₂ - q̂·vₙ₋₁vₙ₋₂ < 0, +and + + uₙuₙ₋₁uₙ₋₂ - q̂·vₙ₋₁vₙ₋₂ = (uₙuₙ₋₁·B + uₙ₋₂) - q̂·(vₙ₋₁·B + vₙ₋₂) + [splitting off the bottom digit] + = (uₙuₙ₋₁ - q̂·vₙ₋₁)·B + uₙ₋₂ - q̂·vₙ₋₂ + [regrouping] + +The expression (uₙuₙ₋₁ - q̂·vₙ₋₁) is the remainder of uₙuₙ₋₁ / vₙ₋₁. +If the initial guess returns both q̂ and its remainder r̂, then checking +whether uₙuₙ₋₁uₙ₋₂ < q̂·vₙ₋₁vₙ₋₂ is the same as checking r̂·B + uₙ₋₂ < q̂·vₙ₋₂. + +If we find that r̂·B + uₙ₋₂ < q̂·vₙ₋₂, then we can adjust the guess by +decrementing q̂ and adding vₙ₋₁ to r̂. We repeat until r̂·B + uₙ₋₂ ≥ q̂·vₙ₋₂. +(As before, this fixup is only needed at most twice.) + +Now that q̂ = ⌊uₙuₙ₋₁uₙ₋₂ / vₙ₋₁vₙ₋₂⌋, as mentioned above it is at most one +away from the correct q, and we've avoided doing any n-digit math. +(If we need the new remainder, it can be computed as r̂·B + uₙ₋₂ - q̂·vₙ₋₂.) + +The final check u < q̂·v and the possible fixup must be done at full precision. +For random inputs, a fixup at this step is exceedingly rare: the 3-by-2 guess +is not often wrong at all. But still we must do the check. Note that since the +3-by-2 guess is off by at most 1, it can be convenient to perform the final +u < q̂·v as part of the computation of the remainder r = u - q̂·v. If the +subtraction underflows, decremeting q̂ and adding one v back to r is enough to +arrive at the final q, r. + +That's the entirety of long division: scale the inputs, and then loop over +each output position, guessing, checking, and correcting the next output digit. + +For a 2n-digit number divided by an n-digit number (the worst size-n case for +division complexity), this algorithm uses n+1 iterations, each of which must do +at least the 1-by-n-digit multiplication q̂·v. That's O(n) iterations of +O(n) time each, so O(n²) time overall. + + +Recursive Division + +For very large inputs, it is possible to improve on the O(n²) algorithm. +Let's call a group of n/2 real digits a (very) “wide digit”. We can run the +standard long division algorithm explained above over the wide digits instead of +the actual digits. This will result in many fewer steps, but the math involved in +each step is more work. + +Where basic long division uses a 2-by-1-digit division to guess the initial q̂, +the new algorithm must use a 2-by-1-wide-digit division, which is of course +really an n-by-n/2-digit division. That's OK: if we implement n-digit division +in terms of n/2-digit division, the recursion will terminate when the divisor +becomes small enough to handle with standard long division or even with the +2-by-1 hardware instruction. + +For example, here is a sketch of dividing 10 digits by 4, proceeding with +wide digits corresponding to two regular digits. The first step, still special, +must leave off a (regular) digit, dividing 5 by 4 and producing a 4-digit +remainder less than v. The middle steps divide 6 digits by 4, guaranteed to +produce two output digits each (one wide digit) with 4-digit remainders. +The final step must use what it has: the 4-digit remainder plus one more, +5 digits to divide by 4. + + q₆ q₅ q₄ q₃ q₂ q₁ q₀ + _______________________________ + v₃ v₂ v₁ v₀ ) u₉ u₈ u₇ u₆ u₅ u₄ u₃ u₂ u₁ u₀ + ↓ ↓ ↓ ↓ ↓ | | | | | + [u₉ u₈ u₇ u₆ u₅]| | | | | + - [ q₆q₅·v ]| | | | | + ----------------- ↓ ↓ | | | + [ rem |u₄ u₃]| | | + - [ q₄q₃·v ]| | | + -------------------- ↓ ↓ | + [ rem |u₂ u₁]| + - [ q₂q₁·v ]| + -------------------- ↓ + [ rem |u₀] + - [ q₀·v ] + ------------------ + [ rem ] + +An alternative would be to look ahead to how well n/2 divides into n+m and +adjust the first step to use fewer digits as needed, making the first step +more special to make the last step not special at all. For example, using the +same input, we could choose to use only 4 digits in the first step, leaving +a full wide digit for the last step: + + q₆ q₅ q₄ q₃ q₂ q₁ q₀ + _______________________________ + v₃ v₂ v₁ v₀ ) u₉ u₈ u₇ u₆ u₅ u₄ u₃ u₂ u₁ u₀ + ↓ ↓ ↓ ↓ | | | | | | + [u₉ u₈ u₇ u₆]| | | | | | + - [ q₆·v ]| | | | | | + -------------- ↓ ↓ | | | | + [ rem |u₅ u₄]| | | | + - [ q₅q₄·v ]| | | | + -------------------- ↓ ↓ | | + [ rem |u₃ u₂]| | + - [ q₃q₂·v ]| | + -------------------- ↓ ↓ + [ rem |u₁ u₀] + - [ q₁q₀·v ] + --------------------- + [ rem ] + +Today, the code in divRecursiveStep works like the first example. Perhaps in +the future we will make it work like the alternative, to avoid a special case +in the final iteration. + +Either way, each step is a 3-by-2-wide-digit division approximated first by +a 2-by-1-wide-digit division, just as we did for regular digits in long division. +Because the actual answer we want is a 3-by-2-wide-digit division, instead of +multiplying q̂·v directly during the fixup, we can use the quick refinement +from long division (an n/2-by-n/2 multiply) to correct q to its actual value +and also compute the remainder (as mentioned above), and then stop after that, +never doing a full n-by-n multiply. + +Instead of using an n-by-n/2-digit division to produce n/2 digits, we can add +(not discard) one more real digit, doing an (n+1)-by-(n/2+1)-digit division that +produces n/2+1 digits. That single extra digit tightens the Good Guess Guarantee +to q ≤ q̂ ≤ q+1 and lets us drop long division's special treatment of the first +digit. These benefits are discussed more after the Good Guess Guarantee proof +below. + + +How Fast is Recursive Division? + +For a 2n-by-n-digit division, this algorithm runs a 4-by-2 long division over +wide digits, producing two wide digits plus a possible leading regular digit 1, +which can be handled without a recursive call. That is, the algorithm uses two +full iterations, each using an n-by-n/2-digit division and an n/2-by-n/2-digit +multiplication, along with a few n-digit additions and subtractions. The standard +n-by-n-digit multiplication algorithm requires O(n²) time, making the overall +algorithm require time T(n) where + + T(n) = 2T(n/2) + O(n) + O(n²) + +which, by the Bentley-Haken-Saxe theorem, ends up reducing to T(n) = O(n²). +This is not an improvement over regular long division. + +When the number of digits n becomes large enough, Karatsuba's algorithm for +multiplication can be used instead, which takes O(n^log₂3) = O(n^1.6) time. +(Karatsuba multiplication is implemented in func karatsuba in nat.go.) +That makes the overall recursive division algorithm take O(n^1.6) time as well, +which is an improvement, but again only for large enough numbers. + +It is not critical to make sure that every recursion does only two recursive +calls. While in general the number of recursive calls can change the time +analysis, in this case doing three calls does not change the analysis: + + T(n) = 3T(n/2) + O(n) + O(n^log₂3) + +ends up being T(n) = O(n^log₂3). Because the Karatsuba multiplication taking +time O(n^log₂3) is itself doing 3 half-sized recursions, doing three for the +division does not hurt the asymptotic performance. Of course, it is likely +still faster in practice to do two. + + +Proof of the Good Guess Guarantee + +Given numbers x, y, let us break them into the quotients and remainders when +divided by some scaling factor S, with the added constraints that the quotient +x/y and the high part of y are both less than some limit T, and that the high +part of y is at least half as big as T. + + x₁ = ⌊x/S⌋ y₁ = ⌊y/S⌋ + x₀ = x mod S y₀ = y mod S + + x = x₁·S + x₀ 0 ≤ x₀ < S x/y < T + y = y₁·S + y₀ 0 ≤ y₀ < S T/2 ≤ y₁ < T + +And consider the two truncated quotients: + + q = ⌊x/y⌋ + q̂ = ⌊x₁/y₁⌋ + +We will prove that q ≤ q̂ ≤ q+2. + +The guarantee makes no real demands on the scaling factor S: it is simply the +magnitude of the digits cut from both x and y to produce x₁ and y₁. +The guarantee makes only limited demands on T: it must be large enough to hold +the quotient x/y, and y₁ must have roughly the same size. + +To apply to the earlier discussion of 2-by-1 guesses in long division, +we would choose: + + S = Bⁿ⁻¹ + T = B + x = u + x₁ = uₙuₙ₋₁ + x₀ = uₙ₋₂...u₀ + y = v + y₁ = vₙ₋₁ + y₀ = vₙ₋₂...u₀ + +These simpler variables avoid repeating those longer expressions in the proof. + +Note also that, by definition, truncating division ⌊x/y⌋ satisfies + + x/y - 1 < ⌊x/y⌋ ≤ x/y. + +This fact will be used a few times in the proofs. + +Proof that q ≤ q̂: + + q̂·y₁ = ⌊x₁/y₁⌋·y₁ [by definition, q̂ = ⌊x₁/y₁⌋] + > (x₁/y₁ - 1)·y₁ [x₁/y₁ - 1 < ⌊x₁/y₁⌋] + = x₁ - y₁ [distribute y₁] + + So q̂·y₁ > x₁ - y₁. + Since q̂·y₁ is an integer, q̂·y₁ ≥ x₁ - y₁ + 1. + + q̂ - q = q̂ - ⌊x/y⌋ [by definition, q = ⌊x/y⌋] + ≥ q̂ - x/y [⌊x/y⌋ < x/y] + = (1/y)·(q̂·y - x) [factor out 1/y] + ≥ (1/y)·(q̂·y₁·S - x) [y = y₁·S + y₀ ≥ y₁·S] + ≥ (1/y)·((x₁ - y₁ + 1)·S - x) [above: q̂·y₁ ≥ x₁ - y₁ + 1] + = (1/y)·(x₁·S - y₁·S + S - x) [distribute S] + = (1/y)·(S - x₀ - y₁·S) [-x = -x₁·S - x₀] + > -y₁·S / y [x₀ < S, so S - x₀ < 0; drop it] + ≥ -1 [y₁·S ≤ y] + + So q̂ - q > -1. + Since q̂ - q is an integer, q̂ - q ≥ 0, or equivalently q ≤ q̂. + +Proof that q̂ ≤ q+2: + + x₁/y₁ - x/y = x₁·S/y₁·S - x/y [multiply left term by S/S] + ≤ x/y₁·S - x/y [x₁S ≤ x] + = (x/y)·(y/y₁·S - 1) [factor out x/y] + = (x/y)·((y - y₁·S)/y₁·S) [move -1 into y/y₁·S fraction] + = (x/y)·(y₀/y₁·S) [y - y₁·S = y₀] + = (x/y)·(1/y₁)·(y₀/S) [factor out 1/y₁] + < (x/y)·(1/y₁) [y₀ < S, so y₀/S < 1] + ≤ (x/y)·(2/T) [y₁ ≥ T/2, so 1/y₁ ≤ 2/T] + < T·(2/T) [x/y < T] + = 2 [T·(2/T) = 2] + + So x₁/y₁ - x/y < 2. + + q̂ - q = ⌊x₁/y₁⌋ - q [by definition, q̂ = ⌊x₁/y₁⌋] + = ⌊x₁/y₁⌋ - ⌊x/y⌋ [by definition, q = ⌊x/y⌋] + ≤ x₁/y₁ - ⌊x/y⌋ [⌊x₁/y₁⌋ ≤ x₁/y₁] + < x₁/y₁ - (x/y - 1) [⌊x/y⌋ > x/y - 1] + = (x₁/y₁ - x/y) + 1 [regrouping] + < 2 + 1 [above: x₁/y₁ - x/y < 2] + = 3 + + So q̂ - q < 3. + Since q̂ - q is an integer, q̂ - q ≤ 2. + +Note that when x/y < T/2, the bounds tighten to x₁/y₁ - x/y < 1 and therefore +q̂ - q ≤ 1. + +Note also that in the general case 2n-by-n division where we don't know that +x/y < T, we do know that x/y < 2T, yielding the bound q̂ - q ≤ 4. So we could +remove the special case first step of long division as long as we allow the +first fixup loop to run up to four times. (Using a simple comparison to decide +whether the first digit is 0 or 1 is still more efficient, though.) + +Finally, note that when dividing three leading base-B digits by two (scaled), +we have T = B² and x/y < B = T/B, a much tighter bound than x/y < T. +This in turn yields the much tighter bound x₁/y₁ - x/y < 2/B. This means that +⌊x₁/y₁⌋ and ⌊x/y⌋ can only differ when x/y is less than 2/B greater than an +integer. For random x and y, the chance of this is 2/B, or, for large B, +approximately zero. This means that after we produce the 3-by-2 guess in the +long division algorithm, the fixup loop essentially never runs. + +In the recursive algorithm, the extra digit in (2·⌊n/2⌋+1)-by-(⌊n/2⌋+1)-digit +division has exactly the same effect: the probability of needing a fixup is the +same 2/B. Even better, we can allow the general case x/y < 2T and the fixup +probability only grows to 4/B, still essentially zero. + + +References + +There are no great references for implementing long division; thus this comment. +Here are some notes about what to expect from the obvious references. + +Knuth Volume 2 (Seminumerical Algorithms) section 4.3.1 is the usual canonical +reference for long division, but that entire series is highly compressed, never +repeating a necessary fact and leaving important insights to the exercises. +For example, no rationale whatsoever is given for the calculation that extends +q̂ from a 2-by-1 to a 3-by-2 guess, nor why it reduces the error bound. +The proof that the calculation even has the desired effect is left to exercises. +The solutions to those exercises provided at the back of the book are entirely +calculations, still with no explanation as to what is going on or how you would +arrive at the idea of doing those exact calculations. Nowhere is it mentioned +that this test extends the 2-by-1 guess into a 3-by-2 guess. The proof of the +Good Guess Guarantee is only for the 2-by-1 guess and argues by contradiction, +making it difficult to understand how modifications like adding another digit +or adjusting the quotient range affects the overall bound. + +All that said, Knuth remains the canonical reference. It is dense but packed +full of information and references, and the proofs are simpler than many other +presentations. The proofs above are reworkings of Knuth's to remove the +arguments by contradiction and add explanations or steps that Knuth omitted. +But beware of errors in older printings. Take the published errata with you. + +Brinch Hansen's “Multiple-length Division Revisited: a Tour of the Minefield” +starts with a blunt critique of Knuth's presentation (among others) and then +presents a more detailed and easier to follow treatment of long division, +including an implementation in Pascal. But the algorithm and implementation +work entirely in terms of 3-by-2 division, which is much less useful on modern +hardware than an algorithm using 2-by-1 division. The proofs are a bit too +focused on digit counting and seem needlessly complex, especially compared to +the ones given above. + +Burnikel and Ziegler's “Fast Recursive Division” introduced the key insight of +implementing division by an n-digit divisor using recursive calls to division +by an n/2-digit divisor, relying on Karatsuba multiplication to yield a +sub-quadratic run time. However, the presentation decisions are made almost +entirely for the purpose of simplifying the run-time analysis, rather than +simplifying the presentation. Instead of a single algorithm that loops over +quotient digits, the paper presents two mutually-recursive algorithms, for +2n-by-n and 3n-by-2n. The paper also does not present any general (n+m)-by-n +algorithm. + +The proofs in the paper are remarkably complex, especially considering that +the algorithm is at its core just long division on wide digits, so that the +usual long division proofs apply essentially unaltered. +*/ + package big import "math/bits" +// div returns q, r such that q = ⌊u/v⌋ and r = u%v = u - q·v. +// It uses z and z2 as the storage for q and r. func (z nat) div(z2, u, v nat) (q, r nat) { if len(v) == 0 { panic("division by zero") @@ -18,6 +514,8 @@ func (z nat) div(z2, u, v nat) (q, r nat) { } if len(v) == 1 { + // Short division: long optimized for a single-word divisor. + // In that case, the 2-by-1 guess is all we need at each step. var r2 Word q, r2 = z.divW(u, v[0]) r = z2.setWord(r2) @@ -28,7 +526,9 @@ func (z nat) div(z2, u, v nat) (q, r nat) { return } -// q = (x-r)/y, with 0 <= r < y +// divW returns q, r such that q = ⌊x/y⌋ and r = x%y = x - q·y. +// It uses z as the storage for q. +// Note that y is a single digit (Word), not a big number. func (z nat) divW(x nat, y Word) (q nat, r Word) { m := len(x) switch { @@ -56,6 +556,8 @@ func (x nat) modW(d Word) (r Word) { return divWVW(q, 0, x, d) } +// divWVW overwrites z with ⌊x/y⌋, returning the remainder r. +// The caller must ensure that len(z) = len(x). func divWVW(z []Word, xn Word, x []Word, y Word) (r Word) { r = xn if len(x) == 1 { @@ -70,34 +572,33 @@ func divWVW(z []Word, xn Word, x []Word, y Word) (r Word) { return r } -// q = (uIn-r)/vIn, with 0 <= r < vIn -// Uses z as storage for q, and u as storage for r if possible. -// See Knuth, Volume 2, section 4.3.1, Algorithm D. -// Preconditions: -// len(vIn) >= 2 -// len(uIn) >= len(vIn) -// u must not alias z +// div returns q, r such that q = ⌊uIn/vIn⌋ and r = uIn%vIn = uIn - q·vIn. +// It uses z and u as the storage for q and r. +// The caller must ensure that len(vIn) ≥ 2 (use divW otherwise) +// and that len(uIn) ≥ len(vIn) (the answer is 0, uIn otherwise). func (z nat) divLarge(u, uIn, vIn nat) (q, r nat) { n := len(vIn) m := len(uIn) - n - // D1. + // Scale the inputs so vIn's top bit is 1 (see “Scaling Inputs” above). + // vIn is treated as a read-only input (it may be in use by another + // goroutine), so we must make a copy. + // uIn is copied to u. shift := nlz(vIn[n-1]) - // do not modify vIn, it may be used by another goroutine simultaneously vp := getNat(n) v := *vp shlVU(v, vIn, shift) - - // u may safely alias uIn or vIn, the value of uIn is used to set u and vIn was already used u = u.make(len(uIn) + 1) u[len(uIn)] = shlVU(u[0:len(uIn)], uIn, shift) - // z may safely alias uIn or vIn, both values were used already + // The caller should not pass aliased z and u, since those are + // the two different outputs, but correct just in case. if alias(z, u) { - z = nil // z is an alias for u - cannot reuse + z = nil } q = z.make(m + 1) + // Use basic or recursive long division depending on size. if n < divRecursiveThreshold { q.divBasic(u, v) } else { @@ -106,19 +607,17 @@ func (z nat) divLarge(u, uIn, vIn nat) (q, r nat) { putNat(vp) q = q.norm() + + // Undo scaling of remainder. shrVU(u, u, shift) r = u.norm() return q, r } -// divBasic performs word-by-word division of u by v. -// The quotient is written in pre-allocated q. -// The remainder overwrites input u. -// -// Precondition: -// - q is large enough to hold the quotient u / v -// which has a maximum length of len(u)-len(v)+1. +// divBasic implements long division as described above. +// It overwrites q with ⌊u/v⌋ and overwrites u with the remainder r. +// q must be large enough to hold ⌊u/v⌋. func (q nat) divBasic(u, v nat) { n := len(v) m := len(u) - n @@ -126,45 +625,56 @@ func (q nat) divBasic(u, v nat) { qhatvp := getNat(n + 1) qhatv := *qhatvp - // D2. + // Set up for divWW below, precomputing reciprocal argument. vn1 := v[n-1] rec := reciprocalWord(vn1) + + // Compute each digit of quotient. for j := m; j >= 0; j-- { - // D3. + // Compute the 2-by-1 guess q̂. + // The first iteration must invent a leading 0 for u. qhat := Word(_M) var ujn Word if j+n < len(u) { ujn = u[j+n] } + + // ujn ≤ vn1, or else q̂ would be more than one digit. + // For ujn == vn1, we set q̂ to the max digit M above. + // Otherwise, we compute the 2-by-1 guess. if ujn != vn1 { var rhat Word qhat, rhat = divWW(ujn, u[j+n-1], vn1, rec) - // x1 | x2 = q̂v_{n-2} + // Refine q̂ to a 3-by-2 guess. See “Refining Guesses” above. vn2 := v[n-2] x1, x2 := mulWW(qhat, vn2) - // test if q̂v_{n-2} > br̂ + u_{j+n-2} ujn2 := u[j+n-2] - for greaterThan(x1, x2, rhat, ujn2) { + for greaterThan(x1, x2, rhat, ujn2) { // x1x2 > r̂ u[j+n-2] qhat-- prevRhat := rhat rhat += vn1 - // v[n-1] >= 0, so this tests for overflow. + // If r̂ overflows, then + // r̂ u[j+n-2]v[n-1] is now definitely > x1 x2. if rhat < prevRhat { break } + // TODO(rsc): No need for a full mulWW. + // x2 += vn2; if x2 overflows, x1++ x1, x2 = mulWW(qhat, vn2) } } - // D4. - // Compute the remainder u - (q̂*v) << (_W*j). - // The subtraction may overflow if q̂ estimate was off by one. + // Compute q̂·v. qhatv[n] = mulAddVWW(qhatv[0:n], v, qhat, 0) qhl := len(qhatv) if j+qhl > len(u) && qhatv[n] == 0 { qhl-- } + + // Subtract q̂·v from the current section of u. + // If it underflows, q̂·v > u, which we fix up + // by decrementing q̂ and adding v back. c := subVV(u[j:j+qhl], u[j:], qhatv) if c != 0 { c := addVV(u[j:j+n], u[j:], v) @@ -176,6 +686,8 @@ func (q nat) divBasic(u, v nat) { qhat-- } + // Save quotient digit. + // Caller may know the top digit is zero and not leave room for it. if j == m && m == len(q) && qhat == 0 { continue } @@ -185,30 +697,34 @@ func (q nat) divBasic(u, v nat) { putNat(qhatvp) } -// greaterThan reports whether (x1<<_W + x2) > (y1<<_W + y2) +// greaterThan reports whether the two digit numbers x1 x2 > y1 y2. +// TODO(rsc): In contradiction to most of this file, x1 is the high +// digit and x2 is the low digit. This should be fixed. func greaterThan(x1, x2, y1, y2 Word) bool { return x1 > y1 || x1 == y1 && x2 > y2 } +// divRecursiveThreshold is the number of divisor digits +// at which point divRecursive is faster than divBasic. const divRecursiveThreshold = 100 -// divRecursive performs word-by-word division of u by v. -// The quotient is written in pre-allocated z. -// The remainder overwrites input u. -// -// Precondition: -// - len(z) >= len(u)-len(v) -// -// See Burnikel, Ziegler, "Fast Recursive Division", Algorithm 1 and 2. +// divRecursive implements recursive division as described above. +// It overwrites z with ⌊u/v⌋ and overwrites u with the remainder r. +// z must be large enough to hold ⌊u/v⌋. +// This function is just for allocating and freeing temporaries +// around divRecursiveStep, the real implementation. func (z nat) divRecursive(u, v nat) { - // Recursion depth is less than 2 log2(len(v)) - // Allocate a slice of temporaries to be reused across recursion. + // Recursion depth is (much) less than 2 log₂(len(v)). + // Allocate a slice of temporaries to be reused across recursion, + // plus one extra temporary not live across the recursion. recDepth := 2 * bits.Len(uint(len(v))) - // large enough to perform Karatsuba on operands as large as v tmp := getNat(3 * len(v)) temps := make([]*nat, recDepth) + z.clear() z.divRecursiveStep(u, v, 0, tmp, temps) + + // Free temporaries. for _, n := range temps { if n != nil { putNat(n) @@ -217,72 +733,92 @@ func (z nat) divRecursive(u, v nat) { putNat(tmp) } -// divRecursiveStep computes the division of u by v. -// - z must be large enough to hold the quotient -// - the quotient will overwrite z -// - the remainder will overwrite u +// divRecursiveStep is the actual implementation of recursive division. +// It adds ⌊u/v⌋ to z and overwrites u with the remainder r. +// z must be large enough to hold ⌊u/v⌋. +// It uses temps[depth] (allocating if needed) as a temporary live across +// the recursive call. It also uses tmp, but not live across the recursion. func (z nat) divRecursiveStep(u, v nat, depth int, tmp *nat, temps []*nat) { + // u is a subsection of the original and may have leading zeros. + // TODO(rsc): The v = v.norm() is useless and should be removed. + // We know (and require) that v's top digit is ≥ B/2. u = u.norm() v = v.norm() - if len(u) == 0 { z.clear() return } + + // Fall back to basic division if the problem is now small enough. n := len(v) if n < divRecursiveThreshold { z.divBasic(u, v) return } + + // Nothing to do if u is shorter than v (implies u < v). m := len(u) - n if m < 0 { return } - // Produce the quotient by blocks of B words. - // Division by v (length n) is done using a length n/2 division - // and a length n/2 multiplication for each block. The final - // complexity is driven by multiplication complexity. + // We consider B digits in a row as a single wide digit. + // (See “Recursive Division” above.) + // + // TODO(rsc): rename B to Wide, to avoid confusion with _B, + // which is something entirely different. + // TODO(rsc): Look into whether using ⌈n/2⌉ is better than ⌊n/2⌋. B := n / 2 // Allocate a nat for qhat below. if temps[depth] == nil { - temps[depth] = getNat(n) + temps[depth] = getNat(n) // TODO(rsc): Can be just B+1. } else { *temps[depth] = temps[depth].make(B + 1) } + // Compute each wide digit of the quotient. + // + // TODO(rsc): Change the loop to be + // for j := (m+B-1)/B*B; j > 0; j -= B { + // which will make the final step a regular step, letting us + // delete what amounts to an extra copy of the loop body below. j := m for j > B { - // Divide u[j-B:j+n] by vIn. Keep remainder in u - // for next block. + // Divide u[j-B:j+n] (3 wide digits) by v (2 wide digits). + // First make the 2-by-1-wide-digit guess using a recursive call. + // Then extend the guess to the full 3-by-2 (see “Refining Guesses”). // - // The following property will be used (Lemma 2): - // if u = u1 << s + u0 - // v = v1 << s + v0 - // then floor(u1/v1) >= floor(u/v) - // - // Moreover, the difference is at most 2 if len(v1) >= len(u/v) - // We choose s = B-1 since len(v)-s >= B+1 >= len(u/v) + // For the 2-by-1-wide-digit guess, instead of doing 2B-by-B-digit, + // we use a (2B+1)-by-(B+1) digit, which handles the possibility that + // the result has an extra leading 1 digit as well as guaranteeing + // that the computed q̂ will be off by at most 1 instead of 2. + + // s is the number of digits to drop from the 3B- and 2B-digit chunks. + // We drop B-1 to be left with 2B+1 and B+1. s := (B - 1) - // Except for the first step, the top bits are always - // a division remainder, so the quotient length is <= n. + + // uu is the up-to-3B-digit section of u we are working on. uu := u[j-B:] + // Compute the 2-by-1 guess q̂, leaving r̂ in uu[s:B+n]. qhat := *temps[depth] qhat.clear() qhat.divRecursiveStep(uu[s:B+n], v[s:], depth+1, tmp, temps) qhat = qhat.norm() - // Adjust the quotient: - // u = u_h << s + u_l - // v = v_h << s + v_l - // u_h = q̂ v_h + rh - // u = q̂ (v - v_l) + rh << s + u_l - // After the above step, u contains a remainder: - // u = rh << s + u_l - // and we need to subtract q̂ v_l - // - // But it may be a bit too large, in which case q̂ needs to be smaller. + + // Extend to a 3-by-2 quotient and remainder. + // Because divRecursiveStep overwrote the top part of uu with + // the remainder r̂, the full uu already contains the equivalent + // of r̂·B + uₙ₋₂ from the “Refining Guesses” discussion. + // Subtracting q̂·vₙ₋₂ from it will compute the full-length remainder. + // If that subtraction underflows, q̂·v > u, which we fix up + // by decrementing q̂ and adding v back, same as in long division. + + // TODO(rsc): Instead of subtract and fix-up, this code is computing + // q̂·vₙ₋₂ and decrementing q̂ until that product is ≤ u. + // But we can do the subtraction directly, as in the comment above + // and in long division, because we know that q̂ is wrong by at most one. qhatv := tmp.make(3 * n) qhatv.clear() qhatv = qhatv.mul(qhat, v[:s]) @@ -309,6 +845,8 @@ func (z nat) divRecursiveStep(u, v nat, depth int, tmp *nat, temps []*nat) { j -= B } + // TODO(rsc): Rewrite loop as described above and delete all this code. + // Now u < (v< Date: Mon, 7 Jun 2021 14:29:43 -0400 Subject: [PATCH 360/940] net/url: reject query values with semicolons Semicolons are no longer valid separators, so net/url.ParseQuery will now return an error if any part of the query contains a semicolon. net/http.(*Request).ParseMultipartForm has been changed to fall through and continue parsing even if the call to (*Request).ParseForm fails. This change also includes a few minor refactors to existing tests. Fixes #25192 Change-Id: Iba3f108950fb99b9288e402c41fe71ca3a2ababd Reviewed-on: https://go-review.googlesource.com/c/go/+/325697 Trust: Katie Hockman Run-TryBot: Katie Hockman TryBot-Result: Go Bot Reviewed-by: Filippo Valsorda --- src/net/http/request.go | 12 ++-- src/net/http/request_test.go | 31 +++++++++- src/net/http/server.go | 5 ++ src/net/url/example_test.go | 4 +- src/net/url/url.go | 13 ++-- src/net/url/url_test.go | 116 +++++++++++++++++++++++++++-------- 6 files changed, 145 insertions(+), 36 deletions(-) diff --git a/src/net/http/request.go b/src/net/http/request.go index 7895417af50..09cb0c7f564 100644 --- a/src/net/http/request.go +++ b/src/net/http/request.go @@ -1293,16 +1293,18 @@ func (r *Request) ParseForm() error { // its file parts are stored in memory, with the remainder stored on // disk in temporary files. // ParseMultipartForm calls ParseForm if necessary. +// If ParseForm returns an error, ParseMultipartForm returns it but also +// continues parsing the request body. // After one call to ParseMultipartForm, subsequent calls have no effect. func (r *Request) ParseMultipartForm(maxMemory int64) error { if r.MultipartForm == multipartByReader { return errors.New("http: multipart handled by MultipartReader") } + var parseFormErr error if r.Form == nil { - err := r.ParseForm() - if err != nil { - return err - } + // Let errors in ParseForm fall through, and just + // return it at the end. + parseFormErr = r.ParseForm() } if r.MultipartForm != nil { return nil @@ -1329,7 +1331,7 @@ func (r *Request) ParseMultipartForm(maxMemory int64) error { r.MultipartForm = f - return nil + return parseFormErr } // FormValue returns the first value for the named component of the query. diff --git a/src/net/http/request_test.go b/src/net/http/request_test.go index 952828b395e..4e0c4ba207f 100644 --- a/src/net/http/request_test.go +++ b/src/net/http/request_test.go @@ -32,9 +32,26 @@ func TestQuery(t *testing.T) { } } +// Issue #25192: Test that ParseForm fails but still parses the form when an URL +// containing a semicolon is provided. +func TestParseFormSemicolonSeparator(t *testing.T) { + for _, method := range []string{"POST", "PATCH", "PUT", "GET"} { + req, _ := NewRequest(method, "http://www.google.com/search?q=foo;q=bar&a=1", + strings.NewReader("q")) + err := req.ParseForm() + if err == nil { + t.Fatalf(`for method %s, ParseForm expected an error, got success`, method) + } + wantForm := url.Values{"a": []string{"1"}} + if !reflect.DeepEqual(req.Form, wantForm) { + t.Fatalf("for method %s, ParseForm expected req.Form = %v, want %v", method, req.Form, wantForm) + } + } +} + func TestParseFormQuery(t *testing.T) { req, _ := NewRequest("POST", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&orphan=nope&empty=not", - strings.NewReader("z=post&both=y&prio=2&=nokey&orphan;empty=&")) + strings.NewReader("z=post&both=y&prio=2&=nokey&orphan&empty=&")) req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value") if q := req.FormValue("q"); q != "foo" { @@ -365,6 +382,18 @@ func TestMultipartRequest(t *testing.T) { validateTestMultipartContents(t, req, false) } +// Issue #25192: Test that ParseMultipartForm fails but still parses the +// multi-part form when an URL containing a semicolon is provided. +func TestParseMultipartFormSemicolonSeparator(t *testing.T) { + req := newTestMultipartRequest(t) + req.URL = &url.URL{RawQuery: "q=foo;q=bar"} + if err := req.ParseMultipartForm(25); err == nil { + t.Fatal("ParseMultipartForm expected error due to invalid semicolon, got nil") + } + defer req.MultipartForm.RemoveAll() + validateTestMultipartContents(t, req, false) +} + func TestMultipartRequestAuto(t *testing.T) { // Test that FormValue and FormFile automatically invoke // ParseMultipartForm and return the right values. diff --git a/src/net/http/server.go b/src/net/http/server.go index 430019de509..8a1847e67a5 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -2863,6 +2863,11 @@ func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) { handler = globalOptionsHandler{} } handler.ServeHTTP(rw, req) + if req.URL != nil && strings.Contains(req.URL.RawQuery, ";") { + // TODO(filippo): update this not to log if the special + // semicolon handler was called. + sh.srv.logf("http: URL query contains semicolon, which is no longer a supported separator; parts of the query may be stripped when parsed; see golang.org/issue/25192") + } } // ListenAndServe listens on the TCP network address srv.Addr and then diff --git a/src/net/url/example_test.go b/src/net/url/example_test.go index cb9e8922a2e..476132a1c93 100644 --- a/src/net/url/example_test.go +++ b/src/net/url/example_test.go @@ -72,13 +72,13 @@ func ExampleURL_ResolveReference() { } func ExampleParseQuery() { - m, err := url.ParseQuery(`x=1&y=2&y=3;z`) + m, err := url.ParseQuery(`x=1&y=2&y=3`) if err != nil { log.Fatal(err) } fmt.Println(toJSON(m)) // Output: - // {"x":["1"], "y":["2", "3"], "z":[""]} + // {"x":["1"], "y":["2", "3"]} } func ExampleURL_EscapedPath() { diff --git a/src/net/url/url.go b/src/net/url/url.go index 73bef22e456..20de0f6f517 100644 --- a/src/net/url/url.go +++ b/src/net/url/url.go @@ -921,9 +921,10 @@ func (v Values) Has(key string) bool { // valid query parameters found; err describes the first decoding error // encountered, if any. // -// Query is expected to be a list of key=value settings separated by -// ampersands or semicolons. A setting without an equals sign is -// interpreted as a key set to an empty value. +// Query is expected to be a list of key=value settings separated by ampersands. +// A setting without an equals sign is interpreted as a key set to an empty +// value. +// Settings containing a non-URL-encoded semicolon are considered invalid. func ParseQuery(query string) (Values, error) { m := make(Values) err := parseQuery(m, query) @@ -933,11 +934,15 @@ func ParseQuery(query string) (Values, error) { func parseQuery(m Values, query string) (err error) { for query != "" { key := query - if i := strings.IndexAny(key, "&;"); i >= 0 { + if i := strings.IndexAny(key, "&"); i >= 0 { key, query = key[:i], key[i+1:] } else { query = "" } + if strings.Contains(key, ";") { + err = fmt.Errorf("invalid semicolon separator in query") + continue + } if key == "" { continue } diff --git a/src/net/url/url_test.go b/src/net/url/url_test.go index 55348c4a7da..63c8e695af7 100644 --- a/src/net/url/url_test.go +++ b/src/net/url/url_test.go @@ -1334,57 +1334,125 @@ func TestQueryValues(t *testing.T) { type parseTest struct { query string out Values + ok bool } var parseTests = []parseTest{ + { + query: "a=1", + out: Values{"a": []string{"1"}}, + ok: true, + }, { query: "a=1&b=2", out: Values{"a": []string{"1"}, "b": []string{"2"}}, + ok: true, }, { query: "a=1&a=2&a=banana", out: Values{"a": []string{"1", "2", "banana"}}, + ok: true, }, { query: "ascii=%3Ckey%3A+0x90%3E", out: Values{"ascii": []string{""}}, + ok: true, + }, { + query: "a=1;b=2", + out: Values{}, + ok: false, + }, { + query: "a;b=1", + out: Values{}, + ok: false, + }, { + query: "a=%3B", // hex encoding for semicolon + out: Values{"a": []string{";"}}, + ok: true, }, { - query: "a=1;b=2", - out: Values{"a": []string{"1"}, "b": []string{"2"}}, + query: "a%3Bb=1", + out: Values{"a;b": []string{"1"}}, + ok: true, }, { query: "a=1&a=2;a=banana", - out: Values{"a": []string{"1", "2", "banana"}}, + out: Values{"a": []string{"1"}}, + ok: false, + }, + { + query: "a;b&c=1", + out: Values{"c": []string{"1"}}, + ok: false, + }, + { + query: "a=1&b=2;a=3&c=4", + out: Values{"a": []string{"1"}, "c": []string{"4"}}, + ok: false, + }, + { + query: "a=1&b=2;c=3", + out: Values{"a": []string{"1"}}, + ok: false, + }, + { + query: ";", + out: Values{}, + ok: false, + }, + { + query: "a=1;", + out: Values{}, + ok: false, + }, + { + query: "a=1&;", + out: Values{"a": []string{"1"}}, + ok: false, + }, + { + query: ";a=1&b=2", + out: Values{"b": []string{"2"}}, + ok: false, + }, + { + query: "a=1&b=2;", + out: Values{"a": []string{"1"}}, + ok: false, }, } func TestParseQuery(t *testing.T) { - for i, test := range parseTests { - form, err := ParseQuery(test.query) - if err != nil { - t.Errorf("test %d: Unexpected error: %v", i, err) - continue - } - if len(form) != len(test.out) { - t.Errorf("test %d: len(form) = %d, want %d", i, len(form), len(test.out)) - } - for k, evs := range test.out { - vs, ok := form[k] - if !ok { - t.Errorf("test %d: Missing key %q", i, k) - continue + for _, test := range parseTests { + t.Run(test.query, func(t *testing.T) { + form, err := ParseQuery(test.query) + if test.ok != (err == nil) { + want := "" + if test.ok { + want = "" + } + t.Errorf("Unexpected error: %v, want %v", err, want) } - if len(vs) != len(evs) { - t.Errorf("test %d: len(form[%q]) = %d, want %d", i, k, len(vs), len(evs)) - continue + if len(form) != len(test.out) { + t.Errorf("len(form) = %d, want %d", len(form), len(test.out)) } - for j, ev := range evs { - if v := vs[j]; v != ev { - t.Errorf("test %d: form[%q][%d] = %q, want %q", i, k, j, v, ev) + for k, evs := range test.out { + vs, ok := form[k] + if !ok { + t.Errorf("Missing key %q", k) + continue + } + if len(vs) != len(evs) { + t.Errorf("len(form[%q]) = %d, want %d", k, len(vs), len(evs)) + continue + } + for j, ev := range evs { + if v := vs[j]; v != ev { + t.Errorf("form[%q][%d] = %q, want %q", k, j, v, ev) + } } } - } + }) } } From ec3026d032be065fb26c5826b9abb7b6b806d7ef Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 9 Jun 2021 11:04:58 -0400 Subject: [PATCH 361/940] doc/go1.17: remove TODO for ports section I'm not aware of anything more to mention for ports. Change-Id: I686df8a230a55ad7f4c5eae43ca27f85fad9dd84 Reviewed-on: https://go-review.googlesource.com/c/go/+/326409 Trust: Cherry Mui Reviewed-by: Jeremy Faller Reviewed-by: Dmitri Shuralyov --- doc/go1.17.html | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 011377a84e7..2a56b6d2703 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -120,10 +120,6 @@ Do not send CLs removing the interior tags from such phrases. stack frame pointers only on Linux, macOS, and iOS.

-

- TODO: complete the Ports section -

-

Tools

Go command

From e4e7807d240eb62e1d4a73eec2706975c8cc847b Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Wed, 9 Jun 2021 07:43:57 -0400 Subject: [PATCH 362/940] net/http: add AllowQuerySemicolons Fixes #45973 Change-Id: I6cbe05f5d1d3c324900c74314b0ea0e12524d7f2 Reviewed-on: https://go-review.googlesource.com/c/go/+/326309 Run-TryBot: Filippo Valsorda Reviewed-by: Katie Hockman Trust: Katie Hockman Trust: Filippo Valsorda TryBot-Result: Go Bot --- src/net/http/serve_test.go | 84 ++++++++++++++++++++++++++++++++++++++ src/net/http/server.go | 45 ++++++++++++++++++-- 2 files changed, 125 insertions(+), 4 deletions(-) diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go index a9714682c7e..c2f88114697 100644 --- a/src/net/http/serve_test.go +++ b/src/net/http/serve_test.go @@ -6524,3 +6524,87 @@ func TestMuxRedirectRelative(t *testing.T) { t.Errorf("Expected response code %d; got %d", want, got) } } + +// TestQuerySemicolon tests the behavior of semicolons in queries. See Issue 25192. +func TestQuerySemicolon(t *testing.T) { + t.Cleanup(func() { afterTest(t) }) + + tests := []struct { + query string + xNoSemicolons string + xWithSemicolons string + warning bool + }{ + {"?a=1;x=bad&x=good", "good", "bad", true}, + {"?a=1;b=bad&x=good", "good", "good", true}, + {"?a=1%3Bx=bad&x=good%3B", "good;", "good;", false}, + {"?a=1;x=good;x=bad", "", "good", true}, + } + + for _, tt := range tests { + t.Run(tt.query+"/allow=false", func(t *testing.T) { + allowSemicolons := false + testQuerySemicolon(t, tt.query, tt.xNoSemicolons, allowSemicolons, tt.warning) + }) + t.Run(tt.query+"/allow=true", func(t *testing.T) { + allowSemicolons, expectWarning := true, false + testQuerySemicolon(t, tt.query, tt.xWithSemicolons, allowSemicolons, expectWarning) + }) + } +} + +func testQuerySemicolon(t *testing.T, query string, wantX string, allowSemicolons, expectWarning bool) { + setParallel(t) + + writeBackX := func(w ResponseWriter, r *Request) { + x := r.URL.Query().Get("x") + if expectWarning { + if err := r.ParseForm(); err == nil || !strings.Contains(err.Error(), "semicolon") { + t.Errorf("expected error mentioning semicolons from ParseForm, got %v", err) + } + } else { + if err := r.ParseForm(); err != nil { + t.Errorf("expected no error from ParseForm, got %v", err) + } + } + if got := r.FormValue("x"); x != got { + t.Errorf("got %q from FormValue, want %q", got, x) + } + fmt.Fprintf(w, "%s", x) + } + + h := Handler(HandlerFunc(writeBackX)) + if allowSemicolons { + h = AllowQuerySemicolons(h) + } + + ts := httptest.NewUnstartedServer(h) + logBuf := &bytes.Buffer{} + ts.Config.ErrorLog = log.New(logBuf, "", 0) + ts.Start() + defer ts.Close() + + req, _ := NewRequest("GET", ts.URL+query, nil) + res, err := ts.Client().Do(req) + if err != nil { + t.Fatal(err) + } + slurp, _ := io.ReadAll(res.Body) + res.Body.Close() + if got, want := res.StatusCode, 200; got != want { + t.Errorf("Status = %d; want = %d", got, want) + } + if got, want := string(slurp), wantX; got != want { + t.Errorf("Body = %q; want = %q", got, want) + } + + if expectWarning { + if !strings.Contains(logBuf.String(), "semicolon") { + t.Errorf("got %q from ErrorLog, expected a mention of semicolons", logBuf.String()) + } + } else { + if strings.Contains(logBuf.String(), "semicolon") { + t.Errorf("got %q from ErrorLog, expected no mention of semicolons", logBuf.String()) + } + } +} diff --git a/src/net/http/server.go b/src/net/http/server.go index 8a1847e67a5..50fab4520dd 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -2862,12 +2862,49 @@ func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) { if req.RequestURI == "*" && req.Method == "OPTIONS" { handler = globalOptionsHandler{} } - handler.ServeHTTP(rw, req) + if req.URL != nil && strings.Contains(req.URL.RawQuery, ";") { - // TODO(filippo): update this not to log if the special - // semicolon handler was called. - sh.srv.logf("http: URL query contains semicolon, which is no longer a supported separator; parts of the query may be stripped when parsed; see golang.org/issue/25192") + var allowQuerySemicolonsInUse int32 + req = req.WithContext(context.WithValue(req.Context(), silenceSemWarnContextKey, func() { + atomic.StoreInt32(&allowQuerySemicolonsInUse, 1) + })) + defer func() { + if atomic.LoadInt32(&allowQuerySemicolonsInUse) == 0 { + sh.srv.logf("http: URL query contains semicolon, which is no longer a supported separator; parts of the query may be stripped when parsed; see golang.org/issue/25192") + } + }() } + + handler.ServeHTTP(rw, req) +} + +var silenceSemWarnContextKey = &contextKey{"silence-semicolons"} + +// AllowQuerySemicolons returns a handler that serves requests by converting any +// unescaped semicolons in the URL query to ampersands, and invoking the handler h. +// +// This restores the pre-Go 1.17 behavior of splitting query parameters on both +// semicolons and ampersands. (See golang.org/issue/25192). Note that this +// behavior doesn't match that of many proxies, and the mismatch can lead to +// security issues. +// +// AllowQuerySemicolons should be invoked before Request.ParseForm is called. +func AllowQuerySemicolons(h Handler) Handler { + return HandlerFunc(func(w ResponseWriter, r *Request) { + if silenceSemicolonsWarning, ok := r.Context().Value(silenceSemWarnContextKey).(func()); ok { + silenceSemicolonsWarning() + } + if strings.Contains(r.URL.RawQuery, ";") { + r2 := new(Request) + *r2 = *r + r2.URL = new(url.URL) + *r2.URL = *r.URL + r2.URL.RawQuery = strings.ReplaceAll(r.URL.RawQuery, ";", "&") + h.ServeHTTP(w, r2) + } else { + h.ServeHTTP(w, r) + } + }) } // ListenAndServe listens on the TCP network address srv.Addr and then From df35ade067f22ef1f3aad3c2f3576997ff9646b4 Mon Sep 17 00:00:00 2001 From: Heschi Kreinick Date: Tue, 8 Jun 2021 20:34:16 -0400 Subject: [PATCH 363/940] doc/go1.17: document //go:build lines In 1.17, //go:build lines are fully supported. This entails changes to the go command, vet, and gofmt. Document all of them. I'm not Russ, but this is a significant change, it slipped under the radar, and we're trying to get the release out. So here's what I got. I wasn't sure where to put the go command change. On the one hand, it's pretty significant. On the other, it certainly affects fewer people than lazy loading. So it probably shouldn't be first, but I also didn't want to bury it the middle of all the other module changes. Open to suggestions. Change-Id: Ia1a96bcfb1977973c5b0b0a6b18a9242a745af12 Reviewed-on: https://go-review.googlesource.com/c/go/+/326209 Trust: Heschi Kreinick Run-TryBot: Heschi Kreinick TryBot-Result: Go Bot Reviewed-by: Dmitri Shuralyov --- doc/go1.17.html | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 2a56b6d2703..6c53aaaa88c 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -279,12 +279,41 @@ Do not send CLs removing the interior tags from such phrases. mod download all.

+

//go:build lines

+ +

+ The go command now understands //go:build lines + and prefers them over // +build lines. The new syntax uses + boolean expressions, just like Go, and should be less error-prone. + As of this release, the new syntax is fully supported, and all Go files + should be updated to have both forms with the same meaning. To aid in + migration, gofmt now automatically + synchronizes the two forms. For more details on the syntax and migration plan, + see + https://golang.org/design/draft-gobuild. +

+ +

gofmt

+ gofmt (and go fmt) now synchronizes + //go:build lines with // +build lines. If a file + only has // +build lines, they will be moved to the appropriate + location in the file, and matching //go:build lines will be + added. Otherwise, // +build lines will be overwritten based on + any existing //go:build lines. For more information, see + https://golang.org/design/draft-gobuild. + +

Vet

-

New warning within buildtags

+

New warning for mismatched //go:build and // +build lines

- TODO(rsc): Describe changes to buildtags https://golang.org/cl/240609 + The vet tool now verifies that //go:build and + // +build lines are in the correct part of the file and + synchronized with each other. If they aren't, + gofmt can be used to fix them. For more + information, see + https://golang.org/design/draft-gobuild.

New warning for calling signal.Notify on unbuffered channels

@@ -638,6 +667,22 @@ func Foo() bool {
+
go/format
+
+

+ The Source and + Node functions now + synchronize //go:build lines with // +build + lines. If a file only has // +build lines, they will be + moved to the appropriate location in the file, and matching + //go:build lines will be added. Otherwise, + // +build lines will be overwritten based on any existing + //go:build lines. For more information, see + https://golang.org/design/draft-gobuild. +

+
+
+
io/fs

From 1402b27d465d9949027a048ea2c86a3583400b4c Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Mon, 7 Jun 2021 16:30:03 -0700 Subject: [PATCH 364/940] strconv: document parsing of leading +/- Explicitly document the handling of a sign prefix, and the interaction between the sign and base prefixes. Fixes #46641. Change-Id: I3cd6773e3f074fe671a944a05a79d2408137fcd4 Reviewed-on: https://go-review.googlesource.com/c/go/+/325875 Trust: Damien Neil Run-TryBot: Damien Neil TryBot-Result: Go Bot Reviewed-by: Rob Pike --- src/strconv/atoi.go | 11 ++++++++--- src/strconv/atoi_test.go | 10 ++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/strconv/atoi.go b/src/strconv/atoi.go index c9ba0383b3f..631b487d976 100644 --- a/src/strconv/atoi.go +++ b/src/strconv/atoi.go @@ -57,6 +57,8 @@ const IntSize = intSize const maxUint64 = 1<<64 - 1 // ParseUint is like ParseInt but for unsigned numbers. +// +// A sign prefix is not permitted. func ParseUint(s string, base int, bitSize int) (uint64, error) { const fnParseUint = "ParseUint" @@ -159,10 +161,13 @@ func ParseUint(s string, base int, bitSize int) (uint64, error) { // ParseInt interprets a string s in the given base (0, 2 to 36) and // bit size (0 to 64) and returns the corresponding value i. // +// The string may begin with a leading sign: "+" or "-". +// // If the base argument is 0, the true base is implied by the string's -// prefix: 2 for "0b", 8 for "0" or "0o", 16 for "0x", and 10 otherwise. -// Also, for argument base 0 only, underscore characters are permitted -// as defined by the Go syntax for integer literals. +// prefix following the sign (if present): 2 for "0b", 8 for "0" or "0o", +// 16 for "0x", and 10 otherwise. Also, for argument base 0 only, +// underscore characters are permitted as defined by the Go syntax for +// integer literals. // // The bitSize argument specifies the integer type // that the result must fit into. Bit sizes 0, 8, 16, 32, and 64 diff --git a/src/strconv/atoi_test.go b/src/strconv/atoi_test.go index 178fb01ea7e..867fa66a14c 100644 --- a/src/strconv/atoi_test.go +++ b/src/strconv/atoi_test.go @@ -33,6 +33,9 @@ var parseUint64Tests = []parseUint64Test{ {"_12345", 0, ErrSyntax}, {"1__2345", 0, ErrSyntax}, {"12345_", 0, ErrSyntax}, + {"-0", 0, ErrSyntax}, + {"-1", 0, ErrSyntax}, + {"+1", 0, ErrSyntax}, } type parseUint64BaseTest struct { @@ -140,8 +143,10 @@ var parseInt64Tests = []parseInt64Test{ {"", 0, ErrSyntax}, {"0", 0, nil}, {"-0", 0, nil}, + {"+0", 0, nil}, {"1", 1, nil}, {"-1", -1, nil}, + {"+1", 1, nil}, {"12345", 12345, nil}, {"-12345", -12345, nil}, {"012345", 12345, nil}, @@ -236,6 +241,11 @@ var parseInt64BaseTests = []parseInt64BaseTest{ {"0__12345", 0, 0, ErrSyntax}, {"01234__5", 0, 0, ErrSyntax}, {"012345_", 0, 0, ErrSyntax}, + + {"+0xf", 0, 0xf, nil}, + {"-0xf", 0, -0xf, nil}, + {"0x+f", 0, 0, ErrSyntax}, + {"0x-f", 0, 0, ErrSyntax}, } type parseUint32Test struct { From a5bc060b42fe1bee8910a1081eff0a1047b15869 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Tue, 8 Jun 2021 14:26:13 -0700 Subject: [PATCH 365/940] doc/go1.17: document strconv changes for Go 1.17 For #44513. Fixes #46021. Change-Id: I40a4645fedfae24f67e249743c6a143e71b9f507 Reviewed-on: https://go-review.googlesource.com/c/go/+/326150 Trust: Damien Neil Run-TryBot: Damien Neil TryBot-Result: Go Bot Reviewed-by: Heschi Kreinick Reviewed-by: Dmitri Shuralyov --- doc/go1.17.html | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 6c53aaaa88c..988026f44dd 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -838,12 +838,9 @@ func Foo() bool {

strconv
-

- TODO: https://golang.org/cl/170079: implement Ryū-like algorithm for fixed precision ftoa -

- -

- TODO: https://golang.org/cl/170080: Implement Ryū algorithm for ftoa shortest mode +

+ The strconv package now uses Ulf Adams's Ryū algorithm for formatting floating-point numbers. + This algorithm improves performance on most inputs, and is more than 99% faster on worst-case inputs.

From 182157c81ad5a147ba13c6e80f844b2242598aed Mon Sep 17 00:00:00 2001 From: Heschi Kreinick Date: Wed, 9 Jun 2021 12:59:30 -0400 Subject: [PATCH 366/940] doc/go1.17: remove lingering TODO As far as I can tell the Core Library section is complete. Remove its TODO. Change-Id: Ia84c6656fac045e25fae1a7ce8b488a3a26fd250 Reviewed-on: https://go-review.googlesource.com/c/go/+/326469 Trust: Heschi Kreinick Run-TryBot: Heschi Kreinick TryBot-Result: Go Bot Reviewed-by: Dmitri Shuralyov Reviewed-by: Damien Neil --- doc/go1.17.html | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 988026f44dd..49fbabdc3f4 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -418,10 +418,6 @@ func Foo() bool {

Core library

-

- TODO: complete the Core library section -

-

Cgo

From 27f83723e98d8e3795a07bdca2b3a8155b0d72b3 Mon Sep 17 00:00:00 2001 From: Heschi Kreinick Date: Wed, 9 Jun 2021 15:21:39 -0400 Subject: [PATCH 367/940] api: promote next to go1.17 Change-Id: If631878a2f6ec0317b4fad614f98ab102810ed47 Reviewed-on: https://go-review.googlesource.com/c/go/+/326410 Trust: Heschi Kreinick Run-TryBot: Heschi Kreinick TryBot-Result: Go Bot Reviewed-by: Dmitri Shuralyov --- api/go1.17.txt | 159 +++++++++++++++++++++++++++++++++++++++++++++++++ api/next.txt | 99 ------------------------------ 2 files changed, 159 insertions(+), 99 deletions(-) create mode 100644 api/go1.17.txt diff --git a/api/go1.17.txt b/api/go1.17.txt new file mode 100644 index 00000000000..f054458715f --- /dev/null +++ b/api/go1.17.txt @@ -0,0 +1,159 @@ +pkg archive/zip, method (*File) OpenRaw() (io.Reader, error) +pkg archive/zip, method (*Writer) Copy(*File) error +pkg archive/zip, method (*Writer) CreateRaw(*FileHeader) (io.Writer, error) +pkg compress/lzw, method (*Reader) Close() error +pkg compress/lzw, method (*Reader) Read([]uint8) (int, error) +pkg compress/lzw, method (*Reader) Reset(io.Reader, Order, int) +pkg compress/lzw, method (*Writer) Close() error +pkg compress/lzw, method (*Writer) Reset(io.Writer, Order, int) +pkg compress/lzw, method (*Writer) Write([]uint8) (int, error) +pkg compress/lzw, type Reader struct +pkg compress/lzw, type Writer struct +pkg crypto/tls, method (*CertificateRequestInfo) Context() context.Context +pkg crypto/tls, method (*ClientHelloInfo) Context() context.Context +pkg crypto/tls, method (*Conn) HandshakeContext(context.Context) error +pkg database/sql, method (*NullByte) Scan(interface{}) error +pkg database/sql, method (*NullInt16) Scan(interface{}) error +pkg database/sql, method (NullByte) Value() (driver.Value, error) +pkg database/sql, method (NullInt16) Value() (driver.Value, error) +pkg database/sql, type NullByte struct +pkg database/sql, type NullByte struct, Byte uint8 +pkg database/sql, type NullByte struct, Valid bool +pkg database/sql, type NullInt16 struct +pkg database/sql, type NullInt16 struct, Int16 int16 +pkg database/sql, type NullInt16 struct, Valid bool +pkg debug/elf, const SHT_MIPS_ABIFLAGS = 1879048234 +pkg debug/elf, const SHT_MIPS_ABIFLAGS SectionType +pkg encoding/csv, method (*Reader) FieldPos(int) (int, int) +pkg go/build, type Context struct, ToolTags []string +pkg go/parser, const SkipObjectResolution = 64 +pkg go/parser, const SkipObjectResolution Mode +pkg io/fs, func FileInfoToDirEntry(FileInfo) DirEntry +pkg math, const MaxFloat64 = 1.79769e+308 // 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368 +pkg math, const MaxInt = 9223372036854775807 +pkg math, const MaxInt ideal-int +pkg math, const MaxUint = 18446744073709551615 +pkg math, const MaxUint ideal-int +pkg math, const MinInt = -9223372036854775808 +pkg math, const MinInt ideal-int +pkg math, const SmallestNonzeroFloat32 = 1.4013e-45 // 1/713623846352979940529142984724747568191373312 +pkg math, const SmallestNonzeroFloat64 = 4.94066e-324 // 1/202402253307310618352495346718917307049556649764142118356901358027430339567995346891960383701437124495187077864316811911389808737385793476867013399940738509921517424276566361364466907742093216341239767678472745068562007483424692698618103355649159556340810056512358769552333414615230502532186327508646006263307707741093494784 +pkg net, method (*ParseError) Temporary() bool +pkg net, method (*ParseError) Timeout() bool +pkg net, method (IP) IsPrivate() bool +pkg net/http, func AllowQuerySemicolons(Handler) Handler +pkg net/url, method (Values) Has(string) bool +pkg reflect, func VisibleFields(Type) []StructField +pkg reflect, method (Method) IsExported() bool +pkg reflect, method (StructField) IsExported() bool +pkg runtime/cgo (darwin-amd64-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (darwin-amd64-cgo), method (Handle) Delete() +pkg runtime/cgo (darwin-amd64-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (darwin-amd64-cgo), type Handle uintptr +pkg runtime/cgo (freebsd-386-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (freebsd-386-cgo), method (Handle) Delete() +pkg runtime/cgo (freebsd-386-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (freebsd-386-cgo), type Handle uintptr +pkg runtime/cgo (freebsd-amd64-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (freebsd-amd64-cgo), method (Handle) Delete() +pkg runtime/cgo (freebsd-amd64-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (freebsd-amd64-cgo), type Handle uintptr +pkg runtime/cgo (freebsd-arm-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (freebsd-arm-cgo), method (Handle) Delete() +pkg runtime/cgo (freebsd-arm-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (freebsd-arm-cgo), type Handle uintptr +pkg runtime/cgo (linux-386-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (linux-386-cgo), method (Handle) Delete() +pkg runtime/cgo (linux-386-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (linux-386-cgo), type Handle uintptr +pkg runtime/cgo (linux-amd64-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (linux-amd64-cgo), method (Handle) Delete() +pkg runtime/cgo (linux-amd64-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (linux-amd64-cgo), type Handle uintptr +pkg runtime/cgo (linux-arm-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (linux-arm-cgo), method (Handle) Delete() +pkg runtime/cgo (linux-arm-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (linux-arm-cgo), type Handle uintptr +pkg runtime/cgo (netbsd-386-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (netbsd-386-cgo), method (Handle) Delete() +pkg runtime/cgo (netbsd-386-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (netbsd-386-cgo), type Handle uintptr +pkg runtime/cgo (netbsd-amd64-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (netbsd-amd64-cgo), method (Handle) Delete() +pkg runtime/cgo (netbsd-amd64-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (netbsd-amd64-cgo), type Handle uintptr +pkg runtime/cgo (netbsd-arm-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (netbsd-arm-cgo), method (Handle) Delete() +pkg runtime/cgo (netbsd-arm-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (netbsd-arm-cgo), type Handle uintptr +pkg runtime/cgo (netbsd-arm64-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (netbsd-arm64-cgo), method (Handle) Delete() +pkg runtime/cgo (netbsd-arm64-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (netbsd-arm64-cgo), type Handle uintptr +pkg runtime/cgo (openbsd-386-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (openbsd-386-cgo), method (Handle) Delete() +pkg runtime/cgo (openbsd-386-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (openbsd-386-cgo), type Handle uintptr +pkg runtime/cgo (openbsd-amd64-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (openbsd-amd64-cgo), method (Handle) Delete() +pkg runtime/cgo (openbsd-amd64-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (openbsd-amd64-cgo), type Handle uintptr +pkg strconv, func QuotedPrefix(string) (string, error) +pkg sync/atomic, method (*Value) CompareAndSwap(interface{}, interface{}) bool +pkg sync/atomic, method (*Value) Swap(interface{}) interface{} +pkg syscall (netbsd-386), const SYS_WAIT6 = 481 +pkg syscall (netbsd-386), const SYS_WAIT6 ideal-int +pkg syscall (netbsd-386), const WEXITED = 32 +pkg syscall (netbsd-386), const WEXITED ideal-int +pkg syscall (netbsd-386-cgo), const SYS_WAIT6 = 481 +pkg syscall (netbsd-386-cgo), const SYS_WAIT6 ideal-int +pkg syscall (netbsd-386-cgo), const WEXITED = 32 +pkg syscall (netbsd-386-cgo), const WEXITED ideal-int +pkg syscall (netbsd-amd64), const SYS_WAIT6 = 481 +pkg syscall (netbsd-amd64), const SYS_WAIT6 ideal-int +pkg syscall (netbsd-amd64), const WEXITED = 32 +pkg syscall (netbsd-amd64), const WEXITED ideal-int +pkg syscall (netbsd-amd64-cgo), const SYS_WAIT6 = 481 +pkg syscall (netbsd-amd64-cgo), const SYS_WAIT6 ideal-int +pkg syscall (netbsd-amd64-cgo), const WEXITED = 32 +pkg syscall (netbsd-amd64-cgo), const WEXITED ideal-int +pkg syscall (netbsd-arm), const SYS_WAIT6 = 481 +pkg syscall (netbsd-arm), const SYS_WAIT6 ideal-int +pkg syscall (netbsd-arm), const WEXITED = 32 +pkg syscall (netbsd-arm), const WEXITED ideal-int +pkg syscall (netbsd-arm-cgo), const SYS_WAIT6 = 481 +pkg syscall (netbsd-arm-cgo), const SYS_WAIT6 ideal-int +pkg syscall (netbsd-arm-cgo), const WEXITED = 32 +pkg syscall (netbsd-arm-cgo), const WEXITED ideal-int +pkg syscall (netbsd-arm64), const SYS_WAIT6 = 481 +pkg syscall (netbsd-arm64), const SYS_WAIT6 ideal-int +pkg syscall (netbsd-arm64), const WEXITED = 32 +pkg syscall (netbsd-arm64), const WEXITED ideal-int +pkg syscall (netbsd-arm64-cgo), const SYS_WAIT6 = 481 +pkg syscall (netbsd-arm64-cgo), const SYS_WAIT6 ideal-int +pkg syscall (netbsd-arm64-cgo), const WEXITED = 32 +pkg syscall (netbsd-arm64-cgo), const WEXITED ideal-int +pkg syscall (openbsd-386), const MSG_CMSG_CLOEXEC = 2048 +pkg syscall (openbsd-386), const MSG_CMSG_CLOEXEC ideal-int +pkg syscall (openbsd-386-cgo), const MSG_CMSG_CLOEXEC = 2048 +pkg syscall (openbsd-386-cgo), const MSG_CMSG_CLOEXEC ideal-int +pkg syscall (openbsd-amd64), const MSG_CMSG_CLOEXEC = 2048 +pkg syscall (openbsd-amd64), const MSG_CMSG_CLOEXEC ideal-int +pkg syscall (openbsd-amd64-cgo), const MSG_CMSG_CLOEXEC = 2048 +pkg syscall (openbsd-amd64-cgo), const MSG_CMSG_CLOEXEC ideal-int +pkg syscall (windows-386), type SysProcAttr struct, AdditionalInheritedHandles []Handle +pkg syscall (windows-386), type SysProcAttr struct, ParentProcess Handle +pkg syscall (windows-amd64), type SysProcAttr struct, AdditionalInheritedHandles []Handle +pkg syscall (windows-amd64), type SysProcAttr struct, ParentProcess Handle +pkg testing, method (*B) Setenv(string, string) +pkg testing, method (*T) Setenv(string, string) +pkg text/template/parse, const SkipFuncCheck = 2 +pkg text/template/parse, const SkipFuncCheck Mode +pkg time, const Layout = "01/02 03:04:05PM '06 -0700" +pkg time, const Layout ideal-string +pkg time, func UnixMicro(int64) Time +pkg time, func UnixMilli(int64) Time +pkg time, method (*Time) IsDST() bool +pkg time, method (Time) GoString() string +pkg time, method (Time) UnixMicro() int64 +pkg time, method (Time) UnixMilli() int64 diff --git a/api/next.txt b/api/next.txt index 9e996005c62..e69de29bb2d 100644 --- a/api/next.txt +++ b/api/next.txt @@ -1,99 +0,0 @@ -pkg compress/lzw, method (*Reader) Close() error -pkg compress/lzw, method (*Reader) Read([]uint8) (int, error) -pkg compress/lzw, method (*Reader) Reset(io.Reader, Order, int) -pkg compress/lzw, method (*Writer) Close() error -pkg compress/lzw, method (*Writer) Reset(io.Writer, Order, int) -pkg compress/lzw, method (*Writer) Write([]uint8) (int, error) -pkg compress/lzw, type Reader struct -pkg compress/lzw, type Writer struct -pkg crypto/tls, method (*CertificateRequestInfo) Context() context.Context -pkg crypto/tls, method (*ClientHelloInfo) Context() context.Context -pkg crypto/tls, method (*Conn) HandshakeContext(context.Context) error -pkg debug/elf, const SHT_MIPS_ABIFLAGS = 1879048234 -pkg debug/elf, const SHT_MIPS_ABIFLAGS SectionType -pkg encoding/csv, method (*Reader) FieldPos(int) (int, int) -pkg go/ast, method (*FuncDecl) IsMethod() bool -pkg go/build, type Context struct, ToolTags []string -pkg go/parser, const SkipObjectResolution = 64 -pkg go/parser, const SkipObjectResolution Mode -pkg go/types, type Config struct, GoVersion string -pkg io/fs, func FileInfoToDirEntry(FileInfo) DirEntry -pkg net, method (*ParseError) Temporary() bool -pkg net, method (*ParseError) Timeout() bool -pkg net, method (IP) IsPrivate() bool -pkg reflect, func VisibleFields(Type) []StructField -pkg reflect, method (Method) IsExported() bool -pkg reflect, method (StructField) IsExported() bool -pkg runtime/cgo (darwin-amd64-cgo), func NewHandle(interface{}) Handle -pkg runtime/cgo (darwin-amd64-cgo), method (Handle) Delete() -pkg runtime/cgo (darwin-amd64-cgo), method (Handle) Value() interface{} -pkg runtime/cgo (darwin-amd64-cgo), type Handle uintptr -pkg runtime/cgo (freebsd-386-cgo), func NewHandle(interface{}) Handle -pkg runtime/cgo (freebsd-386-cgo), method (Handle) Delete() -pkg runtime/cgo (freebsd-386-cgo), method (Handle) Value() interface{} -pkg runtime/cgo (freebsd-386-cgo), type Handle uintptr -pkg runtime/cgo (freebsd-amd64-cgo), func NewHandle(interface{}) Handle -pkg runtime/cgo (freebsd-amd64-cgo), method (Handle) Delete() -pkg runtime/cgo (freebsd-amd64-cgo), method (Handle) Value() interface{} -pkg runtime/cgo (freebsd-amd64-cgo), type Handle uintptr -pkg runtime/cgo (freebsd-arm-cgo), func NewHandle(interface{}) Handle -pkg runtime/cgo (freebsd-arm-cgo), method (Handle) Delete() -pkg runtime/cgo (freebsd-arm-cgo), method (Handle) Value() interface{} -pkg runtime/cgo (freebsd-arm-cgo), type Handle uintptr -pkg runtime/cgo (linux-386-cgo), func NewHandle(interface{}) Handle -pkg runtime/cgo (linux-386-cgo), method (Handle) Delete() -pkg runtime/cgo (linux-386-cgo), method (Handle) Value() interface{} -pkg runtime/cgo (linux-386-cgo), type Handle uintptr -pkg runtime/cgo (linux-amd64-cgo), func NewHandle(interface{}) Handle -pkg runtime/cgo (linux-amd64-cgo), method (Handle) Delete() -pkg runtime/cgo (linux-amd64-cgo), method (Handle) Value() interface{} -pkg runtime/cgo (linux-amd64-cgo), type Handle uintptr -pkg runtime/cgo (linux-arm-cgo), func NewHandle(interface{}) Handle -pkg runtime/cgo (linux-arm-cgo), method (Handle) Delete() -pkg runtime/cgo (linux-arm-cgo), method (Handle) Value() interface{} -pkg runtime/cgo (linux-arm-cgo), type Handle uintptr -pkg runtime/cgo (netbsd-386-cgo), func NewHandle(interface{}) Handle -pkg runtime/cgo (netbsd-386-cgo), method (Handle) Delete() -pkg runtime/cgo (netbsd-386-cgo), method (Handle) Value() interface{} -pkg runtime/cgo (netbsd-386-cgo), type Handle uintptr -pkg runtime/cgo (netbsd-amd64-cgo), func NewHandle(interface{}) Handle -pkg runtime/cgo (netbsd-amd64-cgo), method (Handle) Delete() -pkg runtime/cgo (netbsd-amd64-cgo), method (Handle) Value() interface{} -pkg runtime/cgo (netbsd-amd64-cgo), type Handle uintptr -pkg runtime/cgo (netbsd-arm-cgo), func NewHandle(interface{}) Handle -pkg runtime/cgo (netbsd-arm-cgo), method (Handle) Delete() -pkg runtime/cgo (netbsd-arm-cgo), method (Handle) Value() interface{} -pkg runtime/cgo (netbsd-arm-cgo), type Handle uintptr -pkg runtime/cgo (netbsd-arm64-cgo), func NewHandle(interface{}) Handle -pkg runtime/cgo (netbsd-arm64-cgo), method (Handle) Delete() -pkg runtime/cgo (netbsd-arm64-cgo), method (Handle) Value() interface{} -pkg runtime/cgo (netbsd-arm64-cgo), type Handle uintptr -pkg runtime/cgo (openbsd-386-cgo), func NewHandle(interface{}) Handle -pkg runtime/cgo (openbsd-386-cgo), method (Handle) Delete() -pkg runtime/cgo (openbsd-386-cgo), method (Handle) Value() interface{} -pkg runtime/cgo (openbsd-386-cgo), type Handle uintptr -pkg runtime/cgo (openbsd-amd64-cgo), func NewHandle(interface{}) Handle -pkg runtime/cgo (openbsd-amd64-cgo), method (Handle) Delete() -pkg runtime/cgo (openbsd-amd64-cgo), method (Handle) Value() interface{} -pkg runtime/cgo (openbsd-amd64-cgo), type Handle uintptr -pkg syscall (openbsd-386), const MSG_CMSG_CLOEXEC = 2048 -pkg syscall (openbsd-386), const MSG_CMSG_CLOEXEC ideal-int -pkg syscall (openbsd-386-cgo), const MSG_CMSG_CLOEXEC = 2048 -pkg syscall (openbsd-386-cgo), const MSG_CMSG_CLOEXEC ideal-int -pkg syscall (openbsd-amd64), const MSG_CMSG_CLOEXEC = 2048 -pkg syscall (openbsd-amd64), const MSG_CMSG_CLOEXEC ideal-int -pkg syscall (openbsd-amd64-cgo), const MSG_CMSG_CLOEXEC = 2048 -pkg syscall (openbsd-amd64-cgo), const MSG_CMSG_CLOEXEC ideal-int -pkg syscall (windows-386), type SysProcAttr struct, AdditionalInheritedHandles []Handle -pkg syscall (windows-386), type SysProcAttr struct, ParentProcess Handle -pkg syscall (windows-amd64), type SysProcAttr struct, AdditionalInheritedHandles []Handle -pkg syscall (windows-amd64), type SysProcAttr struct, ParentProcess Handle -pkg testing, method (*B) Setenv(string, string) -pkg testing, method (*T) Setenv(string, string) -pkg text/template/parse, const SkipFuncCheck = 2 -pkg text/template/parse, const SkipFuncCheck Mode -pkg time, func UnixMicro(int64) Time -pkg time, func UnixMilli(int64) Time -pkg time, method (*Time) IsDST() bool -pkg time, method (Time) UnixMicro() int64 -pkg time, method (Time) UnixMilli() int64 From dc00dc6c6bf3b5554e37f60799aec092276ff807 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 7 Jun 2021 08:24:22 -0400 Subject: [PATCH 368/940] crypto/tls: let HTTP/1.1 clients connect to servers with NextProtos "h2" Fixes #46310 Change-Id: Idd5e30f05c439f736ae6f3904cbb9cc2ba772315 Reviewed-on: https://go-review.googlesource.com/c/go/+/325432 Trust: Filippo Valsorda Run-TryBot: Filippo Valsorda TryBot-Result: Go Bot Reviewed-by: Roland Shoemaker --- src/crypto/tls/handshake_client.go | 44 ++++---- src/crypto/tls/handshake_client_tls13.go | 14 +-- src/crypto/tls/handshake_server.go | 42 ++++++-- src/crypto/tls/handshake_server_test.go | 21 ++++ src/crypto/tls/handshake_server_tls13.go | 15 ++- .../tls/testdata/Server-TLSv12-ALPN-Fallback | 91 ++++++++++++++++ .../tls/testdata/Server-TLSv13-ALPN-Fallback | 100 ++++++++++++++++++ 7 files changed, 277 insertions(+), 50 deletions(-) create mode 100644 src/crypto/tls/testdata/Server-TLSv12-ALPN-Fallback create mode 100644 src/crypto/tls/testdata/Server-TLSv13-ALPN-Fallback diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go index 13a7f3442c9..4af3d998a36 100644 --- a/src/crypto/tls/handshake_client.go +++ b/src/crypto/tls/handshake_client.go @@ -711,17 +711,11 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) { } } - if hs.serverHello.alpnProtocol != "" { - if len(hs.hello.alpnProtocols) == 0 { - c.sendAlert(alertUnsupportedExtension) - return false, errors.New("tls: server advertised unrequested ALPN extension") - } - if mutualProtocol([]string{hs.serverHello.alpnProtocol}, hs.hello.alpnProtocols) == "" { - c.sendAlert(alertUnsupportedExtension) - return false, errors.New("tls: server selected unadvertised ALPN protocol") - } - c.clientProtocol = hs.serverHello.alpnProtocol + if err := checkALPN(hs.hello.alpnProtocols, hs.serverHello.alpnProtocol); err != nil { + c.sendAlert(alertUnsupportedExtension) + return false, err } + c.clientProtocol = hs.serverHello.alpnProtocol c.scts = hs.serverHello.scts @@ -753,6 +747,23 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) { return true, nil } +// checkALPN ensure that the server's choice of ALPN protocol is compatible with +// the protocols that we advertised in the Client Hello. +func checkALPN(clientProtos []string, serverProto string) error { + if serverProto == "" { + return nil + } + if len(clientProtos) == 0 { + return errors.New("tls: server advertised unrequested ALPN extension") + } + for _, proto := range clientProtos { + if proto == serverProto { + return nil + } + } + return errors.New("tls: server selected unadvertised ALPN protocol") +} + func (hs *clientHandshakeState) readFinished(out []byte) error { c := hs.c @@ -979,19 +990,6 @@ func clientSessionCacheKey(serverAddr net.Addr, config *Config) string { return serverAddr.String() } -// mutualProtocol finds the mutual ALPN protocol given list of possible -// protocols and a list of the preference order. -func mutualProtocol(protos, preferenceProtos []string) string { - for _, s := range preferenceProtos { - for _, c := range protos { - if s == c { - return s - } - } - } - return "" -} - // hostnameInSNI converts name into an appropriate hostname for SNI. // Literal IP addresses and absolute FQDNs are not permitted as SNI values. // See RFC 6066, Section 3. diff --git a/src/crypto/tls/handshake_client_tls13.go b/src/crypto/tls/handshake_client_tls13.go index be37c681c6d..eb59ac90d11 100644 --- a/src/crypto/tls/handshake_client_tls13.go +++ b/src/crypto/tls/handshake_client_tls13.go @@ -396,17 +396,11 @@ func (hs *clientHandshakeStateTLS13) readServerParameters() error { } hs.transcript.Write(encryptedExtensions.marshal()) - if encryptedExtensions.alpnProtocol != "" { - if len(hs.hello.alpnProtocols) == 0 { - c.sendAlert(alertUnsupportedExtension) - return errors.New("tls: server advertised unrequested ALPN extension") - } - if mutualProtocol([]string{encryptedExtensions.alpnProtocol}, hs.hello.alpnProtocols) == "" { - c.sendAlert(alertUnsupportedExtension) - return errors.New("tls: server selected unadvertised ALPN protocol") - } - c.clientProtocol = encryptedExtensions.alpnProtocol + if err := checkALPN(hs.hello.alpnProtocols, encryptedExtensions.alpnProtocol); err != nil { + c.sendAlert(alertUnsupportedExtension) + return err } + c.clientProtocol = encryptedExtensions.alpnProtocol return nil } diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go index b231981e09f..43f30e2fefd 100644 --- a/src/crypto/tls/handshake_server.go +++ b/src/crypto/tls/handshake_server.go @@ -217,15 +217,13 @@ func (hs *serverHandshakeState) processClientHello() error { c.serverName = hs.clientHello.serverName } - if len(c.config.NextProtos) > 0 && len(hs.clientHello.alpnProtocols) > 0 { - selectedProto := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos) - if selectedProto == "" { - c.sendAlert(alertNoApplicationProtocol) - return fmt.Errorf("tls: client requested unsupported application protocols (%s)", hs.clientHello.alpnProtocols) - } - hs.hello.alpnProtocol = selectedProto - c.clientProtocol = selectedProto + selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols) + if err != nil { + c.sendAlert(alertNoApplicationProtocol) + return err } + hs.hello.alpnProtocol = selectedProto + c.clientProtocol = selectedProto hs.cert, err = c.config.getCertificate(clientHelloInfo(hs.ctx, c, hs.clientHello)) if err != nil { @@ -277,6 +275,34 @@ func (hs *serverHandshakeState) processClientHello() error { return nil } +// negotiateALPN picks a shared ALPN protocol that both sides support in server +// preference order. If ALPN is not configured or the peer doesn't support it, +// it returns "" and no error. +func negotiateALPN(serverProtos, clientProtos []string) (string, error) { + if len(serverProtos) == 0 || len(clientProtos) == 0 { + return "", nil + } + var http11fallback bool + for _, s := range serverProtos { + for _, c := range clientProtos { + if s == c { + return s, nil + } + if s == "h2" && c == "http/1.1" { + http11fallback = true + } + } + } + // As a special case, let http/1.1 clients connect to h2 servers as if they + // didn't support ALPN. We used not to enforce protocol overlap, so over + // time a number of HTTP servers were configured with only "h2", but + // expected to accept connections from "http/1.1" clients. See Issue 46310. + if http11fallback { + return "", nil + } + return "", fmt.Errorf("tls: client requested unsupported application protocols (%s)", clientProtos) +} + // supportsECDHE returns whether ECDHE key exchanges can be used with this // pre-TLS 1.3 client. func supportsECDHE(c *Config, supportedCurves []CurveID, supportedPoints []uint8) bool { diff --git a/src/crypto/tls/handshake_server_test.go b/src/crypto/tls/handshake_server_test.go index 4483838045c..f61b4c88efa 100644 --- a/src/crypto/tls/handshake_server_test.go +++ b/src/crypto/tls/handshake_server_test.go @@ -949,6 +949,27 @@ func TestHandshakeServerALPNNotConfigured(t *testing.T) { runServerTestTLS13(t, test) } +func TestHandshakeServerALPNFallback(t *testing.T) { + config := testConfig.Clone() + config.NextProtos = []string{"proto1", "h2", "proto2"} + + test := &serverTest{ + name: "ALPN-Fallback", + // Note that this needs OpenSSL 1.0.2 because that is the first + // version that supports the -alpn flag. + command: []string{"openssl", "s_client", "-alpn", "proto3,http/1.1,proto4", "-cipher", "ECDHE-RSA-CHACHA20-POLY1305", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256"}, + config: config, + validate: func(state ConnectionState) error { + if state.NegotiatedProtocol != "" { + return fmt.Errorf("Got protocol %q, wanted nothing", state.NegotiatedProtocol) + } + return nil + }, + } + runServerTestTLS12(t, test) + runServerTestTLS13(t, test) +} + // TestHandshakeServerSNI involves a client sending an SNI extension of // "snitest.com", which happens to match the CN of testSNICertificate. The test // verifies that the server correctly selects that certificate. diff --git a/src/crypto/tls/handshake_server_tls13.go b/src/crypto/tls/handshake_server_tls13.go index c375ec42466..08251b84def 100644 --- a/src/crypto/tls/handshake_server_tls13.go +++ b/src/crypto/tls/handshake_server_tls13.go @@ -11,7 +11,6 @@ import ( "crypto/hmac" "crypto/rsa" "errors" - "fmt" "hash" "io" "sync/atomic" @@ -551,15 +550,13 @@ func (hs *serverHandshakeStateTLS13) sendServerParameters() error { encryptedExtensions := new(encryptedExtensionsMsg) - if len(c.config.NextProtos) > 0 && len(hs.clientHello.alpnProtocols) > 0 { - selectedProto := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos) - if selectedProto == "" { - c.sendAlert(alertNoApplicationProtocol) - return fmt.Errorf("tls: client requested unsupported application protocols (%s)", hs.clientHello.alpnProtocols) - } - encryptedExtensions.alpnProtocol = selectedProto - c.clientProtocol = selectedProto + selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols) + if err != nil { + c.sendAlert(alertNoApplicationProtocol) + return err } + encryptedExtensions.alpnProtocol = selectedProto + c.clientProtocol = selectedProto hs.transcript.Write(encryptedExtensions.marshal()) if _, err := c.writeRecord(recordTypeHandshake, encryptedExtensions.marshal()); err != nil { diff --git a/src/crypto/tls/testdata/Server-TLSv12-ALPN-Fallback b/src/crypto/tls/testdata/Server-TLSv12-ALPN-Fallback new file mode 100644 index 00000000000..4fadf390623 --- /dev/null +++ b/src/crypto/tls/testdata/Server-TLSv12-ALPN-Fallback @@ -0,0 +1,91 @@ +>>> Flow 1 (client to server) +00000000 16 03 01 00 a6 01 00 00 a2 03 03 b5 c9 ab 32 7f |..............2.| +00000010 e1 af 3f f2 ac 2a 11 dd 33 f9 b5 21 88 0d e4 29 |..?..*..3..!...)| +00000020 e2 47 49 dc c7 31 a8 a5 25 81 0c 00 00 04 cc a8 |.GI..1..%.......| +00000030 00 ff 01 00 00 75 00 0b 00 04 03 00 01 02 00 0a |.....u..........| +00000040 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 23 |...............#| +00000050 00 00 00 10 00 19 00 17 06 70 72 6f 74 6f 33 08 |.........proto3.| +00000060 68 74 74 70 2f 31 2e 31 06 70 72 6f 74 6f 34 00 |http/1.1.proto4.| +00000070 16 00 00 00 17 00 00 00 0d 00 30 00 2e 04 03 05 |..........0.....| +00000080 03 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 |................| +00000090 05 08 06 04 01 05 01 06 01 03 03 02 03 03 01 02 |................| +000000a0 01 03 02 02 02 04 02 05 02 06 02 |...........| +>>> Flow 2 (server to client) +00000000 16 03 03 00 3b 02 00 00 37 03 03 00 00 00 00 00 |....;...7.......| +00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 cc a8 00 00 |...DOWNGRD......| +00000030 0f 00 23 00 00 ff 01 00 01 00 00 0b 00 02 01 00 |..#.............| +00000040 16 03 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 |....Y...U..R..O0| +00000050 82 02 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 |..K0............| +00000060 f0 9d 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 |..?.[..0...*.H..| +00000070 0d 01 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 |......0.1.0...U.| +00000080 0a 13 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 |...Go1.0...U....| +00000090 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 |Go Root0...16010| +000000a0 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 |1000000Z..250101| +000000b0 30 30 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 |000000Z0.1.0...U| +000000c0 04 0a 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 |....Go1.0...U...| +000000d0 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d |.Go0..0...*.H...| +000000e0 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 |.........0......| +000000f0 db 46 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 |.F}...'.H..(!.~.| +00000100 b6 a2 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 |..]..RE.z6G....B| +00000110 5b c2 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 |[.....y.@.Om..+.| +00000120 8b c2 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 |....g....."8.J.t| +00000130 73 2b c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c |s+.4......t{.X.l| +00000140 61 3c c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd |a<..A..++$#w[.;.| +00000150 75 5d ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a |u]. T..c...$....| +00000160 50 8b aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 |P....C...ub...R.| +00000170 02 03 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 |........0..0...U| +00000180 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 |...........0...U| +00000190 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......| +000001a0 06 08 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d |..+.......0...U.| +000001b0 13 01 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 |......0.0...U...| +000001c0 12 04 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 |.......CC>I..m..| +000001d0 d7 9f 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 |..`0...U.#..0...| +000001e0 48 13 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b |H.IM.~.1......n{| +000001f0 30 19 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 |0...U....0...exa| +00000200 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a |mple.golang0...*| +00000210 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 |.H.............0| +00000220 cc 40 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 |.@+[P.a...SX...(| +00000230 a9 58 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 |.X..8....1Z..f=C| +00000240 d3 2d d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc |.-...... d8.$:..| +00000250 cf 9c 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd |..}.@ ._...a..v.| +00000260 13 c3 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb |.....\.....l..s.| +00000270 b3 43 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 |.Cw.......@.a.Lr| +00000280 2b 9d ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 |+...F..M...>...B| +00000290 d4 db fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 |...=.`.\!.;.....| +000002a0 03 00 ac 0c 00 00 a8 03 00 1d 20 2f e5 7d a3 47 |.......... /.}.G| +000002b0 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af |.bC.(.._.).0....| +000002c0 c4 cf c2 ed 90 99 5f 58 cb 3b 74 08 04 00 80 5f |......_X.;t...._| +000002d0 37 27 84 58 1e ea 1e 40 1b de a9 8f 04 d4 94 64 |7'.X...@.......d| +000002e0 4e 27 c7 f1 b3 30 d0 53 f5 3d 57 50 d2 17 97 c8 |N'...0.S.=WP....| +000002f0 3d 61 af a6 21 ab 1c 34 47 70 f8 b1 3b 9c 06 86 |=a..!..4Gp..;...| +00000300 87 00 e2 13 50 83 91 ad bc 84 bd b4 7b f3 4b ed |....P.......{.K.| +00000310 ca 81 0c 94 37 a8 ec 67 ca 9c f3 00 f6 af c2 92 |....7..g........| +00000320 c4 8c 78 07 18 0e 43 24 1b 98 16 50 5c 2b 75 0e |..x...C$...P\+u.| +00000330 40 66 dc 40 cd 10 1a 51 25 f3 96 25 1a 3e 70 af |@f.@...Q%..%.>p.| +00000340 16 24 d0 1c 0e 33 f9 c1 74 cf b7 e2 28 ac 60 16 |.$...3..t...(.`.| +00000350 03 03 00 04 0e 00 00 00 |........| +>>> Flow 3 (client to server) +00000000 16 03 03 00 25 10 00 00 21 20 30 f2 bb f7 a7 ac |....%...! 0.....| +00000010 23 20 22 ee 73 0d 49 9c b3 7b c1 9a db 2c 85 f3 |# ".s.I..{...,..| +00000020 c0 82 31 60 bd 8b 14 4e 73 43 14 03 03 00 01 01 |..1`...NsC......| +00000030 16 03 03 00 20 09 8d c7 86 ee cc f4 c7 36 a3 49 |.... ........6.I| +00000040 d3 f7 a1 4a 68 a2 1e b4 fc cc a2 15 cb 01 92 d8 |...Jh...........| +00000050 72 b0 d1 6f eb |r..o.| +>>> Flow 4 (server to client) +00000000 16 03 03 00 8b 04 00 00 87 00 00 00 00 00 81 50 |...............P| +00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................| +00000030 6f e0 18 83 51 ed 14 ef 68 ca 42 c5 4c a2 ac 05 |o...Q...h.B.L...| +00000040 9c 69 69 99 08 9f de a4 d4 e7 37 ab 14 38 4c 47 |.ii.......7..8LG| +00000050 70 f0 97 1d db 2d 0a 14 c2 1e f0 16 9f 6d 37 02 |p....-.......m7.| +00000060 4b f1 16 be 98 3f df 74 83 7c 19 85 61 49 38 16 |K....?.t.|..aI8.| +00000070 ee 35 7a e2 3f 74 fe 8d e3 07 93 a1 5e fa f2 02 |.5z.?t......^...| +00000080 e5 c8 60 3f 11 83 8b 0e 32 52 f1 aa 52 b7 0a 89 |..`?....2R..R...| +00000090 14 03 03 00 01 01 16 03 03 00 20 9e 65 15 cf 45 |.......... .e..E| +000000a0 a5 03 69 c9 b1 d8 9e 92 a3 a2 b0 df 2e 62 b1 3a |..i..........b.:| +000000b0 17 78 cd e5 1d f3 51 42 7e 4e 25 17 03 03 00 1d |.x....QB~N%.....| +000000c0 d9 ae d0 fa b7 90 a9 2f 28 8d 1d 6f 54 1f c0 1e |......./(..oT...| +000000d0 4d ae b6 91 f0 e8 84 cf 86 11 22 25 ea 15 03 03 |M........."%....| +000000e0 00 12 0e 71 f2 11 9e 9f 58 ad c0 d8 fc fa 34 bc |...q....X.....4.| +000000f0 02 5a 60 00 |.Z`.| diff --git a/src/crypto/tls/testdata/Server-TLSv13-ALPN-Fallback b/src/crypto/tls/testdata/Server-TLSv13-ALPN-Fallback new file mode 100644 index 00000000000..6203e6877cd --- /dev/null +++ b/src/crypto/tls/testdata/Server-TLSv13-ALPN-Fallback @@ -0,0 +1,100 @@ +>>> Flow 1 (client to server) +00000000 16 03 01 00 eb 01 00 00 e7 03 03 1c d3 8e 3b d9 |..............;.| +00000010 fe 7d e7 f9 9f fa c6 51 c3 8c 1b dd dc 87 95 f4 |.}.....Q........| +00000020 39 23 67 e4 d6 bd 94 93 fc 88 4e 20 c3 c0 e2 c1 |9#g.......N ....| +00000030 3d 12 ec 4c 0a 3f 40 51 13 24 61 11 c0 5d 09 f9 |=..L.?@Q.$a..]..| +00000040 08 d6 3e cd e7 b3 51 c3 06 8f b4 42 00 04 13 03 |..>...Q....B....| +00000050 00 ff 01 00 00 9a 00 0b 00 04 03 00 01 02 00 0a |................| +00000060 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 23 |...............#| +00000070 00 00 00 10 00 19 00 17 06 70 72 6f 74 6f 33 08 |.........proto3.| +00000080 68 74 74 70 2f 31 2e 31 06 70 72 6f 74 6f 34 00 |http/1.1.proto4.| +00000090 16 00 00 00 17 00 00 00 0d 00 1e 00 1c 04 03 05 |................| +000000a0 03 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 |................| +000000b0 05 08 06 04 01 05 01 06 01 00 2b 00 03 02 03 04 |..........+.....| +000000c0 00 2d 00 02 01 01 00 33 00 26 00 24 00 1d 00 20 |.-.....3.&.$... | +000000d0 f4 05 eb 4a 7a 73 20 18 74 aa 14 2a 0c 35 63 29 |...Jzs .t..*.5c)| +000000e0 cb f2 ad d1 a2 3d bd 9d 02 b4 62 00 bc eb 10 58 |.....=....b....X| +>>> Flow 2 (server to client) +00000000 16 03 03 00 7a 02 00 00 76 03 03 00 00 00 00 00 |....z...v.......| +00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000020 00 00 00 00 00 00 00 00 00 00 00 20 c3 c0 e2 c1 |........... ....| +00000030 3d 12 ec 4c 0a 3f 40 51 13 24 61 11 c0 5d 09 f9 |=..L.?@Q.$a..]..| +00000040 08 d6 3e cd e7 b3 51 c3 06 8f b4 42 13 03 00 00 |..>...Q....B....| +00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 2f |..+.....3.$... /| +00000060 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0| +00000070 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 14 |.........._X.;t.| +00000080 03 03 00 01 01 17 03 03 00 17 fb 75 d8 5c 50 35 |...........u.\P5| +00000090 55 82 ba 65 1e 63 73 b8 c1 e9 d7 f5 28 68 3c c1 |U..e.cs.....(h<.| +000000a0 5d 17 03 03 02 6d 56 c9 a9 09 73 6a bc fd 1a 3c |]....mV...sj...<| +000000b0 6a f8 3e 32 99 83 e8 f6 01 9e 5e 30 e8 53 7f 72 |j.>2......^0.S.r| +000000c0 fd 86 72 a8 9e 47 25 67 c1 f1 9a 03 c0 9d 6f 9d |..r..G%g......o.| +000000d0 bd ed 29 30 8f 3c 01 ce 49 bb 5f dd 58 9a ae 80 |..)0.<..I._.X...| +000000e0 5c 2d 81 fc ea 7b 03 03 3d 5d bb 92 23 73 67 89 |\-...{..=]..#sg.| +000000f0 2e f0 ec 08 20 8a 36 eb 43 a6 a1 68 d0 39 95 37 |.... .6.C..h.9.7| +00000100 6b 15 a9 0e 46 20 92 51 9c 04 bf 3b 07 97 84 cb |k...F .Q...;....| +00000110 1f 30 38 37 2e ff e7 0f f5 14 93 5a 84 f1 f7 10 |.087.......Z....| +00000120 c2 a5 0d bb 97 96 ef 4a e0 13 c0 63 72 2b 60 f3 |.......J...cr+`.| +00000130 59 b5 57 aa 5f d1 da a9 0e dd 9c dd c2 cb 61 fe |Y.W._.........a.| +00000140 e2 69 8e db 5d 70 6c 3a 33 e0 9e db 9a 31 26 6a |.i..]pl:3....1&j| +00000150 2b 9e 19 8e bb 5d 06 48 ea c0 a1 c6 11 24 fb c4 |+....].H.....$..| +00000160 ce ae 48 54 64 81 d1 84 38 a6 e0 7a 7b 74 2b bc |..HTd...8..z{t+.| +00000170 ce 07 8b b6 04 1f 5b 4c 36 29 68 0c 8c c7 32 15 |......[L6)h...2.| +00000180 93 e0 10 52 c2 27 23 96 c5 0c 9c e9 e2 a9 08 7d |...R.'#........}| +00000190 25 68 65 f5 4e 44 eb a9 85 78 13 e1 0d 86 5e dc |%he.ND...x....^.| +000001a0 fd e5 c6 dd 65 46 8e 2f 32 82 83 0b dd 67 f8 42 |....eF./2....g.B| +000001b0 65 87 3b 08 fe b1 f5 12 e9 74 21 04 12 6d 75 35 |e.;......t!..mu5| +000001c0 b2 eb 93 95 72 10 fa 56 96 77 c3 0c 17 8c 9e f6 |....r..V.w......| +000001d0 77 19 28 37 96 3e 73 98 f4 d2 91 4f 40 db 76 56 |w.(7.>s....O@.vV| +000001e0 ce b5 a8 7a b8 86 d0 9a ba b5 8b 40 c2 63 e1 cf |...z.......@.c..| +000001f0 49 29 2c 5d 1a 9b 8b 56 cb 93 ca 2c c0 d0 15 b7 |I),]...V...,....| +00000200 8a f1 6a d5 0a a8 81 57 b1 6e 10 cd a5 ff b1 4d |..j....W.n.....M| +00000210 47 c6 9b 35 f1 5f 83 91 22 f6 88 68 65 b3 b9 c9 |G..5._.."..he...| +00000220 02 dc 4b f7 13 39 06 e6 3a ec 94 ef 51 15 05 72 |..K..9..:...Q..r| +00000230 1d f4 9d 3b da ca 8d 2c 64 be 9b 45 99 2c 63 cc |...;...,d..E.,c.| +00000240 22 b3 8b 93 ad f6 2c f0 d2 d9 11 3f 5b c0 40 fa |".....,....?[.@.| +00000250 90 6e a0 76 b2 43 b9 4c 72 c4 24 28 a2 bf 56 d6 |.n.v.C.Lr.$(..V.| +00000260 d2 a7 2a d1 8c 5e 1d eb f8 be d0 43 da 7a c7 88 |..*..^.....C.z..| +00000270 61 67 a2 69 85 23 43 3e d4 88 f2 33 c3 5b 38 0a |ag.i.#C>...3.[8.| +00000280 1e de 28 3b 3b 19 de 95 2f 84 c0 37 88 80 59 2f |..(;;.../..7..Y/| +00000290 a6 ee 93 1a 69 08 c3 df 7c cf da c3 9b 96 70 d9 |....i...|.....p.| +000002a0 60 c5 e9 0f 42 f6 1a f2 58 5e f2 32 61 6a b2 a3 |`...B...X^.2aj..| +000002b0 1f 97 fa 08 6c 3f 4b 83 1f 04 66 80 8a 26 3a 7f |....l?K...f..&:.| +000002c0 24 30 ec 10 ae 7d 19 ff 39 91 ca 97 4e ed 0a d7 |$0...}..9...N...| +000002d0 64 3b 6b 50 29 33 0d b2 10 bc 83 63 3c fb 9a 82 |d;kP)3.....c<...| +000002e0 3b 7f bc 04 40 f1 33 64 4a 80 cd 01 f9 f4 c6 89 |;...@.3dJ.......| +000002f0 65 27 25 f9 cf 4f 7e c8 6e d9 0e ec 47 4a 51 29 |e'%..O~.n...GJQ)| +00000300 2f be 34 50 bd 9b d2 d8 b7 ea bb 0b a1 e0 20 1b |/.4P.......... .| +00000310 02 9c f2 17 03 03 00 99 61 dc 0b 3a 30 de 39 f6 |........a..:0.9.| +00000320 f3 db f8 6c 3b fa 4e 1e 7e 62 a5 ae 73 ba e1 41 |...l;.N.~b..s..A| +00000330 58 77 2a c1 7a 0c 50 bb 0c 57 b4 c4 25 bf 2f 9f |Xw*.z.P..W..%./.| +00000340 38 91 e2 65 22 9d ca ac 18 58 7e 81 2d fd 74 24 |8..e"....X~.-.t$| +00000350 28 69 76 11 df 9d 23 b8 be ae 8b e0 93 8e 5d df |(iv...#.......].| +00000360 0a 64 d0 b7 02 68 aa 86 01 0d 55 11 3b 76 70 c6 |.d...h....U.;vp.| +00000370 83 0c 5e 0a e3 37 a5 8b ad 25 50 b9 e8 5c 6b 04 |..^..7...%P..\k.| +00000380 b4 51 ec 9c d3 fa c6 b7 9c f0 46 aa 73 da 3c 0d |.Q........F.s.<.| +00000390 d3 bd 32 81 d4 d2 f1 1a b0 92 f3 73 3e 54 2b 05 |..2........s>T+.| +000003a0 92 24 34 75 df d6 18 a0 6a 82 95 4c 9b fc 7e b6 |.$4u....j..L..~.| +000003b0 8e 17 03 03 00 35 8f 34 0e 3b 91 d8 e7 74 24 71 |.....5.4.;...t$q| +000003c0 0e 7b f3 12 bb 76 2f 31 12 17 b8 9e 24 ce f9 2f |.{...v/1....$../| +000003d0 3f 5d f2 13 4b 2e 9b 1e c4 78 03 a6 c8 07 11 a3 |?]..K....x......| +000003e0 98 79 61 6e 4f 44 6e 18 ee c4 9b 17 03 03 00 93 |.yanODn.........| +000003f0 64 dd 52 a9 d9 51 63 6a a0 a3 c2 75 6b 5d 1d 54 |d.R..Qcj...uk].T| +00000400 ce d4 53 7e 14 8e d9 26 93 28 78 65 16 1b 95 77 |..S~...&.(xe...w| +00000410 68 0a 46 f1 82 36 bb 8a fa 0d df 54 8c 3d 83 e0 |h.F..6.....T.=..| +00000420 d7 de 2d 96 e9 c4 d7 22 d3 97 8e ae 90 f8 fc e6 |..-...."........| +00000430 a6 4b 78 98 4c c5 28 87 91 46 fa f4 1c 8d 0e ec |.Kx.L.(..F......| +00000440 0d 71 40 9a 04 49 b4 e8 5b 62 6f cd 16 c1 d5 fb |.q@..I..[bo.....| +00000450 73 2a 96 8f e5 a2 f4 11 1e df 2d 40 45 6b d5 a9 |s*........-@Ek..| +00000460 e4 e3 f7 93 fc fa d7 20 af d5 f7 b4 0e 09 ad d5 |....... ........| +00000470 26 87 b8 6c e2 20 95 fb c0 70 3e 38 be b7 b1 9f |&..l. ...p>8....| +00000480 70 da c1 |p..| +>>> Flow 3 (client to server) +00000000 14 03 03 00 01 01 17 03 03 00 35 29 d2 b9 bb 9b |..........5)....| +00000010 de 6c 5d 22 23 c1 fe 99 4c c5 33 bf fd 70 36 6b |.l]"#...L.3..p6k| +00000020 f1 a5 92 e8 bf 7c 3d 6e ef 6a 44 73 bc cb 27 1c |.....|=n.jDs..'.| +00000030 09 5d bf 99 4c 19 24 c3 3b 30 91 b5 e3 b6 63 45 |.]..L.$.;0....cE| +>>> Flow 4 (server to client) +00000000 17 03 03 00 1e 52 55 85 7c b8 87 dd c7 b2 d9 5b |.....RU.|......[| +00000010 18 1d bb ac bf b6 ab 76 82 be 64 0e b2 7b 2c 0f |.......v..d..{,.| +00000020 aa 17 92 17 03 03 00 13 79 0a 60 b1 46 20 33 74 |........y.`.F 3t| +00000030 ed 12 a0 23 de 68 88 fc 6f dd 8e |...#.h..o..| From 8d11b1d1172817359d08231deaf29f72d315b762 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Tue, 8 Jun 2021 15:53:08 -0400 Subject: [PATCH 369/940] cmd/go: report the imports of CompiledGoFiles in ImportMap Ideally we should encode the load.PackageInternal data in a way that doesn't rely on 1:1 correlations of slices, but this is a minimal fix to unblock Go 1.17. Fixes #46462 Change-Id: I6e029c69f757aadc54d4be02c01d6b294c217542 Reviewed-on: https://go-review.googlesource.com/c/go/+/326610 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills Reviewed-by: Michael Matloob TryBot-Result: Go Bot --- src/cmd/go/internal/list/list.go | 14 ++++++- src/cmd/go/internal/load/pkg.go | 4 +- .../script/list_cgo_compiled_importmap.txt | 38 +++++++++++++++++++ 3 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 src/cmd/go/testdata/script/list_cgo_compiled_importmap.txt diff --git a/src/cmd/go/internal/list/list.go b/src/cmd/go/internal/list/list.go index 53aaf311ec4..7cb9ec6d949 100644 --- a/src/cmd/go/internal/list/list.go +++ b/src/cmd/go/internal/list/list.go @@ -724,8 +724,18 @@ func runList(ctx context.Context, cmd *base.Command, args []string) { // Record non-identity import mappings in p.ImportMap. for _, p := range pkgs { - for i, srcPath := range p.Internal.RawImports { - path := p.Imports[i] + nRaw := len(p.Internal.RawImports) + for i, path := range p.Imports { + var srcPath string + if i < nRaw { + srcPath = p.Internal.RawImports[i] + } else { + // This path is not within the raw imports, so it must be an import + // found only within CompiledGoFiles. Those paths are found in + // CompiledImports. + srcPath = p.Internal.CompiledImports[i-nRaw] + } + if path != srcPath { if p.ImportMap == nil { p.ImportMap = make(map[string]string) diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 738904865e2..a83cc9a812b 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -194,8 +194,8 @@ type PackageInternal struct { // Unexported fields are not part of the public API. Build *build.Package Imports []*Package // this package's direct imports - CompiledImports []string // additional Imports necessary when using CompiledGoFiles (all from standard library) - RawImports []string // this package's original imports as they appear in the text of the program + CompiledImports []string // additional Imports necessary when using CompiledGoFiles (all from standard library); 1:1 with the end of PackagePublic.Imports + RawImports []string // this package's original imports as they appear in the text of the program; 1:1 with the end of PackagePublic.Imports ForceLibrary bool // this package is a library (even if named "main") CmdlineFiles bool // package built from files listed on command line CmdlinePkg bool // package listed on command line diff --git a/src/cmd/go/testdata/script/list_cgo_compiled_importmap.txt b/src/cmd/go/testdata/script/list_cgo_compiled_importmap.txt new file mode 100644 index 00000000000..3d68ef30559 --- /dev/null +++ b/src/cmd/go/testdata/script/list_cgo_compiled_importmap.txt @@ -0,0 +1,38 @@ +# Regression test for https://golang.org/issue/46462. +# +# The "runtime/cgo" import found in synthesized .go files (reported in +# the CompiledGoFiles field) should have a corresponding entry in the +# ImportMap field when a runtime/cgo variant (such as a test variant) +# will be used. + +[short] skip # -compiled can be slow (because it compiles things) +[!cgo] skip + +env CGO_ENABLED=1 +env GOFLAGS=-tags=netcgo # Force net to use cgo even on Windows. + + +# "runtime/cgo [runtime.test]" appears in the the test dependencies of "runtime", +# because "runtime/cgo" itself depends on "runtime" + +go list -deps -test -compiled -f '{{if eq .ImportPath "net [runtime.test]"}}{{printf "%q" .Imports}}{{end}}' runtime + + # Control case: the explicitly-imported package "sync" is a test variant, + # because "sync" depends on "runtime". +stdout '"sync \[runtime\.test\]"' +! stdout '"sync"' + + # Experiment: the implicitly-imported package "runtime/cgo" is also a test variant, + # because "runtime/cgo" also depends on "runtime". +stdout '"runtime/cgo \[runtime\.test\]"' +! stdout '"runtime/cgo"' + + +# Because the import of "runtime/cgo" in the cgo-generated file actually refers +# to "runtime/cgo [runtime.test]", the latter should be listed in the ImportMap. +# BUG(#46462): Today, it is not. + +go list -deps -test -compiled -f '{{if eq .ImportPath "net [runtime.test]"}}{{printf "%q" .ImportMap}}{{end}}' runtime + +stdout '"sync":"sync \[runtime\.test\]"' # control +stdout '"runtime/cgo":"runtime/cgo \[runtime\.test\]"' # experiment From 770f1de8c54256d5b17447028e47b201ba8e62c8 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Thu, 10 Jun 2021 10:50:37 -0700 Subject: [PATCH 370/940] net/http: remove test-only private key from production binaries The net/http/internal package contains a PEM-encoded private key used in tests. This key is initialized at init time, which prevents it from being stripped by the linker in non-test binaries. Move the certificate and key to a new net/http/internal/testcert package to ensure it is only included in binaries that reference it. Fixes #46677. Change-Id: Ie98bda529169314cc791063e7ce4d99ef99113c8 Reviewed-on: https://go-review.googlesource.com/c/go/+/326771 Trust: Damien Neil Run-TryBot: Damien Neil TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills --- src/go/build/deps_test.go | 4 +++- src/net/http/httptest/server.go | 4 ++-- src/net/http/internal/{ => testcert}/testcert.go | 5 +++-- src/net/http/serve_test.go | 7 ++++--- src/net/http/transport_internal_test.go | 4 ++-- src/net/http/transport_test.go | 4 ++-- 6 files changed, 16 insertions(+), 12 deletions(-) rename src/net/http/internal/{ => testcert}/testcert.go (94%) diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 5d1cf7f4c97..45e2f25df74 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -440,7 +440,8 @@ var depsRules = ` # HTTP, King of Dependencies. FMT - < golang.org/x/net/http2/hpack, net/http/internal, net/http/internal/ascii; + < golang.org/x/net/http2/hpack + < net/http/internal, net/http/internal/ascii, net/http/internal/testcert; FMT, NET, container/list, encoding/binary, log < golang.org/x/text/transform @@ -459,6 +460,7 @@ var depsRules = ` golang.org/x/net/http2/hpack, net/http/internal, net/http/internal/ascii, + net/http/internal/testcert, net/http/httptrace, mime/multipart, log diff --git a/src/net/http/httptest/server.go b/src/net/http/httptest/server.go index a02a6d64c39..4f85ff55d89 100644 --- a/src/net/http/httptest/server.go +++ b/src/net/http/httptest/server.go @@ -14,7 +14,7 @@ import ( "log" "net" "net/http" - "net/http/internal" + "net/http/internal/testcert" "os" "strings" "sync" @@ -144,7 +144,7 @@ func (s *Server) StartTLS() { if s.client == nil { s.client = &http.Client{Transport: &http.Transport{}} } - cert, err := tls.X509KeyPair(internal.LocalhostCert, internal.LocalhostKey) + cert, err := tls.X509KeyPair(testcert.LocalhostCert, testcert.LocalhostKey) if err != nil { panic(fmt.Sprintf("httptest: NewTLSServer: %v", err)) } diff --git a/src/net/http/internal/testcert.go b/src/net/http/internal/testcert/testcert.go similarity index 94% rename from src/net/http/internal/testcert.go rename to src/net/http/internal/testcert/testcert.go index 2284a836fb7..5f94704ef59 100644 --- a/src/net/http/internal/testcert.go +++ b/src/net/http/internal/testcert/testcert.go @@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package internal +// Package testcert contains a test-only localhost certificate. +package testcert import "strings" @@ -25,7 +26,7 @@ h1fIw3cSS2OolhloGw/XM6RWPWtPAlGykKLciQrBru5NAPvCMsb/I1DAceTiotQM fblo6RBxUQ== -----END CERTIFICATE-----`) -// LocalhostKey is the private key for localhostCert. +// LocalhostKey is the private key for LocalhostCert. var LocalhostKey = []byte(testingKey(`-----BEGIN RSA TESTING KEY----- MIICXgIBAAKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9 SjY1bIw4iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZB diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go index c2f88114697..6394da3bb7c 100644 --- a/src/net/http/serve_test.go +++ b/src/net/http/serve_test.go @@ -25,6 +25,7 @@ import ( "net/http/httptest" "net/http/httputil" "net/http/internal" + "net/http/internal/testcert" "net/url" "os" "os/exec" @@ -1475,7 +1476,7 @@ func TestServeTLS(t *testing.T) { defer afterTest(t) defer SetTestHookServerServe(nil) - cert, err := tls.X509KeyPair(internal.LocalhostCert, internal.LocalhostKey) + cert, err := tls.X509KeyPair(testcert.LocalhostCert, testcert.LocalhostKey) if err != nil { t.Fatal(err) } @@ -1599,7 +1600,7 @@ func TestAutomaticHTTP2_Serve_WithTLSConfig(t *testing.T) { } func TestAutomaticHTTP2_ListenAndServe(t *testing.T) { - cert, err := tls.X509KeyPair(internal.LocalhostCert, internal.LocalhostKey) + cert, err := tls.X509KeyPair(testcert.LocalhostCert, testcert.LocalhostKey) if err != nil { t.Fatal(err) } @@ -1609,7 +1610,7 @@ func TestAutomaticHTTP2_ListenAndServe(t *testing.T) { } func TestAutomaticHTTP2_ListenAndServe_GetCertificate(t *testing.T) { - cert, err := tls.X509KeyPair(internal.LocalhostCert, internal.LocalhostKey) + cert, err := tls.X509KeyPair(testcert.LocalhostCert, testcert.LocalhostKey) if err != nil { t.Fatal(err) } diff --git a/src/net/http/transport_internal_test.go b/src/net/http/transport_internal_test.go index 1097ffd1739..1cce27235df 100644 --- a/src/net/http/transport_internal_test.go +++ b/src/net/http/transport_internal_test.go @@ -12,7 +12,7 @@ import ( "errors" "io" "net" - "net/http/internal" + "net/http/internal/testcert" "strings" "testing" ) @@ -191,7 +191,7 @@ func (f roundTripFunc) RoundTrip(r *Request) (*Response, error) { // Issue 25009 func TestTransportBodyAltRewind(t *testing.T) { - cert, err := tls.X509KeyPair(internal.LocalhostCert, internal.LocalhostKey) + cert, err := tls.X509KeyPair(testcert.LocalhostCert, testcert.LocalhostKey) if err != nil { t.Fatal(err) } diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index dcaacece617..690e0c299d2 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -30,7 +30,7 @@ import ( "net/http/httptest" "net/http/httptrace" "net/http/httputil" - "net/http/internal" + "net/http/internal/testcert" "net/textproto" "net/url" "os" @@ -4299,7 +4299,7 @@ func TestTransportReuseConnEmptyResponseBody(t *testing.T) { // Issue 13839 func TestNoCrashReturningTransportAltConn(t *testing.T) { - cert, err := tls.X509KeyPair(internal.LocalhostCert, internal.LocalhostKey) + cert, err := tls.X509KeyPair(testcert.LocalhostCert, testcert.LocalhostKey) if err != nil { t.Fatal(err) } From 18788245ea25a6f0ac11b02c15f5a94eab7a9e97 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 11 Jun 2021 01:10:10 -0700 Subject: [PATCH 371/940] [dev.typeparams] cmd/compile: add ir.TypeNodeAt This CL adds a variant of ir.TypeNode that allows specifying position information. This shouldn't normally be needed/used, but it's occasionally helpful for writing code that passes toolstash -cmp. Change-Id: I2be5da0339fd1ec2bee01d6c5310bd2ef58c46b4 Reviewed-on: https://go-review.googlesource.com/c/go/+/327049 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/ir/type.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/ir/type.go b/src/cmd/compile/internal/ir/type.go index a903ea8cd45..431468375a1 100644 --- a/src/cmd/compile/internal/ir/type.go +++ b/src/cmd/compile/internal/ir/type.go @@ -300,11 +300,22 @@ func (n *typeNode) CanBeNtype() {} // TypeNode returns the Node representing the type t. func TypeNode(t *types.Type) Ntype { + return TypeNodeAt(src.NoXPos, t) +} + +// TypeNodeAt is like TypeNode, but allows specifying the position +// information if a new OTYPE needs to be constructed. +// +// Deprecated: Use TypeNode instead. For typical use, the position for +// an anonymous OTYPE node should not matter. However, TypeNodeAt is +// available for use with toolstash -cmp to refactor existing code +// that is sensitive to OTYPE position. +func TypeNodeAt(pos src.XPos, t *types.Type) Ntype { if n := t.Obj(); n != nil { if n.Type() != t { base.Fatalf("type skew: %v has type %v, but expected %v", n, n.Type(), t) } return n.(Ntype) } - return newTypeNode(src.NoXPos, t) + return newTypeNode(pos, t) } From 62e32dd386103b5ee8dfe921eb791b14277843b5 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 11 Jun 2021 01:10:56 -0700 Subject: [PATCH 372/940] [dev.typeparams] cmd/compile: extract SetBaseTypeIndex function The unified IR importer requires a way to set symbol indices for imported types, so provide an exported API for this. Change-Id: I2f088628f56d5b9f1097196dc1aa23f0a8b8d496 Reviewed-on: https://go-review.googlesource.com/c/go/+/327050 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/typecheck/iimport.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 6d42875f496..9054a83e6e9 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -993,7 +993,13 @@ func (r *importReader) symIdx(s *types.Sym) { func (r *importReader) typeExt(t *types.Type) { t.SetNotInHeap(r.bool()) - i, pi := r.int64(), r.int64() + SetBaseTypeIndex(t, r.int64(), r.int64()) +} + +func SetBaseTypeIndex(t *types.Type, i, pi int64) { + if t.Obj() == nil { + base.Fatalf("SetBaseTypeIndex on non-defined type %v", t) + } if i != -1 && pi != -1 { typeSymIdx[t] = [2]int64{i, pi} } @@ -1001,6 +1007,7 @@ func (r *importReader) typeExt(t *types.Type) { // Map imported type T to the index of type descriptor symbols of T and *T, // so we can use index to reference the symbol. +// TODO(mdempsky): Store this information directly in the Type's Name. var typeSymIdx = make(map[*types.Type][2]int64) func BaseTypeIndex(t *types.Type) int64 { From 61888d47c4c49afc2e4ac3aeea42e83cda84d37b Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 11 Jun 2021 03:47:07 -0700 Subject: [PATCH 373/940] [dev.typeparams] cmd/compile: allow embedding Type.Vargen into Sym.Name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unified IR currently works by hoisting local type definitions to package scope, which requires giving them a unique name. Its current solution is to directly embed the ·N suffix in Sym.Name, rather than set Type.Vargen. This CL extends types/fmt.go to support trimming this suffix again when appropriate. Longer term, I want to revisit this hack, but this seemed like the least invasive solution while also handling generics and local types. Change-Id: If99fcdcc1e19e37d5887de3b021c256a3fe46b98 Reviewed-on: https://go-review.googlesource.com/c/go/+/327052 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/types/fmt.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/types/fmt.go b/src/cmd/compile/internal/types/fmt.go index cecd1b3cc1c..b4d1f6c8bbd 100644 --- a/src/cmd/compile/internal/types/fmt.go +++ b/src/cmd/compile/internal/types/fmt.go @@ -324,7 +324,21 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type verb = 'v' } - sconv2(b, t.Sym(), verb, mode) + // In unified IR, function-scope defined types will have a ·N + // suffix embedded directly in their Name. Trim this off for + // non-fmtTypeID modes. + sym := t.Sym() + if mode != fmtTypeID { + i := len(sym.Name) + for i > 0 && sym.Name[i-1] >= '0' && sym.Name[i-1] <= '9' { + i-- + } + const dot = "·" + if i >= len(dot) && sym.Name[i-len(dot):i] == dot { + sym = &Sym{Pkg: sym.Pkg, Name: sym.Name[:i-len(dot)]} + } + } + sconv2(b, sym, verb, mode) // TODO(mdempsky): Investigate including Vargen in fmtTypeIDName // output too. It seems like it should, but that mode is currently From 2721da26083f253c46c2fd0c1dadee14ae4202f5 Mon Sep 17 00:00:00 2001 From: Rhys Hiltner Date: Thu, 10 Jun 2021 15:05:07 -0700 Subject: [PATCH 374/940] doc/go1.17: fix formatting near httptest Change-Id: Ic1a0add3a1e137ca5cd0f3e9ce3266191b0b55cd Reviewed-on: https://go-review.googlesource.com/c/go/+/326777 Trust: Alberto Donizetti Reviewed-by: Dmitri Shuralyov --- doc/go1.17.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 49fbabdc3f4..101957aabdd 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -763,9 +763,9 @@ func Foo() bool {

net/http/httptest

- ResponseRecorder.WriteHeader> + ResponseRecorder.WriteHeader now panics when the provided code is not a valid three-digit HTTP status code. - This matches the behavior of ResponseWriter> + This matches the behavior of ResponseWriter implementations in the net/http package.

From 4a735ce0680e5ea6088da8072ba4c2b0076e51cb Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 11 Jun 2021 01:45:24 -0700 Subject: [PATCH 375/940] [dev.typeparams] cmd/compile: add "check" field to noder.gcimports The unified IR importer needs access to the *types2.Checker instance to lazily construct objects and types. Eventually, maybe the types2.Importer API can be extended to add the Checker as another parameter (or more likely something like an ImportConfig struct), but right now we can handle this ourselves as long as we forgo the types2.(*Config).Check convenience wrapper. Updates #46449. Change-Id: I89c41d5d47c224a58841247cd236cd9f701a23a1 Reviewed-on: https://go-review.googlesource.com/c/go/+/327053 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/noder/import.go | 8 ++++---- src/cmd/compile/internal/noder/irgen.go | 18 ++++++++++-------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/cmd/compile/internal/noder/import.go b/src/cmd/compile/internal/noder/import.go index 8076b74650f..08e3f77b665 100644 --- a/src/cmd/compile/internal/noder/import.go +++ b/src/cmd/compile/internal/noder/import.go @@ -31,8 +31,8 @@ import ( "cmd/internal/src" ) -// Temporary import helper to get type2-based type-checking going. type gcimports struct { + check *types2.Checker packages map[string]*types2.Package } @@ -45,7 +45,7 @@ func (m *gcimports) ImportFrom(path, srcDir string, mode types2.ImportMode) (*ty panic("mode must be 0") } - _, pkg, err := readImportFile(path, typecheck.Target, m.packages) + _, pkg, err := readImportFile(path, typecheck.Target, m.check, m.packages) return pkg, err } @@ -176,7 +176,7 @@ func importfile(decl *syntax.ImportDecl) *types.Pkg { return nil } - pkg, _, err := readImportFile(path, typecheck.Target, nil) + pkg, _, err := readImportFile(path, typecheck.Target, nil, nil) if err != nil { base.Errorf("%s", err) return nil @@ -208,7 +208,7 @@ func parseImportPath(pathLit *syntax.BasicLit) (string, error) { // readImportFile reads the import file for the given package path and // returns its types.Pkg representation. If packages is non-nil, the // types2.Package representation is also returned. -func readImportFile(path string, target *ir.Package, packages map[string]*types2.Package) (pkg1 *types.Pkg, pkg2 *types2.Package, err error) { +func readImportFile(path string, target *ir.Package, check *types2.Checker, packages map[string]*types2.Package) (pkg1 *types.Pkg, pkg2 *types2.Package, err error) { path, err = resolveImportPath(path) if err != nil { return diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go index b70d82d7e67..aac8b5e6418 100644 --- a/src/cmd/compile/internal/noder/irgen.go +++ b/src/cmd/compile/internal/noder/irgen.go @@ -20,7 +20,7 @@ import ( // checkFiles configures and runs the types2 checker on the given // parsed source files and then returns the result. -func checkFiles(noders []*noder, importer types2.Importer) (posMap, *types2.Package, *types2.Info) { +func checkFiles(noders []*noder) (posMap, *types2.Package, *types2.Info) { if base.SyntaxErrors() != 0 { base.ErrorExit() } @@ -34,6 +34,9 @@ func checkFiles(noders []*noder, importer types2.Importer) (posMap, *types2.Pack } // typechecking + importer := gcimports{ + packages: make(map[string]*types2.Package), + } conf := types2.Config{ GoVersion: base.Flag.Lang, IgnoreLabels: true, // parser already checked via syntax.CheckBranches mode @@ -43,7 +46,7 @@ func checkFiles(noders []*noder, importer types2.Importer) (posMap, *types2.Pack terr := err.(types2.Error) base.ErrorfAt(m.makeXPos(terr.Pos), "%s", terr.Msg) }, - Importer: importer, + Importer: &importer, Sizes: &gcSizes{}, } info := &types2.Info{ @@ -57,7 +60,10 @@ func checkFiles(noders []*noder, importer types2.Importer) (posMap, *types2.Pack // expand as needed } - pkg, err := conf.Check(base.Ctxt.Pkgpath, files, info) + pkg := types2.NewPackage(base.Ctxt.Pkgpath, "") + importer.check = types2.NewChecker(&conf, pkg, info) + err := importer.check.Files(files) + base.ExitIfErrors() if err != nil { base.FatalfAt(src.NoXPos, "conf.Check error: %v", err) @@ -69,11 +75,7 @@ func checkFiles(noders []*noder, importer types2.Importer) (posMap, *types2.Pack // check2 type checks a Go package using types2, and then generates IR // using the results. func check2(noders []*noder) { - importer := &gcimports{ - packages: make(map[string]*types2.Package), - } - - m, pkg, info := checkFiles(noders, importer) + m, pkg, info := checkFiles(noders) if base.Flag.G < 2 { os.Exit(0) From 2f1128461dcc6c9915f21327ce18fa1925269f30 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Thu, 10 Jun 2021 16:54:53 -0400 Subject: [PATCH 376/940] cmd/go: match Windows paths in TestScript/mod_invalid_version Fixes #46691 Change-Id: I3bef9a773be640bed96eb2dc395cb11671a0767a Reviewed-on: https://go-review.googlesource.com/c/go/+/326869 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/cmd/go/testdata/script/mod_invalid_version.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cmd/go/testdata/script/mod_invalid_version.txt b/src/cmd/go/testdata/script/mod_invalid_version.txt index 34d9c47674e..6846a792a5d 100644 --- a/src/cmd/go/testdata/script/mod_invalid_version.txt +++ b/src/cmd/go/testdata/script/mod_invalid_version.txt @@ -19,7 +19,7 @@ cp go.mod.orig go.mod go mod edit -require golang.org/x/text@14c0d48ead0c cd outside ! go list -m golang.org/x/text -stderr 'go list -m: example.com@v0.0.0 \(replaced by \./\..\): parsing ../go.mod: '$WORK'/gopath/src/go.mod:5: require golang.org/x/text: version "14c0d48ead0c" invalid: must be of the form v1.2.3' +stderr 'go list -m: example.com@v0.0.0 \(replaced by \./\.\.\): parsing ..[/\\]go.mod: '$WORK'[/\\]gopath[/\\]src[/\\]go.mod:5: require golang.org/x/text: version "14c0d48ead0c" invalid: must be of the form v1.2.3' cd .. go list -m golang.org/x/text stdout 'golang.org/x/text v0.1.1-0.20170915032832-14c0d48ead0c' @@ -47,10 +47,10 @@ cp go.mod.orig go.mod go mod edit -require golang.org/x/text@v2.1.1-0.20170915032832-14c0d48ead0c cd outside ! go list -m golang.org/x/text -stderr 'go list -m: example.com@v0.0.0 \(replaced by \./\.\.\): parsing ../go.mod: '$WORK'/gopath/src/go.mod:5: require golang.org/x/text: version "v2.1.1-0.20170915032832-14c0d48ead0c" invalid: should be v0 or v1, not v2' +stderr 'go list -m: example.com@v0.0.0 \(replaced by \./\.\.\): parsing ..[/\\]go.mod: '$WORK'[/\\]gopath[/\\]src[/\\]go.mod:5: require golang.org/x/text: version "v2.1.1-0.20170915032832-14c0d48ead0c" invalid: should be v0 or v1, not v2' cd .. ! go list -m golang.org/x/text -stderr $WORK'/gopath/src/go.mod:5: require golang.org/x/text: version "v2.1.1-0.20170915032832-14c0d48ead0c" invalid: should be v0 or v1, not v2' +stderr $WORK'[/\\]gopath[/\\]src[/\\]go.mod:5: require golang.org/x/text: version "v2.1.1-0.20170915032832-14c0d48ead0c" invalid: should be v0 or v1, not v2' # A pseudo-version with fewer than 12 digits of SHA-1 prefix is invalid. cp go.mod.orig go.mod From e2dc6dd5c9b6799c9bb987f3a4600fb0df686d09 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Thu, 10 Jun 2021 14:40:58 -0700 Subject: [PATCH 377/940] doc/go1.17: clean up formatting of gofmt section It was the only h3 in , and it lacked

around its content. It looked like it was part of the prior section: https://tip.golang.org/doc/go1.17#gofmt Change-Id: I7e9ef70e9a03474225833f44420aabd70dab3cd5 Reviewed-on: https://go-review.googlesource.com/c/go/+/326774 Reviewed-by: Dmitri Shuralyov Trust: Brad Fitzpatrick --- doc/go1.17.html | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 101957aabdd..4fa38921f01 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -293,7 +293,9 @@ Do not send CLs removing the interior tags from such phrases. https://golang.org/design/draft-gobuild.

-

gofmt

+

Gofmt

+ +

gofmt (and go fmt) now synchronizes //go:build lines with // +build lines. If a file only has // +build lines, they will be moved to the appropriate @@ -301,7 +303,7 @@ Do not send CLs removing the interior tags from such phrases. added. Otherwise, // +build lines will be overwritten based on any existing //go:build lines. For more information, see https://golang.org/design/draft-gobuild. - +

Vet

From ef6c5be16025a1868fc27267b7abfb1c28329fe2 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 11 Jun 2021 02:44:16 -0700 Subject: [PATCH 378/940] [dev.typeparams] cmd/compile: fix wrapper generation for imported generics This CL fixes reflectdata.methodWrapper to compile wrapper functions for method expressions involving imported, instantiated interface types. CL 322193 fixed a similar issue for generating wrappers for imported, instantiated concrete types, but missed this case. This is necessary to fix CL 326169's test case 10. However, that test case is not included currently, because -G=3 mode crashes on method expressions involving *any* instantiated interface type. Adding a test will have to wait until either this issue is fixed in -G=3 mode, or unified IR is merged. Updates #46704. Change-Id: Ib02d3c20e7c69d16288f1286cd1c98e7cbbba114 Reviewed-on: https://go-review.googlesource.com/c/go/+/327055 Run-TryBot: Matthew Dempsky Reviewed-by: Dan Scales Trust: Dan Scales Trust: Matthew Dempsky TryBot-Result: Go Bot --- src/cmd/compile/internal/reflectdata/reflect.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index 0fcb7e3d6db..bdc35270114 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -1800,8 +1800,11 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy } // Only generate I.M wrappers for I in I's own package - // but keep doing it for error.Error (was issue #29304). - if rcvr.IsInterface() && rcvr.Sym() != nil && rcvr.Sym().Pkg != types.LocalPkg && rcvr != types.ErrorType { + // but keep doing it for error.Error (was issue #29304) + // and methods of instantiated interfaces. + if rcvr.IsInterface() && rcvr != types.ErrorType && + rcvr.Sym() != nil && rcvr.Sym().Pkg != types.LocalPkg && + !rcvr.IsFullyInstantiated() { return lsym } From 4468e1cfb94ed07fea5514dce740180fd3a6d20f Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Fri, 4 Jun 2021 20:04:57 -0400 Subject: [PATCH 379/940] [dev.typeparams] runtime: allow newproc split stack newproc was not allowed to split stack because it had a special stack layout, where the go'd function's arguments were passed on stack but not included in the signature (therefore the stack map). Now it no longer has argument, so it does not need to be nosplit. Change-Id: I6f39730fb1595c4b0438c74118fef418fe1c082b Reviewed-on: https://go-review.googlesource.com/c/go/+/325919 Trust: Cherry Mui Run-TryBot: Cherry Mui Reviewed-by: Michael Knyszek TryBot-Result: Go Bot --- src/runtime/proc.go | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 5d2511b83cf..d6f3af690ba 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -4220,18 +4220,6 @@ func malg(stacksize int32) *g { // Create a new g running fn. // Put it on the queue of g's waiting to run. // The compiler turns a go statement into a call to this. -// -// The stack layout of this call is unusual: it assumes that the -// arguments to pass to fn are on the stack sequentially immediately -// after &fn. Hence, they are logically part of newproc's argument -// frame, even though they don't appear in its signature (and can't -// because their types differ between call sites). -// -// This must be nosplit because this stack layout means there are -// untyped arguments in newproc's argument frame. Stack copies won't -// be able to adjust them and stack splits won't be able to copy them. -// -//go:nosplit func newproc(fn *funcval) { gp := getg() pc := getcallerpc() @@ -4250,17 +4238,7 @@ func newproc(fn *funcval) { // Create a new g in state _Grunnable, starting at fn. callerpc is the // address of the go statement that created this. The caller is responsible // for adding the new g to the scheduler. -// -// This must run on the system stack because it's the continuation of -// newproc, which cannot split the stack. -// -//go:systemstack func newproc1(fn *funcval, callergp *g, callerpc uintptr) *g { - // TODO: When we commit to GOEXPERIMENT=regabidefer, - // rewrite the comments for newproc and newproc1. - // newproc will no longer have a funny stack layout or - // need to be nosplit. - _g_ := getg() if fn == nil { From e0e9fb8affbe37c2ff73b9afb60f726e747f428d Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 8 Jun 2021 18:45:18 -0400 Subject: [PATCH 380/940] [dev.typeparams] runtime: simplify defer record allocation Now that deferred functions are always argumentless and defer records are no longer with arguments, defer record can be fixed size (just the _defer struct). This allows us to simplify the allocation of defer records, specifically, remove the defer classes and the pools of different sized defers. Change-Id: Icc4b16afc23b38262ca9dd1f7369ad40874cf701 Reviewed-on: https://go-review.googlesource.com/c/go/+/326062 Trust: Cherry Mui Run-TryBot: Cherry Mui Reviewed-by: Michael Knyszek TryBot-Result: Go Bot --- src/cmd/compile/internal/test/inl_test.go | 2 - src/runtime/malloc.go | 11 -- src/runtime/mgc.go | 18 ++- src/runtime/panic.go | 141 ++++++---------------- src/runtime/proc.go | 12 +- src/runtime/runtime2.go | 8 +- 6 files changed, 50 insertions(+), 142 deletions(-) diff --git a/src/cmd/compile/internal/test/inl_test.go b/src/cmd/compile/internal/test/inl_test.go index 5b0db833010..bbdbe0c37ca 100644 --- a/src/cmd/compile/internal/test/inl_test.go +++ b/src/cmd/compile/internal/test/inl_test.go @@ -42,7 +42,6 @@ func TestIntendedInlining(t *testing.T) { "bucketMask", "bucketShift", "chanbuf", - "deferclass", "evacuated", "fastlog2", "fastrand", @@ -63,7 +62,6 @@ func TestIntendedInlining(t *testing.T) { "subtract1", "subtractb", "tophash", - "totaldefersize", "(*bmap).keys", "(*bmap).overflow", "(*waitq).enqueue", diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 2759bbdaf90..c5f62483ffc 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -420,8 +420,6 @@ func mallocinit() { throw("bad TinySizeClass") } - testdefersizes() - if heapArenaBitmapBytes&(heapArenaBitmapBytes-1) != 0 { // heapBits expects modular arithmetic on bitmap // addresses to work. @@ -1088,15 +1086,6 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { var scanSize uintptr if !noscan { - // If allocating a defer+arg block, now that we've picked a malloc size - // large enough to hold everything, cut the "asked for" size down to - // just the defer header, so that the GC bitmap will record the arg block - // as containing nothing at all (as if it were unused space at the end of - // a malloc block caused by size rounding). - // The defer arg areas are scanned as part of scanstack. - if typ == deferType { - dataSize = unsafe.Sizeof(_defer{}) - } heapBitsSetType(uintptr(x), size, dataSize, typ) if dataSize > typ.size { // Array allocation. If there are any diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index c239fa0f636..34b5b482a35 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -1558,19 +1558,17 @@ func clearpools() { sched.sudogcache = nil unlock(&sched.sudoglock) - // Clear central defer pools. + // Clear central defer pool. // Leave per-P pools alone, they have strictly bounded size. lock(&sched.deferlock) - for i := range sched.deferpool { - // disconnect cached list before dropping it on the floor, - // so that a dangling ref to one entry does not pin all of them. - var d, dlink *_defer - for d = sched.deferpool[i]; d != nil; d = dlink { - dlink = d.link - d.link = nil - } - sched.deferpool[i] = nil + // disconnect cached list before dropping it on the floor, + // so that a dangling ref to one entry does not pin all of them. + var d, dlink *_defer + for d = sched.deferpool; d != nil; d = dlink { + dlink = d.link + d.link = nil } + sched.deferpool = nil unlock(&sched.deferlock) } diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 39013163b6e..86d41c4e1c5 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -236,7 +236,7 @@ func deferproc(fn func()) { sp := getcallersp() callerpc := getcallerpc() - d := newdefer(0) + d := newdefer() if d._panic != nil { throw("deferproc: d.panic != nil after newdefer") } @@ -302,106 +302,37 @@ func deferprocStack(d *_defer) { // been set and must not be clobbered. } -// Small malloc size classes >= 16 are the multiples of 16: 16, 32, 48, 64, 80, 96, 112, 128, 144, ... -// Each P holds a pool for defers with small arg sizes. -// Assign defer allocations to pools by rounding to 16, to match malloc size classes. - -const ( - deferHeaderSize = unsafe.Sizeof(_defer{}) - minDeferAlloc = (deferHeaderSize + 15) &^ 15 - minDeferArgs = minDeferAlloc - deferHeaderSize -) - -// defer size class for arg size sz -//go:nosplit -func deferclass(siz uintptr) uintptr { - if siz <= minDeferArgs { - return 0 - } - return (siz - minDeferArgs + 15) / 16 -} - -// total size of memory block for defer with arg size sz -func totaldefersize(siz uintptr) uintptr { - if siz <= minDeferArgs { - return minDeferAlloc - } - return deferHeaderSize + siz -} - -// Ensure that defer arg sizes that map to the same defer size class -// also map to the same malloc size class. -func testdefersizes() { - var m [len(p{}.deferpool)]int32 - - for i := range m { - m[i] = -1 - } - for i := uintptr(0); ; i++ { - defersc := deferclass(i) - if defersc >= uintptr(len(m)) { - break - } - siz := roundupsize(totaldefersize(i)) - if m[defersc] < 0 { - m[defersc] = int32(siz) - continue - } - if m[defersc] != int32(siz) { - print("bad defer size class: i=", i, " siz=", siz, " defersc=", defersc, "\n") - throw("bad defer size class") - } - } -} - -var deferType *_type // type of _defer struct - -func init() { - var x interface{} - x = (*_defer)(nil) - deferType = (*(**ptrtype)(unsafe.Pointer(&x))).elem -} +// Each P holds a pool for defers. // Allocate a Defer, usually using per-P pool. // Each defer must be released with freedefer. The defer is not // added to any defer chain yet. -// -// This must not grow the stack because there may be a frame without -// stack map information when this is called. -// -//go:nosplit -func newdefer(siz int32) *_defer { +func newdefer() *_defer { var d *_defer - sc := deferclass(uintptr(siz)) gp := getg() - if sc < uintptr(len(p{}.deferpool)) { - pp := gp.m.p.ptr() - if len(pp.deferpool[sc]) == 0 && sched.deferpool[sc] != nil { - // Take the slow path on the system stack so - // we don't grow newdefer's stack. - systemstack(func() { - lock(&sched.deferlock) - for len(pp.deferpool[sc]) < cap(pp.deferpool[sc])/2 && sched.deferpool[sc] != nil { - d := sched.deferpool[sc] - sched.deferpool[sc] = d.link - d.link = nil - pp.deferpool[sc] = append(pp.deferpool[sc], d) - } - unlock(&sched.deferlock) - }) - } - if n := len(pp.deferpool[sc]); n > 0 { - d = pp.deferpool[sc][n-1] - pp.deferpool[sc][n-1] = nil - pp.deferpool[sc] = pp.deferpool[sc][:n-1] - } + pp := gp.m.p.ptr() + if len(pp.deferpool) == 0 && sched.deferpool != nil { + // Take the slow path on the system stack so + // we don't grow newdefer's stack. + systemstack(func() { + lock(&sched.deferlock) + for len(pp.deferpool) < cap(pp.deferpool)/2 && sched.deferpool != nil { + d := sched.deferpool + sched.deferpool = d.link + d.link = nil + pp.deferpool = append(pp.deferpool, d) + } + unlock(&sched.deferlock) + }) + } + if n := len(pp.deferpool); n > 0 { + d = pp.deferpool[n-1] + pp.deferpool[n-1] = nil + pp.deferpool = pp.deferpool[:n-1] } if d == nil { - // Allocate new defer+args. - systemstack(func() { - total := roundupsize(totaldefersize(uintptr(siz))) - d = (*_defer)(mallocgc(total, deferType, true)) - }) + // Allocate new defer. + d = new(_defer) } d.heap = true return d @@ -424,23 +355,19 @@ func freedefer(d *_defer) { if !d.heap { return } - sc := deferclass(0) - if sc >= uintptr(len(p{}.deferpool)) { - return - } pp := getg().m.p.ptr() - if len(pp.deferpool[sc]) == cap(pp.deferpool[sc]) { + if len(pp.deferpool) == cap(pp.deferpool) { // Transfer half of local cache to the central cache. // // Take this slow path on the system stack so // we don't grow freedefer's stack. systemstack(func() { var first, last *_defer - for len(pp.deferpool[sc]) > cap(pp.deferpool[sc])/2 { - n := len(pp.deferpool[sc]) - d := pp.deferpool[sc][n-1] - pp.deferpool[sc][n-1] = nil - pp.deferpool[sc] = pp.deferpool[sc][:n-1] + for len(pp.deferpool) > cap(pp.deferpool)/2 { + n := len(pp.deferpool) + d := pp.deferpool[n-1] + pp.deferpool[n-1] = nil + pp.deferpool = pp.deferpool[:n-1] if first == nil { first = d } else { @@ -449,8 +376,8 @@ func freedefer(d *_defer) { last = d } lock(&sched.deferlock) - last.link = sched.deferpool[sc] - sched.deferpool[sc] = first + last.link = sched.deferpool + sched.deferpool = first unlock(&sched.deferlock) }) } @@ -469,7 +396,7 @@ func freedefer(d *_defer) { // both of which throw. d.link = nil - pp.deferpool[sc] = append(pp.deferpool[sc], d) + pp.deferpool = append(pp.deferpool, d) } // Separate function so that it can split stack. @@ -720,7 +647,7 @@ func addOneOpenDeferFrame(gp *g, pc uintptr, sp unsafe.Pointer) { throw("missing deferreturn") } - d1 := newdefer(0) + d1 := newdefer() d1.openDefer = true d1._panic = nil // These are the pc/sp to set after we've diff --git a/src/runtime/proc.go b/src/runtime/proc.go index d6f3af690ba..4a116130a54 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -4784,9 +4784,7 @@ func (pp *p) init(id int32) { pp.id = id pp.status = _Pgcstop pp.sudogcache = pp.sudogbuf[:0] - for i := range pp.deferpool { - pp.deferpool[i] = pp.deferpoolbuf[i][:0] - } + pp.deferpool = pp.deferpoolbuf[:0] pp.wbBuf.reset() if pp.mcache == nil { if id == 0 { @@ -4864,12 +4862,10 @@ func (pp *p) destroy() { pp.sudogbuf[i] = nil } pp.sudogcache = pp.sudogbuf[:0] - for i := range pp.deferpool { - for j := range pp.deferpoolbuf[i] { - pp.deferpoolbuf[i][j] = nil - } - pp.deferpool[i] = pp.deferpoolbuf[i][:0] + for j := range pp.deferpoolbuf { + pp.deferpoolbuf[j] = nil } + pp.deferpool = pp.deferpoolbuf[:0] systemstack(func() { for i := 0; i < pp.mspancache.len; i++ { // Safe to call since the world is stopped. diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index cf4b0bff430..75c48185990 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -613,8 +613,8 @@ type p struct { pcache pageCache raceprocctx uintptr - deferpool [5][]*_defer // pool of available defer structs of different sizes (see panic.go) - deferpoolbuf [5][32]*_defer + deferpool []*_defer // pool of available defer structs (see panic.go) + deferpoolbuf [32]*_defer // Cache of goroutine ids, amortizes accesses to runtime·sched.goidgen. goidcache uint64 @@ -801,9 +801,9 @@ type schedt struct { sudoglock mutex sudogcache *sudog - // Central pool of available defer structs of different sizes. + // Central pool of available defer structs. deferlock mutex - deferpool [5]*_defer + deferpool *_defer // freem is the list of m's waiting to be freed when their // m.exited is set. Linked through m.freelink. From 77aa209b386a184e7f4b44938f2a05a1b5c5a3cf Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 10 Jun 2021 15:35:05 -0700 Subject: [PATCH 381/940] runtime: loop on EINTR in macOS sigNoteSleep Fixes #46466 Change-Id: I8fb15d0c8ef7ef6e6fc1b9e0e033d213255fe0df Reviewed-on: https://go-review.googlesource.com/c/go/+/326778 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Michael Knyszek Reviewed-by: Cherry Mui --- src/runtime/os_darwin.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go index 00139351abc..079be107d71 100644 --- a/src/runtime/os_darwin.go +++ b/src/runtime/os_darwin.go @@ -118,10 +118,15 @@ func sigNoteWakeup(*note) { // sigNoteSleep waits for a note created by sigNoteSetup to be woken. func sigNoteSleep(*note) { - entersyscallblock() - var b byte - read(sigNoteRead, unsafe.Pointer(&b), 1) - exitsyscall() + for { + var b byte + entersyscallblock() + n := read(sigNoteRead, unsafe.Pointer(&b), 1) + exitsyscall() + if n != -_EINTR { + return + } + } } // BSD interface for threading. From 2fe324858b31a672070f8529191d0769013b8488 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 9 Jun 2021 13:51:59 -0400 Subject: [PATCH 382/940] [dev.typeparams] internal/buildcfg: always enable regabiwrappers on AMD64 Always enable regabiwrappers on AMD64. GOEXPERIMENT=none will not turn it off. Change-Id: I0aa208c02157661ac3676b753bcfbfa050b99e41 Reviewed-on: https://go-review.googlesource.com/c/go/+/327271 Trust: Cherry Mui Run-TryBot: Cherry Mui Reviewed-by: David Chase Reviewed-by: Than McIntosh TryBot-Result: Go Bot --- src/internal/buildcfg/exp.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/internal/buildcfg/exp.go b/src/internal/buildcfg/exp.go index 9402da2ebff..b3f3de62a88 100644 --- a/src/internal/buildcfg/exp.go +++ b/src/internal/buildcfg/exp.go @@ -97,6 +97,10 @@ func parseExperiments() goexperiment.Flags { } } + // regabiwrappers is always enabled on amd64. + if GOARCH == "amd64" { + flags.RegabiWrappers = true + } // regabi is only supported on amd64 and arm64. if GOARCH != "amd64" && GOARCH != "arm64" { flags.RegabiWrappers = false From 16b5d766d8af8bc348f93e6cb2b53a4e2d5d72ca Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Fri, 11 Jun 2021 17:36:50 +0200 Subject: [PATCH 383/940] syscall: do not load native libraries on non-native powershell on arm The powershell that currently ships on ARM Windows isn't native, so it won't load native DLLs. So just skip the tests for now, and reenable it if this ever changes. Updates #46701. Change-Id: I2559fdf13cb65d3ecdc4c6f6df7dec1b490b9651 Reviewed-on: https://go-review.googlesource.com/c/go/+/327210 TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor Trust: Jason A. Donenfeld Run-TryBot: Jason A. Donenfeld --- src/syscall/syscall_windows_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/syscall/syscall_windows_test.go b/src/syscall/syscall_windows_test.go index ea8fa191dcb..3243952ded1 100644 --- a/src/syscall/syscall_windows_test.go +++ b/src/syscall/syscall_windows_test.go @@ -10,6 +10,7 @@ import ( "os" "os/exec" "path/filepath" + "runtime" "strings" "syscall" "testing" @@ -79,6 +80,9 @@ func TestTOKEN_ALL_ACCESS(t *testing.T) { func TestStdioAreInheritable(t *testing.T) { testenv.MustHaveGoBuild(t) testenv.MustHaveExecPath(t, "gcc") + if runtime.GOARCH == "arm64" || runtime.GOARCH == "arm" { + t.Skip("Powershell is not native on ARM; see golang.org/issues/46701") + } tmpdir := t.TempDir() From c93d5d1a5245d4baa6824a2c88a6b79e3d895e4d Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 9 Jun 2021 14:29:20 -0400 Subject: [PATCH 384/940] [dev.typeparams] all: always enable regabig on AMD64 Always enable regabig on AMD64, which enables the G register and the X15 zero register. Remove the fallback path. Also remove the regabig GOEXPERIMENT. On AMD64 it is always enabled (this CL). Other architectures already have a G register, except for 386, where there are too few registers and it is unlikely that we will reserve one. (If we really do, we can just add a new experiment). Change-Id: I229cac0060f48fe58c9fdaabd38d6fa16b8a0855 Reviewed-on: https://go-review.googlesource.com/c/go/+/327272 Trust: Cherry Mui Run-TryBot: Cherry Mui Reviewed-by: Than McIntosh Reviewed-by: David Chase TryBot-Result: Go Bot --- src/cmd/compile/internal/amd64/ggen.go | 10 -------- src/cmd/compile/internal/amd64/ssa.go | 12 +++++----- src/cmd/compile/internal/ssa/config.go | 2 +- src/cmd/compile/internal/ssa/gen/AMD64.rules | 2 +- src/cmd/compile/internal/ssa/rewriteAMD64.go | 5 ++-- src/cmd/internal/obj/x86/obj6.go | 4 +--- src/internal/buildcfg/exp.go | 10 ++------ src/internal/goexperiment/exp_regabig_off.go | 9 -------- src/internal/goexperiment/exp_regabig_on.go | 9 -------- src/internal/goexperiment/flags.go | 5 ---- src/runtime/asm_amd64.s | 16 ------------- src/runtime/memclr_amd64.s | 3 --- src/runtime/memmove_amd64.s | 4 ---- src/runtime/race_amd64.s | 24 -------------------- src/runtime/sys_linux_amd64.s | 10 -------- src/runtime/time_linux_amd64.s | 10 -------- 16 files changed, 13 insertions(+), 122 deletions(-) delete mode 100644 src/internal/goexperiment/exp_regabig_off.go delete mode 100644 src/internal/goexperiment/exp_regabig_on.go diff --git a/src/cmd/compile/internal/amd64/ggen.go b/src/cmd/compile/internal/amd64/ggen.go index 1484ad5404b..b8dce81a92d 100644 --- a/src/cmd/compile/internal/amd64/ggen.go +++ b/src/cmd/compile/internal/amd64/ggen.go @@ -57,7 +57,6 @@ func dzDI(b int64) int64 { func zerorange(pp *objw.Progs, p *obj.Prog, off, cnt int64, state *uint32) *obj.Prog { const ( r13 = 1 << iota // if R13 is already zeroed. - x15 // if X15 is already zeroed. Note: in new ABI, X15 is always zero. ) if cnt == 0 { @@ -85,11 +84,6 @@ func zerorange(pp *objw.Progs, p *obj.Prog, off, cnt int64, state *uint32) *obj. } p = pp.Append(p, x86.AMOVQ, obj.TYPE_REG, x86.REG_R13, 0, obj.TYPE_MEM, x86.REG_SP, off) } else if !isPlan9 && cnt <= int64(8*types.RegSize) { - if !buildcfg.Experiment.RegabiG && *state&x15 == 0 { - p = pp.Append(p, x86.AXORPS, obj.TYPE_REG, x86.REG_X15, 0, obj.TYPE_REG, x86.REG_X15, 0) - *state |= x15 - } - for i := int64(0); i < cnt/16; i++ { p = pp.Append(p, x86.AMOVUPS, obj.TYPE_REG, x86.REG_X15, 0, obj.TYPE_MEM, x86.REG_SP, off+i*16) } @@ -98,10 +92,6 @@ func zerorange(pp *objw.Progs, p *obj.Prog, off, cnt int64, state *uint32) *obj. p = pp.Append(p, x86.AMOVUPS, obj.TYPE_REG, x86.REG_X15, 0, obj.TYPE_MEM, x86.REG_SP, off+cnt-int64(16)) } } else if !isPlan9 && (cnt <= int64(128*types.RegSize)) { - if !buildcfg.Experiment.RegabiG && *state&x15 == 0 { - p = pp.Append(p, x86.AXORPS, obj.TYPE_REG, x86.REG_X15, 0, obj.TYPE_REG, x86.REG_X15, 0) - *state |= x15 - } // Save DI to r12. With the amd64 Go register abi, DI can contain // an incoming parameter, whereas R12 is always scratch. p = pp.Append(p, x86.AMOVQ, obj.TYPE_REG, x86.REG_DI, 0, obj.TYPE_REG, x86.REG_R12, 0) diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go index c27a5fe5b5a..30dba057d01 100644 --- a/src/cmd/compile/internal/amd64/ssa.go +++ b/src/cmd/compile/internal/amd64/ssa.go @@ -823,7 +823,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.To.Reg = v.Args[0].Reg() ssagen.AddAux2(&p.To, v, sc.Off64()) case ssa.OpAMD64MOVOstorezero: - if !buildcfg.Experiment.RegabiG || s.ABI != obj.ABIInternal { + if s.ABI != obj.ABIInternal { // zero X15 manually opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15) } @@ -914,7 +914,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.To.Type = obj.TYPE_REG p.To.Reg = v.Reg() case ssa.OpAMD64DUFFZERO: - if !buildcfg.Experiment.RegabiG || s.ABI != obj.ABIInternal { + if s.ABI != obj.ABIInternal { // zero X15 manually opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15) } @@ -997,13 +997,13 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { // Closure pointer is DX. ssagen.CheckLoweredGetClosurePtr(v) case ssa.OpAMD64LoweredGetG: - if buildcfg.Experiment.RegabiG && s.ABI == obj.ABIInternal { + if s.ABI == obj.ABIInternal { v.Fatalf("LoweredGetG should not appear in ABIInternal") } r := v.Reg() getgFromTLS(s, r) case ssa.OpAMD64CALLstatic: - if buildcfg.Experiment.RegabiG && s.ABI == obj.ABI0 && v.Aux.(*ssa.AuxCall).Fn.ABI() == obj.ABIInternal { + if s.ABI == obj.ABI0 && v.Aux.(*ssa.AuxCall).Fn.ABI() == obj.ABIInternal { // zeroing X15 when entering ABIInternal from ABI0 if buildcfg.GOOS != "plan9" { // do not use SSE on Plan 9 opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15) @@ -1012,7 +1012,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { getgFromTLS(s, x86.REG_R14) } s.Call(v) - if buildcfg.Experiment.RegabiG && s.ABI == obj.ABIInternal && v.Aux.(*ssa.AuxCall).Fn.ABI() == obj.ABI0 { + if s.ABI == obj.ABIInternal && v.Aux.(*ssa.AuxCall).Fn.ABI() == obj.ABI0 { // zeroing X15 when entering ABIInternal from ABI0 if buildcfg.GOOS != "plan9" { // do not use SSE on Plan 9 opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15) @@ -1308,7 +1308,7 @@ func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) { case ssa.BlockRet: s.Prog(obj.ARET) case ssa.BlockRetJmp: - if buildcfg.Experiment.RegabiG && s.ABI == obj.ABI0 && b.Aux.(*obj.LSym).ABI() == obj.ABIInternal { + if s.ABI == obj.ABI0 && b.Aux.(*obj.LSym).ABI() == obj.ABIInternal { // zeroing X15 when entering ABIInternal from ABI0 if buildcfg.GOOS != "plan9" { // do not use SSE on Plan 9 opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15) diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index 7d680304c9c..61c65f9e54c 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -196,7 +196,7 @@ func NewConfig(arch string, types Types, ctxt *obj.Link, optimize bool) *Config c.floatParamRegs = paramFloatRegAMD64 c.FPReg = framepointerRegAMD64 c.LinkReg = linkRegAMD64 - c.hasGReg = buildcfg.Experiment.RegabiG + c.hasGReg = true case "386": c.PtrSize = 4 c.RegSize = 4 diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules index 4cd00732fc3..45c02383172 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules @@ -460,7 +460,7 @@ (IsInBounds idx len) => (SETB (CMPQ idx len)) (IsSliceInBounds idx len) => (SETBE (CMPQ idx len)) (NilCheck ...) => (LoweredNilCheck ...) -(GetG mem) && !(buildcfg.Experiment.RegabiG && v.Block.Func.OwnAux.Fn.ABI() == obj.ABIInternal) => (LoweredGetG mem) // only lower in old ABI. in new ABI we have a G register. +(GetG mem) && v.Block.Func.OwnAux.Fn.ABI() != obj.ABIInternal => (LoweredGetG mem) // only lower in old ABI. in new ABI we have a G register. (GetClosurePtr ...) => (LoweredGetClosurePtr ...) (GetCallerPC ...) => (LoweredGetCallerPC ...) (GetCallerSP ...) => (LoweredGetCallerSP ...) diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index 5045ba7351f..89d32c06572 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -3,7 +3,6 @@ package ssa -import "internal/buildcfg" import "math" import "cmd/internal/obj" import "cmd/compile/internal/types" @@ -29339,11 +29338,11 @@ func rewriteValueAMD64_OpFloor(v *Value) bool { func rewriteValueAMD64_OpGetG(v *Value) bool { v_0 := v.Args[0] // match: (GetG mem) - // cond: !(buildcfg.Experiment.RegabiG && v.Block.Func.OwnAux.Fn.ABI() == obj.ABIInternal) + // cond: v.Block.Func.OwnAux.Fn.ABI() != obj.ABIInternal // result: (LoweredGetG mem) for { mem := v_0 - if !(!(buildcfg.Experiment.RegabiG && v.Block.Func.OwnAux.Fn.ABI() == obj.ABIInternal)) { + if !(v.Block.Func.OwnAux.Fn.ABI() != obj.ABIInternal) { break } v.reset(OpAMD64LoweredGetG) diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go index e2732d53e30..183ca2ebe91 100644 --- a/src/cmd/internal/obj/x86/obj6.go +++ b/src/cmd/internal/obj/x86/obj6.go @@ -35,7 +35,6 @@ import ( "cmd/internal/objabi" "cmd/internal/src" "cmd/internal/sys" - "internal/buildcfg" "log" "math" "path" @@ -647,13 +646,12 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { var regg int16 if !p.From.Sym.NoSplit() || p.From.Sym.Wrapper() { - if ctxt.Arch.Family == sys.AMD64 && buildcfg.Experiment.RegabiG && cursym.ABI() == obj.ABIInternal { + if ctxt.Arch.Family == sys.AMD64 && cursym.ABI() == obj.ABIInternal { regg = REGG // use the g register directly in ABIInternal } else { p = obj.Appendp(p, newprog) regg = REG_CX if ctxt.Arch.Family == sys.AMD64 { - // Using this register means that stacksplit works w/ //go:registerparams even when !buildcfg.Experiment.RegabiG regg = REGG // == REG_R14 } p = load_g(ctxt, p, newprog, regg) // load g into regg diff --git a/src/internal/buildcfg/exp.go b/src/internal/buildcfg/exp.go index b3f3de62a88..e78f9879991 100644 --- a/src/internal/buildcfg/exp.go +++ b/src/internal/buildcfg/exp.go @@ -28,7 +28,6 @@ var regabiDeveloping = false // configuration and any variation from this is an experiment. var experimentBaseline = goexperiment.Flags{ RegabiWrappers: regabiSupported, - RegabiG: regabiSupported, RegabiReflect: regabiSupported, RegabiArgs: regabiSupported, } @@ -67,7 +66,6 @@ func parseExperiments() goexperiment.Flags { // do the right thing. names["regabi"] = func(v bool) { flags.RegabiWrappers = v - flags.RegabiG = v flags.RegabiReflect = v flags.RegabiArgs = v } @@ -104,16 +102,12 @@ func parseExperiments() goexperiment.Flags { // regabi is only supported on amd64 and arm64. if GOARCH != "amd64" && GOARCH != "arm64" { flags.RegabiWrappers = false - flags.RegabiG = false flags.RegabiReflect = false flags.RegabiArgs = false } // Check regabi dependencies. - if flags.RegabiG && !flags.RegabiWrappers { - Error = fmt.Errorf("GOEXPERIMENT regabig requires regabiwrappers") - } - if flags.RegabiArgs && !(flags.RegabiWrappers && flags.RegabiG && flags.RegabiReflect) { - Error = fmt.Errorf("GOEXPERIMENT regabiargs requires regabiwrappers,regabig,regabireflect") + if flags.RegabiArgs && !(flags.RegabiWrappers && flags.RegabiReflect) { + Error = fmt.Errorf("GOEXPERIMENT regabiargs requires regabiwrappers,regabireflect") } return flags } diff --git a/src/internal/goexperiment/exp_regabig_off.go b/src/internal/goexperiment/exp_regabig_off.go deleted file mode 100644 index 1b37d451868..00000000000 --- a/src/internal/goexperiment/exp_regabig_off.go +++ /dev/null @@ -1,9 +0,0 @@ -// Code generated by mkconsts.go. DO NOT EDIT. - -//go:build !goexperiment.regabig -// +build !goexperiment.regabig - -package goexperiment - -const RegabiG = false -const RegabiGInt = 0 diff --git a/src/internal/goexperiment/exp_regabig_on.go b/src/internal/goexperiment/exp_regabig_on.go deleted file mode 100644 index 7e5b162e0b2..00000000000 --- a/src/internal/goexperiment/exp_regabig_on.go +++ /dev/null @@ -1,9 +0,0 @@ -// Code generated by mkconsts.go. DO NOT EDIT. - -//go:build goexperiment.regabig -// +build goexperiment.regabig - -package goexperiment - -const RegabiG = true -const RegabiGInt = 1 diff --git a/src/internal/goexperiment/flags.go b/src/internal/goexperiment/flags.go index c20dbcd9f5e..71e38cd0479 100644 --- a/src/internal/goexperiment/flags.go +++ b/src/internal/goexperiment/flags.go @@ -68,11 +68,6 @@ type Flags struct { // ABI0 and ABIInternal functions. Without this, the ABIs are // assumed to be identical so cross-ABI calls are direct. RegabiWrappers bool - // RegabiG enables dedicated G and zero registers in - // ABIInternal. - // - // Requires wrappers because it makes the ABIs incompatible. - RegabiG bool // RegabiReflect enables the register-passing paths in // reflection calls. This is also gated by intArgRegs in // reflect and runtime (which are disabled by default) so it diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index f8f5fc62e6c..50ffa30ac56 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -683,10 +683,6 @@ TEXT runtime·jmpdefer(SB), NOSPLIT, $0-16 // or else unwinding from systemstack_switch is incorrect. // Smashes R9. TEXT gosave_systemstack_switch<>(SB),NOSPLIT,$0 -#ifndef GOEXPERIMENT_regabig - get_tls(R14) - MOVQ g(R14), R14 -#endif MOVQ $runtime·systemstack_switch(SB), R9 MOVQ R9, (g_sched+gobuf_pc)(R14) LEAQ 8(SP), R9 @@ -1284,10 +1280,8 @@ aes65to128: PXOR X10, X8 PXOR X11, X9 PXOR X9, X8 -#ifdef GOEXPERIMENT_regabig // X15 must be zero on return PXOR X15, X15 -#endif #ifdef GOEXPERIMENT_regabiargs MOVQ X8, AX // return X8 #else @@ -1408,10 +1402,8 @@ aesloop: PXOR X10, X8 PXOR X11, X9 PXOR X9, X8 -#ifdef GOEXPERIMENT_regabig // X15 must be zero on return PXOR X15, X15 -#endif #ifdef GOEXPERIMENT_regabiargs MOVQ X8, AX // return X8 #else @@ -1595,12 +1587,10 @@ TEXT runtime·addmoduledata(SB),NOSPLIT,$0-0 // signals. It is quite painful to set X15 in the signal context, // so we do it here. TEXT ·sigpanic0(SB),NOSPLIT,$0-0 -#ifdef GOEXPERIMENT_regabig get_tls(R14) MOVQ g(R14), R14 #ifndef GOOS_plan9 XORPS X15, X15 -#endif #endif JMP ·sigpanic(SB) @@ -1619,13 +1609,7 @@ TEXT runtime·gcWriteBarrier(SB),NOSPLIT,$112 MOVQ R13, 104(SP) // TODO: Consider passing g.m.p in as an argument so they can be shared // across a sequence of write barriers. -#ifdef GOEXPERIMENT_regabig MOVQ g_m(R14), R13 -#else - get_tls(R13) - MOVQ g(R13), R13 - MOVQ g_m(R13), R13 -#endif MOVQ m_p(R13), R13 MOVQ (p_wbBuf+wbBuf_next)(R13), R12 // Increment wbBuf.next position. diff --git a/src/runtime/memclr_amd64.s b/src/runtime/memclr_amd64.s index a10f57bd8cb..6c78869f4c6 100644 --- a/src/runtime/memclr_amd64.s +++ b/src/runtime/memclr_amd64.s @@ -37,9 +37,6 @@ tail: JE _8 CMPQ BX, $16 JBE _9through16 -#ifndef GOEXPERIMENT_regabig - PXOR X15, X15 -#endif CMPQ BX, $32 JBE _17through32 CMPQ BX, $64 diff --git a/src/runtime/memmove_amd64.s b/src/runtime/memmove_amd64.s index 24c6529f584..af538d4bced 100644 --- a/src/runtime/memmove_amd64.s +++ b/src/runtime/memmove_amd64.s @@ -254,10 +254,8 @@ move_129through256: MOVOU X13, -48(DI)(BX*1) MOVOU X14, -32(DI)(BX*1) MOVOU X15, -16(DI)(BX*1) -#ifdef GOEXPERIMENT_regabig // X15 must be zero on return PXOR X15, X15 -#endif RET move_256through2048: SUBQ $256, BX @@ -297,10 +295,8 @@ move_256through2048: LEAQ 256(SI), SI LEAQ 256(DI), DI JGE move_256through2048 -#ifdef GOEXPERIMENT_regabig // X15 must be zero on return PXOR X15, X15 -#endif JMP tail avxUnaligned: diff --git a/src/runtime/race_amd64.s b/src/runtime/race_amd64.s index 469623ff20a..8a171132328 100644 --- a/src/runtime/race_amd64.s +++ b/src/runtime/race_amd64.s @@ -161,10 +161,6 @@ TEXT runtime·racewriterangepc1(SB), NOSPLIT, $0-24 // If addr (RARG1) is out of range, do nothing. // Otherwise, setup goroutine context and invoke racecall. Other arguments already set. TEXT racecalladdr<>(SB), NOSPLIT, $0-0 -#ifndef GOEXPERIMENT_regabig - get_tls(R12) - MOVQ g(R12), R14 -#endif MOVQ g_racectx(R14), RARG0 // goroutine context // Check that addr is within [arenastart, arenaend) or within [racedatastart, racedataend). CMPQ RARG1, runtime·racearenastart(SB) @@ -192,10 +188,6 @@ TEXT runtime·racefuncenter(SB), NOSPLIT, $0-8 // R11 = caller's return address TEXT racefuncenter<>(SB), NOSPLIT, $0-0 MOVQ DX, BX // save function entry context (for closures) -#ifndef GOEXPERIMENT_regabig - get_tls(R12) - MOVQ g(R12), R14 -#endif MOVQ g_racectx(R14), RARG0 // goroutine context MOVQ R11, RARG1 // void __tsan_func_enter(ThreadState *thr, void *pc); @@ -208,10 +200,6 @@ TEXT racefuncenter<>(SB), NOSPLIT, $0-0 // func runtime·racefuncexit() // Called from instrumented code. TEXT runtime·racefuncexit(SB), NOSPLIT, $0-0 -#ifndef GOEXPERIMENT_regabig - get_tls(R12) - MOVQ g(R12), R14 -#endif MOVQ g_racectx(R14), RARG0 // goroutine context // void __tsan_func_exit(ThreadState *thr); MOVQ $__tsan_func_exit(SB), AX @@ -370,10 +358,6 @@ racecallatomic_data: JAE racecallatomic_ignore racecallatomic_ok: // Addr is within the good range, call the atomic function. -#ifndef GOEXPERIMENT_regabig - get_tls(R12) - MOVQ g(R12), R14 -#endif MOVQ g_racectx(R14), RARG0 // goroutine context MOVQ 8(SP), RARG1 // caller pc MOVQ (SP), RARG2 // pc @@ -385,10 +369,6 @@ racecallatomic_ignore: // An attempt to synchronize on the address would cause crash. MOVQ AX, BX // remember the original function MOVQ $__tsan_go_ignore_sync_begin(SB), AX -#ifndef GOEXPERIMENT_regabig - get_tls(R12) - MOVQ g(R12), R14 -#endif MOVQ g_racectx(R14), RARG0 // goroutine context CALL racecall<>(SB) MOVQ BX, AX // restore the original function @@ -416,10 +396,6 @@ TEXT runtime·racecall(SB), NOSPLIT, $0-0 // Switches SP to g0 stack and calls (AX). Arguments already set. TEXT racecall<>(SB), NOSPLIT, $0-0 -#ifndef GOEXPERIMENT_regabig - get_tls(R12) - MOVQ g(R12), R14 -#endif MOVQ g_m(R14), R13 // Switch to g0 stack. MOVQ SP, R12 // callee-saved, preserved across the CALL diff --git a/src/runtime/sys_linux_amd64.s b/src/runtime/sys_linux_amd64.s index f22b7ad9282..64ddc2354e6 100644 --- a/src/runtime/sys_linux_amd64.s +++ b/src/runtime/sys_linux_amd64.s @@ -215,13 +215,7 @@ TEXT runtime·nanotime1(SB),NOSPLIT,$16-8 MOVQ SP, R12 // Save old SP; R12 unchanged by C code. -#ifdef GOEXPERIMENT_regabig MOVQ g_m(R14), BX // BX unchanged by C code. -#else - get_tls(CX) - MOVQ g(CX), AX - MOVQ g_m(AX), BX // BX unchanged by C code. -#endif // Set vdsoPC and vdsoSP for SIGPROF traceback. // Save the old values on stack and restore them on exit, @@ -236,11 +230,7 @@ TEXT runtime·nanotime1(SB),NOSPLIT,$16-8 MOVQ CX, m_vdsoPC(BX) MOVQ DX, m_vdsoSP(BX) -#ifdef GOEXPERIMENT_regabig CMPQ R14, m_curg(BX) // Only switch if on curg. -#else - CMPQ AX, m_curg(BX) // Only switch if on curg. -#endif JNE noswitch MOVQ m_g0(BX), DX diff --git a/src/runtime/time_linux_amd64.s b/src/runtime/time_linux_amd64.s index 0dd79198968..c88e92bd0ca 100644 --- a/src/runtime/time_linux_amd64.s +++ b/src/runtime/time_linux_amd64.s @@ -15,13 +15,7 @@ TEXT time·now(SB),NOSPLIT,$16-24 MOVQ SP, R12 // Save old SP; R12 unchanged by C code. -#ifdef GOEXPERIMENT_regabig MOVQ g_m(R14), BX // BX unchanged by C code. -#else - get_tls(CX) - MOVQ g(CX), AX - MOVQ g_m(AX), BX // BX unchanged by C code. -#endif // Store CLOCK_REALTIME results directly to return space. LEAQ sec+0(FP), SI @@ -38,11 +32,7 @@ TEXT time·now(SB),NOSPLIT,$16-24 MOVQ CX, m_vdsoPC(BX) MOVQ SI, m_vdsoSP(BX) -#ifdef GOEXPERIMENT_regabig CMPQ R14, m_curg(BX) // Only switch if on curg. -#else - CMPQ AX, m_curg(BX) // Only switch if on curg. -#endif JNE noswitch MOVQ m_g0(BX), DX From e552a6d31270c86064632af1d092e0db5a930250 Mon Sep 17 00:00:00 2001 From: Constantin Konstantinidis Date: Sat, 5 Jun 2021 07:48:30 +0200 Subject: [PATCH 385/940] cmd/go: remove hint when no module is suggested Fixes #46528 Change-Id: I2453d321ece878ea7823865758aa4a16b3ed7fe8 Reviewed-on: https://go-review.googlesource.com/c/go/+/325430 Reviewed-by: Bryan C. Mills Run-TryBot: Bryan C. Mills Trust: Heschi Kreinick Trust: Dmitri Shuralyov TryBot-Result: Go Bot --- src/cmd/go/internal/modload/import.go | 10 ++++++---- src/cmd/go/testdata/script/mod_install_hint.txt | 5 +++++ 2 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 src/cmd/go/testdata/script/mod_install_hint.txt diff --git a/src/cmd/go/internal/modload/import.go b/src/cmd/go/internal/modload/import.go index f76befcfe35..60bd26fb22f 100644 --- a/src/cmd/go/internal/modload/import.go +++ b/src/cmd/go/internal/modload/import.go @@ -178,11 +178,13 @@ func (e *ImportMissingSumError) Error() string { // Importing package is unknown, or the missing package was named on the // command line. Recommend 'go mod download' for the modules that could // provide the package, since that shouldn't change go.mod. - args := make([]string, len(e.mods)) - for i, mod := range e.mods { - args[i] = mod.Path + if len(e.mods) > 0 { + args := make([]string, len(e.mods)) + for i, mod := range e.mods { + args[i] = mod.Path + } + hint = fmt.Sprintf("; to add:\n\tgo mod download %s", strings.Join(args, " ")) } - hint = fmt.Sprintf("; to add:\n\tgo mod download %s", strings.Join(args, " ")) } else { // Importing package is known (common case). Recommend 'go get' on the // current version of the importing package. diff --git a/src/cmd/go/testdata/script/mod_install_hint.txt b/src/cmd/go/testdata/script/mod_install_hint.txt new file mode 100644 index 00000000000..ab02840eb8b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_install_hint.txt @@ -0,0 +1,5 @@ +# Module is replaced but not required. No hint appears as no module is suggested. +go mod init m +go mod edit -replace=github.com/notrequired@v0.5.0=github.com/doesnotexist@v0.5.0 +! go install github.com/notrequired +! stderr 'to add it:' \ No newline at end of file From 2954f11eadf344786d0ec6e3e1d34f6a5c385246 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 11 Jun 2021 06:33:30 -0700 Subject: [PATCH 386/940] [dev.typeparams] cmd/compile: scaffolding for export data experiments This CL adds a simple framework for augmenting the current export data format by writing out additional data *after* the existing data, with an extra header before it that current readers ignore. In particular, this is used by unified IR to be able to experiment and iterate on export data designs without having to keep the go/internal/gcimporter and x/tools/go/gcexportdata importers in sync. Instead, they simply continue reading the existing data written out by typecheck/iexport.go. Change-Id: I883211c2892e2c7dec758b85ff6bc31b244440a0 Reviewed-on: https://go-review.googlesource.com/c/go/+/327169 Run-TryBot: Matthew Dempsky Trust: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/noder/export.go | 47 +++++++++++- src/cmd/compile/internal/noder/import.go | 95 +++++++++++++++++------- 2 files changed, 111 insertions(+), 31 deletions(-) diff --git a/src/cmd/compile/internal/noder/export.go b/src/cmd/compile/internal/noder/export.go index 9fb3b4da109..1a296e22c84 100644 --- a/src/cmd/compile/internal/noder/export.go +++ b/src/cmd/compile/internal/noder/export.go @@ -5,22 +5,61 @@ package noder import ( + "bytes" "fmt" + "io" "cmd/compile/internal/base" "cmd/compile/internal/typecheck" "cmd/internal/bio" ) +// writeNewExportFunc is a hook that can be added to append extra +// export data after the normal export data section. It allows +// experimenting with new export data format designs without requiring +// immediate support in the go/internal or x/tools importers. +var writeNewExportFunc func(out io.Writer) + func WriteExports(out *bio.Writer) { + // When unified IR exports are enable, we simply append it to the + // end of the normal export data (with compiler extensions + // disabled), and write an extra header giving its size. + // + // If the compiler sees this header, it knows to read the new data + // instead; meanwhile the go/types importers will silently ignore it + // and continue processing the old export instead. + // + // This allows us to experiment with changes to the new export data + // format without needing to update the go/internal/gcimporter or + // (worse) x/tools/go/gcexportdata. + + useNewExport := writeNewExportFunc != nil + + var old, new bytes.Buffer + + typecheck.WriteExports(&old, !useNewExport) + + if useNewExport { + writeNewExportFunc(&new) + } + + oldLen := old.Len() + newLen := new.Len() + + if useNewExport { + fmt.Fprintf(out, "\nnewexportsize %v\n", newLen) + } + // The linker also looks for the $$ marker - use char after $$ to distinguish format. out.WriteString("\n$$B\n") // indicate binary export format - off := out.Offset() - typecheck.WriteExports(out, true) - size := out.Offset() - off + io.Copy(out, &old) out.WriteString("\n$$\n") + io.Copy(out, &new) if base.Debug.Export != 0 { - fmt.Printf("BenchmarkExportSize:%s 1 %d bytes\n", base.Ctxt.Pkgpath, size) + fmt.Printf("BenchmarkExportSize:%s 1 %d bytes\n", base.Ctxt.Pkgpath, oldLen) + if useNewExport { + fmt.Printf("BenchmarkNewExportSize:%s 1 %d bytes\n", base.Ctxt.Pkgpath, newLen) + } } } diff --git a/src/cmd/compile/internal/noder/import.go b/src/cmd/compile/internal/noder/import.go index 08e3f77b665..48f0e480284 100644 --- a/src/cmd/compile/internal/noder/import.go +++ b/src/cmd/compile/internal/noder/import.go @@ -31,6 +31,22 @@ import ( "cmd/internal/src" ) +// haveLegacyImports records whether we've imported any packages +// without a new export data section. This is useful for experimenting +// with new export data format designs, when you need to support +// existing tests that manually compile files with inconsistent +// compiler flags. +var haveLegacyImports = false + +// newReadImportFunc is an extension hook for experimenting with new +// export data formats. If a new export data payload was written out +// for an imported package by overloading writeNewExportFunc, then +// that payload will be mapped into memory and passed to +// newReadImportFunc. +var newReadImportFunc = func(data string, pkg1 *types.Pkg, check *types2.Checker, packages map[string]*types2.Package) (pkg2 *types2.Package, err error) { + panic("unexpected new export data payload") +} + type gcimports struct { check *types2.Checker packages map[string]*types2.Package @@ -245,7 +261,7 @@ func readImportFile(path string, target *ir.Package, check *types2.Checker, pack } defer f.Close() - r, end, err := findExportData(f) + r, end, newsize, err := findExportData(f) if err != nil { return } @@ -254,34 +270,51 @@ func readImportFile(path string, target *ir.Package, check *types2.Checker, pack fmt.Printf("importing %s (%s)\n", path, f.Name()) } - var c byte - switch c, err = r.ReadByte(); { - case err != nil: - return - - case c != 'i': - // Indexed format is distinguished by an 'i' byte, - // whereas previous export formats started with 'c', 'd', or 'v'. - err = fmt.Errorf("unexpected package format byte: %v", c) - return - } - - // Map string (and data) section into memory as a single large - // string. This reduces heap fragmentation and allows - // returning individual substrings very efficiently. - pos := r.Offset() - data, err := base.MapFile(r.File(), pos, end-pos) - if err != nil { - return - } - - typecheck.ReadImports(pkg1, data) - - if packages != nil { - pkg2, err = importer.ImportData(packages, data, path) + if newsize != 0 { + // We have unified IR data. Map it, and feed to the importers. + end -= newsize + var data string + data, err = base.MapFile(r.File(), end, newsize) if err != nil { return } + + pkg2, err = newReadImportFunc(data, pkg1, check, packages) + } else { + // We only have old data. Oh well, fall back to the legacy importers. + haveLegacyImports = true + + var c byte + switch c, err = r.ReadByte(); { + case err != nil: + return + + case c != 'i': + // Indexed format is distinguished by an 'i' byte, + // whereas previous export formats started with 'c', 'd', or 'v'. + err = fmt.Errorf("unexpected package format byte: %v", c) + return + } + + pos := r.Offset() + + // Map string (and data) section into memory as a single large + // string. This reduces heap fragmentation and allows + // returning individual substrings very efficiently. + var data string + data, err = base.MapFile(r.File(), pos, end-pos) + if err != nil { + return + } + + typecheck.ReadImports(pkg1, data) + + if packages != nil { + pkg2, err = importer.ImportData(packages, data, path) + if err != nil { + return + } + } } err = addFingerprint(path, f, end) @@ -291,7 +324,7 @@ func readImportFile(path string, target *ir.Package, check *types2.Checker, pack // findExportData returns a *bio.Reader positioned at the start of the // binary export data section, and a file offset for where to stop // reading. -func findExportData(f *os.File) (r *bio.Reader, end int64, err error) { +func findExportData(f *os.File) (r *bio.Reader, end, newsize int64, err error) { r = bio.NewReader(f) // check object header @@ -334,6 +367,14 @@ func findExportData(f *os.File) (r *bio.Reader, end int64, err error) { // process header lines for !strings.HasPrefix(line, "$$") { + if strings.HasPrefix(line, "newexportsize ") { + fields := strings.Fields(line) + newsize, err = strconv.ParseInt(fields[1], 10, 64) + if err != nil { + return + } + } + line, err = r.ReadString('\n') if err != nil { return From 9d46ee5ac4acd6602692f70c5149a3f6db058558 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Fri, 11 Jun 2021 13:58:05 +0000 Subject: [PATCH 387/940] reflect: handle stack-to-register translation in callMethod callMethod previously assumed erroneously that between the "value" and "method" ABIs (that is, the ABI the caller is following to call this method value and the actual ABI of the method), it could never happen that an argument passed on the stack in the former could be passed in registers in the latter. The cited reason was that the latter always uses strictly more registers. However, there are situations where the value ABI could pass a value on the stack, but later is passed in a register. For instance, if the receiver pushes a value passed in registers that uses multiple registers to be passed on the stack, later arguments which were passed on the stack may now be passed in registers. This change fixes callMethod to no longer makes this assumption, and handles the stack-to-register translation explicitly. Fixes #46696. Change-Id: I7100a664d97bbe401302cc893b3a98b28cdcdfc0 Reviewed-on: https://go-review.googlesource.com/c/go/+/327089 Trust: Michael Knyszek Run-TryBot: Michael Knyszek TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/reflect/abi_test.go | 43 ++++++++++++++++++++++++++++++++++++++++- src/reflect/value.go | 42 ++++++++++++++++++++++++++++++---------- 2 files changed, 74 insertions(+), 11 deletions(-) diff --git a/src/reflect/abi_test.go b/src/reflect/abi_test.go index 1a2a48b5ed9..5a0130f7b45 100644 --- a/src/reflect/abi_test.go +++ b/src/reflect/abi_test.go @@ -79,7 +79,34 @@ func TestMethodValueCallABI(t *testing.T) { t.Errorf("bad method value call: got %#v, want %#v", r2, a2) } if s.Value != 3 { - t.Errorf("bad method value call: failed to set s.Value: got %d, want %d", s.Value, 1) + t.Errorf("bad method value call: failed to set s.Value: got %d, want %d", s.Value, 3) + } + + s, i = makeMethodValue("ValueRegMethodSpillInt") + f3 := i.(func(StructFillRegs, int, MagicLastTypeNameForTestingRegisterABI) (StructFillRegs, int)) + r3a, r3b := f3(a2, 42, MagicLastTypeNameForTestingRegisterABI{}) + if r3a != a2 { + t.Errorf("bad method value call: got %#v, want %#v", r3a, a2) + } + if r3b != 42 { + t.Errorf("bad method value call: got %#v, want %#v", r3b, 42) + } + if s.Value != 4 { + t.Errorf("bad method value call: failed to set s.Value: got %d, want %d", s.Value, 4) + } + + s, i = makeMethodValue("ValueRegMethodSpillPtr") + f4 := i.(func(StructFillRegs, *byte, MagicLastTypeNameForTestingRegisterABI) (StructFillRegs, *byte)) + vb := byte(10) + r4a, r4b := f4(a2, &vb, MagicLastTypeNameForTestingRegisterABI{}) + if r4a != a2 { + t.Errorf("bad method value call: got %#v, want %#v", r4a, a2) + } + if r4b != &vb { + t.Errorf("bad method value call: got %#v, want %#v", r4b, &vb) + } + if s.Value != 5 { + t.Errorf("bad method value call: failed to set s.Value: got %d, want %d", s.Value, 5) } } @@ -112,6 +139,20 @@ func (m *StructWithMethods) SpillStructCall(s StructFillRegs, _ MagicLastTypeNam return s } +// When called as a method value, i is passed on the stack. +// When called as a method, i is passed in a register. +func (m *StructWithMethods) ValueRegMethodSpillInt(s StructFillRegs, i int, _ MagicLastTypeNameForTestingRegisterABI) (StructFillRegs, int) { + m.Value = 4 + return s, i +} + +// When called as a method value, i is passed on the stack. +// When called as a method, i is passed in a register. +func (m *StructWithMethods) ValueRegMethodSpillPtr(s StructFillRegs, i *byte, _ MagicLastTypeNameForTestingRegisterABI) (StructFillRegs, *byte) { + m.Value = 5 + return s, i +} + func TestReflectCallABI(t *testing.T) { // Enable register-based reflect.Call and ensure we don't // use potentially incorrect cached versions by clearing diff --git a/src/reflect/value.go b/src/reflect/value.go index 418dff781f4..c963a407bcc 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -952,25 +952,47 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer, retValid *bool, regs *a continue } - // There are three cases to handle in translating each + // There are four cases to handle in translating each // argument: // 1. Stack -> stack translation. - // 2. Registers -> stack translation. - // 3. Registers -> registers translation. - // The fourth cases can't happen, because a method value - // call uses strictly fewer registers than a method call. + // 2. Stack -> registers translation. + // 3. Registers -> stack translation. + // 4. Registers -> registers translation. + // TODO(mknyszek): Cases 2 and 3 below only work on little endian + // architectures. This is OK for now, but this needs to be fixed + // before supporting the register ABI on big endian architectures. // If the value ABI passes the value on the stack, // then the method ABI does too, because it has strictly // fewer arguments. Simply copy between the two. if vStep := valueSteps[0]; vStep.kind == abiStepStack { mStep := methodSteps[0] - if mStep.kind != abiStepStack || vStep.size != mStep.size { - panic("method ABI and value ABI do not align") + // Handle stack -> stack translation. + if mStep.kind == abiStepStack { + if vStep.size != mStep.size { + panic("method ABI and value ABI do not align") + } + typedmemmove(t, + add(methodFrame, mStep.stkOff, "precomputed stack offset"), + add(valueFrame, vStep.stkOff, "precomputed stack offset")) + continue + } + // Handle stack -> register translation. + for _, mStep := range methodSteps { + from := add(valueFrame, vStep.stkOff+mStep.offset, "precomputed stack offset") + switch mStep.kind { + case abiStepPointer: + // Do the pointer copy directly so we get a write barrier. + methodRegs.Ptrs[mStep.ireg] = *(*unsafe.Pointer)(from) + fallthrough // We need to make sure this ends up in Ints, too. + case abiStepIntReg: + memmove(unsafe.Pointer(&methodRegs.Ints[mStep.ireg]), from, mStep.size) + case abiStepFloatReg: + memmove(unsafe.Pointer(&methodRegs.Floats[mStep.freg]), from, mStep.size) + default: + panic("unexpected method step") + } } - typedmemmove(t, - add(methodFrame, mStep.stkOff, "precomputed stack offset"), - add(valueFrame, vStep.stkOff, "precomputed stack offset")) continue } // Handle register -> stack translation. From 8f00eb009978e2e1bb681e698a0b51e20333eb05 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 11 Jun 2021 18:51:56 -0700 Subject: [PATCH 388/940] [dev.typeparams] cmd/compile: avoid ir.DeepCopy in noder.constDecl Instead of using ir.DeepCopy to copy the IR from the previous constant declaration, just call exprList again and then fix up the position information. This is equivalent in practice, but has cleaner semantics for tricky corner cases like constant declarations that contain function literals. In particular, this refactoring is necessary for the next CL that cleans up function literal construction, because it adds extra consistency checks that weren't satisfied by DeepCopy'd OCLOSUREs. Change-Id: I0372bde5d6613695ee572cc8bf8fb4ff9aef4cb4 Reviewed-on: https://go-review.googlesource.com/c/go/+/327449 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/noder/noder.go | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go index 08c05a69bea..9dc05182d13 100644 --- a/src/cmd/compile/internal/noder/noder.go +++ b/src/cmd/compile/internal/noder/noder.go @@ -450,7 +450,7 @@ func (p *noder) varDecl(decl *syntax.VarDecl) []ir.Node { type constState struct { group *syntax.Group typ ir.Ntype - values []ir.Node + values syntax.Expr iota int64 } @@ -468,16 +468,15 @@ func (p *noder) constDecl(decl *syntax.ConstDecl, cs *constState) []ir.Node { names := p.declNames(ir.OLITERAL, decl.NameList) typ := p.typeExprOrNil(decl.Type) - var values []ir.Node if decl.Values != nil { - values = p.exprList(decl.Values) - cs.typ, cs.values = typ, values + cs.typ, cs.values = typ, decl.Values } else { if typ != nil { base.Errorf("const declaration cannot have type without expression") } - typ, values = cs.typ, cs.values + typ = cs.typ } + values := p.exprList(cs.values) nn := make([]ir.Node, 0, len(names)) for i, n := range names { @@ -485,10 +484,16 @@ func (p *noder) constDecl(decl *syntax.ConstDecl, cs *constState) []ir.Node { base.Errorf("missing value in const declaration") break } + v := values[i] if decl.Values == nil { - v = ir.DeepCopy(n.Pos(), v) + ir.Visit(v, func(v ir.Node) { + if ir.HasUniquePos(v) { + v.SetPos(n.Pos()) + } + }) } + typecheck.Declare(n, typecheck.DeclContext) n.Ntype = typ From 0132b91127c3cf6e19e0e1db014a04219427171e Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 11 Jun 2021 03:09:26 -0700 Subject: [PATCH 389/940] [dev.typeparams] cmd/compile: refactor closure construction typecheck.tcClosure is complicated with many code flows because all of its callers setup the closure funcs in slightly different ways. E.g., it's non-obvious who's responsible for setting the underlying func's Sym or adding it to target.Decls, or how to write new code that constructs a closure without interfering with existing code. This CL refactors everything to use three common functions in package ir: NewClosureFunc (which handle creating the Func, Name, and ClosureExpr and wiring them together), NameClosure (which generates and assigns its unique Sym), and UseClosure (which handles adding the Func to target.Decls). Most IR builders can actually name the closure right away, but the legacy noder+typecheck path may not yet know the name of the enclosing function. In particular, for methods declared with aliased receiver parameters, we need to wait until after typechecking top-level declarations to know the method's true name. So they're left anonymous until typecheck. UseClosure does relatively little work today, but it serves as a useful spot to check that the code setting up closures got it right. It may also eventually serve as an optimization point for early lifting of trivial closures, which may or may not ultimately be beneficial. Change-Id: I7da1e93c70d268f575b12d6aaeb2336eb910a6f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/327051 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/inline/inl.go | 32 ++---- src/cmd/compile/internal/ir/expr.go | 1 + src/cmd/compile/internal/ir/func.go | 100 ++++++++++++++++++ src/cmd/compile/internal/noder/expr.go | 16 +-- src/cmd/compile/internal/noder/noder.go | 69 ++++++------ src/cmd/compile/internal/noder/stencil.go | 47 +++----- src/cmd/compile/internal/typecheck/func.go | 80 +++++--------- src/cmd/compile/internal/typecheck/iimport.go | 17 +-- .../compile/internal/typecheck/typecheck.go | 6 +- src/cmd/compile/internal/walk/order.go | 28 ++--- 10 files changed, 200 insertions(+), 196 deletions(-) diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go index e12a30f9369..76a15dab8ba 100644 --- a/src/cmd/compile/internal/inline/inl.go +++ b/src/cmd/compile/internal/inline/inl.go @@ -1143,8 +1143,6 @@ func (subst *inlsubst) clovar(n *ir.Name) *ir.Name { // closure does the necessary substitions for a ClosureExpr n and returns the new // closure node. func (subst *inlsubst) closure(n *ir.ClosureExpr) ir.Node { - m := ir.Copy(n) - // Prior to the subst edit, set a flag in the inlsubst to // indicated that we don't want to update the source positions in // the new closure. If we do this, it will appear that the closure @@ -1152,29 +1150,21 @@ func (subst *inlsubst) closure(n *ir.ClosureExpr) ir.Node { // issue #46234 for more details. defer func(prev bool) { subst.noPosUpdate = prev }(subst.noPosUpdate) subst.noPosUpdate = true - ir.EditChildren(m, subst.edit) //fmt.Printf("Inlining func %v with closure into %v\n", subst.fn, ir.FuncName(ir.CurFunc)) - // The following is similar to funcLit + outerfunc := subst.newclofn + if outerfunc == nil { + outerfunc = ir.CurFunc + } + oldfn := n.Func - newfn := ir.NewFunc(oldfn.Pos()) - // These three lines are not strictly necessary, but just to be clear - // that new function needs to redo typechecking and inlinability. - newfn.SetTypecheck(0) - newfn.SetInlinabilityChecked(false) - newfn.Inl = nil - newfn.SetIsHiddenClosure(true) - newfn.Nname = ir.NewNameAt(n.Pos(), ir.BlankNode.Sym()) - newfn.Nname.Func = newfn + newfn := ir.NewClosureFunc(oldfn.Pos(), outerfunc) + // Ntype can be nil for -G=3 mode. if oldfn.Nname.Ntype != nil { newfn.Nname.Ntype = subst.node(oldfn.Nname.Ntype).(ir.Ntype) } - newfn.Nname.Defn = newfn - - m.(*ir.ClosureExpr).Func = newfn - newfn.OClosure = m.(*ir.ClosureExpr) if subst.newclofn != nil { //fmt.Printf("Inlining a closure with a nested closure\n") @@ -1224,13 +1214,13 @@ func (subst *inlsubst) closure(n *ir.ClosureExpr) ir.Node { // Actually create the named function for the closure, now that // the closure is inlined in a specific function. - m.SetTypecheck(0) + newclo := newfn.OClosure + newclo.SetInit(subst.list(n.Init())) if oldfn.ClosureCalled() { - typecheck.Callee(m) + return typecheck.Callee(newclo) } else { - typecheck.Expr(m) + return typecheck.Expr(newclo) } - return m } // node recursively copies a node from the saved pristine body of the diff --git a/src/cmd/compile/internal/ir/expr.go b/src/cmd/compile/internal/ir/expr.go index bcc0e412d58..779793b2f26 100644 --- a/src/cmd/compile/internal/ir/expr.go +++ b/src/cmd/compile/internal/ir/expr.go @@ -195,6 +195,7 @@ type ClosureExpr struct { IsGoWrap bool // whether this is wrapper closure of a go statement } +// Deprecated: Use NewClosureFunc instead. func NewClosureExpr(pos src.XPos, fn *Func) *ClosureExpr { n := &ClosureExpr{Func: fn} n.op = OCLOSURE diff --git a/src/cmd/compile/internal/ir/func.go b/src/cmd/compile/internal/ir/func.go index 1d76813a4c3..3d4f8c44865 100644 --- a/src/cmd/compile/internal/ir/func.go +++ b/src/cmd/compile/internal/ir/func.go @@ -9,6 +9,7 @@ import ( "cmd/compile/internal/types" "cmd/internal/obj" "cmd/internal/src" + "fmt" ) // A Func corresponds to a single function in a Go program @@ -311,3 +312,102 @@ func ClosureDebugRuntimeCheck(clo *ClosureExpr) { func IsTrivialClosure(clo *ClosureExpr) bool { return len(clo.Func.ClosureVars) == 0 } + +// globClosgen is like Func.Closgen, but for the global scope. +var globClosgen int32 + +// closureName generates a new unique name for a closure within outerfn. +func closureName(outerfn *Func) *types.Sym { + pkg := types.LocalPkg + outer := "glob." + prefix := "func" + gen := &globClosgen + + if outerfn != nil { + if outerfn.OClosure != nil { + prefix = "" + } + + pkg = outerfn.Sym().Pkg + outer = FuncName(outerfn) + + // There may be multiple functions named "_". In those + // cases, we can't use their individual Closgens as it + // would lead to name clashes. + if !IsBlank(outerfn.Nname) { + gen = &outerfn.Closgen + } + } + + *gen++ + return pkg.Lookup(fmt.Sprintf("%s.%s%d", outer, prefix, *gen)) +} + +// NewClosureFunc creates a new Func to represent a function literal +// within outerfn. +func NewClosureFunc(pos src.XPos, outerfn *Func) *Func { + fn := NewFunc(pos) + fn.SetIsHiddenClosure(outerfn != nil) + + fn.Nname = NewNameAt(pos, BlankNode.Sym()) + fn.Nname.Func = fn + fn.Nname.Defn = fn + + fn.OClosure = NewClosureExpr(pos, fn) + + return fn +} + +// NameClosure generates a unique for the given function literal, +// which must have appeared within outerfn. +func NameClosure(clo *ClosureExpr, outerfn *Func) { + name := clo.Func.Nname + if !IsBlank(name) { + base.FatalfAt(clo.Pos(), "closure already named: %v", name) + } + + name.SetSym(closureName(outerfn)) + MarkFunc(name) +} + +// UseClosure checks that the ginen function literal has been setup +// correctly, and then returns it as an expression. +// It must be called after clo.Func.ClosureVars has been set. +func UseClosure(clo *ClosureExpr, pkg *Package) Node { + fn := clo.Func + name := fn.Nname + + if IsBlank(name) { + base.FatalfAt(fn.Pos(), "unnamed closure func: %v", fn) + } + // Caution: clo.Typecheck() is still 0 when UseClosure is called by + // tcClosure. + if fn.Typecheck() != 1 || name.Typecheck() != 1 { + base.FatalfAt(fn.Pos(), "missed typecheck: %v", fn) + } + if clo.Type() == nil || name.Type() == nil { + base.FatalfAt(fn.Pos(), "missing types: %v", fn) + } + if !types.Identical(clo.Type(), name.Type()) { + base.FatalfAt(fn.Pos(), "mismatched types: %v", fn) + } + + if base.Flag.W > 1 { + s := fmt.Sprintf("new closure func: %v", fn) + Dump(s, fn) + } + + if pkg != nil { + pkg.Decls = append(pkg.Decls, fn) + } + + if false && IsTrivialClosure(clo) { + // TODO(mdempsky): Investigate if we can/should optimize this + // case. walkClosure already handles it later, but it could be + // useful to recognize earlier (e.g., it might allow multiple + // inlined calls to a function to share a common trivial closure + // func, rather than cloning it for each inlined call). + } + + return clo +} diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go index 7034a19b815..86a61bc7595 100644 --- a/src/cmd/compile/internal/noder/expr.go +++ b/src/cmd/compile/internal/noder/expr.go @@ -373,19 +373,13 @@ func (g *irgen) compLit(typ types2.Type, lit *syntax.CompositeLit) ir.Node { } func (g *irgen) funcLit(typ2 types2.Type, expr *syntax.FuncLit) ir.Node { - fn := ir.NewFunc(g.pos(expr)) - fn.SetIsHiddenClosure(ir.CurFunc != nil) + fn := ir.NewClosureFunc(g.pos(expr), ir.CurFunc) + ir.NameClosure(fn.OClosure, ir.CurFunc) - fn.Nname = ir.NewNameAt(g.pos(expr), typecheck.ClosureName(ir.CurFunc)) - ir.MarkFunc(fn.Nname) typ := g.typ(typ2) - fn.Nname.Func = fn - fn.Nname.Defn = fn typed(typ, fn.Nname) - fn.SetTypecheck(1) - - fn.OClosure = ir.NewClosureExpr(g.pos(expr), fn) typed(typ, fn.OClosure) + fn.SetTypecheck(1) g.funcBody(fn, nil, expr.Type, expr.Body) @@ -399,9 +393,7 @@ func (g *irgen) funcLit(typ2 types2.Type, expr *syntax.FuncLit) ir.Node { cv.SetWalkdef(1) } - g.target.Decls = append(g.target.Decls, fn) - - return fn.OClosure + return ir.UseClosure(fn.OClosure, g.target) } func (g *irgen) typeExpr(typ syntax.Expr) *types.Type { diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go index 9dc05182d13..ced3f32a534 100644 --- a/src/cmd/compile/internal/noder/noder.go +++ b/src/cmd/compile/internal/noder/noder.go @@ -110,25 +110,35 @@ func LoadPackage(filenames []string) { // We also defer type alias declarations until phase 2 // to avoid cycles like #18640. // TODO(gri) Remove this again once we have a fix for #25838. - - // Don't use range--typecheck can add closures to Target.Decls. - base.Timer.Start("fe", "typecheck", "top1") - for i := 0; i < len(typecheck.Target.Decls); i++ { - n := typecheck.Target.Decls[i] - if op := n.Op(); op != ir.ODCL && op != ir.OAS && op != ir.OAS2 && (op != ir.ODCLTYPE || !n.(*ir.Decl).X.Alias()) { - typecheck.Target.Decls[i] = typecheck.Stmt(n) - } - } - + // // Phase 2: Variable assignments. // To check interface assignments, depends on phase 1. // Don't use range--typecheck can add closures to Target.Decls. - base.Timer.Start("fe", "typecheck", "top2") - for i := 0; i < len(typecheck.Target.Decls); i++ { - n := typecheck.Target.Decls[i] - if op := n.Op(); op == ir.ODCL || op == ir.OAS || op == ir.OAS2 || op == ir.ODCLTYPE && n.(*ir.Decl).X.Alias() { - typecheck.Target.Decls[i] = typecheck.Stmt(n) + for phase, name := range []string{"top1", "top2"} { + base.Timer.Start("fe", "typecheck", name) + for i := 0; i < len(typecheck.Target.Decls); i++ { + n := typecheck.Target.Decls[i] + op := n.Op() + + // Closure function declarations are typechecked as part of the + // closure expression. + if fn, ok := n.(*ir.Func); ok && fn.OClosure != nil { + continue + } + + // We don't actually add ir.ODCL nodes to Target.Decls. Make sure of that. + if op == ir.ODCL { + base.FatalfAt(n.Pos(), "unexpected top declaration: %v", op) + } + + // Identify declarations that should be deferred to the second + // iteration. + late := op == ir.OAS || op == ir.OAS2 || op == ir.ODCLTYPE && n.(*ir.Decl).X.Alias() + + if late == (phase == 1) { + typecheck.Target.Decls[i] = typecheck.Stmt(n) + } } } @@ -137,16 +147,15 @@ func LoadPackage(filenames []string) { base.Timer.Start("fe", "typecheck", "func") var fcount int64 for i := 0; i < len(typecheck.Target.Decls); i++ { - n := typecheck.Target.Decls[i] - if n.Op() == ir.ODCLFUNC { + if fn, ok := typecheck.Target.Decls[i].(*ir.Func); ok { if base.Flag.W > 1 { - s := fmt.Sprintf("\nbefore typecheck %v", n) - ir.Dump(s, n) + s := fmt.Sprintf("\nbefore typecheck %v", fn) + ir.Dump(s, fn) } - typecheck.FuncBody(n.(*ir.Func)) + typecheck.FuncBody(fn) if base.Flag.W > 1 { - s := fmt.Sprintf("\nafter typecheck %v", n) - ir.Dump(s, n) + s := fmt.Sprintf("\nafter typecheck %v", fn) + ir.Dump(s, fn) } fcount++ } @@ -1794,24 +1803,14 @@ func fakeRecv() *ir.Field { } func (p *noder) funcLit(expr *syntax.FuncLit) ir.Node { - xtype := p.typeExpr(expr.Type) - - fn := ir.NewFunc(p.pos(expr)) - fn.SetIsHiddenClosure(ir.CurFunc != nil) - - fn.Nname = ir.NewNameAt(p.pos(expr), ir.BlankNode.Sym()) // filled in by tcClosure - fn.Nname.Func = fn - fn.Nname.Ntype = xtype - fn.Nname.Defn = fn - - clo := ir.NewClosureExpr(p.pos(expr), fn) - fn.OClosure = clo + fn := ir.NewClosureFunc(p.pos(expr), ir.CurFunc) + fn.Nname.Ntype = p.typeExpr(expr.Type) p.funcBody(fn, expr.Body) ir.FinishCaptureNames(base.Pos, ir.CurFunc, fn) - return clo + return fn.OClosure } // A function named init is a special case. diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 3e3de1908ec..a82274a2408 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -280,8 +280,8 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { // } // Make a new internal function. - fn := ir.NewFunc(pos) - fn.SetIsHiddenClosure(true) + fn := ir.NewClosureFunc(pos, outer) + ir.NameClosure(fn.OClosure, outer) // This is the dictionary we want to use. // It may be a constant, or it may be a dictionary acquired from the outer function's dictionary. @@ -346,13 +346,8 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { // Build an internal function with the right signature. closureType := types.NewSignature(x.Type().Pkg(), nil, nil, formalParams, formalResults) - sym := typecheck.ClosureName(outer) - sym.SetFunc(true) - fn.Nname = ir.NewNameAt(pos, sym) - fn.Nname.Class = ir.PFUNC - fn.Nname.Func = fn - fn.Nname.Defn = fn typed(closureType, fn.Nname) + typed(x.Type(), fn.OClosure) fn.SetTypecheck(1) // Build body of closure. This involves just calling the wrapped function directly @@ -401,15 +396,12 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { typecheck.Stmt(innerCall) ir.CurFunc = nil fn.Body = []ir.Node{innerCall} - if outer == nil { - g.target.Decls = append(g.target.Decls, fn) - } // We're all done with the captured dictionary (and receiver, for method values). ir.FinishCaptureNames(pos, outer, fn) // Make a closure referencing our new internal function. - c := ir.NewClosureExpr(pos, fn) + c := ir.UseClosure(fn.OClosure, g.target) var init []ir.Node if outer != nil { init = append(init, dictAssign) @@ -417,9 +409,7 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { if rcvrValue != nil { init = append(init, rcvrAssign) } - c.SetInit(init) - typed(x.Type(), c) - return c + return ir.InitExpr(init, c) } // instantiateMethods instantiates all the methods of all fully-instantiated @@ -859,24 +849,18 @@ func (subst *subster) node(n ir.Node) ir.Node { } case ir.OCLOSURE: + // We're going to create a new closure from scratch, so clear m + // to avoid using the ir.Copy by accident until we reassign it. + m = nil + x := x.(*ir.ClosureExpr) // Need to duplicate x.Func.Nname, x.Func.Dcl, x.Func.ClosureVars, and // x.Func.Body. oldfn := x.Func - newfn := ir.NewFunc(oldfn.Pos()) - if oldfn.ClosureCalled() { - newfn.SetClosureCalled(true) - } - newfn.SetIsHiddenClosure(true) - m.(*ir.ClosureExpr).Func = newfn - // Closure name can already have brackets, if it derives - // from a generic method - newsym := typecheck.MakeInstName(oldfn.Nname.Sym(), subst.ts.Targs, subst.isMethod) - newfn.Nname = ir.NewNameAt(oldfn.Nname.Pos(), newsym) - newfn.Nname.Func = newfn - newfn.Nname.Defn = newfn - ir.MarkFunc(newfn.Nname) - newfn.OClosure = m.(*ir.ClosureExpr) + newfn := ir.NewClosureFunc(oldfn.Pos(), subst.newf) + ir.NameClosure(newfn.OClosure, subst.newf) + + newfn.SetClosureCalled(oldfn.ClosureCalled()) saveNewf := subst.newf ir.CurFunc = newfn @@ -885,7 +869,7 @@ func (subst *subster) node(n ir.Node) ir.Node { newfn.ClosureVars = subst.namelist(oldfn.ClosureVars) typed(subst.ts.Typ(oldfn.Nname.Type()), newfn.Nname) - typed(newfn.Nname.Type(), m) + typed(newfn.Nname.Type(), newfn.OClosure) newfn.SetTypecheck(1) // Make sure type of closure function is set before doing body. @@ -893,7 +877,8 @@ func (subst *subster) node(n ir.Node) ir.Node { subst.newf = saveNewf ir.CurFunc = saveNewf - subst.g.target.Decls = append(subst.g.target.Decls, newfn) + m = ir.UseClosure(newfn.OClosure, subst.g.target) + m.(*ir.ClosureExpr).SetInit(subst.list(x.Init())) case ir.OCONVIFACE: x := x.(*ir.ConvExpr) diff --git a/src/cmd/compile/internal/typecheck/func.go b/src/cmd/compile/internal/typecheck/func.go index 15756a47e48..bd21977f26b 100644 --- a/src/cmd/compile/internal/typecheck/func.go +++ b/src/cmd/compile/internal/typecheck/func.go @@ -199,35 +199,6 @@ func fnpkg(fn *ir.Name) *types.Pkg { return fn.Sym().Pkg } -// ClosureName generates a new unique name for a closure within -// outerfunc. -func ClosureName(outerfunc *ir.Func) *types.Sym { - outer := "glob." - prefix := "func" - gen := &globClosgen - - if outerfunc != nil { - if outerfunc.OClosure != nil { - prefix = "" - } - - outer = ir.FuncName(outerfunc) - - // There may be multiple functions named "_". In those - // cases, we can't use their individual Closgens as it - // would lead to name clashes. - if !ir.IsBlank(outerfunc.Nname) { - gen = &outerfunc.Closgen - } - } - - *gen++ - return Lookup(fmt.Sprintf("%s.%s%d", outer, prefix, *gen)) -} - -// globClosgen is like Func.Closgen, but for the global scope. -var globClosgen int32 - // MethodValueWrapper returns the DCLFUNC node representing the // wrapper function (*-fm) needed for the given method value. If the // wrapper function hasn't already been created yet, it's created and @@ -312,8 +283,20 @@ func MethodValueWrapper(dot *ir.SelectorExpr) *ir.Func { // function associated with the closure. // TODO: This creation of the named function should probably really be done in a // separate pass from type-checking. -func tcClosure(clo *ir.ClosureExpr, top int) { +func tcClosure(clo *ir.ClosureExpr, top int) ir.Node { fn := clo.Func + + // We used to allow IR builders to typecheck the underlying Func + // themselves, but that led to too much variety and inconsistency + // around who's responsible for naming the function, typechecking + // it, or adding it to Target.Decls. + // + // It's now all or nothing. Callers are still allowed to do these + // themselves, but then they assume responsibility for all of them. + if fn.Typecheck() == 1 { + base.FatalfAt(fn.Pos(), "underlying closure func already typechecked: %v", fn) + } + // Set current associated iota value, so iota can be used inside // function in ConstSpec, see issue #22344 if x := getIotaValue(); x >= 0 { @@ -322,30 +305,14 @@ func tcClosure(clo *ir.ClosureExpr, top int) { fn.SetClosureCalled(top&ctxCallee != 0) - // Do not typecheck fn twice, otherwise, we will end up pushing - // fn to Target.Decls multiple times, causing InitLSym called twice. - // See #30709 - if fn.Typecheck() == 1 { - clo.SetType(fn.Type()) - return - } - - // Don't give a name and add to Target.Decls if we are typechecking an inlined - // body in ImportedBody(), since we only want to create the named function - // when the closure is actually inlined (and then we force a typecheck - // explicitly in (*inlsubst).node()). - if !inTypeCheckInl { - fn.Nname.SetSym(ClosureName(ir.CurFunc)) - ir.MarkFunc(fn.Nname) - } + ir.NameClosure(clo, ir.CurFunc) Func(fn) - clo.SetType(fn.Type()) // Type check the body now, but only if we're inside a function. // At top level (in a variable initialization: curfn==nil) we're not // ready to type check code yet; we'll check it later, because the // underlying closure function we create is added to Target.Decls. - if ir.CurFunc != nil && clo.Type() != nil { + if ir.CurFunc != nil { oldfn := ir.CurFunc ir.CurFunc = fn Stmts(fn.Body) @@ -371,14 +338,17 @@ func tcClosure(clo *ir.ClosureExpr, top int) { } fn.ClosureVars = fn.ClosureVars[:out] - if base.Flag.W > 1 { - s := fmt.Sprintf("New closure func: %s", ir.FuncName(fn)) - ir.Dump(s, fn) - } - if !inTypeCheckInl { - // Add function to Target.Decls once only when we give it a name - Target.Decls = append(Target.Decls, fn) + clo.SetType(fn.Type()) + + target := Target + if inTypeCheckInl { + // We're typechecking an imported function, so it's not actually + // part of Target. Skip adding it to Target.Decls so we don't + // compile it again. + target = nil } + + return ir.UseClosure(clo, target) } // type check function definition diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 9054a83e6e9..b1b3c27898e 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -1283,12 +1283,7 @@ func (r *importReader) node() ir.Node { // All the remaining code below is similar to (*noder).funcLit(), but // with Dcls and ClosureVars lists already set up - fn := ir.NewFunc(pos) - fn.SetIsHiddenClosure(true) - fn.Nname = ir.NewNameAt(pos, ir.BlankNode.Sym()) - fn.Nname.Func = fn - fn.Nname.Ntype = ir.TypeNode(typ) - fn.Nname.Defn = fn + fn := ir.NewClosureFunc(pos, r.curfn) fn.Nname.SetType(typ) cvars := make([]*ir.Name, r.int64()) @@ -1321,18 +1316,10 @@ func (r *importReader) node() ir.Node { ir.FinishCaptureNames(pos, r.curfn, fn) - clo := ir.NewClosureExpr(pos, fn) - fn.OClosure = clo + clo := fn.OClosure if go117ExportTypes { clo.SetType(typ) } - if r.curfn.Type().HasTParam() { - // Generic functions aren't inlined, so give the closure a - // function name now, which is then available for use - // (after appending the type args) for each stenciling. - fn.Nname.SetSym(ClosureName(r.curfn)) - } - return clo case ir.OSTRUCTLIT: diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go index 9868c2d9a92..a6b21f948a0 100644 --- a/src/cmd/compile/internal/typecheck/typecheck.go +++ b/src/cmd/compile/internal/typecheck/typecheck.go @@ -787,11 +787,7 @@ func typecheck1(n ir.Node, top int) ir.Node { case ir.OCLOSURE: n := n.(*ir.ClosureExpr) - tcClosure(n, top) - if n.Type() == nil { - return n - } - return n + return tcClosure(n, top) case ir.OITAB: n := n.(*ir.UnaryExpr) diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go index d1fd3a9b732..750cb6bfc5f 100644 --- a/src/cmd/compile/internal/walk/order.go +++ b/src/cmd/compile/internal/walk/order.go @@ -1704,14 +1704,10 @@ func (o *orderState) wrapGoDefer(n *ir.GoDeferStmt) { } // Create a new no-argument function that we'll hand off to defer. - var noFuncArgs []*ir.Field - noargst := ir.NewFuncType(base.Pos, nil, noFuncArgs, nil) - wrapGoDefer_prgen++ outerfn := ir.CurFunc - wrapname := fmt.Sprintf("%v·dwrap·%d", outerfn, wrapGoDefer_prgen) - sym := types.LocalPkg.Lookup(wrapname) - fn := typecheck.DeclFunc(sym, noargst) - fn.SetIsHiddenClosure(true) + + fn := ir.NewClosureFunc(base.Pos, outerfn) + fn.Nname.SetType(types.NewSignature(types.LocalPkg, nil, nil, nil, nil)) fn.SetWrapper(true) // helper for capturing reference to a var declared in an outer scope. @@ -1741,7 +1737,6 @@ func (o *orderState) wrapGoDefer(n *ir.GoDeferStmt) { if methSelectorExpr != nil { methSelectorExpr.X = capName(callX.Pos(), fn, methSelectorExpr.X.(*ir.Name)) } - ir.FinishCaptureNames(n.Pos(), outerfn, fn) // This flags a builtin as opposed to a regular call. irregular := (call.Op() != ir.OCALLFUNC && @@ -1755,23 +1750,12 @@ func (o *orderState) wrapGoDefer(n *ir.GoDeferStmt) { } newcall := mkNewCall(call.Pos(), op, callX, newCallArgs) - // Type-check the result. - if !irregular { - typecheck.Call(newcall.(*ir.CallExpr)) - } else { - typecheck.Stmt(newcall) - } - // Finalize body, register function on the main decls list. fn.Body = []ir.Node{newcall} - typecheck.FinishFuncBody() - typecheck.Func(fn) - typecheck.Target.Decls = append(typecheck.Target.Decls, fn) + ir.FinishCaptureNames(n.Pos(), outerfn, fn) // Create closure expr - clo := ir.NewClosureExpr(n.Pos(), fn) - fn.OClosure = clo - clo.SetType(fn.Type()) + clo := typecheck.Expr(fn.OClosure).(*ir.ClosureExpr) // Set escape properties for closure. if n.Op() == ir.OGO { @@ -1788,7 +1772,7 @@ func (o *orderState) wrapGoDefer(n *ir.GoDeferStmt) { } // Create new top level call to closure over argless function. - topcall := ir.NewCallExpr(n.Pos(), ir.OCALL, clo, []ir.Node{}) + topcall := ir.NewCallExpr(n.Pos(), ir.OCALL, clo, nil) typecheck.Call(topcall) // Tag the call to insure that directClosureCall doesn't undo our work. From db7c868307c87c5e9338e1cb0b5738eb96a929ad Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 11 Jun 2021 09:54:40 -0700 Subject: [PATCH 390/940] [dev.typeparams] test: add string quoting support to test/run.go This CL copies go/build's splitQuoted function (used for parsing #cgo directives within `import "C"` preambles) to parse test recipe commands. In particular, this now allows writing "build" and "run" tests that use -gcflags to pass multiple compiler flags. Change-Id: I0d18a9c13a4ce24bbdfa1da8662c0498c93a6762 Reviewed-on: https://go-review.googlesource.com/c/go/+/327275 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- test/run.go | 68 +++++++++- test/typeparam/dictionaryCapture-noinline.go | 126 +++++++++++++++++++ test/typeparam/dictionaryCapture.go | 2 - 3 files changed, 193 insertions(+), 3 deletions(-) create mode 100644 test/typeparam/dictionaryCapture-noinline.go diff --git a/test/run.go b/test/run.go index ef1e9de1502..ca6a0f5c295 100644 --- a/test/run.go +++ b/test/run.go @@ -573,7 +573,11 @@ func (t *test) run() { singlefilepkgs := false setpkgpaths := false localImports := true - f := strings.Fields(action) + f, err := splitQuoted(action) + if err != nil { + t.err = fmt.Errorf("invalid test recipe: %v", err) + return + } if len(f) > 0 { action = f[0] args = f[1:] @@ -2116,3 +2120,65 @@ var excludedFiles = map[string]bool{ "fixedbugs/issue7921.go": true, "inline.go": true, } + +// splitQuoted splits the string s around each instance of one or more consecutive +// white space characters while taking into account quotes and escaping, and +// returns an array of substrings of s or an empty list if s contains only white space. +// Single quotes and double quotes are recognized to prevent splitting within the +// quoted region, and are removed from the resulting substrings. If a quote in s +// isn't closed err will be set and r will have the unclosed argument as the +// last element. The backslash is used for escaping. +// +// For example, the following string: +// +// a b:"c d" 'e''f' "g\"" +// +// Would be parsed as: +// +// []string{"a", "b:c d", "ef", `g"`} +// +// [copied from src/go/build/build.go] +func splitQuoted(s string) (r []string, err error) { + var args []string + arg := make([]rune, len(s)) + escaped := false + quoted := false + quote := '\x00' + i := 0 + for _, rune := range s { + switch { + case escaped: + escaped = false + case rune == '\\': + escaped = true + continue + case quote != '\x00': + if rune == quote { + quote = '\x00' + continue + } + case rune == '"' || rune == '\'': + quoted = true + quote = rune + continue + case unicode.IsSpace(rune): + if quoted || i > 0 { + quoted = false + args = append(args, string(arg[:i])) + i = 0 + } + continue + } + arg[i] = rune + i++ + } + if quoted || i > 0 { + args = append(args, string(arg[:i])) + } + if quote != 0 { + err = errors.New("unclosed quote") + } else if escaped { + err = errors.New("unfinished escaping") + } + return args, err +} diff --git a/test/typeparam/dictionaryCapture-noinline.go b/test/typeparam/dictionaryCapture-noinline.go new file mode 100644 index 00000000000..4b46d5f57f3 --- /dev/null +++ b/test/typeparam/dictionaryCapture-noinline.go @@ -0,0 +1,126 @@ +// run -gcflags="-G=3 -l" + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test situations where functions/methods are not +// immediately called and we need to capture the dictionary +// required for later invocation. + +package main + +func main() { + functions() + methodExpressions() + methodValues() + interfaceMethods() + globals() +} + +func g0[T any](x T) { +} +func g1[T any](x T) T { + return x +} +func g2[T any](x T) (T, T) { + return x, x +} + +func functions() { + f0 := g0[int] + f0(7) + f1 := g1[int] + is7(f1(7)) + f2 := g2[int] + is77(f2(7)) +} + +func is7(x int) { + if x != 7 { + println(x) + panic("assertion failed") + } +} +func is77(x, y int) { + if x != 7 || y != 7 { + println(x,y) + panic("assertion failed") + } +} + +type s[T any] struct { + a T +} + +func (x s[T]) g0() { +} +func (x s[T]) g1() T { + return x.a +} +func (x s[T]) g2() (T, T) { + return x.a, x.a +} + +func methodExpressions() { + x := s[int]{a:7} + f0 := s[int].g0 + f0(x) + f1 := s[int].g1 + is7(f1(x)) + f2 := s[int].g2 + is77(f2(x)) +} + +func methodValues() { + x := s[int]{a:7} + f0 := x.g0 + f0() + f1 := x.g1 + is7(f1()) + f2 := x.g2 + is77(f2()) +} + +var x interface{ + g0() + g1()int + g2()(int,int) +} = s[int]{a:7} +var y interface{} = s[int]{a:7} + +func interfaceMethods() { + x.g0() + is7(x.g1()) + is77(x.g2()) + y.(interface{g0()}).g0() + is7(y.(interface{g1()int}).g1()) + is77(y.(interface{g2()(int,int)}).g2()) +} + +// Also check for instantiations outside functions. +var gg0 = g0[int] +var gg1 = g1[int] +var gg2 = g2[int] + +var hh0 = s[int].g0 +var hh1 = s[int].g1 +var hh2 = s[int].g2 + +var xtop = s[int]{a:7} +var ii0 = x.g0 +var ii1 = x.g1 +var ii2 = x.g2 + +func globals() { + gg0(7) + is7(gg1(7)) + is77(gg2(7)) + x := s[int]{a:7} + hh0(x) + is7(hh1(x)) + is77(hh2(x)) + ii0() + is7(ii1()) + is77(ii2()) +} diff --git a/test/typeparam/dictionaryCapture.go b/test/typeparam/dictionaryCapture.go index bb35df53098..1b2ee1de910 100644 --- a/test/typeparam/dictionaryCapture.go +++ b/test/typeparam/dictionaryCapture.go @@ -8,8 +8,6 @@ // immediately called and we need to capture the dictionary // required for later invocation. -// TODO: copy this test file, add -l to gcflags. - package main func main() { From f1b1c2f67fae0598db5c20f324334c23d4cd3038 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Sat, 12 Jun 2021 07:33:18 -0700 Subject: [PATCH 391/940] [dev.typeparams] cmd/compile: simplify NewClosureFunc I initially made NewClosureFunc take an "outerfn *Func" parameter because I was planning on having it handle closure naming, until remembering that naming needs to wait until typecheck for noder. We don't actually need the *Func yet, just to know whether it's non-nil. So change the parameter to a bool, which simplifies callers a little. Change-Id: Ie83ee4a1ed0571ac6d3879ffd8474c6c3c1a9ff9 Reviewed-on: https://go-review.googlesource.com/c/go/+/327450 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky Reviewed-by: Cuong Manh Le TryBot-Result: Go Bot --- src/cmd/compile/internal/inline/inl.go | 7 +------ src/cmd/compile/internal/ir/func.go | 17 ++++++++++++----- src/cmd/compile/internal/noder/expr.go | 2 +- src/cmd/compile/internal/noder/noder.go | 2 +- src/cmd/compile/internal/noder/stencil.go | 4 ++-- src/cmd/compile/internal/typecheck/iimport.go | 2 +- src/cmd/compile/internal/walk/order.go | 6 ++---- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go index 76a15dab8ba..0620191bbf6 100644 --- a/src/cmd/compile/internal/inline/inl.go +++ b/src/cmd/compile/internal/inline/inl.go @@ -1153,13 +1153,8 @@ func (subst *inlsubst) closure(n *ir.ClosureExpr) ir.Node { //fmt.Printf("Inlining func %v with closure into %v\n", subst.fn, ir.FuncName(ir.CurFunc)) - outerfunc := subst.newclofn - if outerfunc == nil { - outerfunc = ir.CurFunc - } - oldfn := n.Func - newfn := ir.NewClosureFunc(oldfn.Pos(), outerfunc) + newfn := ir.NewClosureFunc(oldfn.Pos(), true) // Ntype can be nil for -G=3 mode. if oldfn.Nname.Ntype != nil { diff --git a/src/cmd/compile/internal/ir/func.go b/src/cmd/compile/internal/ir/func.go index 3d4f8c44865..6480becc931 100644 --- a/src/cmd/compile/internal/ir/func.go +++ b/src/cmd/compile/internal/ir/func.go @@ -343,11 +343,13 @@ func closureName(outerfn *Func) *types.Sym { return pkg.Lookup(fmt.Sprintf("%s.%s%d", outer, prefix, *gen)) } -// NewClosureFunc creates a new Func to represent a function literal -// within outerfn. -func NewClosureFunc(pos src.XPos, outerfn *Func) *Func { +// NewClosureFunc creates a new Func to represent a function literal. +// If hidden is true, then the closure is marked hidden (i.e., as a +// function literal contained within another function, rather than a +// package-scope variable initialization expression). +func NewClosureFunc(pos src.XPos, hidden bool) *Func { fn := NewFunc(pos) - fn.SetIsHiddenClosure(outerfn != nil) + fn.SetIsHiddenClosure(hidden) fn.Nname = NewNameAt(pos, BlankNode.Sym()) fn.Nname.Func = fn @@ -361,7 +363,12 @@ func NewClosureFunc(pos src.XPos, outerfn *Func) *Func { // NameClosure generates a unique for the given function literal, // which must have appeared within outerfn. func NameClosure(clo *ClosureExpr, outerfn *Func) { - name := clo.Func.Nname + fn := clo.Func + if fn.IsHiddenClosure() != (outerfn != nil) { + base.FatalfAt(clo.Pos(), "closure naming inconsistency: hidden %v, but outer %v", fn.IsHiddenClosure(), outerfn) + } + + name := fn.Nname if !IsBlank(name) { base.FatalfAt(clo.Pos(), "closure already named: %v", name) } diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go index 86a61bc7595..98dc504ee98 100644 --- a/src/cmd/compile/internal/noder/expr.go +++ b/src/cmd/compile/internal/noder/expr.go @@ -373,7 +373,7 @@ func (g *irgen) compLit(typ types2.Type, lit *syntax.CompositeLit) ir.Node { } func (g *irgen) funcLit(typ2 types2.Type, expr *syntax.FuncLit) ir.Node { - fn := ir.NewClosureFunc(g.pos(expr), ir.CurFunc) + fn := ir.NewClosureFunc(g.pos(expr), ir.CurFunc != nil) ir.NameClosure(fn.OClosure, ir.CurFunc) typ := g.typ(typ2) diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go index ced3f32a534..63822d30893 100644 --- a/src/cmd/compile/internal/noder/noder.go +++ b/src/cmd/compile/internal/noder/noder.go @@ -1803,7 +1803,7 @@ func fakeRecv() *ir.Field { } func (p *noder) funcLit(expr *syntax.FuncLit) ir.Node { - fn := ir.NewClosureFunc(p.pos(expr), ir.CurFunc) + fn := ir.NewClosureFunc(p.pos(expr), ir.CurFunc != nil) fn.Nname.Ntype = p.typeExpr(expr.Type) p.funcBody(fn, expr.Body) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index a82274a2408..8b53671dbe2 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -280,7 +280,7 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { // } // Make a new internal function. - fn := ir.NewClosureFunc(pos, outer) + fn := ir.NewClosureFunc(pos, outer != nil) ir.NameClosure(fn.OClosure, outer) // This is the dictionary we want to use. @@ -857,7 +857,7 @@ func (subst *subster) node(n ir.Node) ir.Node { // Need to duplicate x.Func.Nname, x.Func.Dcl, x.Func.ClosureVars, and // x.Func.Body. oldfn := x.Func - newfn := ir.NewClosureFunc(oldfn.Pos(), subst.newf) + newfn := ir.NewClosureFunc(oldfn.Pos(), subst.newf != nil) ir.NameClosure(newfn.OClosure, subst.newf) newfn.SetClosureCalled(oldfn.ClosureCalled()) diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index b1b3c27898e..81f8ea05d9c 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -1283,7 +1283,7 @@ func (r *importReader) node() ir.Node { // All the remaining code below is similar to (*noder).funcLit(), but // with Dcls and ClosureVars lists already set up - fn := ir.NewClosureFunc(pos, r.curfn) + fn := ir.NewClosureFunc(pos, true) fn.Nname.SetType(typ) cvars := make([]*ir.Name, r.int64()) diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go index 750cb6bfc5f..845bf036571 100644 --- a/src/cmd/compile/internal/walk/order.go +++ b/src/cmd/compile/internal/walk/order.go @@ -1704,9 +1704,7 @@ func (o *orderState) wrapGoDefer(n *ir.GoDeferStmt) { } // Create a new no-argument function that we'll hand off to defer. - outerfn := ir.CurFunc - - fn := ir.NewClosureFunc(base.Pos, outerfn) + fn := ir.NewClosureFunc(base.Pos, true) fn.Nname.SetType(types.NewSignature(types.LocalPkg, nil, nil, nil, nil)) fn.SetWrapper(true) @@ -1752,7 +1750,7 @@ func (o *orderState) wrapGoDefer(n *ir.GoDeferStmt) { // Finalize body, register function on the main decls list. fn.Body = []ir.Node{newcall} - ir.FinishCaptureNames(n.Pos(), outerfn, fn) + ir.FinishCaptureNames(n.Pos(), ir.CurFunc, fn) // Create closure expr clo := typecheck.Expr(fn.OClosure).(*ir.ClosureExpr) From 1ed0d129e9ba9b55e9ae36ac1d7f2766ba16b373 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 11 Jun 2021 11:50:42 -0700 Subject: [PATCH 392/940] runtime: testprogcgo: don't call exported Go functions directly from Go Instead route through a C function, to avoid declaration conflicts between the declaration needed in the cgo comment and the declaration generated by cgo in _cgo_export.h. This is not something user code will ever do, so no need to make it work in cgo. Fixes #46502 Change-Id: I1bfffdc76ef8ea63e3829871298d0774157957a5 Reviewed-on: https://go-review.googlesource.com/c/go/+/327309 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Cherry Mui Reviewed-by: Jason A. Donenfeld --- src/runtime/testdata/testprogcgo/aprof.go | 4 ++-- src/runtime/testdata/testprogcgo/aprof_c.c | 9 +++++++++ src/runtime/testdata/testprogcgo/bigstack1_windows.c | 12 ++++++++++++ src/runtime/testdata/testprogcgo/bigstack_windows.go | 4 ++-- 4 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 src/runtime/testdata/testprogcgo/aprof_c.c create mode 100644 src/runtime/testdata/testprogcgo/bigstack1_windows.c diff --git a/src/runtime/testdata/testprogcgo/aprof.go b/src/runtime/testdata/testprogcgo/aprof.go index aabca9e1ebd..44a15b08650 100644 --- a/src/runtime/testdata/testprogcgo/aprof.go +++ b/src/runtime/testdata/testprogcgo/aprof.go @@ -10,7 +10,7 @@ package main // The test fails when the function is the first C function. // The exported functions are the first C functions, so we use that. -// extern void GoNop(); +// extern void CallGoNop(); import "C" import ( @@ -38,7 +38,7 @@ func CgoCCodeSIGPROF() { break } } - C.GoNop() + C.CallGoNop() } c <- true }() diff --git a/src/runtime/testdata/testprogcgo/aprof_c.c b/src/runtime/testdata/testprogcgo/aprof_c.c new file mode 100644 index 00000000000..d588e13045f --- /dev/null +++ b/src/runtime/testdata/testprogcgo/aprof_c.c @@ -0,0 +1,9 @@ +// Copyright 2021 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. + +#include "_cgo_export.h" + +void CallGoNop() { + GoNop(); +} diff --git a/src/runtime/testdata/testprogcgo/bigstack1_windows.c b/src/runtime/testdata/testprogcgo/bigstack1_windows.c new file mode 100644 index 00000000000..551fb683093 --- /dev/null +++ b/src/runtime/testdata/testprogcgo/bigstack1_windows.c @@ -0,0 +1,12 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This is not in bigstack_windows.c because it needs to be part of +// testprogcgo but is not part of the DLL built from bigstack_windows.c. + +#include "_cgo_export.h" + +void CallGoBigStack1(char* p) { + goBigStack1(p); +} diff --git a/src/runtime/testdata/testprogcgo/bigstack_windows.go b/src/runtime/testdata/testprogcgo/bigstack_windows.go index f58fcf993f0..135b5fcfe04 100644 --- a/src/runtime/testdata/testprogcgo/bigstack_windows.go +++ b/src/runtime/testdata/testprogcgo/bigstack_windows.go @@ -6,7 +6,7 @@ package main /* typedef void callback(char*); -extern void goBigStack1(char*); +extern void CallGoBigStack1(char*); extern void bigStack(callback*); */ import "C" @@ -18,7 +18,7 @@ func init() { func BigStack() { // Create a large thread stack and call back into Go to test // if Go correctly determines the stack bounds. - C.bigStack((*C.callback)(C.goBigStack1)) + C.bigStack((*C.callback)(C.CallGoBigStack1)) } //export goBigStack1 From 8eeaf961c50973b0aa2065d2c31dfa5d9949bf93 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Sat, 12 Jun 2021 18:44:51 -0700 Subject: [PATCH 393/940] [dev.typeparams] cmd/compile: move //go:embed -lang check to noder User errors should be reported in noder and/or typecheck, we already know the -lang flag's value during noding, and checking it then works better for unified IR. The "multiple files for type" and "cannot apply to var of type" errors should also be moved to typecheck, but then they'd have to be duplicated for -G=3 mode (because it avoids typecheck). So those are left behind for now. Change-Id: I7caf16163c9faf975784acacdb8147514d2e698e Reviewed-on: https://go-review.googlesource.com/c/go/+/327609 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/noder/noder.go | 2 ++ src/cmd/compile/internal/staticdata/embed.go | 7 ------- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go index 63822d30893..d417edcbd52 100644 --- a/src/cmd/compile/internal/noder/noder.go +++ b/src/cmd/compile/internal/noder/noder.go @@ -1886,6 +1886,8 @@ func checkEmbed(decl *syntax.VarDecl, haveEmbed, withinFunc bool) error { return errors.New("go:embed cannot apply to var without type") case withinFunc: return errors.New("go:embed cannot apply to var inside func") + case !types.AllowsGoVersion(types.LocalPkg, 1, 16): + return fmt.Errorf("go:embed requires go1.16 or later (-lang was set to %s; check go.mod)", base.Flag.Lang) default: return nil diff --git a/src/cmd/compile/internal/staticdata/embed.go b/src/cmd/compile/internal/staticdata/embed.go index 8936c4f5b44..0730d346b24 100644 --- a/src/cmd/compile/internal/staticdata/embed.go +++ b/src/cmd/compile/internal/staticdata/embed.go @@ -108,13 +108,6 @@ func WriteEmbed(v *ir.Name) { // TODO(mdempsky): User errors should be reported by the frontend. commentPos := (*v.Embed)[0].Pos - if !types.AllowsGoVersion(types.LocalPkg, 1, 16) { - prevPos := base.Pos - base.Pos = commentPos - base.ErrorfVers("go1.16", "go:embed") - base.Pos = prevPos - return - } if base.Flag.Cfg.Embed.Patterns == nil { base.ErrorfAt(commentPos, "invalid go:embed: build system did not supply embed configuration") return From 67b1b6a2e3a405e3e0b5c6a76f702b2a6071c1f0 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Sun, 13 Jun 2021 10:55:19 +0700 Subject: [PATCH 394/940] cmd/compile: allow ir.OSLICE2ARRPTR in mayCall CL 301650 adds conversion from slice to array ptr. The conversion expression may appear as argument to a function call, so it will be tested by mayCall. But ir.OSLICE2ARRPTR op is not handled by mayCall, causes the compiler crashes. Updates #395 Fixes #46720 Change-Id: I39e1b3e38e224a31f3dec46dbbdc855ff3b2c6a5 Reviewed-on: https://go-review.googlesource.com/c/go/+/327649 Trust: Cuong Manh Le Trust: Josh Bleecher Snyder Run-TryBot: Cuong Manh Le Reviewed-by: Matthew Dempsky Reviewed-by: Josh Bleecher Snyder TryBot-Result: Go Bot --- src/cmd/compile/internal/walk/walk.go | 2 +- test/fixedbugs/issue46720.go | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue46720.go diff --git a/src/cmd/compile/internal/walk/walk.go b/src/cmd/compile/internal/walk/walk.go index fe2c62cd4f8..26da6e31457 100644 --- a/src/cmd/compile/internal/walk/walk.go +++ b/src/cmd/compile/internal/walk/walk.go @@ -313,7 +313,7 @@ func mayCall(n ir.Node) bool { return true case ir.OINDEX, ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR, ir.OSLICESTR, - ir.ODEREF, ir.ODOTPTR, ir.ODOTTYPE, ir.ODIV, ir.OMOD: + ir.ODEREF, ir.ODOTPTR, ir.ODOTTYPE, ir.ODIV, ir.OMOD, ir.OSLICE2ARRPTR: // These ops might panic, make sure they are done // before we start marshaling args for a call. See issue 16760. return true diff --git a/test/fixedbugs/issue46720.go b/test/fixedbugs/issue46720.go new file mode 100644 index 00000000000..3b0151ae84f --- /dev/null +++ b/test/fixedbugs/issue46720.go @@ -0,0 +1,15 @@ +// compile + +// Copyright 2021 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 + +func f() { + nonce := make([]byte, 24) + g((*[24]byte)(nonce)) +} + +//go:noinline +func g(*[24]byte) {} From 24cff0f0444793be81062684c478a3f7ca955499 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sat, 12 Jun 2021 12:34:40 +0200 Subject: [PATCH 395/940] cmd/go, misc/cgo: skip test if no .edata Clang does not produce binaries with an .edata section, even when it exports symbols properly, so just skip this binutils-specific test for that case. Later we can rewrite these tests entirely to do something more robust. Updates #46719. Change-Id: I864b3c2d91e66800c55454ae11d4ab1623693d14 Reviewed-on: https://go-review.googlesource.com/c/go/+/327549 Trust: Jason A. Donenfeld Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- misc/cgo/testcshared/cshared_test.go | 2 +- src/cmd/go/go_test.go | 10 +--------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/misc/cgo/testcshared/cshared_test.go b/misc/cgo/testcshared/cshared_test.go index 90d8c365e6d..fdc6df9602c 100644 --- a/misc/cgo/testcshared/cshared_test.go +++ b/misc/cgo/testcshared/cshared_test.go @@ -400,7 +400,7 @@ func main() { defer f.Close() section := f.Section(".edata") if section == nil { - t.Fatalf(".edata section is not present") + t.Skip(".edata section is not present") } // TODO: deduplicate this struct from cmd/link/internal/ld/pe.go diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index a059a6dd902..c0c86ab9f58 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -72,7 +72,6 @@ func tooSlow(t *testing.T) { // (temp) directory. var testGOROOT string -var testCC string var testGOCACHE string var testGo string @@ -179,13 +178,6 @@ func TestMain(m *testing.M) { os.Exit(2) } - out, err = exec.Command(gotool, "env", "CC").CombinedOutput() - if err != nil { - fmt.Fprintf(os.Stderr, "could not find testing CC: %v\n%s", err, out) - os.Exit(2) - } - testCC = strings.TrimSpace(string(out)) - cmd := exec.Command(testGo, "env", "CGO_ENABLED") cmd.Stderr = new(strings.Builder) if out, err := cmd.Output(); err != nil { @@ -2185,7 +2177,7 @@ func testBuildmodePIE(t *testing.T, useCgo, setBuildmodeToPIE bool) { // See https://sourceware.org/bugzilla/show_bug.cgi?id=19011 section := f.Section(".edata") if section == nil { - t.Fatalf(".edata section is not present") + t.Skip(".edata section is not present") } // TODO: deduplicate this struct from cmd/link/internal/ld/pe.go type IMAGE_EXPORT_DIRECTORY struct { From 14305bf0b9ab87bcaca11416ab61e7a4ba09690d Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Fri, 11 Jun 2021 17:53:29 +0200 Subject: [PATCH 396/940] misc/cgo: generate Windows import libraries for clang LLD won't import a .dll directly and instead requires an import library. So generate these using -out-implib, the same way as was done in CL 312046, where it makes sense, and elsewhere build the import library using a def file. We can't use -out-implib all the time, because the output file gets overwritten each time the linker is called, rather than merged. Updates #46502. Change-Id: Iefe54cb6c576004b83b1039ba673881b8640423d Reviewed-on: https://go-review.googlesource.com/c/go/+/327211 Trust: Jason A. Donenfeld Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- misc/cgo/testcshared/cshared_test.go | 56 +++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/misc/cgo/testcshared/cshared_test.go b/misc/cgo/testcshared/cshared_test.go index fdc6df9602c..19ad8c76a83 100644 --- a/misc/cgo/testcshared/cshared_test.go +++ b/misc/cgo/testcshared/cshared_test.go @@ -292,11 +292,60 @@ func createHeaders() error { "-installsuffix", "testcshared", "-o", libgoname, filepath.Join(".", "libgo", "libgo.go")} + if GOOS == "windows" && strings.HasSuffix(args[6], ".a") { + args[6] = strings.TrimSuffix(args[6], ".a") + ".dll" + } cmd = exec.Command(args[0], args[1:]...) out, err = cmd.CombinedOutput() if err != nil { return fmt.Errorf("command failed: %v\n%v\n%s\n", args, err, out) } + if GOOS == "windows" { + // We can't simply pass -Wl,--out-implib, because this relies on having imports from multiple packages, + // which results in the linkers output implib getting overwritten at each step. So instead build the + // import library the traditional way, using a def file. + err = os.WriteFile("libgo.def", + []byte("LIBRARY libgo.dll\nEXPORTS\n\tDidInitRun\n\tDidMainRun\n\tDivu\n\tFromPkg\n\t_cgo_dummy_export\n"), + 0644) + if err != nil { + return fmt.Errorf("unable to write def file: %v", err) + } + out, err = exec.Command(cc[0], append(cc[1:], "-print-prog-name=dlltool")...).CombinedOutput() + if err != nil { + return fmt.Errorf("unable to find dlltool path: %v\n%s\n", err, out) + } + args := []string{strings.TrimSpace(string(out)), "-D", args[6], "-l", libgoname, "-d", "libgo.def"} + + // This is an unfortunate workaround for https://github.com/mstorsjo/llvm-mingw/issues/205 in which + // we basically reimplement the contents of the dlltool.sh wrapper: https://git.io/JZFlU + dlltoolContents, err := os.ReadFile(args[0]) + if err != nil { + return fmt.Errorf("unable to read dlltool: %v\n", err) + } + if bytes.HasPrefix(dlltoolContents, []byte("#!/bin/sh")) && bytes.Contains(dlltoolContents, []byte("llvm-dlltool")) { + base, name := filepath.Split(args[0]) + args[0] = filepath.Join(base, "llvm-dlltool") + var machine string + switch strings.SplitN(name, "-", 2)[0] { + case "i686": + machine = "i386" + case "x86_64": + machine = "i386:x86-64" + case "armv7": + machine = "arm" + case "aarch64": + machine = "arm64" + } + if len(machine) > 0 { + args = append(args, "-m", machine) + } + } + + out, err = exec.Command(args[0], args[1:]...).CombinedOutput() + if err != nil { + return fmt.Errorf("unable to run dlltool to create import library: %v\n%s\n", err, out) + } + } if runtime.GOOS != GOOS && GOOS == "android" { args = append(adbCmd(), "push", libgoname, fmt.Sprintf("%s/%s", androiddir, libgoname)) @@ -749,7 +798,12 @@ func TestGo2C2Go(t *testing.T) { defer os.RemoveAll(tmpdir) lib := filepath.Join(tmpdir, "libtestgo2c2go."+libSuffix) - run(t, nil, "go", "build", "-buildmode=c-shared", "-o", lib, "./go2c2go/go") + var env []string + if GOOS == "windows" && strings.HasSuffix(lib, ".a") { + env = append(env, "CGO_LDFLAGS=-Wl,--out-implib,"+lib, "CGO_LDFLAGS_ALLOW=.*") + lib = strings.TrimSuffix(lib, ".a") + ".dll" + } + run(t, env, "go", "build", "-buildmode=c-shared", "-o", lib, "./go2c2go/go") cgoCflags := os.Getenv("CGO_CFLAGS") if cgoCflags != "" { From 3249b645c986849bbf72c1dc71efc4f90df465ec Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Sun, 13 Jun 2021 22:26:21 +0700 Subject: [PATCH 397/940] cmd/compile: factor out rewrite multi-valued f() So next CL can reuse code to rewrite OAS2FUNC. Passes toolstash -cmp. For #46725 Change-Id: I1113ed615b6d6b9494dd87000ce342d7a46d9e7b Reviewed-on: https://go-review.googlesource.com/c/go/+/327650 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- .../compile/internal/typecheck/typecheck.go | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go index 95f7b50259f..391e18bd0a9 100644 --- a/src/cmd/compile/internal/typecheck/typecheck.go +++ b/src/cmd/compile/internal/typecheck/typecheck.go @@ -945,16 +945,18 @@ func typecheckargs(n ir.InitNode) { return } - // Rewrite f(g()) into t1, t2, ... = g(); f(t1, t2, ...). - // Save n as n.Orig for fmt.go. if ir.Orig(n) == n { n.(ir.OrigNode).SetOrig(ir.SepCopy(n)) } - as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil) - as.Rhs.Append(list...) + // Rewrite f(g()) into t1, t2, ... = g(); f(t1, t2, ...). + rewriteMultiValueCall(n, list[0]) +} +// rewriteMultiValueCall rewrites multi-valued f() to use temporaries, +// so the backend wouldn't need to worry about tuple-valued expressions. +func rewriteMultiValueCall(n ir.InitNode, call ir.Node) { // If we're outside of function context, then this call will // be executed during the generated init function. However, // init.go hasn't yet created it. Instead, associate the @@ -964,25 +966,30 @@ func typecheckargs(n ir.InitNode) { if static { ir.CurFunc = InitTodoFunc } - list = nil - for _, f := range t.FieldSlice() { - t := Temp(f.Type) - as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, t)) - as.Lhs.Append(t) - list = append(list, t) + + as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, []ir.Node{call}) + results := call.Type().FieldSlice() + list := make([]ir.Node, len(results)) + for i, result := range results { + tmp := Temp(result.Type) + as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, tmp)) + as.Lhs.Append(tmp) + list[i] = tmp } if static { ir.CurFunc = nil } + n.PtrInit().Append(Stmt(as)) + switch n := n.(type) { + default: + base.Fatalf("rewriteMultiValueCall %+v", n.Op()) case *ir.CallExpr: n.Args = list case *ir.ReturnStmt: n.Results = list } - - n.PtrInit().Append(Stmt(as)) } func checksliceindex(l ir.Node, r ir.Node, tp *types.Type) bool { From 326ea438bb579a2010e38e00f515a04344ff96b0 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Sun, 13 Jun 2021 22:28:44 +0700 Subject: [PATCH 398/940] cmd/compile: rewrite a, b = f() to use temporaries when type not identical If any of the LHS expressions of an OAS2FUNC are not identical to the respective function call results, escape analysis mishandles the implicit conversion, causes memory corruption. Instead, we should insert autotmps like we already do for f(g()) calls and return g() statements. Fixes #46725 Change-Id: I71a08da0bf1a03d09a023da5b6f78fb37a4a4690 Reviewed-on: https://go-review.googlesource.com/c/go/+/327651 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/typecheck/stmt.go | 14 +++++- .../compile/internal/typecheck/typecheck.go | 10 ++++ test/declbad.go | 4 +- test/fixedbugs/issue46725.go | 48 +++++++++++++++++++ 4 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 test/fixedbugs/issue46725.go diff --git a/src/cmd/compile/internal/typecheck/stmt.go b/src/cmd/compile/internal/typecheck/stmt.go index 175216f279c..922a01bfbe9 100644 --- a/src/cmd/compile/internal/typecheck/stmt.go +++ b/src/cmd/compile/internal/typecheck/stmt.go @@ -204,8 +204,20 @@ assignOK: r.Use = ir.CallUseList rtyp := r.Type() + mismatched := false + failed := false for i := range lhs { - assignType(i, rtyp.Field(i).Type) + result := rtyp.Field(i).Type + assignType(i, result) + + if lhs[i].Type() == nil || result == nil { + failed = true + } else if lhs[i] != ir.BlankNode && !types.Identical(lhs[i].Type(), result) { + mismatched = true + } + } + if mismatched && !failed { + rewriteMultiValueCall(stmt, r) } return } diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go index 391e18bd0a9..bf52941b2cf 100644 --- a/src/cmd/compile/internal/typecheck/typecheck.go +++ b/src/cmd/compile/internal/typecheck/typecheck.go @@ -989,6 +989,16 @@ func rewriteMultiValueCall(n ir.InitNode, call ir.Node) { n.Args = list case *ir.ReturnStmt: n.Results = list + case *ir.AssignListStmt: + if n.Op() != ir.OAS2FUNC { + base.Fatalf("rewriteMultiValueCall: invalid op %v", n.Op()) + } + as.SetOp(ir.OAS2FUNC) + n.SetOp(ir.OAS2) + n.Rhs = make([]ir.Node, len(list)) + for i, tmp := range list { + n.Rhs[i] = AssignConv(tmp, n.Lhs[i].Type(), "assignment") + } } } diff --git a/test/declbad.go b/test/declbad.go index 728eceb7f1e..b978652a2b1 100644 --- a/test/declbad.go +++ b/test/declbad.go @@ -23,13 +23,13 @@ func main() { { // change of type for f i, f, s := f3() - f, g, t := f3() // ERROR "redeclared|cannot assign|incompatible" + f, g, t := f3() // ERROR "redeclared|cannot assign|incompatible|cannot use" _, _, _, _, _ = i, f, s, g, t } { // change of type for i i, f, s := f3() - j, i, t := f3() // ERROR "redeclared|cannot assign|incompatible" + j, i, t := f3() // ERROR "redeclared|cannot assign|incompatible|cannot use" _, _, _, _, _ = i, f, s, j, t } { diff --git a/test/fixedbugs/issue46725.go b/test/fixedbugs/issue46725.go new file mode 100644 index 00000000000..29799c7d7ee --- /dev/null +++ b/test/fixedbugs/issue46725.go @@ -0,0 +1,48 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "runtime" + +type T [4]int + +//go:noinline +func g(x []*T) ([]*T, []*T) { return x, x } + +func main() { + const Jenny = 8675309 + s := [10]*T{{Jenny}} + + done := make(chan struct{}) + runtime.SetFinalizer(s[0], func(p *T) { close(done) }) + + var h, _ interface{} = g(s[:]) + + if wait(done) { + panic("GC'd early") + } + + if h.([]*T)[0][0] != Jenny { + panic("lost Jenny's number") + } + + if !wait(done) { + panic("never GC'd") + } +} + +func wait(done <-chan struct{}) bool { + for i := 0; i < 10; i++ { + runtime.GC() + select { + case <-done: + return true + default: + } + } + return false +} From fdab5be159c508c4c1cf5be84119fd2b38403cdf Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Mon, 14 Jun 2021 23:47:10 +1000 Subject: [PATCH 399/940] doc/go1.17: further revise OpenBSD release notes Simplify and remove forward-compatibility reference, as OpenBSD 6.9 has already been released (1st of May 2021). Updates #44513 Change-Id: I0a1abbb397f31d15c80a970edaa9723f894cafa9 Reviewed-on: https://go-review.googlesource.com/c/go/+/327652 Trust: Joel Sing Reviewed-by: Cherry Mui --- doc/go1.17.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 4fa38921f01..35d0f974502 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -106,8 +106,7 @@ Do not send CLs removing the interior tags from such phrases. of directly using machine instructions. In Go 1.17, this is also done on the 32-bit x86 and 32-bit ARM architectures on OpenBSD (the openbsd/386 and openbsd/arm ports). - This ensures forward-compatibility with future versions of - OpenBSD, in particular, with OpenBSD 6.9 onwards, which requires + This ensures compatibility with OpenBSD 6.9 onwards, which require system calls to be made through libc for non-static Go binaries.

From d4f34f8c63b753160716e9f90ca530016ce019d7 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Mon, 14 Jun 2021 12:35:21 -0400 Subject: [PATCH 400/940] doc/go1.17: reword "results" in stack trace printing "Results" may sound like the results from the previous sentence. Reword to "function return values" for clarity. Suggested by Tobias Kohlbau. Change-Id: Ie78df36b5b191b06e98b802f9a46db6d067a8ea0 Reviewed-on: https://go-review.googlesource.com/c/go/+/327774 Trust: Cherry Mui Reviewed-by: Michael Knyszek Reviewed-by: Tobias Kohlbau --- doc/go1.17.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 35d0f974502..e0856ff83ab 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -406,7 +406,8 @@ func Foo() bool { by commas. Aggregate-typed (struct, array, string, slice, interface, and complex) arguments are delimited by curly braces. A caveat is that the value of an argument that only lives in a register and is not stored to memory may be - inaccurate. Results (which were usually inaccurate) are no longer printed. + inaccurate. Function return values (which were usually inaccurate) are no longer + printed.

From 6bbb0a9d4a086af04d8eb16e17d1b144622a86f5 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Fri, 11 Jun 2021 17:38:23 +0200 Subject: [PATCH 401/940] cmd/internal/sys: mark windows/arm64 as c-shared-capable The platform supports c-shared now, so flip this on. I've given this a small smoke test using [1], and it was able to pass packets and generally function well. Since [1] uses quite a bit of Go functionality under the hood, I think it's a decent test that a lot of things that should be working are working. So this commit enables it. [1] https://git.zx2c4.com/wireguard-windows/about/embeddable-dll-service/README.md Updates #46502. Change-Id: I5c771d033bd20e5ce472c315d7c207bbc1020b4a Reviewed-on: https://go-review.googlesource.com/c/go/+/326310 Trust: Jason A. Donenfeld Trust: Alex Brainman Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/cmd/dist/test.go | 2 +- src/cmd/internal/sys/supported.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 1ed2c0f631e..f2c4cf0b430 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -1057,7 +1057,7 @@ func (t *tester) supportedBuildmode(mode string) bool { "darwin-amd64", "darwin-arm64", "freebsd-amd64", "android-arm", "android-arm64", "android-386", - "windows-amd64", "windows-386": + "windows-amd64", "windows-386", "windows-arm64": return true } return false diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go index fa477b837ff..0d2bad96127 100644 --- a/src/cmd/internal/sys/supported.go +++ b/src/cmd/internal/sys/supported.go @@ -74,7 +74,7 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool { "android/amd64", "android/arm", "android/arm64", "android/386", "freebsd/amd64", "darwin/amd64", "darwin/arm64", - "windows/amd64", "windows/386": + "windows/amd64", "windows/386", "windows/arm64": return true } return false From 0fd20ed5b67a950c7085b20c36dbfd9a70d2bfda Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 14 Jun 2021 14:30:46 -0700 Subject: [PATCH 402/940] reflect: use same conversion panic in reflect and runtime Consistently say "pointer to array", not "array pointer". Fixes #46743 Change-Id: I2388ec5c16f96e82a3a383b9b462b350686ddc5e Reviewed-on: https://go-review.googlesource.com/c/go/+/327870 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor Reviewed-by: Matthew Dempsky TryBot-Result: Go Bot --- src/reflect/all_test.go | 2 +- src/reflect/value.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 17104ad4fab..0db5e132172 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -4371,7 +4371,7 @@ func TestConvertPanic(t *testing.T) { if !v.Type().ConvertibleTo(pt) { t.Errorf("[]byte should be convertible to *[8]byte") } - shouldPanic("reflect: cannot convert slice with length 4 to array pointer with length 8", func() { + shouldPanic("reflect: cannot convert slice with length 4 to pointer to array with length 8", func() { _ = v.Convert(pt) }) } diff --git a/src/reflect/value.go b/src/reflect/value.go index c963a407bcc..6ba6202a1a1 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -3067,7 +3067,7 @@ func cvtSliceArrayPtr(v Value, t Type) Value { n := t.Elem().Len() h := (*unsafeheader.Slice)(v.ptr) if n > h.Len { - panic("reflect: cannot convert slice with length " + itoa.Itoa(h.Len) + " to array pointer with length " + itoa.Itoa(n)) + panic("reflect: cannot convert slice with length " + itoa.Itoa(h.Len) + " to pointer to array with length " + itoa.Itoa(n)) } return Value{t.common(), h.Data, v.flag&^(flagIndir|flagAddr|flagKindMask) | flag(Ptr)} } From 9d13f8d43e88a349762c61aee84614ac83dab521 Mon Sep 17 00:00:00 2001 From: Eric Wang Date: Mon, 14 Jun 2021 11:29:33 +0000 Subject: [PATCH 403/940] runtime: update the variable name in comment The comment use allg to refer to allgs in code. Update the comment to use the same variable name. Change-Id: Id059fce7846776737fb038b86bcf8765a4a7c9c0 GitHub-Last-Rev: 234fb0a208f105352d33456159725a3fce3a3071 GitHub-Pull-Request: golang/go#46723 Reviewed-on: https://go-review.googlesource.com/c/go/+/327629 Reviewed-by: Ian Lance Taylor Trust: Dmitri Shuralyov --- src/runtime/proc.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 59160c6525f..8f1a4439456 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -529,8 +529,8 @@ var ( allglock mutex allgs []*g - // allglen and allgptr are atomic variables that contain len(allg) and - // &allg[0] respectively. Proper ordering depends on totally-ordered + // allglen and allgptr are atomic variables that contain len(allgs) and + // &allgs[0] respectively. Proper ordering depends on totally-ordered // loads and stores. Writes are protected by allglock. // // allgptr is updated before allglen. Readers should read allglen From 8a5a6f46dc51597174d0044dcd3bdffa950ae65e Mon Sep 17 00:00:00 2001 From: Victor Michel Date: Fri, 11 Jun 2021 05:44:00 +0000 Subject: [PATCH 404/940] debug/elf: don't apply DWARF relocations for ET_EXEC binaries Some ET_EXEC binaries might have relocations for non-loadable sections like .debug_info. These relocations must not be applied, because: * They may be incorrect * The correct relocations were already applied at link time Binaries in Linux Kernel debug packages like Fedora/Centos kernel-debuginfo are such examples. Relocations for .debug_* sections are included in the final binaries because they are compiled with --emit-relocs, but the resulting relocations are incorrect and shouldn't be used when reading DWARF sections. Fixes #46673 Change-Id: I2b4214f1584bfc243446d0eaee41512657325b95 GitHub-Last-Rev: 8350fad059e70422d13dfaa5bab7fb8a56c0f76f GitHub-Pull-Request: golang/go#46698 Reviewed-on: https://go-review.googlesource.com/c/go/+/327009 Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor Reviewed-by: Cherry Mui --- src/debug/elf/file.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/debug/elf/file.go b/src/debug/elf/file.go index cd5bf8fab00..b25d8209e36 100644 --- a/src/debug/elf/file.go +++ b/src/debug/elf/file.go @@ -1164,6 +1164,13 @@ func (f *File) DWARF() (*dwarf.Data, error) { b = dbuf } + if f.Type == ET_EXEC { + // Do not apply relocations to DWARF sections for ET_EXEC binaries. + // Relocations should already be applied, and .rela sections may + // contain incorrect data. + return b, nil + } + for _, r := range f.Sections { if r.Type != SHT_RELA && r.Type != SHT_REL { continue From 7841cb14d95cf64c29b865c8a761a9e00fbbb37c Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Sun, 13 Jun 2021 16:00:28 -0700 Subject: [PATCH 405/940] doc/go1.17: assorted fixes Change-Id: I64235ad920240de9e2414b9ee6f4cfc4006b2862 Reviewed-on: https://go-review.googlesource.com/c/go/+/327709 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder Reviewed-by: Ian Lance Taylor --- doc/go1.17.html | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index e0856ff83ab..642bd601494 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -59,7 +59,7 @@ Do not send CLs removing the interior tags from such phrases.

- These enhancements were added to simplify writing code that conforms + The package unsafe enhancements were added to simplify writing code that conforms to unsafe.Pointer's safety rules, but the rules remain unchanged. In particular, existing programs that correctly use unsafe.Pointer remain @@ -735,7 +735,7 @@ func Foo() bool { These components were always interpreted as decimal, but some operating systems treat them as octal. This mismatch could hypothetically lead to security issues if a Go application was used to validate IP addresses which were then used in their original form with non-Go applications which interpreted components as octal. Generally, - it is advisable to always re-encoded values after validation, which avoids this class of parser misalignment issues. + it is advisable to always re-encode values after validation, which avoids this class of parser misalignment issues.

@@ -786,7 +786,7 @@ func Foo() bool {

The File.WriteString method - has been optimized to no longer make a copy of the input string. + has been optimized to not make a copy of the input string.

@@ -812,6 +812,14 @@ func Foo() bool { The ArrayOf function now panics when called with a negative length.

+ +

+ Checking the Type.ConvertibleTo method + is no longer sufficient to guarantee that a call to + Value.Convert will not panic. + It may panic when converting `[]T` to `*[N]T` if the slice's length is less than N. + See the language changes section above. +

@@ -838,7 +846,7 @@ func Foo() bool {

The strconv package now uses Ulf Adams's Ryū algorithm for formatting floating-point numbers. - This algorithm improves performance on most inputs, and is more than 99% faster on worst-case inputs. + This algorithm improves performance on most inputs and is more than 99% faster on worst-case inputs.

From cf4e3e3d3b3a713ec4df7e995d5bf5caef045a09 Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Sat, 12 Jun 2021 12:25:12 -0700 Subject: [PATCH 406/940] reflect: explain why convertible or comparable types may still panic Conversions of slices to arrays may panic since the slice is too short. Comparibility of interfaces may panic since the underlying value is incomparable. This is a follow-up to CL 301652 Change-Id: Ia5d84a6e556a7b82c39add4be93ed7463e63cc8d Reviewed-on: https://go-review.googlesource.com/c/go/+/327589 Trust: Joe Tsai Trust: Joe Tsai Run-TryBot: Joe Tsai TryBot-Result: Go Bot Reviewed-by: Josh Bleecher Snyder Reviewed-by: Ian Lance Taylor Reviewed-by: Katie Hockman Reviewed-by: Matthew Dempsky --- src/reflect/type.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/reflect/type.go b/src/reflect/type.go index 39414fc2a64..df863ae106f 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -107,10 +107,14 @@ type Type interface { // ConvertibleTo reports whether a value of the type is convertible to type u. // Even if ConvertibleTo returns true, the conversion may still panic. + // For example, a slice of type []T is convertible to *[N]T, + // but the conversion will panic if its length is less than N. ConvertibleTo(u Type) bool // Comparable reports whether values of this type are comparable. // Even if Comparable returns true, the comparison may still panic. + // For example, values of interface type are comparable, + // but the comparison will panic if their dynamic type is not comparable. Comparable() bool // Methods applicable only to some types, depending on Kind. From 4061d3463bb02def972e24aff173b0e5f98c0c3d Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Tue, 15 Jun 2021 01:55:50 +0200 Subject: [PATCH 407/940] syscall: rewrite handle inheritance test to use C rather than Powershell In CL 327210, we disabled this test on arm platforms, because the powershell shipped with those systems isn't native, which means it'd refuse to load native DLLs. This commit rewrites the test to simply not use Powershell, and instead compiles a trivial C program that tests for the same thing. Reverting CL 316269 makes this test fail, as desired, while applying it makes this test succeed. Fixes #46701 Change-Id: If39612c57bf74c63adf58e2c49b5cb739b461fe5 Reviewed-on: https://go-review.googlesource.com/c/go/+/327969 Trust: Jason A. Donenfeld Trust: Alex Brainman Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Alex Brainman --- src/syscall/syscall_windows_test.go | 38 +++++++++++++++++------------ 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/src/syscall/syscall_windows_test.go b/src/syscall/syscall_windows_test.go index 3243952ded1..581a246cd93 100644 --- a/src/syscall/syscall_windows_test.go +++ b/src/syscall/syscall_windows_test.go @@ -10,7 +10,6 @@ import ( "os" "os/exec" "path/filepath" - "runtime" "strings" "syscall" "testing" @@ -80,9 +79,6 @@ func TestTOKEN_ALL_ACCESS(t *testing.T) { func TestStdioAreInheritable(t *testing.T) { testenv.MustHaveGoBuild(t) testenv.MustHaveExecPath(t, "gcc") - if runtime.GOARCH == "arm64" || runtime.GOARCH == "arm" { - t.Skip("Powershell is not native on ARM; see golang.org/issues/46701") - } tmpdir := t.TempDir() @@ -114,18 +110,28 @@ func main() {} t.Fatalf("failed to build go library: %s\n%s", err, out) } - // run powershell script - psscript := fmt.Sprintf(` -hostname; -$signature = " [DllImport("%q")] public static extern void HelloWorld(); "; -Add-Type -MemberDefinition $signature -Name World -Namespace Hello; -[Hello.World]::HelloWorld(); -hostname; -`, dll) - psscript = strings.ReplaceAll(psscript, "\n", "") - out, err = exec.Command("powershell", "-Command", psscript).CombinedOutput() + // build c exe + const exetext = ` +#include +#include +int main(int argc, char *argv[]) +{ + system("hostname"); + ((void(*)(void))GetProcAddress(LoadLibraryA(%q), "HelloWorld"))(); + system("hostname"); + return 0; +} +` + exe := filepath.Join(tmpdir, "helloworld.exe") + cmd = exec.Command("gcc", "-o", exe, "-xc", "-") + cmd.Stdin = strings.NewReader(fmt.Sprintf(exetext, dll)) + out, err = testenv.CleanCmdEnv(cmd).CombinedOutput() if err != nil { - t.Fatalf("Powershell command failed: %v: %v", err, string(out)) + t.Fatalf("failed to build c executable: %s\n%s", err, out) + } + out, err = exec.Command(exe).CombinedOutput() + if err != nil { + t.Fatalf("c program execution failed: %v: %v", err, string(out)) } hostname, err := os.Hostname() @@ -137,6 +143,6 @@ hostname; have = strings.ReplaceAll(have, "\r", "") want := fmt.Sprintf("%sHello World%s", hostname, hostname) if have != want { - t.Fatalf("Powershell command output is wrong: got %q, want %q", have, want) + t.Fatalf("c program output is wrong: got %q, want %q", have, want) } } From abc56fd1a0505d4fc27943cbcda81ac783fb2d2f Mon Sep 17 00:00:00 2001 From: cuishuang Date: Tue, 15 Jun 2021 10:11:06 +0000 Subject: [PATCH 408/940] internal/bytealg: remove duplicate go:build line Change-Id: I6b71bf468b9544820829f02e320673f5edd785fa GitHub-Last-Rev: 8082ac5fba18e630dd2a21771837e6f0b1f9853f GitHub-Pull-Request: golang/go#46683 Reviewed-on: https://go-review.googlesource.com/c/go/+/326730 Reviewed-by: Ian Lance Taylor Trust: Tobias Klauser --- src/internal/bytealg/index_generic.go | 1 - src/internal/bytealg/index_native.go | 1 - 2 files changed, 2 deletions(-) diff --git a/src/internal/bytealg/index_generic.go b/src/internal/bytealg/index_generic.go index 287bdba4c68..0a6eb90d2d9 100644 --- a/src/internal/bytealg/index_generic.go +++ b/src/internal/bytealg/index_generic.go @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// go:build !amd64 && !arm64 && !s390x && !ppc64le && !ppc64 //go:build !amd64 && !arm64 && !s390x && !ppc64le && !ppc64 // +build !amd64,!arm64,!s390x,!ppc64le,!ppc64 diff --git a/src/internal/bytealg/index_native.go b/src/internal/bytealg/index_native.go index 75aff4b3cb0..9547a5d8e2a 100644 --- a/src/internal/bytealg/index_native.go +++ b/src/internal/bytealg/index_native.go @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// go:build amd64 || arm64 || s390x || ppc64le || ppc64 //go:build amd64 || arm64 || s390x || ppc64le || ppc64 // +build amd64 arm64 s390x ppc64le ppc64 From ea8612ef42bfbf837e22aef669e9f715100e532a Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Tue, 15 Jun 2021 17:04:01 +0200 Subject: [PATCH 409/940] syscall: disable c-shared test when no cgo, for windows/arm The windows/arm port does not yet support cgo, so disable a test that requires it. This fixes a regression from CL 327969, which added support for arm64, but errantly dropped the t.Skip for both arm and arm64, rather than just for arm64. With this commit, we make the test specific to cgo, rather than the architecture. Change-Id: Ibe1166c1965e007c7af899b07ded65f2a2633ddd Reviewed-on: https://go-review.googlesource.com/c/go/+/327970 Trust: Jason A. Donenfeld Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills --- src/syscall/syscall_windows_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/syscall/syscall_windows_test.go b/src/syscall/syscall_windows_test.go index 581a246cd93..194c87805cd 100644 --- a/src/syscall/syscall_windows_test.go +++ b/src/syscall/syscall_windows_test.go @@ -78,6 +78,7 @@ func TestTOKEN_ALL_ACCESS(t *testing.T) { func TestStdioAreInheritable(t *testing.T) { testenv.MustHaveGoBuild(t) + testenv.MustHaveCGO(t) testenv.MustHaveExecPath(t, "gcc") tmpdir := t.TempDir() From 033d885315dd67c509d6f7f12f3e3a26bb1ca127 Mon Sep 17 00:00:00 2001 From: Michael Matloob Date: Thu, 10 Jun 2021 17:02:44 -0400 Subject: [PATCH 410/940] doc/go1.17: document go run pkg@version Fixes #46687 Change-Id: I6c311f15d3871a9824306b901fa0b81818ed2df8 Reviewed-on: https://go-review.googlesource.com/c/go/+/326870 Trust: Michael Matloob Run-TryBot: Michael Matloob TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills --- doc/go1.17.html | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/go1.17.html b/doc/go1.17.html index 642bd601494..75c05c9e255 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -292,6 +292,18 @@ Do not send CLs removing the interior tags from such phrases. https://golang.org/design/draft-gobuild.

+

go run

+ +

+ go run now accepts arguments with version suffixes + (for example, go run + example.com/cmd@v1.0.0). This causes go + run to build and run packages in module-aware mode, ignoring the + go.mod file in the current directory or any parent directory, if + there is one. This is useful for running executables without installing them or + without changing dependencies of the current module. +

+

Gofmt

From 4d2d89ff42ca07eac5e600a3f5bba8fb137b6e99 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Wed, 2 Jun 2021 14:39:53 -0700 Subject: [PATCH 411/940] cmd/go, go/build: update docs to use //go:build syntax Fixes #46124. Change-Id: I6b8179032102a14befc37719f64ddace98397c97 Reviewed-on: https://go-review.googlesource.com/c/go/+/326931 Trust: Damien Neil Run-TryBot: Damien Neil TryBot-Result: Go Bot Reviewed-by: Russ Cox --- src/cmd/go/alldocs.go | 42 +++++++++++++---------------- src/cmd/go/internal/help/helpdoc.go | 42 +++++++++++++---------------- src/go/build/doc.go | 2 +- 3 files changed, 37 insertions(+), 49 deletions(-) diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index ab61017c4eb..3febe880cdd 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -1568,7 +1568,7 @@ // // A build constraint, also known as a build tag, is a line comment that begins // -// // +build +// //go:build // // that lists the conditions under which a file should be included in the package. // Constraints may appear in any kind of source file (not just Go), but @@ -1576,30 +1576,20 @@ // only by blank lines and other line comments. These rules mean that in Go // files a build constraint must appear before the package clause. // -// To distinguish build constraints from package documentation, a series of -// build constraints must be followed by a blank line. +// To distinguish build constraints from package documentation, +// a build constraint should be followed by a blank line. // -// A build constraint is evaluated as the OR of space-separated options. -// Each option evaluates as the AND of its comma-separated terms. -// Each term consists of letters, digits, underscores, and dots. -// A term may be negated with a preceding !. -// For example, the build constraint: +// A build constraint is evaluated as an expression containing options +// combined by ||, &&, and ! operators and parentheses. Operators have +// the same meaning as in Go. // -// // +build linux,386 darwin,!cgo +// For example, the following build constraint constrains a file to +// build when the "linux" and "386" constraints are satisfied, or when +// "darwin" is satisfied and "cgo" is not: // -// corresponds to the boolean formula: +// //go:build (linux && 386) || (darwin && !cgo) // -// (linux AND 386) OR (darwin AND (NOT cgo)) -// -// A file may have multiple build constraints. The overall constraint is the AND -// of the individual constraints. That is, the build constraints: -// -// // +build linux darwin -// // +build amd64 -// -// corresponds to the boolean formula: -// -// (linux OR darwin) AND amd64 +// It is an error for a file to have more than one //go:build line. // // During a particular build, the following words are satisfied: // @@ -1637,24 +1627,28 @@ // // To keep a file from being considered for the build: // -// // +build ignore +// //go:build ignore // // (any other unsatisfied word will work as well, but "ignore" is conventional.) // // To build a file only when using cgo, and only on Linux and OS X: // -// // +build linux,cgo darwin,cgo +// //go:build cgo && (linux || darwin) // // Such a file is usually paired with another file implementing the // default functionality for other systems, which in this case would // carry the constraint: // -// // +build !linux,!darwin !cgo +// //go:build !(cgo && (linux || darwin)) // // Naming a file dns_windows.go will cause it to be included only when // building the package for Windows; similarly, math_386.s will be included // only when building the package for 32-bit x86. // +// Go versions 1.16 and earlier used a different syntax for build constraints, +// with a "// +build" prefix. The gofmt command will add an equivalent //go:build +// constraint when encountering the older syntax. +// // // Build modes // diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go index 2f86e4195d9..9ec65018926 100644 --- a/src/cmd/go/internal/help/helpdoc.go +++ b/src/cmd/go/internal/help/helpdoc.go @@ -784,7 +784,7 @@ var HelpBuildConstraint = &base.Command{ Long: ` A build constraint, also known as a build tag, is a line comment that begins - // +build + //go:build that lists the conditions under which a file should be included in the package. Constraints may appear in any kind of source file (not just Go), but @@ -792,30 +792,20 @@ they must appear near the top of the file, preceded only by blank lines and other line comments. These rules mean that in Go files a build constraint must appear before the package clause. -To distinguish build constraints from package documentation, a series of -build constraints must be followed by a blank line. +To distinguish build constraints from package documentation, +a build constraint should be followed by a blank line. -A build constraint is evaluated as the OR of space-separated options. -Each option evaluates as the AND of its comma-separated terms. -Each term consists of letters, digits, underscores, and dots. -A term may be negated with a preceding !. -For example, the build constraint: +A build constraint is evaluated as an expression containing options +combined by ||, &&, and ! operators and parentheses. Operators have +the same meaning as in Go. - // +build linux,386 darwin,!cgo +For example, the following build constraint constrains a file to +build when the "linux" and "386" constraints are satisfied, or when +"darwin" is satisfied and "cgo" is not: -corresponds to the boolean formula: + //go:build (linux && 386) || (darwin && !cgo) - (linux AND 386) OR (darwin AND (NOT cgo)) - -A file may have multiple build constraints. The overall constraint is the AND -of the individual constraints. That is, the build constraints: - - // +build linux darwin - // +build amd64 - -corresponds to the boolean formula: - - (linux OR darwin) AND amd64 +It is an error for a file to have more than one //go:build line. During a particular build, the following words are satisfied: @@ -853,22 +843,26 @@ in addition to ios tags and files. To keep a file from being considered for the build: - // +build ignore + //go:build ignore (any other unsatisfied word will work as well, but "ignore" is conventional.) To build a file only when using cgo, and only on Linux and OS X: - // +build linux,cgo darwin,cgo + //go:build cgo && (linux || darwin) Such a file is usually paired with another file implementing the default functionality for other systems, which in this case would carry the constraint: - // +build !linux,!darwin !cgo + //go:build !(cgo && (linux || darwin)) Naming a file dns_windows.go will cause it to be included only when building the package for Windows; similarly, math_386.s will be included only when building the package for 32-bit x86. + +Go versions 1.16 and earlier used a different syntax for build constraints, +with a "// +build" prefix. The gofmt command will add an equivalent //go:build +constraint when encountering the older syntax. `, } diff --git a/src/go/build/doc.go b/src/go/build/doc.go index 2c6f0a83bea..778b4f40f7c 100644 --- a/src/go/build/doc.go +++ b/src/go/build/doc.go @@ -59,7 +59,7 @@ // // A build constraint, also known as a build tag, is a line comment that begins // -// // +build +// //go:build // // that lists the conditions under which a file should be included in the // package. Build constraints may also be part of a file's name From 723f199edd8619c8eedc1c4e8df1e5f96599d51a Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Tue, 15 Jun 2021 08:01:54 -0400 Subject: [PATCH 412/940] cmd/link: set correct flags in .dynamic for PIE buildmode For internal linking, when generating a PIE binary, set the proper .dynamic section flags to mark the binary as position-independent. Fixes #46747. Change-Id: I2b899148c6d06f92c9d12257a9761278b4236dfc Reviewed-on: https://go-review.googlesource.com/c/go/+/328089 Run-TryBot: Than McIntosh TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor Reviewed-by: Cherry Mui Trust: Than McIntosh --- src/cmd/link/internal/ld/elf.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go index 6f81e74da29..81011638bc5 100644 --- a/src/cmd/link/internal/ld/elf.go +++ b/src/cmd/link/internal/ld/elf.go @@ -950,6 +950,11 @@ func elfdynhash(ctxt *Link) { } s = ldr.CreateSymForUpdate(".dynamic", 0) + if ctxt.BuildMode == BuildModePIE { + // https://github.com/bminor/glibc/blob/895ef79e04a953cac1493863bcae29ad85657ee1/elf/elf.h#L986 + const DTFLAGS_1_PIE = 0x08000000 + Elfwritedynent(ctxt.Arch, s, elf.DT_FLAGS_1, uint64(DTFLAGS_1_PIE)) + } elfverneed = nfile if elfverneed != 0 { elfWriteDynEntSym(ctxt, s, elf.DT_VERNEED, gnuVersionR.Sym()) From 219fe9d547d09d3de1b024c6c8b8314dd0bf12e4 Mon Sep 17 00:00:00 2001 From: unbyte Date: Tue, 15 Jun 2021 17:11:05 +0000 Subject: [PATCH 413/940] cmd/go: ignore UTF8 BOM when reading source code Fix the problem that UTF8 BOM can cause the parsing of import path and directives to fail. Fixes #46198 Fixes #46290 Fixes #35726 Change-Id: I2d9995ee82b094bcfa5583f0cb4e8547cb973077 GitHub-Last-Rev: 98abf91377f155266fa60505c0c12beccad38eeb GitHub-Pull-Request: golang/go#46643 Reviewed-on: https://go-review.googlesource.com/c/go/+/325990 Reviewed-by: Bryan C. Mills Trust: Bryan C. Mills Trust: Robert Findley Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot --- src/cmd/go/internal/imports/read.go | 18 ++++++++-- src/cmd/go/internal/imports/read_test.go | 26 ++++++++++++++ .../script/build_ignore_leading_bom.txt | 27 ++++++++++++++ src/go/build/read.go | 13 ++++++- src/go/build/read_test.go | 36 +++++++++++++++++++ 5 files changed, 117 insertions(+), 3 deletions(-) create mode 100644 src/cmd/go/testdata/script/build_ignore_leading_bom.txt diff --git a/src/cmd/go/internal/imports/read.go b/src/cmd/go/internal/imports/read.go index 5e270781d77..70d51904505 100644 --- a/src/cmd/go/internal/imports/read.go +++ b/src/cmd/go/internal/imports/read.go @@ -8,6 +8,7 @@ package imports import ( "bufio" + "bytes" "errors" "io" "unicode/utf8" @@ -22,6 +23,19 @@ type importReader struct { nerr int } +var bom = []byte{0xef, 0xbb, 0xbf} + +func newImportReader(b *bufio.Reader) *importReader { + // Remove leading UTF-8 BOM. + // Per https://golang.org/ref/spec#Source_code_representation: + // a compiler may ignore a UTF-8-encoded byte order mark (U+FEFF) + // if it is the first Unicode code point in the source text. + if leadingBytes, err := b.Peek(3); err == nil && bytes.Equal(leadingBytes, bom) { + b.Discard(3) + } + return &importReader{b: b} +} + func isIdent(c byte) bool { return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_' || c >= utf8.RuneSelf } @@ -201,7 +215,7 @@ func (r *importReader) readImport(imports *[]string) { // ReadComments is like io.ReadAll, except that it only reads the leading // block of comments in the file. func ReadComments(f io.Reader) ([]byte, error) { - r := &importReader{b: bufio.NewReader(f)} + r := newImportReader(bufio.NewReader(f)) r.peekByte(true) if r.err == nil && !r.eof { // Didn't reach EOF, so must have found a non-space byte. Remove it. @@ -213,7 +227,7 @@ func ReadComments(f io.Reader) ([]byte, error) { // ReadImports is like io.ReadAll, except that it expects a Go file as input // and stops reading the input once the imports have completed. func ReadImports(f io.Reader, reportSyntaxError bool, imports *[]string) ([]byte, error) { - r := &importReader{b: bufio.NewReader(f)} + r := newImportReader(bufio.NewReader(f)) r.readKeyword("package") r.readIdent() diff --git a/src/cmd/go/internal/imports/read_test.go b/src/cmd/go/internal/imports/read_test.go index 6ea356f1ff0..6a1a6524a11 100644 --- a/src/cmd/go/internal/imports/read_test.go +++ b/src/cmd/go/internal/imports/read_test.go @@ -66,6 +66,10 @@ var readImportsTests = []readTest{ `, "", }, + { + "\ufeff𝔻" + `package p; import "x";ℙvar x = 1`, + "", + }, } var readCommentsTests = []readTest{ @@ -81,6 +85,10 @@ var readCommentsTests = []readTest{ `ℙpackage p; import . "x"`, "", }, + { + "\ufeff𝔻" + `ℙpackage p; import . "x"`, + "", + }, { `// foo @@ -90,6 +98,19 @@ var readCommentsTests = []readTest{ /*/ zot */ + // asdf + ℙHello, world`, + "", + }, + { + "\ufeff𝔻" + `// foo + + /* bar */ + + /* quux */ // baz + + /*/ zot */ + // asdf ℙHello, world`, "", @@ -107,6 +128,11 @@ func testRead(t *testing.T, tests []readTest, read func(io.Reader) ([]byte, erro in = tt.in[:j] + tt.in[j+len("ℙ"):] testOut = tt.in[:j] } + d := strings.Index(tt.in, "𝔻") + if d >= 0 { + in = in[:d] + in[d+len("𝔻"):] + testOut = testOut[d+len("𝔻"):] + } r := strings.NewReader(in) buf, err := read(r) if err != nil { diff --git a/src/cmd/go/testdata/script/build_ignore_leading_bom.txt b/src/cmd/go/testdata/script/build_ignore_leading_bom.txt new file mode 100644 index 00000000000..37141f3466b --- /dev/null +++ b/src/cmd/go/testdata/script/build_ignore_leading_bom.txt @@ -0,0 +1,27 @@ +# Per https://golang.org/ref/spec#Source_code_representation: +# a compiler may ignore a UTF-8-encoded byte order mark (U+FEFF) +# if it is the first Unicode code point in the source text. + +go list -f 'Imports: {{.Imports}} EmbedFiles: {{.EmbedFiles}}' . +stdout '^Imports: \[embed m/hello\] EmbedFiles: \[.*file\]$' + +-- go.mod -- +module m + +go 1.16 +-- m.go -- +package main + +import ( + _ "embed" + + "m/hello" +) + +//go:embed file +var s string + +-- hello/hello.go -- +package hello + +-- file -- diff --git a/src/go/build/read.go b/src/go/build/read.go index aa7c6ee59eb..b98c7938a85 100644 --- a/src/go/build/read.go +++ b/src/go/build/read.go @@ -6,6 +6,7 @@ package build import ( "bufio" + "bytes" "errors" "fmt" "go/ast" @@ -28,9 +29,19 @@ type importReader struct { pos token.Position } +var bom = []byte{0xef, 0xbb, 0xbf} + func newImportReader(name string, r io.Reader) *importReader { + b := bufio.NewReader(r) + // Remove leading UTF-8 BOM. + // Per https://golang.org/ref/spec#Source_code_representation: + // a compiler may ignore a UTF-8-encoded byte order mark (U+FEFF) + // if it is the first Unicode code point in the source text. + if leadingBytes, err := b.Peek(3); err == nil && bytes.Equal(leadingBytes, bom) { + b.Discard(3) + } return &importReader{ - b: bufio.NewReader(r), + b: b, pos: token.Position{ Filename: name, Line: 1, diff --git a/src/go/build/read_test.go b/src/go/build/read_test.go index 32e6bae0088..1e5e1c2de2e 100644 --- a/src/go/build/read_test.go +++ b/src/go/build/read_test.go @@ -66,6 +66,10 @@ var readGoInfoTests = []readTest{ `, "", }, + { + "\ufeff𝔻" + `package p; import "x";ℙvar x = 1`, + "", + }, } var readCommentsTests = []readTest{ @@ -81,6 +85,10 @@ var readCommentsTests = []readTest{ `ℙpackage p; import . "x"`, "", }, + { + "\ufeff𝔻" + `ℙpackage p; import . "x"`, + "", + }, { `// foo @@ -90,6 +98,19 @@ var readCommentsTests = []readTest{ /*/ zot */ + // asdf + ℙHello, world`, + "", + }, + { + "\ufeff𝔻" + `// foo + + /* bar */ + + /* quux */ // baz + + /*/ zot */ + // asdf ℙHello, world`, "", @@ -107,6 +128,11 @@ func testRead(t *testing.T, tests []readTest, read func(io.Reader) ([]byte, erro in = tt.in[:j] + tt.in[j+len("ℙ"):] testOut = tt.in[:j] } + d := strings.Index(tt.in, "𝔻") + if d >= 0 { + in = in[:d] + in[d+len("𝔻"):] + testOut = testOut[d+len("𝔻"):] + } r := strings.NewReader(in) buf, err := read(r) if err != nil { @@ -264,6 +290,12 @@ var readEmbedTests = []struct { test:3:14:y test:3:16:z`, }, + { + "\ufeffpackage p\nimport \"embed\"\n//go:embed x y z\nvar files embed.FS", + `test:3:12:x + test:3:14:y + test:3:16:z`, + }, { "package p\nimport \"embed\"\nvar s = \"/*\"\n//go:embed x\nvar files embed.FS", `test:4:12:x`, @@ -292,6 +324,10 @@ var readEmbedTests = []struct { "package p\n//go:embed x y z\nvar files embed.FS", // no import, no scan "", }, + { + "\ufeffpackage p\n//go:embed x y z\nvar files embed.FS", // no import, no scan + "", + }, } func TestReadEmbed(t *testing.T) { From 79cd1687e6abf8c565281d310b4c2b44a8d4bb84 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 13 May 2021 20:23:13 -0700 Subject: [PATCH 414/940] [dev.typeparams] cmd/compile: unified IR construction This CL adds a new unified IR construction mode to the frontend. It's purely additive, and all files include "UNREVIEWED" at the top, like how types2 was initially imported. The next CL adds a -d=unified flag to actually enable unified IR mode. See below for more details, but some highlights: 1. It adds ~6kloc (excluding enum listings and stringer output), but I estimate it will allow removing ~14kloc (see CL 324670, including its commit message); 2. When enabled by default, it passes more tests than -G=3 does (see CL 325213 and CL 324673); 3. Without requiring any new code, it supports inlining of more code than the current inliner (see CL 324574; contrast CL 283112 and CL 266203, which added support for inlining function literals and type switches, respectively); 4. Aside from dictionaries (which I intend to add still), its support for generics is more complete (e.g., it fully supports local types, including local generic types within generic functions and instantiating generic types with local types; see test/typeparam/nested.go); 5. It supports lazy loading of types and objects for types2 type checking; 6. It supports re-exporting of types, objects, and inline bodies without needing to parse them into IR; 7. The new export data format has extensive support for debugging with "sync" markers, so mistakes during development are easier to catch; 8. When compiling with -d=inlfuncswithclosures=0, it enables "quirks mode" where it generates output that passes toolstash -cmp. -- The new unified IR pipeline combines noding, stenciling, inlining, and import/export into a single, shared code path. Previously, IR trees went through multiple phases of copying during compilation: 1. "Noding": the syntax AST is copied into the initial IR form. To support generics, there's now also "irgen", which implements the same idea, but takes advantage of types2 type-checking results to more directly construct IR. 2. "Stenciling": generic IR forms are copied into instantiated IR forms, substituting type parameters as appropriate. 3. "Inlining": the inliner made backup copies of inlinable functions, and then copied them again when inlining into a call site, with some modifications (e.g., updating position information, rewriting variable references, changing "return" statements into "goto"). 4. "Importing/exporting": the exporter wrote out the IR as saved by the inliner, and then the importer read it back as to be used by the inliner again. Normal functions are imported/exported "desugared", while generic functions are imported/exported in source form. These passes are all conceptually the same thing: make a copy of a function body, maybe with some minor changes/substitutions. However, they're all completely separate implementations that frequently run into the same issues because IR has many nuanced corner cases. For example, inlining currently doesn't support local defined types, "range" loops, or labeled "for"/"switch" statements, because these require special handling around Sym references. We've recently extended the inliner to support new features like inlining type switches and function literals, and they've had issues. The exporter only knows how to export from IR form, so when re-exporting inlinable functions (e.g., methods on imported types that are exposed via exported APIs), these functions may need to be imported as IR for the sole purpose of being immediately exported back out again. By unifying all of these modes of copying into a single code path that cleanly separates concerns, we eliminate many of these possible issues. Some recent examples: 1. Issues #45743 and #46472 were issues where type switches were mishandled by inlining and stenciling, respectively; but neither of these affected unified IR, because it constructs type switches using the exact same code as for normal functions. 2. CL 325409 fixes an issue in stenciling with implicit conversion of values of type-parameter type to variables of interface type, but this issue did not affect unified IR. Change-Id: I5a05991fe16d68bb0f712503e034cb9f2d19e296 Reviewed-on: https://go-review.googlesource.com/c/go/+/324573 Trust: Matthew Dempsky Trust: Robert Griesemer Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/noder/codes.go | 126 ++ src/cmd/compile/internal/noder/decoder.go | 243 ++ src/cmd/compile/internal/noder/encoder.go | 245 ++ src/cmd/compile/internal/noder/linker.go | 296 +++ src/cmd/compile/internal/noder/quirks.go | 453 ++++ src/cmd/compile/internal/noder/reader.go | 1970 +++++++++++++++++ src/cmd/compile/internal/noder/reader2.go | 463 ++++ src/cmd/compile/internal/noder/reloc.go | 40 + src/cmd/compile/internal/noder/sync.go | 154 ++ .../internal/noder/syncmarker_string.go | 152 ++ src/cmd/compile/internal/noder/unified.go | 276 +++ src/cmd/compile/internal/noder/writer.go | 1746 +++++++++++++++ 12 files changed, 6164 insertions(+) create mode 100644 src/cmd/compile/internal/noder/codes.go create mode 100644 src/cmd/compile/internal/noder/decoder.go create mode 100644 src/cmd/compile/internal/noder/encoder.go create mode 100644 src/cmd/compile/internal/noder/linker.go create mode 100644 src/cmd/compile/internal/noder/quirks.go create mode 100644 src/cmd/compile/internal/noder/reader.go create mode 100644 src/cmd/compile/internal/noder/reader2.go create mode 100644 src/cmd/compile/internal/noder/reloc.go create mode 100644 src/cmd/compile/internal/noder/sync.go create mode 100644 src/cmd/compile/internal/noder/syncmarker_string.go create mode 100644 src/cmd/compile/internal/noder/unified.go create mode 100644 src/cmd/compile/internal/noder/writer.go diff --git a/src/cmd/compile/internal/noder/codes.go b/src/cmd/compile/internal/noder/codes.go new file mode 100644 index 00000000000..4a6a4e83071 --- /dev/null +++ b/src/cmd/compile/internal/noder/codes.go @@ -0,0 +1,126 @@ +// UNREVIEWED + +// Copyright 2021 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 noder + +type code interface { + marker() syncMarker + value() int +} + +type codeVal int + +func (c codeVal) marker() syncMarker { return syncVal } +func (c codeVal) value() int { return int(c) } + +const ( + valBool codeVal = iota + valString + valInt64 + valBigInt + valBigRat + valBigFloat +) + +type codeType int + +func (c codeType) marker() syncMarker { return syncType } +func (c codeType) value() int { return int(c) } + +const ( + typeBasic codeType = iota + typeNamed + typePointer + typeSlice + typeArray + typeChan + typeMap + typeSignature + typeStruct + typeInterface + typeUnion + typeTypeParam +) + +type codeObj int + +func (c codeObj) marker() syncMarker { return syncCodeObj } +func (c codeObj) value() int { return int(c) } + +const ( + objAlias codeObj = iota + objConst + objType + objFunc + objVar + objStub +) + +type codeStmt int + +func (c codeStmt) marker() syncMarker { return syncStmt1 } +func (c codeStmt) value() int { return int(c) } + +const ( + stmtEnd codeStmt = iota + stmtLabel + stmtBlock + stmtExpr + stmtSend + stmtAssign + stmtAssignOp + stmtIncDec + stmtBranch + stmtCall + stmtReturn + stmtIf + stmtFor + stmtSwitch + stmtSelect + + // TODO(mdempsky): Remove after we don't care about toolstash -cmp. + stmtTypeDeclHack +) + +type codeExpr int + +func (c codeExpr) marker() syncMarker { return syncExpr } +func (c codeExpr) value() int { return int(c) } + +// TODO(mdempsky): Split expr into addr, for lvalues. +const ( + exprNone codeExpr = iota + exprConst + exprType // type expression + exprLocal // local variable + exprName // global variable or function + exprBlank + exprCompLit + exprFuncLit + exprSelector + exprIndex + exprSlice + exprAssert + exprUnaryOp + exprBinaryOp + exprCall + + // TODO(mdempsky): Handle in switchStmt directly instead. + exprTypeSwitchGuard +) + +type codeDecl int + +func (c codeDecl) marker() syncMarker { return syncDecl } +func (c codeDecl) value() int { return int(c) } + +const ( + declEnd codeDecl = iota + declFunc + declMethod + declVar + declOther +) diff --git a/src/cmd/compile/internal/noder/decoder.go b/src/cmd/compile/internal/noder/decoder.go new file mode 100644 index 00000000000..023388875c4 --- /dev/null +++ b/src/cmd/compile/internal/noder/decoder.go @@ -0,0 +1,243 @@ +// UNREVIEWED + +// Copyright 2021 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 noder + +import ( + "encoding/binary" + "fmt" + "go/constant" + "go/token" + "math/big" + "os" + "strings" + + "cmd/compile/internal/base" +) + +type pkgDecoder struct { + pkgPath string + + elemEndsEnds [numRelocs]uint32 + elemEnds []uint32 + elemData string +} + +func newPkgDecoder(pkgPath, input string) pkgDecoder { + pr := pkgDecoder{ + pkgPath: pkgPath, + } + + // TODO(mdempsky): Implement direct indexing of input string to + // avoid copying the position information. + + r := strings.NewReader(input) + + assert(binary.Read(r, binary.LittleEndian, pr.elemEndsEnds[:]) == nil) + + pr.elemEnds = make([]uint32, pr.elemEndsEnds[len(pr.elemEndsEnds)-1]) + assert(binary.Read(r, binary.LittleEndian, pr.elemEnds[:]) == nil) + + pos, err := r.Seek(0, os.SEEK_CUR) + assert(err == nil) + + pr.elemData = input[pos:] + assert(len(pr.elemData) == int(pr.elemEnds[len(pr.elemEnds)-1])) + + return pr +} + +func (pr *pkgDecoder) numElems(k reloc) int { + count := int(pr.elemEndsEnds[k]) + if k > 0 { + count -= int(pr.elemEndsEnds[k-1]) + } + return count +} + +func (pr *pkgDecoder) totalElems() int { + return len(pr.elemEnds) +} + +func (pr *pkgDecoder) absIdx(k reloc, idx int) int { + absIdx := idx + if k > 0 { + absIdx += int(pr.elemEndsEnds[k-1]) + } + if absIdx >= int(pr.elemEndsEnds[k]) { + base.Fatalf("%v:%v is out of bounds; %v", k, idx, pr.elemEndsEnds) + } + return absIdx +} + +func (pr *pkgDecoder) dataIdx(k reloc, idx int) string { + absIdx := pr.absIdx(k, idx) + + var start uint32 + if absIdx > 0 { + start = pr.elemEnds[absIdx-1] + } + end := pr.elemEnds[absIdx] + + return pr.elemData[start:end] +} + +func (pr *pkgDecoder) stringIdx(idx int) string { + return pr.dataIdx(relocString, idx) +} + +func (pr *pkgDecoder) newDecoder(k reloc, idx int, marker syncMarker) decoder { + r := pr.newDecoderRaw(k, idx) + r.sync(marker) + return r +} + +func (pr *pkgDecoder) newDecoderRaw(k reloc, idx int) decoder { + r := decoder{ + common: pr, + k: k, + idx: idx, + } + + // TODO(mdempsky) r.data.Reset(...) after #44505 is resolved. + r.data = *strings.NewReader(pr.dataIdx(k, idx)) + + r.sync(syncRelocs) + r.relocs = make([]relocEnt, r.len()) + for i := range r.relocs { + r.sync(syncReloc) + r.relocs[i] = relocEnt{reloc(r.len()), r.len()} + } + + return r +} + +type decoder struct { + common *pkgDecoder + + relocs []relocEnt + data strings.Reader + + k reloc + idx int +} + +func (r *decoder) checkErr(err error) { + if err != nil { + base.Fatalf("unexpected error: %v", err) + } +} + +func (r *decoder) sync(m syncMarker) { + if debug { + pos, err0 := r.data.Seek(0, os.SEEK_CUR) + x, err := r.data.ReadByte() + r.checkErr(err) + if x != byte(m) { + // TODO(mdempsky): Revisit this error message, and make it more + // useful (e.g., include r.p.pkgPath). + base.Fatalf("data sync error: found %v at %v (%v) in (%v:%v), but expected %v", syncMarker(x), pos, err0, r.k, r.idx, m) + } + } +} + +func (r *decoder) bool() bool { + r.sync(syncBool) + x, err := r.data.ReadByte() + r.checkErr(err) + assert(x < 2) + return x != 0 +} + +func (r *decoder) int64() int64 { + r.sync(syncInt64) + x, err := binary.ReadVarint(&r.data) + r.checkErr(err) + return x +} + +func (r *decoder) uint64() uint64 { + r.sync(syncUint64) + x, err := binary.ReadUvarint(&r.data) + r.checkErr(err) + return x +} + +func (r *decoder) len() int { x := r.uint64(); v := int(x); assert(uint64(v) == x); return v } +func (r *decoder) int() int { x := r.int64(); v := int(x); assert(int64(v) == x); return v } +func (r *decoder) uint() uint { x := r.uint64(); v := uint(x); assert(uint64(v) == x); return v } + +func (r *decoder) code(mark syncMarker) int { + r.sync(mark) + return r.len() +} + +func (r *decoder) reloc(k reloc) int { + r.sync(syncUseReloc) + idx := r.len() + + e := r.relocs[idx] + assert(e.kind == k) + return e.idx +} + +func (r *decoder) string() string { + r.sync(syncString) + return r.common.stringIdx(r.reloc(relocString)) +} + +func (r *decoder) strings() []string { + res := make([]string, r.len()) + for i := range res { + res[i] = r.string() + } + return res +} + +func (r *decoder) rawValue() constant.Value { + isComplex := r.bool() + val := r.scalar() + if isComplex { + val = constant.BinaryOp(val, token.ADD, constant.MakeImag(r.scalar())) + } + return val +} + +func (r *decoder) scalar() constant.Value { + switch tag := codeVal(r.code(syncVal)); tag { + default: + panic(fmt.Sprintf("unexpected scalar tag: %v", tag)) + + case valBool: + return constant.MakeBool(r.bool()) + case valString: + return constant.MakeString(r.string()) + case valInt64: + return constant.MakeInt64(r.int64()) + case valBigInt: + return constant.Make(r.bigInt()) + case valBigRat: + num := r.bigInt() + denom := r.bigInt() + return constant.Make(new(big.Rat).SetFrac(num, denom)) + case valBigFloat: + return constant.Make(r.bigFloat()) + } +} + +func (r *decoder) bigInt() *big.Int { + v := new(big.Int).SetBytes([]byte(r.string())) + if r.bool() { + v.Neg(v) + } + return v +} + +func (r *decoder) bigFloat() *big.Float { + v := new(big.Float).SetPrec(512) + assert(v.UnmarshalText([]byte(r.string())) == nil) + return v +} diff --git a/src/cmd/compile/internal/noder/encoder.go b/src/cmd/compile/internal/noder/encoder.go new file mode 100644 index 00000000000..dc288dc29fe --- /dev/null +++ b/src/cmd/compile/internal/noder/encoder.go @@ -0,0 +1,245 @@ +// UNREVIEWED + +// Copyright 2021 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 noder + +import ( + "bytes" + "encoding/binary" + "fmt" + "go/constant" + "io" + "math/big" + + "cmd/compile/internal/base" +) + +type pkgEncoder struct { + elems [numRelocs][]string + + stringsIdx map[string]int +} + +func newPkgEncoder() pkgEncoder { + return pkgEncoder{ + stringsIdx: make(map[string]int), + } +} + +func (pw *pkgEncoder) dump(out io.Writer) { + writeUint32 := func(x uint32) { + assert(binary.Write(out, binary.LittleEndian, x) == nil) + } + + var sum uint32 + for _, elems := range &pw.elems { + sum += uint32(len(elems)) + writeUint32(sum) + } + + sum = 0 + for _, elems := range &pw.elems { + for _, elem := range elems { + sum += uint32(len(elem)) + writeUint32(sum) + } + } + + for _, elems := range &pw.elems { + for _, elem := range elems { + _, err := io.WriteString(out, elem) + assert(err == nil) + } + } +} + +func (pw *pkgEncoder) stringIdx(s string) int { + if idx, ok := pw.stringsIdx[s]; ok { + assert(pw.elems[relocString][idx] == s) + return idx + } + + idx := len(pw.elems[relocString]) + pw.elems[relocString] = append(pw.elems[relocString], s) + pw.stringsIdx[s] = idx + return idx +} + +func (pw *pkgEncoder) newEncoder(k reloc, marker syncMarker) encoder { + e := pw.newEncoderRaw(k) + e.sync(marker) + return e +} + +func (pw *pkgEncoder) newEncoderRaw(k reloc) encoder { + idx := len(pw.elems[k]) + pw.elems[k] = append(pw.elems[k], "") // placeholder + + return encoder{ + p: pw, + k: k, + idx: idx, + } +} + +// Encoders + +type encoder struct { + p *pkgEncoder + + relocs []relocEnt + data bytes.Buffer + + k reloc + idx int +} + +func (w *encoder) flush() int { + var sb bytes.Buffer // TODO(mdempsky): strings.Builder after #44505 is resolved + + // Backup the data so we write the relocations at the front. + var tmp bytes.Buffer + io.Copy(&tmp, &w.data) + + // TODO(mdempsky): Consider writing these out separately so they're + // easier to strip, along with function bodies, so that we can prune + // down to just the data that's relevant to go/types. + w.sync(syncRelocs) + w.len(len(w.relocs)) + for _, rent := range w.relocs { + w.sync(syncReloc) + w.len(int(rent.kind)) + w.len(rent.idx) + } + + io.Copy(&sb, &w.data) + io.Copy(&sb, &tmp) + w.p.elems[w.k][w.idx] = sb.String() + + return w.idx +} + +func (w *encoder) checkErr(err error) { + if err != nil { + base.Fatalf("unexpected error: %v", err) + } +} + +func (w *encoder) sync(m syncMarker) { + if debug { + err := w.data.WriteByte(byte(m)) + w.checkErr(err) + } +} + +func (w *encoder) bool(b bool) bool { + w.sync(syncBool) + var x byte + if b { + x = 1 + } + err := w.data.WriteByte(x) + w.checkErr(err) + return b +} + +func (w *encoder) int64(x int64) { + w.sync(syncInt64) + var buf [binary.MaxVarintLen64]byte + n := binary.PutVarint(buf[:], x) + _, err := w.data.Write(buf[:n]) + w.checkErr(err) +} + +func (w *encoder) uint64(x uint64) { + w.sync(syncUint64) + var buf [binary.MaxVarintLen64]byte + n := binary.PutUvarint(buf[:], x) + _, err := w.data.Write(buf[:n]) + w.checkErr(err) +} + +func (w *encoder) len(x int) { assert(x >= 0); w.uint64(uint64(x)) } +func (w *encoder) int(x int) { w.int64(int64(x)) } +func (w *encoder) uint(x uint) { w.uint64(uint64(x)) } + +func (w *encoder) reloc(r reloc, idx int) { + w.sync(syncUseReloc) + + // TODO(mdempsky): Use map for lookup. + for i, rent := range w.relocs { + if rent.kind == r && rent.idx == idx { + w.len(i) + return + } + } + + w.len(len(w.relocs)) + w.relocs = append(w.relocs, relocEnt{r, idx}) +} + +func (w *encoder) code(c code) { + w.sync(c.marker()) + w.len(c.value()) +} + +func (w *encoder) string(s string) { + w.sync(syncString) + w.reloc(relocString, w.p.stringIdx(s)) +} + +func (w *encoder) strings(ss []string) { + w.len(len(ss)) + for _, s := range ss { + w.string(s) + } +} + +func (w *encoder) rawValue(val constant.Value) { + if w.bool(val.Kind() == constant.Complex) { + w.scalar(constant.Real(val)) + w.scalar(constant.Imag(val)) + } else { + w.scalar(val) + } +} + +func (w *encoder) scalar(val constant.Value) { + switch v := constant.Val(val).(type) { + default: + panic(fmt.Sprintf("unhandled %v (%v)", val, val.Kind())) + case bool: + w.code(valBool) + w.bool(v) + case string: + w.code(valString) + w.string(v) + case int64: + w.code(valInt64) + w.int64(v) + case *big.Int: + w.code(valBigInt) + w.bigInt(v) + case *big.Rat: + w.code(valBigRat) + w.bigInt(v.Num()) + w.bigInt(v.Denom()) + case *big.Float: + w.code(valBigFloat) + w.bigFloat(v) + } +} + +func (w *encoder) bigInt(v *big.Int) { + b := v.Bytes() + w.string(string(b)) // TODO: More efficient encoding. + w.bool(v.Sign() < 0) +} + +func (w *encoder) bigFloat(v *big.Float) { + b := v.Append(nil, 'p', -1) + w.string(string(b)) // TODO: More efficient encoding. +} diff --git a/src/cmd/compile/internal/noder/linker.go b/src/cmd/compile/internal/noder/linker.go new file mode 100644 index 00000000000..324902d246e --- /dev/null +++ b/src/cmd/compile/internal/noder/linker.go @@ -0,0 +1,296 @@ +// UNREVIEWED + +// Copyright 2021 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 noder + +import ( + "io" + + "cmd/compile/internal/base" + "cmd/compile/internal/ir" + "cmd/compile/internal/reflectdata" + "cmd/compile/internal/types" + "cmd/internal/goobj" + "cmd/internal/obj" +) + +// This file implements the unified IR linker, which combines the +// local package's stub data with imported package data to produce a +// complete export data file. It also rewrites the compiler's +// extension data sections based on the results of compilation (e.g., +// the function inlining cost and linker symbol index assignments). +// +// TODO(mdempsky): Using the name "linker" here is confusing, because +// readers are likely to mistake references to it for cmd/link. But +// there's a shortage of good names for "something that combines +// multiple parts into a cohesive whole"... e.g., "assembler" and +// "compiler" are also already taken. + +type linker struct { + pw pkgEncoder + + pkgs map[string]int + decls map[*types.Sym]int +} + +func (l *linker) relocAll(pr *pkgReader, relocs []relocEnt) []relocEnt { + res := make([]relocEnt, len(relocs)) + for i, rent := range relocs { + rent.idx = l.relocIdx(pr, rent.kind, rent.idx) + res[i] = rent + } + return res +} + +func (l *linker) relocIdx(pr *pkgReader, k reloc, idx int) int { + assert(pr != nil) + + absIdx := pr.absIdx(k, idx) + + if newidx := pr.newindex[absIdx]; newidx != 0 { + return ^newidx + } + + var newidx int + switch k { + case relocString: + newidx = l.relocString(pr, idx) + case relocPkg: + newidx = l.relocPkg(pr, idx) + case relocObj: + newidx = l.relocObj(pr, idx) + + default: + // Generic relocations. + // + // TODO(mdempsky): Deduplicate more sections? In fact, I think + // every section could be deduplicated. This would also be easier + // if we do external relocations. + + w := l.pw.newEncoderRaw(k) + l.relocCommon(pr, &w, k, idx) + newidx = w.idx + } + + pr.newindex[absIdx] = ^newidx + + return newidx +} + +func (l *linker) relocString(pr *pkgReader, idx int) int { + return l.pw.stringIdx(pr.stringIdx(idx)) +} + +func (l *linker) relocPkg(pr *pkgReader, idx int) int { + path := pr.peekPkgPath(idx) + + if newidx, ok := l.pkgs[path]; ok { + return newidx + } + + r := pr.newDecoder(relocPkg, idx, syncPkgDef) + w := l.pw.newEncoder(relocPkg, syncPkgDef) + l.pkgs[path] = w.idx + + // TODO(mdempsky): We end up leaving an empty string reference here + // from when the package was originally written as "". Probably not + // a big deal, but a little annoying. Maybe relocating + // cross-references in place is the way to go after all. + w.relocs = l.relocAll(pr, r.relocs) + + _ = r.string() // original path + w.string(path) + + io.Copy(&w.data, &r.data) + + return w.flush() +} + +func (l *linker) relocObj(pr *pkgReader, idx int) int { + path, name, tag, _ := pr.peekObj(idx) + sym := types.NewPkg(path, "").Lookup(name) + + if newidx, ok := l.decls[sym]; ok { + return newidx + } + + if tag == objStub && path != "builtin" && path != "unsafe" { + pri, ok := objReader[sym] + if !ok { + base.Fatalf("missing reader for %q.%v", path, name) + } + assert(ok) + + pr = pri.pr + idx = pri.idx + + path2, name2, tag2, _ := pr.peekObj(idx) + sym2 := types.NewPkg(path2, "").Lookup(name2) + assert(sym == sym2) + assert(tag2 != objStub) + } + + w := l.pw.newEncoderRaw(relocObj) + bside := l.pw.newEncoderRaw(relocObjExt) + assert(bside.idx == w.idx) + l.decls[sym] = w.idx + + l.relocCommon(pr, &w, relocObj, idx) + + var obj *ir.Name + if path == "" { + var ok bool + obj, ok = sym.Def.(*ir.Name) + + // Generic types and functions won't have definitions. + // For now, just generically copy their extension data. + if !ok && base.Flag.G == 0 { + base.Fatalf("missing definition for %v", sym) + } + } + + if obj != nil { + bside.sync(syncObject1) + switch tag { + case objFunc: + l.relocFuncExt(&bside, obj) + case objType: + l.relocTypeExt(&bside, obj) + case objVar: + l.relocVarExt(&bside, obj) + } + bside.flush() + } else { + l.relocCommon(pr, &bside, relocObjExt, idx) + } + + return w.idx +} + +func (l *linker) relocCommon(pr *pkgReader, w *encoder, k reloc, idx int) { + r := pr.newDecoderRaw(k, idx) + w.relocs = l.relocAll(pr, r.relocs) + io.Copy(&w.data, &r.data) + w.flush() +} + +func (l *linker) pragmaFlag(w *encoder, pragma ir.PragmaFlag) { + w.sync(syncPragma) + w.int(int(pragma)) +} + +func (l *linker) relocFuncExt(w *encoder, name *ir.Name) { + w.sync(syncFuncExt) + + l.pragmaFlag(w, name.Func.Pragma) + l.linkname(w, name) + + // Relocated extension data. + w.bool(true) + + // Record definition ABI so cross-ABI calls can be direct. + // This is important for the performance of calling some + // common functions implemented in assembly (e.g., bytealg). + w.uint64(uint64(name.Func.ABI)) + + // Escape analysis. + for _, fs := range &types.RecvsParams { + for _, f := range fs(name.Type()).FieldSlice() { + w.string(f.Note) + } + } + + if inl := name.Func.Inl; w.bool(inl != nil) { + w.len(int(inl.Cost)) + w.bool(inl.CanDelayResults) + + pri, ok := bodyReader[name.Func] + assert(ok) + w.sync(syncAddBody) + w.reloc(relocBody, l.relocIdx(pri.pr, relocBody, pri.idx)) + } + + w.sync(syncEOF) +} + +func (l *linker) relocTypeExt(w *encoder, name *ir.Name) { + w.sync(syncTypeExt) + + typ := name.Type() + + l.pragmaFlag(w, name.Pragma()) + + // For type T, export the index of type descriptor symbols of T and *T. + l.lsymIdx(w, "", reflectdata.TypeLinksym(typ)) + l.lsymIdx(w, "", reflectdata.TypeLinksym(typ.PtrTo())) + + if typ.Kind() != types.TINTER { + for _, method := range typ.Methods().Slice() { + l.relocFuncExt(w, method.Nname.(*ir.Name)) + } + } +} + +func (l *linker) relocVarExt(w *encoder, name *ir.Name) { + w.sync(syncVarExt) + l.linkname(w, name) +} + +func (l *linker) linkname(w *encoder, name *ir.Name) { + w.sync(syncLinkname) + + linkname := name.Sym().Linkname + if !l.lsymIdx(w, linkname, name.Linksym()) { + w.string(linkname) + } +} + +func (l *linker) lsymIdx(w *encoder, linkname string, lsym *obj.LSym) bool { + if lsym.PkgIdx > goobj.PkgIdxSelf || (lsym.PkgIdx == goobj.PkgIdxInvalid && !lsym.Indexed()) || linkname != "" { + w.int64(-1) + return false + } + + // For a defined symbol, export its index. + // For re-exporting an imported symbol, pass its index through. + w.int64(int64(lsym.SymIdx)) + return true +} + +// @@@ Helpers + +// TODO(mdempsky): These should probably be removed. I think they're a +// smell that the export data format is not yet quite right. + +func (pr *pkgDecoder) peekPkgPath(idx int) string { + r := pr.newDecoder(relocPkg, idx, syncPkgDef) + path := r.string() + if path == "" { + path = pr.pkgPath + } + return path +} + +func (pr *pkgDecoder) peekObj(idx int) (string, string, codeObj, []int) { + r := pr.newDecoder(relocObj, idx, syncObject1) + r.sync(syncSym) + r.sync(syncPkg) + path := pr.peekPkgPath(r.reloc(relocPkg)) + name := r.string() + assert(name != "") + + r.sync(syncTypeParamBounds) + r.len() // implicits + bounds := make([]int, r.len()) + for i := range bounds { + r.sync(syncType) + bounds[i] = r.reloc(relocType) + } + + tag := codeObj(r.code(syncCodeObj)) + + return path, name, tag, bounds +} diff --git a/src/cmd/compile/internal/noder/quirks.go b/src/cmd/compile/internal/noder/quirks.go new file mode 100644 index 00000000000..9f33fc576d9 --- /dev/null +++ b/src/cmd/compile/internal/noder/quirks.go @@ -0,0 +1,453 @@ +// UNREVIEWED + +// Copyright 2021 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 noder + +import ( + "fmt" + + "cmd/compile/internal/base" + "cmd/compile/internal/ir" + "cmd/compile/internal/syntax" + "cmd/compile/internal/types2" + "cmd/internal/src" +) + +// This file defines helper functions useful for satisfying toolstash +// -cmp when compared against the legacy frontend behavior, but can be +// removed after that's no longer a concern. + +// quirksMode controls whether behavior specific to satsifying +// toolstash -cmp is used. +func quirksMode() bool { + // Currently, unified IR doesn't try to be compatible with + // -d=inlfuncswithclosures=1, so we overload this as a flag for + // enabling quirks mode. + return base.Debug.InlFuncsWithClosures == 0 +} + +// posBasesOf returns all of the position bases in the source files, +// as seen in a straightforward traversal. +// +// This is necessary to ensure position bases (and thus file names) +// get registered in the same order as noder would visit them. +func posBasesOf(noders []*noder) []*syntax.PosBase { + seen := make(map[*syntax.PosBase]bool) + var bases []*syntax.PosBase + + for _, p := range noders { + syntax.Walk(p.file, func(n syntax.Node) bool { + if b := n.Pos().Base(); !seen[b] { + bases = append(bases, b) + seen[b] = true + } + return false + }) + } + + return bases +} + +// importedObjsOf returns the imported objects (i.e., referenced +// objects not declared by curpkg) from the parsed source files, in +// the order that typecheck used to load their definitions. +// +// This is needed because loading the definitions for imported objects +// can also add file names. +func importedObjsOf(curpkg *types2.Package, info *types2.Info, noders []*noder) []types2.Object { + // This code is complex because it matches the precise order that + // typecheck recursively and repeatedly traverses the IR. It's meant + // to be thrown away eventually anyway. + + seen := make(map[types2.Object]bool) + var objs []types2.Object + + var phase int + + decls := make(map[types2.Object]syntax.Decl) + assoc := func(decl syntax.Decl, names ...*syntax.Name) { + for _, name := range names { + obj, ok := info.Defs[name] + assert(ok) + decls[obj] = decl + } + } + + for _, p := range noders { + syntax.Walk(p.file, func(n syntax.Node) bool { + switch n := n.(type) { + case *syntax.ConstDecl: + assoc(n, n.NameList...) + case *syntax.FuncDecl: + assoc(n, n.Name) + case *syntax.TypeDecl: + assoc(n, n.Name) + case *syntax.VarDecl: + assoc(n, n.NameList...) + case *syntax.BlockStmt: + return true + } + return false + }) + } + + var visited map[syntax.Decl]bool + + var resolveDecl func(n syntax.Decl) + var resolveNode func(n syntax.Node, top bool) + + resolveDecl = func(n syntax.Decl) { + if visited[n] { + return + } + visited[n] = true + + switch n := n.(type) { + case *syntax.ConstDecl: + resolveNode(n.Type, true) + resolveNode(n.Values, true) + + case *syntax.FuncDecl: + if n.Recv != nil { + resolveNode(n.Recv, true) + } + resolveNode(n.Type, true) + + case *syntax.TypeDecl: + resolveNode(n.Type, true) + + case *syntax.VarDecl: + if n.Type != nil { + resolveNode(n.Type, true) + } else { + resolveNode(n.Values, true) + } + } + } + + resolveObj := func(pos syntax.Pos, obj types2.Object) { + switch obj.Pkg() { + case nil: + // builtin; nothing to do + + case curpkg: + if decl, ok := decls[obj]; ok { + resolveDecl(decl) + } + + default: + if obj.Parent() == obj.Pkg().Scope() && !seen[obj] { + seen[obj] = true + objs = append(objs, obj) + } + } + } + + checkdefat := func(pos syntax.Pos, n *syntax.Name) { + if n.Value == "_" { + return + } + obj, ok := info.Uses[n] + if !ok { + obj, ok = info.Defs[n] + if !ok { + return + } + } + if obj == nil { + return + } + resolveObj(pos, obj) + } + checkdef := func(n *syntax.Name) { checkdefat(n.Pos(), n) } + + var later []syntax.Node + + resolveNode = func(n syntax.Node, top bool) { + if n == nil { + return + } + syntax.Walk(n, func(n syntax.Node) bool { + switch n := n.(type) { + case *syntax.Name: + checkdef(n) + + case *syntax.SelectorExpr: + if name, ok := n.X.(*syntax.Name); ok { + if _, isPkg := info.Uses[name].(*types2.PkgName); isPkg { + checkdefat(n.X.Pos(), n.Sel) + return true + } + } + + case *syntax.AssignStmt: + resolveNode(n.Rhs, top) + resolveNode(n.Lhs, top) + return true + + case *syntax.VarDecl: + resolveNode(n.Values, top) + + case *syntax.FuncLit: + if top { + resolveNode(n.Type, top) + later = append(later, n.Body) + return true + } + + case *syntax.BlockStmt: + if phase >= 3 { + for _, stmt := range n.List { + resolveNode(stmt, false) + } + } + return true + } + + return false + }) + } + + for phase = 1; phase <= 5; phase++ { + visited = map[syntax.Decl]bool{} + + for _, p := range noders { + for _, decl := range p.file.DeclList { + switch decl := decl.(type) { + case *syntax.ConstDecl: + resolveDecl(decl) + + case *syntax.FuncDecl: + resolveDecl(decl) + if phase >= 3 && decl.Body != nil { + resolveNode(decl.Body, true) + } + + case *syntax.TypeDecl: + if !decl.Alias || phase >= 2 { + resolveDecl(decl) + } + + case *syntax.VarDecl: + if phase >= 2 { + resolveNode(decl.Values, true) + resolveDecl(decl) + } + } + } + + if phase >= 5 { + syntax.Walk(p.file, func(n syntax.Node) bool { + if name, ok := n.(*syntax.Name); ok { + if obj, ok := info.Uses[name]; ok { + resolveObj(name.Pos(), obj) + } + } + return false + }) + } + } + + for i := 0; i < len(later); i++ { + resolveNode(later[i], true) + } + later = nil + } + + return objs +} + +// typeExprEndPos returns the position that noder would leave base.Pos +// after parsing the given type expression. +func typeExprEndPos(expr0 syntax.Expr) syntax.Pos { + for { + switch expr := expr0.(type) { + case *syntax.Name: + return expr.Pos() + case *syntax.SelectorExpr: + return expr.X.Pos() + + case *syntax.ParenExpr: + expr0 = expr.X + + case *syntax.Operation: + assert(expr.Op == syntax.Mul) + assert(expr.Y == nil) + expr0 = expr.X + + case *syntax.ArrayType: + expr0 = expr.Elem + case *syntax.ChanType: + expr0 = expr.Elem + case *syntax.DotsType: + expr0 = expr.Elem + case *syntax.MapType: + expr0 = expr.Value + case *syntax.SliceType: + expr0 = expr.Elem + + case *syntax.StructType: + return expr.Pos() + + case *syntax.InterfaceType: + expr0 = lastFieldType(expr.MethodList) + if expr0 == nil { + return expr.Pos() + } + + case *syntax.FuncType: + expr0 = lastFieldType(expr.ResultList) + if expr0 == nil { + expr0 = lastFieldType(expr.ParamList) + if expr0 == nil { + return expr.Pos() + } + } + + case *syntax.IndexExpr: // explicit type instantiation + targs := unpackListExpr(expr.Index) + expr0 = targs[len(targs)-1] + + default: + panic(fmt.Sprintf("%s: unexpected type expression %v", expr.Pos(), syntax.String(expr))) + } + } +} + +func lastFieldType(fields []*syntax.Field) syntax.Expr { + if len(fields) == 0 { + return nil + } + return fields[len(fields)-1].Type +} + +// sumPos returns the position that noder.sum would produce for +// constant expression x. +func sumPos(x syntax.Expr) syntax.Pos { + orig := x + for { + switch x1 := x.(type) { + case *syntax.BasicLit: + assert(x1.Kind == syntax.StringLit) + return x1.Pos() + case *syntax.Operation: + assert(x1.Op == syntax.Add && x1.Y != nil) + if r, ok := x1.Y.(*syntax.BasicLit); ok { + assert(r.Kind == syntax.StringLit) + x = x1.X + continue + } + } + return orig.Pos() + } +} + +// funcParamsEndPos returns the value of base.Pos left by noder after +// processing a function signature. +func funcParamsEndPos(fn *ir.Func) src.XPos { + sig := fn.Nname.Type() + + fields := sig.Results().FieldSlice() + if len(fields) == 0 { + fields = sig.Params().FieldSlice() + if len(fields) == 0 { + fields = sig.Recvs().FieldSlice() + if len(fields) == 0 { + if fn.OClosure != nil { + return fn.Nname.Ntype.Pos() + } + return fn.Pos() + } + } + } + + return fields[len(fields)-1].Pos +} + +type dupTypes struct { + origs map[types2.Type]types2.Type +} + +func (d *dupTypes) orig(t types2.Type) types2.Type { + if orig, ok := d.origs[t]; ok { + return orig + } + return t +} + +func (d *dupTypes) add(t, orig types2.Type) { + if t == orig { + return + } + + if d.origs == nil { + d.origs = make(map[types2.Type]types2.Type) + } + assert(d.origs[t] == nil) + d.origs[t] = orig + + switch t := t.(type) { + case *types2.Pointer: + orig := orig.(*types2.Pointer) + d.add(t.Elem(), orig.Elem()) + + case *types2.Slice: + orig := orig.(*types2.Slice) + d.add(t.Elem(), orig.Elem()) + + case *types2.Map: + orig := orig.(*types2.Map) + d.add(t.Key(), orig.Key()) + d.add(t.Elem(), orig.Elem()) + + case *types2.Array: + orig := orig.(*types2.Array) + assert(t.Len() == orig.Len()) + d.add(t.Elem(), orig.Elem()) + + case *types2.Chan: + orig := orig.(*types2.Chan) + assert(t.Dir() == orig.Dir()) + d.add(t.Elem(), orig.Elem()) + + case *types2.Struct: + orig := orig.(*types2.Struct) + assert(t.NumFields() == orig.NumFields()) + for i := 0; i < t.NumFields(); i++ { + d.add(t.Field(i).Type(), orig.Field(i).Type()) + } + + case *types2.Interface: + orig := orig.(*types2.Interface) + assert(t.NumExplicitMethods() == orig.NumExplicitMethods()) + assert(t.NumEmbeddeds() == orig.NumEmbeddeds()) + for i := 0; i < t.NumExplicitMethods(); i++ { + d.add(t.ExplicitMethod(i).Type(), orig.ExplicitMethod(i).Type()) + } + for i := 0; i < t.NumEmbeddeds(); i++ { + d.add(t.EmbeddedType(i), orig.EmbeddedType(i)) + } + + case *types2.Signature: + orig := orig.(*types2.Signature) + assert((t.Recv() == nil) == (orig.Recv() == nil)) + if t.Recv() != nil { + d.add(t.Recv().Type(), orig.Recv().Type()) + } + d.add(t.Params(), orig.Params()) + d.add(t.Results(), orig.Results()) + + case *types2.Tuple: + orig := orig.(*types2.Tuple) + assert(t.Len() == orig.Len()) + for i := 0; i < t.Len(); i++ { + d.add(t.At(i).Type(), orig.At(i).Type()) + } + + default: + assert(types2.Identical(t, orig)) + } +} diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go new file mode 100644 index 00000000000..18ecbff3ccf --- /dev/null +++ b/src/cmd/compile/internal/noder/reader.go @@ -0,0 +1,1970 @@ +// UNREVIEWED + +// Copyright 2021 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 noder + +import ( + "bytes" + "fmt" + "go/constant" + "strings" + + "cmd/compile/internal/base" + "cmd/compile/internal/deadcode" + "cmd/compile/internal/dwarfgen" + "cmd/compile/internal/ir" + "cmd/compile/internal/typecheck" + "cmd/compile/internal/types" + "cmd/internal/obj" + "cmd/internal/src" +) + +// TODO(mdempsky): Suppress duplicate type/const errors that can arise +// during typecheck due to naive type substitution (e.g., see #42758). +// I anticipate these will be handled as a consequence of adding +// dictionaries support, so it's probably not important to focus on +// this until after that's done. + +type pkgReader struct { + pkgDecoder + + posBases []*src.PosBase + pkgs []*types.Pkg + typs []*types.Type + + // offset for rewriting the given index into the output, + // but bitwise inverted so we can detect if we're missing the entry or not. + newindex []int +} + +func newPkgReader(pr pkgDecoder) *pkgReader { + return &pkgReader{ + pkgDecoder: pr, + + posBases: make([]*src.PosBase, pr.numElems(relocPosBase)), + pkgs: make([]*types.Pkg, pr.numElems(relocPkg)), + typs: make([]*types.Type, pr.numElems(relocType)), + + newindex: make([]int, pr.totalElems()), + } +} + +type pkgReaderIndex struct { + pr *pkgReader + idx int + implicits []*types.Type +} + +func (pri pkgReaderIndex) asReader(k reloc, marker syncMarker) *reader { + r := pri.pr.newReader(k, pri.idx, marker) + r.implicits = pri.implicits + return r +} + +func (pr *pkgReader) newReader(k reloc, idx int, marker syncMarker) *reader { + return &reader{ + decoder: pr.newDecoder(k, idx, marker), + p: pr, + } +} + +type reader struct { + decoder + + p *pkgReader + + // Implicit and explicit type arguments in use for reading the + // current object. For example: + // + // func F[T any]() { + // type X[U any] struct { t T; u U } + // var _ X[string] + // } + // + // var _ = F[int] + // + // While instantiating F[int], we need to in turn instantiate + // X[string]. [int] and [string] are explicit type arguments for F + // and X, respectively; but [int] is also the implicit type + // arguments for X. + // + // (As an analogy to function literals, explicits are the function + // literal's formal parameters, while implicits are variables + // captured by the function literal.) + implicits []*types.Type + explicits []*types.Type + + ext *reader + + // TODO(mdempsky): The state below is all specific to reading + // function bodies. It probably makes sense to split it out + // separately so that it doesn't take up space in every reader + // instance. + + curfn *ir.Func + locals []*ir.Name + + funarghack bool + + // scopeVars is a stack tracking the number of variables declared in + // the current function at the moment each open scope was opened. + scopeVars []int + marker dwarfgen.ScopeMarker + lastCloseScopePos src.XPos + + // === details for handling inline body expansion === + + // If we're reading in a function body because of inlining, this is + // the call that we're inlining for. + inlCaller *ir.Func + inlCall *ir.CallExpr + inlFunc *ir.Func + inlTreeIndex int + inlPosBases map[*src.PosBase]*src.PosBase + + delayResults bool + + // Label to return to. + retlabel *types.Sym + + inlvars, retvars ir.Nodes +} + +func (r *reader) setType(n ir.Node, typ *types.Type) { + n.SetType(typ) + n.SetTypecheck(1) + + if name, ok := n.(*ir.Name); ok { + name.SetWalkdef(1) + name.Ntype = ir.TypeNode(name.Type()) + } +} + +func (r *reader) setValue(name *ir.Name, val constant.Value) { + name.SetVal(val) + name.Defn = nil +} + +// @@@ Positions + +func (r *reader) pos() src.XPos { + return base.Ctxt.PosTable.XPos(r.pos0()) +} + +func (r *reader) pos0() src.Pos { + r.sync(syncPos) + if !r.bool() { + return src.NoPos + } + + posBase := r.posBase() + line := r.uint() + col := r.uint() + return src.MakePos(posBase, line, col) +} + +func (r *reader) posBase() *src.PosBase { + return r.inlPosBase(r.p.posBaseIdx(r.reloc(relocPosBase))) +} + +func (pr *pkgReader) posBaseIdx(idx int) *src.PosBase { + if b := pr.posBases[idx]; b != nil { + return b + } + + r := pr.newReader(relocPosBase, idx, syncPosBase) + var b *src.PosBase + + fn := r.string() + absfn := r.string() + + if r.bool() { + b = src.NewFileBase(fn, absfn) + } else { + pos := r.pos0() + line := r.uint() + col := r.uint() + b = src.NewLinePragmaBase(pos, fn, absfn, line, col) + } + + pr.posBases[idx] = b + return b +} + +func (r *reader) inlPosBase(oldBase *src.PosBase) *src.PosBase { + if r.inlCall == nil { + return oldBase + } + + if newBase, ok := r.inlPosBases[oldBase]; ok { + return newBase + } + + newBase := src.NewInliningBase(oldBase, r.inlTreeIndex) + r.inlPosBases[oldBase] = newBase + return newBase +} + +func (r *reader) updatePos(xpos src.XPos) src.XPos { + pos := base.Ctxt.PosTable.Pos(xpos) + pos.SetBase(r.inlPosBase(pos.Base())) + return base.Ctxt.PosTable.XPos(pos) +} + +func (r *reader) origPos(xpos src.XPos) src.XPos { + if r.inlCall == nil { + return xpos + } + + pos := base.Ctxt.PosTable.Pos(xpos) + for old, new := range r.inlPosBases { + if pos.Base() == new { + pos.SetBase(old) + return base.Ctxt.PosTable.XPos(pos) + } + } + + base.FatalfAt(xpos, "pos base missing from inlPosBases") + panic("unreachable") +} + +// @@@ Packages + +func (r *reader) pkg() *types.Pkg { + r.sync(syncPkg) + return r.p.pkgIdx(r.reloc(relocPkg)) +} + +func (pr *pkgReader) pkgIdx(idx int) *types.Pkg { + if pkg := pr.pkgs[idx]; pkg != nil { + return pkg + } + + pkg := pr.newReader(relocPkg, idx, syncPkgDef).doPkg() + pr.pkgs[idx] = pkg + return pkg +} + +func (r *reader) doPkg() *types.Pkg { + path := r.string() + if path == "builtin" { + return types.BuiltinPkg + } + if path == "" { + path = r.p.pkgPath + } + + name := r.string() + height := r.len() + + pkg := types.NewPkg(path, "") + + if pkg.Name == "" { + pkg.Name = name + } else { + assert(pkg.Name == name) + } + + if pkg.Height == 0 { + pkg.Height = height + } else { + assert(pkg.Height == height) + } + + return pkg +} + +// @@@ Types + +func (r *reader) typ() *types.Type { + r.sync(syncType) + return r.p.typIdx(r.reloc(relocType), r.implicits, r.explicits) +} + +func (pr *pkgReader) typIdx(idx int, implicits, explicits []*types.Type) *types.Type { + if typ := pr.typs[idx]; typ != nil { + return typ + } + + r := pr.newReader(relocType, idx, syncTypeIdx) + r.implicits = implicits + r.explicits = explicits + typ := r.doTyp() + assert(typ != nil) + + if typ := pr.typs[idx]; typ != nil { + // This happens in fixedbugs/issue27232.go. + // TODO(mdempsky): Explain why/how this happens. + return typ + } + + // If we have type parameters, the type might refer to them, and it + // wouldn't be safe to reuse those in other contexts. So we + // conservatively avoid caching them in that case. + // + // TODO(mdempsky): If we're clever, we should be able to still cache + // types by tracking which type parameters are used. However, in my + // attempts so far, I haven't yet succeeded in being clever enough. + if len(implicits)+len(explicits) == 0 { + pr.typs[idx] = typ + } + + if !typ.IsUntyped() { + types.CheckSize(typ) + } + + return typ +} + +func (r *reader) doTyp() *types.Type { + switch tag := codeType(r.code(syncType)); tag { + default: + panic(fmt.Sprintf("unexpected type: %v", tag)) + + case typeBasic: + return *basics[r.len()] + + case typeNamed: + obj := r.obj() + assert(obj.Op() == ir.OTYPE) + return obj.Type() + + case typeTypeParam: + idx := r.len() + if idx < len(r.implicits) { + return r.implicits[idx] + } + return r.explicits[idx-len(r.implicits)] + + case typeArray: + len := int64(r.uint64()) + return types.NewArray(r.typ(), len) + case typeChan: + dir := dirs[r.len()] + return types.NewChan(r.typ(), dir) + case typeMap: + return types.NewMap(r.typ(), r.typ()) + case typePointer: + return types.NewPtr(r.typ()) + case typeSignature: + return r.signature(types.LocalPkg, nil) + case typeSlice: + return types.NewSlice(r.typ()) + case typeStruct: + return r.structType() + case typeInterface: + return r.interfaceType() + } +} + +func (r *reader) interfaceType() *types.Type { + tpkg := types.LocalPkg // TODO(mdempsky): Remove after iexport is gone. + + nmethods, nembeddeds := r.len(), r.len() + + fields := make([]*types.Field, nmethods+nembeddeds) + methods, embeddeds := fields[:nmethods], fields[nmethods:] + + for i := range methods { + pos := r.pos() + pkg, sym := r.selector() + tpkg = pkg + mtyp := r.signature(pkg, typecheck.FakeRecv()) + methods[i] = types.NewField(pos, sym, mtyp) + } + for i := range embeddeds { + embeddeds[i] = types.NewField(src.NoXPos, nil, r.typ()) + } + + if len(fields) == 0 { + return types.Types[types.TINTER] // empty interface + } + return types.NewInterface(tpkg, fields) +} + +func (r *reader) structType() *types.Type { + tpkg := types.LocalPkg // TODO(mdempsky): Remove after iexport is gone. + fields := make([]*types.Field, r.len()) + for i := range fields { + pos := r.pos() + pkg, sym := r.selector() + tpkg = pkg + ftyp := r.typ() + tag := r.string() + embedded := r.bool() + + f := types.NewField(pos, sym, ftyp) + f.Note = tag + if embedded { + f.Embedded = 1 + } + fields[i] = f + } + return types.NewStruct(tpkg, fields) +} + +func (r *reader) signature(tpkg *types.Pkg, recv *types.Field) *types.Type { + r.sync(syncSignature) + + params := r.params(&tpkg) + results := r.params(&tpkg) + if r.bool() { // variadic + params[len(params)-1].SetIsDDD(true) + } + + return types.NewSignature(tpkg, recv, nil, params, results) +} + +func (r *reader) params(tpkg **types.Pkg) []*types.Field { + r.sync(syncParams) + fields := make([]*types.Field, r.len()) + for i := range fields { + *tpkg, fields[i] = r.param() + } + return fields +} + +func (r *reader) param() (*types.Pkg, *types.Field) { + r.sync(syncParam) + + pos := r.pos() + pkg, sym := r.localIdent() + typ := r.typ() + + return pkg, types.NewField(pos, sym, typ) +} + +// @@@ Objects + +var objReader = map[*types.Sym]pkgReaderIndex{} + +func (r *reader) obj() ir.Node { + r.sync(syncObject) + + idx := r.reloc(relocObj) + + explicits := make([]*types.Type, r.len()) + for i := range explicits { + explicits[i] = r.typ() + } + + return r.p.objIdx(idx, r.implicits, explicits) +} + +func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node { + r := pr.newReader(relocObj, idx, syncObject1) + r.ext = pr.newReader(relocObjExt, idx, syncObject1) + + _, sym := r.qualifiedIdent() + + // Middle dot indicates local defined type; see writer.sym. + // TODO(mdempsky): Come up with a better way to handle this. + if strings.Contains(sym.Name, "·") { + r.implicits = implicits + r.ext.implicits = implicits + } + r.explicits = explicits + r.ext.explicits = explicits + + origSym := sym + + sym = r.mangle(sym) + if !sym.IsBlank() && sym.Def != nil { + return sym.Def.(ir.Node) + } + + r.typeParamBounds(origSym) + tag := codeObj(r.code(syncCodeObj)) + + do := func(op ir.Op, hasTParams bool) *ir.Name { + pos := r.pos() + if hasTParams { + r.typeParamNames() + } + + name := ir.NewDeclNameAt(pos, op, sym) + name.Class = ir.PEXTERN // may be overridden later + if !sym.IsBlank() { + if sym.Def != nil { + base.FatalfAt(name.Pos(), "already have a definition for %v", name) + } + assert(sym.Def == nil) + sym.Def = name + } + return name + } + + switch tag { + default: + panic("unexpected object") + + case objStub: + if pri, ok := objReader[origSym]; ok { + return pri.pr.objIdx(pri.idx, pri.implicits, r.explicits) + } + if haveLegacyImports { + assert(len(r.implicits)+len(r.explicits) == 0) + return typecheck.Resolve(ir.NewIdent(src.NoXPos, origSym)) + } + base.Fatalf("unresolved stub: %v", origSym) + panic("unreachable") + + case objAlias: + name := do(ir.OTYPE, false) + r.setType(name, r.typ()) + name.SetAlias(true) + return name + + case objConst: + name := do(ir.OLITERAL, false) + typ, val := r.value() + r.setType(name, typ) + r.setValue(name, val) + return name + + case objFunc: + if sym.Name == "init" { + sym = renameinit() + } + name := do(ir.ONAME, true) + r.setType(name, r.signature(sym.Pkg, nil)) + + name.Func = ir.NewFunc(r.pos()) + name.Func.Nname = name + + r.ext.funcExt(name) + return name + + case objType: + name := do(ir.OTYPE, true) + typ := types.NewNamed(name) + r.setType(name, typ) + + // Important: We need to do this before SetUnderlying. + r.ext.typeExt(name) + + // We need to defer CheckSize until we've called SetUnderlying to + // handle recursive types. + types.DeferCheckSize() + typ.SetUnderlying(r.typ()) + types.ResumeCheckSize() + + methods := make([]*types.Field, r.len()) + for i := range methods { + methods[i] = r.method() + } + if len(methods) != 0 { + typ.Methods().Set(methods) + } + + return name + + case objVar: + name := do(ir.ONAME, false) + r.setType(name, r.typ()) + r.ext.varExt(name) + return name + } +} + +func (r *reader) mangle(sym *types.Sym) *types.Sym { + if len(r.implicits)+len(r.explicits) == 0 { + return sym + } + + var buf bytes.Buffer + buf.WriteString(sym.Name) + buf.WriteByte('[') + for i, targs := range [2][]*types.Type{r.implicits, r.explicits} { + if i > 0 && len(r.implicits) != 0 && len(r.explicits) != 0 { + buf.WriteByte(';') + } + for j, targ := range targs { + if j > 0 { + buf.WriteByte(',') + } + // TODO(mdempsky): We need the linker to replace "" in the symbol + // names here. + buf.WriteString(targ.ShortString()) + } + } + buf.WriteByte(']') + return sym.Pkg.Lookup(buf.String()) +} + +func (r *reader) typeParamBounds(sym *types.Sym) { + r.sync(syncTypeParamBounds) + + nimplicits := r.len() + nexplicits := r.len() + + if len(r.implicits) != nimplicits || len(r.explicits) != nexplicits { + base.Fatalf("%v has %v+%v params, but instantiated with %v+%v args", sym, nimplicits, nexplicits, len(r.implicits), len(r.explicits)) + } + + // For stenciling, we can just skip over the type parameters. + + for range r.explicits { + // Skip past bounds without actually evaluating them. + r.sync(syncType) + r.reloc(relocType) + } +} + +func (r *reader) typeParamNames() { + r.sync(syncTypeParamNames) + + for range r.explicits { + r.pos() + r.localIdent() + } +} + +func (r *reader) value() (*types.Type, constant.Value) { + r.sync(syncValue) + typ := r.typ() + return typ, FixValue(typ, r.rawValue()) +} + +func (r *reader) method() *types.Field { + r.sync(syncMethod) + pos := r.pos() + pkg, sym := r.selector() + r.typeParamNames() + _, recv := r.param() + typ := r.signature(pkg, recv) + + fnsym := sym + fnsym = ir.MethodSym(recv.Type, fnsym) + name := ir.NewNameAt(pos, fnsym) + r.setType(name, typ) + + name.Func = ir.NewFunc(r.pos()) + name.Func.Nname = name + + // TODO(mdempsky): Make sure we're handling //go:nointerface + // correctly. I don't think this is exercised within the Go repo. + + r.ext.funcExt(name) + + meth := types.NewField(name.Func.Pos(), sym, typ) + meth.Nname = name + return meth +} + +func (r *reader) qualifiedIdent() (pkg *types.Pkg, sym *types.Sym) { + r.sync(syncSym) + pkg = r.pkg() + if name := r.string(); name != "" { + sym = pkg.Lookup(name) + } + return +} + +func (r *reader) localIdent() (pkg *types.Pkg, sym *types.Sym) { + r.sync(syncLocalIdent) + pkg = r.pkg() + if name := r.string(); name != "" { + sym = pkg.Lookup(name) + } + return +} + +func (r *reader) selector() (origPkg *types.Pkg, sym *types.Sym) { + r.sync(syncSelector) + origPkg = r.pkg() + name := r.string() + pkg := origPkg + if types.IsExported(name) { + pkg = types.LocalPkg + } + sym = pkg.Lookup(name) + return +} + +// @@@ Compiler extensions + +func (r *reader) funcExt(name *ir.Name) { + r.sync(syncFuncExt) + + name.Class = 0 // so MarkFunc doesn't complain + ir.MarkFunc(name) + + fn := name.Func + + // XXX: Workaround because linker doesn't know how to copy Pos. + if !fn.Pos().IsKnown() { + fn.SetPos(name.Pos()) + } + + // TODO(mdempsky): Remember why I wrote this code. I think it has to + // do with how ir.VisitFuncsBottomUp works? + if name.Sym().Pkg == types.LocalPkg || len(r.implicits)+len(r.explicits) != 0 { + name.Defn = fn + } + + fn.Pragma = r.pragmaFlag() + r.linkname(name) + + if r.bool() { + fn.ABI = obj.ABI(r.uint64()) + + // Escape analysis. + for _, fs := range &types.RecvsParams { + for _, f := range fs(name.Type()).FieldSlice() { + f.Note = r.string() + } + } + + if r.bool() { + fn.Inl = &ir.Inline{ + Cost: int32(r.len()), + CanDelayResults: r.bool(), + } + r.addBody(name.Func) + } + } else { + r.addBody(name.Func) + } + r.sync(syncEOF) +} + +func (r *reader) typeExt(name *ir.Name) { + r.sync(syncTypeExt) + + typ := name.Type() + + if len(r.implicits)+len(r.explicits) != 0 { + // Set "RParams" (really type arguments here, not parameters) so + // this type is treated as "fully instantiated". This ensures the + // type descriptor is written out as DUPOK and method wrappers are + // generated even for imported types. + var targs []*types.Type + targs = append(targs, r.implicits...) + targs = append(targs, r.explicits...) + typ.SetRParams(targs) + } + + name.SetPragma(r.pragmaFlag()) + if name.Pragma()&ir.NotInHeap != 0 { + typ.SetNotInHeap(true) + } + + typecheck.SetBaseTypeIndex(typ, r.int64(), r.int64()) +} + +func (r *reader) varExt(name *ir.Name) { + r.sync(syncVarExt) + r.linkname(name) +} + +func (r *reader) linkname(name *ir.Name) { + assert(name.Op() == ir.ONAME) + r.sync(syncLinkname) + + if idx := r.int64(); idx >= 0 { + lsym := name.Linksym() + lsym.SymIdx = int32(idx) + lsym.Set(obj.AttrIndexed, true) + } else { + name.Sym().Linkname = r.string() + } +} + +func (r *reader) pragmaFlag() ir.PragmaFlag { + r.sync(syncPragma) + return ir.PragmaFlag(r.int()) +} + +// @@@ Function bodies + +// bodyReader tracks where the serialized IR for a function's body can +// be found. +var bodyReader = map[*ir.Func]pkgReaderIndex{} + +// todoBodies holds the list of function bodies that still need to be +// constructed. +var todoBodies []*ir.Func + +func (r *reader) addBody(fn *ir.Func) { + r.sync(syncAddBody) + + // See commont in writer.addBody for why r.implicits and r.explicits + // should never both be non-empty. + implicits := r.implicits + if len(implicits) == 0 { + implicits = r.explicits + } else { + assert(len(r.explicits) == 0) + } + + pri := pkgReaderIndex{r.p, r.reloc(relocBody), implicits} + bodyReader[fn] = pri + + if r.curfn == nil { + todoBodies = append(todoBodies, fn) + return + } + + pri.funcBody(fn) +} + +func (pri pkgReaderIndex) funcBody(fn *ir.Func) { + r := pri.asReader(relocBody, syncFuncBody) + r.funcBody(fn) +} + +func (r *reader) funcBody(fn *ir.Func) { + r.curfn = fn + r.locals = fn.ClosureVars + + // TODO(mdempsky): Get rid of uses of typecheck.NodAddrAt so we + // don't have to set ir.CurFunc. + outerCurFunc := ir.CurFunc + ir.CurFunc = fn + + r.funcargs(fn) + + if r.bool() { + body := r.stmts() + if body == nil { + pos := src.NoXPos + if quirksMode() { + pos = funcParamsEndPos(fn) + } + body = []ir.Node{ir.NewBlockStmt(pos, nil)} + } + fn.Body = body + fn.Endlineno = r.pos() + } + + ir.CurFunc = outerCurFunc + r.marker.WriteTo(fn) +} + +func (r *reader) funcargs(fn *ir.Func) { + sig := fn.Nname.Type() + + if recv := sig.Recv(); recv != nil { + r.funcarg(recv, recv.Sym, ir.PPARAM) + } + for _, param := range sig.Params().FieldSlice() { + r.funcarg(param, param.Sym, ir.PPARAM) + } + + for i, param := range sig.Results().FieldSlice() { + sym := types.OrigSym(param.Sym) + + if sym == nil || sym.IsBlank() { + prefix := "~r" + if r.inlCall != nil { + prefix = "~R" + } else if sym != nil { + prefix = "~b" + } + sym = typecheck.LookupNum(prefix, i) + } + + r.funcarg(param, sym, ir.PPARAMOUT) + } +} + +func (r *reader) funcarg(param *types.Field, sym *types.Sym, ctxt ir.Class) { + if sym == nil { + assert(ctxt == ir.PPARAM) + if r.inlCall != nil { + r.inlvars.Append(ir.BlankNode) + } + return + } + + name := ir.NewNameAt(r.updatePos(param.Pos), sym) + r.setType(name, param.Type) + r.addLocal(name, ctxt) + + if r.inlCall == nil { + if !r.funarghack { + param.Sym = sym + param.Nname = name + } + } else { + if ctxt == ir.PPARAMOUT { + r.retvars.Append(name) + } else { + r.inlvars.Append(name) + } + } +} + +func (r *reader) addLocal(name *ir.Name, ctxt ir.Class) { + assert(ctxt == ir.PAUTO || ctxt == ir.PPARAM || ctxt == ir.PPARAMOUT) + + r.sync(syncAddLocal) + if debug { + want := r.int() + if have := len(r.locals); have != want { + base.FatalfAt(name.Pos(), "locals table has desynced") + } + } + + name.SetUsed(true) + r.locals = append(r.locals, name) + + // TODO(mdempsky): Move earlier. + if ir.IsBlank(name) { + return + } + + if r.inlCall != nil { + if ctxt == ir.PAUTO { + name.SetInlLocal(true) + } else { + name.SetInlFormal(true) + ctxt = ir.PAUTO + } + + // TODO(mdempsky): Rethink this hack. + if strings.HasPrefix(name.Sym().Name, "~") || base.Flag.GenDwarfInl == 0 { + name.SetPos(r.inlCall.Pos()) + name.SetInlFormal(false) + name.SetInlLocal(false) + } + } + + name.Class = ctxt + name.Curfn = r.curfn + + r.curfn.Dcl = append(r.curfn.Dcl, name) + + if ctxt == ir.PAUTO { + name.SetFrameOffset(0) + } +} + +func (r *reader) useLocal() *ir.Name { + r.sync(syncUseObjLocal) + return r.locals[r.len()] +} + +func (r *reader) openScope() { + r.sync(syncOpenScope) + pos := r.pos() + + if base.Flag.Dwarf { + r.scopeVars = append(r.scopeVars, len(r.curfn.Dcl)) + r.marker.Push(pos) + } +} + +func (r *reader) closeScope() { + r.sync(syncCloseScope) + r.lastCloseScopePos = r.pos() + + r.closeAnotherScope() +} + +// closeAnotherScope is like closeScope, but it reuses the same mark +// position as the last closeScope call. This is useful for "for" and +// "if" statements, as their implicit blocks always end at the same +// position as an explicit block. +func (r *reader) closeAnotherScope() { + r.sync(syncCloseAnotherScope) + + if base.Flag.Dwarf { + scopeVars := r.scopeVars[len(r.scopeVars)-1] + r.scopeVars = r.scopeVars[:len(r.scopeVars)-1] + + if scopeVars == len(r.curfn.Dcl) { + // no variables were declared in this scope, so we can retract it. + r.marker.Unpush() + } else { + r.marker.Pop(r.lastCloseScopePos) + } + } +} + +// @@@ Statements + +func (r *reader) stmt() ir.Node { + switch stmts := r.stmts(); len(stmts) { + case 0: + return nil + case 1: + return stmts[0] + default: + return ir.NewBlockStmt(stmts[0].Pos(), stmts) + } +} + +func (r *reader) stmts() []ir.Node { + var res ir.Nodes + + r.sync(syncStmts) + for { + tag := codeStmt(r.code(syncStmt1)) + if tag == stmtEnd { + r.sync(syncStmtsEnd) + return res + } + + if n := r.stmt1(tag, &res); n != nil { + res.Append(n) + } + } +} + +func (r *reader) stmt1(tag codeStmt, out *ir.Nodes) ir.Node { + var label *types.Sym + if n := len(*out); n > 0 { + if ls, ok := (*out)[n-1].(*ir.LabelStmt); ok { + label = ls.Label + } + } + + switch tag { + default: + panic("unexpected statement") + + case stmtAssign: + pos := r.pos() + names, lhs := r.assignList() + rhs := r.exprList() + + if len(rhs) == 0 { + for _, name := range names { + as := ir.NewAssignStmt(pos, name, nil) + as.PtrInit().Append(ir.NewDecl(pos, ir.ODCL, name)) + out.Append(as) + } + return nil + } + + if len(lhs) == 1 && len(rhs) == 1 { + n := ir.NewAssignStmt(pos, lhs[0], rhs[0]) + n.Def = r.initDefn(n, names) + return n + } + + n := ir.NewAssignListStmt(pos, ir.OAS2, lhs, rhs) + n.Def = r.initDefn(n, names) + return n + + case stmtAssignOp: + op := r.op() + lhs := r.expr() + pos := r.pos() + rhs := r.expr() + return ir.NewAssignOpStmt(pos, op, lhs, rhs) + + case stmtIncDec: + op := r.op() + lhs := r.expr() + pos := r.pos() + n := ir.NewAssignOpStmt(pos, op, lhs, ir.NewBasicLit(pos, one)) + n.IncDec = true + return n + + case stmtBlock: + out.Append(r.blockStmt()...) + return nil + + case stmtBranch: + pos := r.pos() + op := r.op() + sym := r.optLabel() + return ir.NewBranchStmt(pos, op, sym) + + case stmtCall: + pos := r.pos() + op := r.op() + call := r.expr() + return ir.NewGoDeferStmt(pos, op, call) + + case stmtExpr: + return r.expr() + + case stmtFor: + return r.forStmt(label) + + case stmtIf: + return r.ifStmt() + + case stmtLabel: + pos := r.pos() + sym := r.label() + return ir.NewLabelStmt(pos, sym) + + case stmtReturn: + pos := r.pos() + results := r.exprList() + return ir.NewReturnStmt(pos, results) + + case stmtSelect: + return r.selectStmt(label) + + case stmtSend: + pos := r.pos() + ch := r.expr() + value := r.expr() + return ir.NewSendStmt(pos, ch, value) + + case stmtSwitch: + return r.switchStmt(label) + + case stmtTypeDeclHack: + // fake "type _ = int" declaration to prevent inlining in quirks mode. + assert(quirksMode()) + + name := ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, ir.BlankNode.Sym()) + name.SetAlias(true) + r.setType(name, types.Types[types.TINT]) + + n := ir.NewDecl(src.NoXPos, ir.ODCLTYPE, name) + n.SetTypecheck(1) + return n + } +} + +func (r *reader) assignList() ([]*ir.Name, []ir.Node) { + lhs := make([]ir.Node, r.len()) + var names []*ir.Name + + for i := range lhs { + if r.bool() { + pos := r.pos() + _, sym := r.localIdent() + typ := r.typ() + + name := ir.NewNameAt(pos, sym) + lhs[i] = name + names = append(names, name) + r.setType(name, typ) + r.addLocal(name, ir.PAUTO) + continue + } + + lhs[i] = r.expr() + } + + return names, lhs +} + +func (r *reader) blockStmt() []ir.Node { + r.sync(syncBlockStmt) + r.openScope() + stmts := r.stmts() + r.closeScope() + return stmts +} + +func (r *reader) forStmt(label *types.Sym) ir.Node { + r.sync(syncForStmt) + + r.openScope() + + if r.bool() { + pos := r.pos() + names, lhs := r.assignList() + x := r.expr() + body := r.blockStmt() + r.closeAnotherScope() + + rang := ir.NewRangeStmt(pos, nil, nil, x, body) + if len(lhs) >= 1 { + rang.Key = lhs[0] + if len(lhs) >= 2 { + rang.Value = lhs[1] + } + } + rang.Def = r.initDefn(rang, names) + rang.Label = label + return rang + } + + pos := r.pos() + init := r.stmt() + cond := r.expr() + post := r.stmt() + body := r.blockStmt() + r.closeAnotherScope() + + stmt := ir.NewForStmt(pos, init, cond, post, body) + stmt.Label = label + return stmt +} + +func (r *reader) ifStmt() ir.Node { + r.sync(syncIfStmt) + r.openScope() + pos := r.pos() + init := r.stmts() + cond := r.expr() + then := r.blockStmt() + els := r.stmts() + n := ir.NewIfStmt(pos, cond, then, els) + n.SetInit(init) + r.closeAnotherScope() + return n +} + +func (r *reader) selectStmt(label *types.Sym) ir.Node { + r.sync(syncSelectStmt) + + pos := r.pos() + clauses := make([]*ir.CommClause, r.len()) + for i := range clauses { + if i > 0 { + r.closeScope() + } + r.openScope() + + pos := r.pos() + comm := r.stmt() + body := r.stmts() + + clauses[i] = ir.NewCommStmt(pos, comm, body) + } + if len(clauses) > 0 { + r.closeScope() + } + n := ir.NewSelectStmt(pos, clauses) + n.Label = label + return n +} + +func (r *reader) switchStmt(label *types.Sym) ir.Node { + r.sync(syncSwitchStmt) + + r.openScope() + pos := r.pos() + init := r.stmt() + tag := r.expr() + + tswitch, ok := tag.(*ir.TypeSwitchGuard) + if ok && tswitch.Tag == nil { + tswitch = nil + } + + clauses := make([]*ir.CaseClause, r.len()) + for i := range clauses { + if i > 0 { + r.closeScope() + } + r.openScope() + + pos := r.pos() + cases := r.exprList() + + clause := ir.NewCaseStmt(pos, cases, nil) + if tswitch != nil { + pos := r.pos() + typ := r.typ() + + name := ir.NewNameAt(pos, tswitch.Tag.Sym()) + r.setType(name, typ) + r.addLocal(name, ir.PAUTO) + clause.Var = name + name.Defn = tswitch + } + + clause.Body = r.stmts() + clauses[i] = clause + } + if len(clauses) > 0 { + r.closeScope() + } + r.closeScope() + + n := ir.NewSwitchStmt(pos, tag, clauses) + n.Label = label + if init != nil { + n.SetInit([]ir.Node{init}) + } + return n +} + +func (r *reader) label() *types.Sym { + r.sync(syncLabel) + name := r.string() + if r.inlCall != nil { + name = fmt.Sprintf("~%s·%d", name, inlgen) + } + return typecheck.Lookup(name) +} + +func (r *reader) optLabel() *types.Sym { + r.sync(syncOptLabel) + if r.bool() { + return r.label() + } + return nil +} + +// initDefn marks the given names as declared by defn and populates +// its Init field with ODCL nodes. It then reports whether any names +// were so declared, which can be used to initialize defn.Def. +func (r *reader) initDefn(defn ir.InitNode, names []*ir.Name) bool { + if len(names) == 0 { + return false + } + + init := make([]ir.Node, len(names)) + for i, name := range names { + name.Defn = defn + init[i] = ir.NewDecl(name.Pos(), ir.ODCL, name) + } + defn.SetInit(init) + return true +} + +// @@@ Expressions + +func (r *reader) expr() ir.Node { + switch tag := codeExpr(r.code(syncExpr)); tag { + default: + panic("unhandled expression") + + case exprNone: + return nil + + case exprBlank: + return ir.BlankNode + + case exprLocal: + return r.useLocal() + + case exprName: + return r.obj() + + case exprType: + return ir.TypeNode(r.typ()) + + case exprConst: + pos := r.pos() + typ, val := r.value() + op := r.op() + orig := r.string() + return OrigConst(pos, typ, val, op, orig) + + case exprCompLit: + return r.compLit() + + case exprFuncLit: + return r.funcLit() + + case exprSelector: + x := r.expr() + pos := r.pos() + _, sym := r.selector() + return ir.NewSelectorExpr(pos, ir.OXDOT, x, sym) + + case exprIndex: + x := r.expr() + pos := r.pos() + index := r.expr() + return ir.NewIndexExpr(pos, x, index) + + case exprSlice: + x := r.expr() + pos := r.pos() + var index [3]ir.Node + for i := range index { + index[i] = r.expr() + } + op := ir.OSLICE + if index[2] != nil { + op = ir.OSLICE3 + } + return ir.NewSliceExpr(pos, op, x, index[0], index[1], index[2]) + + case exprAssert: + x := r.expr() + pos := r.pos() + typ := r.expr().(ir.Ntype) + return ir.NewTypeAssertExpr(pos, x, typ) + + case exprUnaryOp: + op := r.op() + pos := r.pos() + x := r.expr() + + switch op { + case ir.OADDR: + return typecheck.NodAddrAt(pos, x) + case ir.ODEREF: + return ir.NewStarExpr(pos, x) + } + return ir.NewUnaryExpr(pos, op, x) + + case exprBinaryOp: + op := r.op() + x := r.expr() + pos := r.pos() + y := r.expr() + + switch op { + case ir.OANDAND, ir.OOROR: + return ir.NewLogicalExpr(pos, op, x, y) + } + return ir.NewBinaryExpr(pos, op, x, y) + + case exprCall: + fun := r.expr() + pos := r.pos() + args := r.exprs() + dots := r.bool() + n := ir.NewCallExpr(pos, ir.OCALL, fun, args) + n.IsDDD = dots + return n + + case exprTypeSwitchGuard: + pos := r.pos() + var tag *ir.Ident + if r.bool() { + pos := r.pos() + sym := typecheck.Lookup(r.string()) + tag = ir.NewIdent(pos, sym) + } + x := r.expr() + return ir.NewTypeSwitchGuard(pos, tag, x) + } +} + +func (r *reader) compLit() ir.Node { + r.sync(syncCompLit) + pos := r.pos() + typ := r.typ() + + isPtrLit := typ.IsPtr() + if isPtrLit { + typ = typ.Elem() + } + if typ.Kind() == types.TFORW { + base.FatalfAt(pos, "unresolved composite literal type: %v", typ) + } + isStruct := typ.Kind() == types.TSTRUCT + + elems := make([]ir.Node, r.len()) + for i := range elems { + elemp := &elems[i] + + if isStruct { + sk := ir.NewStructKeyExpr(r.pos(), typ.Field(r.len()), nil) + *elemp, elemp = sk, &sk.Value + } else if r.bool() { + kv := ir.NewKeyExpr(r.pos(), r.expr(), nil) + *elemp, elemp = kv, &kv.Value + } + + *elemp = wrapName(r.pos(), r.expr()) + } + + lit := ir.NewCompLitExpr(pos, ir.OCOMPLIT, ir.TypeNode(typ), elems) + if isPtrLit { + return typecheck.NodAddrAt(pos, lit) + } + return lit +} + +func wrapName(pos src.XPos, x ir.Node) ir.Node { + // These nodes do not carry line numbers. + // Introduce a wrapper node to give them the correct line. + switch ir.Orig(x).Op() { + case ir.OTYPE, ir.OLITERAL: + if x.Sym() == nil { + break + } + fallthrough + case ir.ONAME, ir.ONONAME, ir.OPACK, ir.ONIL: + p := ir.NewParenExpr(pos, x) + p.SetImplicit(true) + return p + } + return x +} + +func (r *reader) funcLit() ir.Node { + r.sync(syncFuncLit) + + pos := r.pos() + typPos := r.pos() + xtype2 := r.signature(types.LocalPkg, nil) + + opos := pos + if quirksMode() { + opos = r.origPos(pos) + } + + fn := ir.NewClosureFunc(opos, r.curfn != nil) + + r.setType(fn.Nname, xtype2) + if quirksMode() { + fn.Nname.Ntype = ir.TypeNodeAt(typPos, xtype2) + } + + fn.ClosureVars = make([]*ir.Name, r.len()) + for i := range fn.ClosureVars { + pos := r.pos() + outer := r.useLocal() + + cv := ir.NewNameAt(pos, outer.Sym()) + r.setType(cv, outer.Type()) + cv.Curfn = fn + cv.Class = ir.PAUTOHEAP + cv.SetIsClosureVar(true) + cv.Defn = outer.Canonical() + cv.Outer = outer + + fn.ClosureVars[i] = cv + } + + r.addBody(fn) + + return fn.OClosure +} + +func (r *reader) exprList() []ir.Node { + r.sync(syncExprList) + return r.exprs() +} + +func (r *reader) exprs() []ir.Node { + r.sync(syncExprs) + nodes := make([]ir.Node, r.len()) + if len(nodes) == 0 { + return nil // TODO(mdempsky): Unclear if this matters. + } + for i := range nodes { + nodes[i] = r.expr() + } + return nodes +} + +func (r *reader) op() ir.Op { + r.sync(syncOp) + return ir.Op(r.len()) +} + +// @@@ Package initialization + +func (r *reader) pkgInit(self *types.Pkg, target *ir.Package) { + if quirksMode() { + for i, n := 0, r.len(); i < n; i++ { + // Eagerly register position bases, so their filenames are + // assigned stable indices. + posBase := r.posBase() + _ = base.Ctxt.PosTable.XPos(src.MakePos(posBase, 0, 0)) + } + + for i, n := 0, r.len(); i < n; i++ { + // Eagerly resolve imported objects, so any filenames registered + // in the process are assigned stable indices too. + _, sym := r.qualifiedIdent() + typecheck.Resolve(ir.NewIdent(src.NoXPos, sym)) + assert(sym.Def != nil) + } + } + + cgoPragmas := make([][]string, r.len()) + for i := range cgoPragmas { + cgoPragmas[i] = r.strings() + } + target.CgoPragmas = cgoPragmas + + r.pkgDecls(target) + + r.sync(syncEOF) +} + +func (r *reader) pkgDecls(target *ir.Package) { + r.sync(syncDecls) + for { + switch code := codeDecl(r.code(syncDecl)); code { + default: + panic(fmt.Sprintf("unhandled decl: %v", code)) + + case declEnd: + return + + case declFunc: + names := r.pkgObjs(target) + assert(len(names) == 1) + target.Decls = append(target.Decls, names[0].Func) + + case declMethod: + typ := r.typ() + _, sym := r.selector() + + method := typecheck.Lookdot1(nil, sym, typ, typ.Methods(), 0) + target.Decls = append(target.Decls, method.Nname.(*ir.Name).Func) + + case declVar: + pos := r.pos() + names := r.pkgObjs(target) + values := r.exprList() + + if len(names) > 1 && len(values) == 1 { + as := ir.NewAssignListStmt(pos, ir.OAS2, nil, values) + for _, name := range names { + as.Lhs.Append(name) + name.Defn = as + } + target.Decls = append(target.Decls, as) + } else { + for i, name := range names { + as := ir.NewAssignStmt(pos, name, nil) + if i < len(values) { + as.Y = values[i] + } + name.Defn = as + target.Decls = append(target.Decls, as) + } + } + + if n := r.len(); n > 0 { + assert(len(names) == 1) + embeds := make([]ir.Embed, n) + for i := range embeds { + embeds[i] = ir.Embed{Pos: r.pos(), Patterns: r.strings()} + } + names[0].Embed = &embeds + target.Embeds = append(target.Embeds, names[0]) + } + + case declOther: + r.pkgObjs(target) + } + } +} + +func (r *reader) pkgObjs(target *ir.Package) []*ir.Name { + r.sync(syncDeclNames) + nodes := make([]*ir.Name, r.len()) + for i := range nodes { + r.sync(syncDeclName) + + name := r.obj().(*ir.Name) + nodes[i] = name + + sym := name.Sym() + if sym.IsBlank() { + continue + } + + switch name.Class { + default: + base.FatalfAt(name.Pos(), "unexpected class: %v", name.Class) + + case ir.PEXTERN: + target.Externs = append(target.Externs, name) + + case ir.PFUNC: + assert(name.Type().Recv() == nil) + + // TODO(mdempsky): Cleaner way to recognize init? + if strings.HasPrefix(sym.Name, "init.") { + target.Inits = append(target.Inits, name.Func) + } + } + + if types.IsExported(sym.Name) { + assert(!sym.OnExportList()) + target.Exports = append(target.Exports, name) + sym.SetOnExportList(true) + } + + if base.Flag.AsmHdr != "" { + assert(!sym.Asm()) + target.Asms = append(target.Asms, name) + sym.SetAsm(true) + } + } + + return nodes +} + +// @@@ Inlining + +var inlgen = 0 + +func InlineCall(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExpr { + // TODO(mdempsky): Turn callerfn into an explicit parameter. + callerfn := ir.CurFunc + + pri, ok := bodyReader[fn] + if !ok { + // Assume it's an imported function or something that we don't + // have access to in quirks mode. + if haveLegacyImports { + return nil + } + + base.FatalfAt(call.Pos(), "missing function body for call to %v", fn) + } + + if fn.Inl.Body == nil { + expandInline(fn, pri) + } + + r := pri.asReader(relocBody, syncFuncBody) + + // TODO(mdempsky): This still feels clumsy. Can we do better? + tmpfn := ir.NewFunc(fn.Pos()) + tmpfn.Nname = ir.NewNameAt(fn.Nname.Pos(), callerfn.Sym()) + tmpfn.Closgen = callerfn.Closgen + defer func() { callerfn.Closgen = tmpfn.Closgen }() + + r.setType(tmpfn.Nname, fn.Type()) + r.curfn = tmpfn + + r.inlCaller = ir.CurFunc + r.inlCall = call + r.inlFunc = fn + r.inlTreeIndex = inlIndex + r.inlPosBases = make(map[*src.PosBase]*src.PosBase) + + for _, cv := range r.inlFunc.ClosureVars { + r.locals = append(r.locals, cv.Outer) + } + + r.funcargs(fn) + + assert(r.bool()) // have body + r.delayResults = fn.Inl.CanDelayResults + + r.retlabel = typecheck.AutoLabel(".i") + inlgen++ + + init := ir.TakeInit(call) + + // For normal function calls, the function callee expression + // may contain side effects (e.g., added by addinit during + // inlconv2expr or inlconv2list). Make sure to preserve these, + // if necessary (#42703). + if call.Op() == ir.OCALLFUNC { + callee := call.X + for callee.Op() == ir.OCONVNOP { + conv := callee.(*ir.ConvExpr) + init.Append(ir.TakeInit(conv)...) + callee = conv.X + } + + switch callee.Op() { + case ir.ONAME, ir.OCLOSURE, ir.OMETHEXPR: + // ok + default: + base.Fatalf("unexpected callee expression: %v", callee) + } + } + + var args ir.Nodes + if call.Op() == ir.OCALLMETH { + assert(call.X.Op() == ir.ODOTMETH) + args.Append(call.X.(*ir.SelectorExpr).X) + } + args.Append(call.Args...) + + // Create assignment to declare and initialize inlvars. + as2 := ir.NewAssignListStmt(call.Pos(), ir.OAS2, r.inlvars, args) + as2.Def = true + var as2init ir.Nodes + for _, name := range r.inlvars { + if ir.IsBlank(name) { + continue + } + // TODO(mdempsky): Use inlined position of name.Pos() instead? + name := name.(*ir.Name) + as2init.Append(ir.NewDecl(call.Pos(), ir.ODCL, name)) + name.Defn = as2 + } + as2.SetInit(as2init) + init.Append(typecheck.Stmt(as2)) + + if !r.delayResults { + // If not delaying retvars, declare and zero initialize the + // result variables now. + for _, name := range r.retvars { + // TODO(mdempsky): Use inlined position of name.Pos() instead? + name := name.(*ir.Name) + init.Append(ir.NewDecl(call.Pos(), ir.ODCL, name)) + ras := ir.NewAssignStmt(call.Pos(), name, nil) + init.Append(typecheck.Stmt(ras)) + } + } + + // Add an inline mark just before the inlined body. + // This mark is inline in the code so that it's a reasonable spot + // to put a breakpoint. Not sure if that's really necessary or not + // (in which case it could go at the end of the function instead). + // Note issue 28603. + init.Append(ir.NewInlineMarkStmt(call.Pos().WithIsStmt(), int64(r.inlTreeIndex))) + + nparams := len(r.curfn.Dcl) + + oldcurfn := ir.CurFunc + ir.CurFunc = r.curfn + + r.curfn.Body = r.stmts() + r.curfn.Endlineno = r.pos() + + typecheck.Stmts(r.curfn.Body) + deadcode.Func(r.curfn) + + // Replace any "return" statements within the function body. + { + var edit func(ir.Node) ir.Node + edit = func(n ir.Node) ir.Node { + if ret, ok := n.(*ir.ReturnStmt); ok { + n = typecheck.Stmt(r.inlReturn(ret)) + } + ir.EditChildren(n, edit) + return n + } + edit(r.curfn) + } + + ir.CurFunc = oldcurfn + + body := ir.Nodes(r.curfn.Body) + + // Quirk: If deadcode elimination turned a non-empty function into + // an empty one, we need to set the position for the empty block + // left behind to the the inlined position for src.NoXPos, so that + // an empty string gets added into the DWARF file name listing at + // the appropriate index. + if quirksMode() && len(body) == 1 { + if block, ok := body[0].(*ir.BlockStmt); ok && len(block.List) == 0 { + block.SetPos(r.updatePos(src.NoXPos)) + } + } + + // Quirkish: We need to eagerly prune variables added during + // inlining, but removed by deadcode.FuncBody above. Unused + // variables will get removed during stack frame layout anyway, but + // len(fn.Dcl) ends up influencing things like autotmp naming. + + used := usedLocals(body) + + for i, name := range r.curfn.Dcl { + if i < nparams || used.Has(name) { + name.Curfn = callerfn + callerfn.Dcl = append(callerfn.Dcl, name) + + // Quirkish. TODO(mdempsky): Document why. + if name.AutoTemp() { + name.SetEsc(ir.EscUnknown) + + if base.Flag.GenDwarfInl != 0 { + name.SetInlLocal(true) + } else { + name.SetPos(r.inlCall.Pos()) + } + } + } + } + + body.Append(ir.NewLabelStmt(call.Pos(), r.retlabel)) + + res := ir.NewInlinedCallExpr(call.Pos(), body, append([]ir.Node(nil), r.retvars...)) + res.SetInit(init) + res.SetType(call.Type()) + res.SetTypecheck(1) + + // Inlining shouldn't add any functions to todoBodies. + assert(len(todoBodies) == 0) + + return res +} + +// inlReturn returns a statement that can substitute for the given +// return statement when inlining. +func (r *reader) inlReturn(ret *ir.ReturnStmt) *ir.BlockStmt { + pos := r.inlCall.Pos() + + block := ir.TakeInit(ret) + + if results := ret.Results; len(results) != 0 { + assert(len(r.retvars) == len(results)) + + as2 := ir.NewAssignListStmt(pos, ir.OAS2, append([]ir.Node(nil), r.retvars...), ret.Results) + + if r.delayResults { + for _, name := range r.retvars { + // TODO(mdempsky): Use inlined position of name.Pos() instead? + name := name.(*ir.Name) + block.Append(ir.NewDecl(pos, ir.ODCL, name)) + name.Defn = as2 + } + } + + block.Append(as2) + } + + block.Append(ir.NewBranchStmt(pos, ir.OGOTO, r.retlabel)) + return ir.NewBlockStmt(pos, block) +} + +// expandInline reads in an extra copy of IR to populate +// fn.Inl.{Dcl,Body}. +func expandInline(fn *ir.Func, pri pkgReaderIndex) { + // TODO(mdempsky): Remove this function. It's currently needed for + // dwarfgen for some reason, but we should be able to provide it + // with the same information some other way. + + fndcls := len(fn.Dcl) + topdcls := len(typecheck.Target.Decls) + + tmpfn := ir.NewFunc(fn.Pos()) + tmpfn.Nname = ir.NewNameAt(fn.Nname.Pos(), fn.Sym()) + tmpfn.ClosureVars = fn.ClosureVars + + { + r := pri.asReader(relocBody, syncFuncBody) + r.setType(tmpfn.Nname, fn.Type()) + + // Don't change parameter's Sym/Nname fields. + r.funarghack = true + + r.funcBody(tmpfn) + } + + oldcurfn := ir.CurFunc + ir.CurFunc = tmpfn + + typecheck.Stmts(tmpfn.Body) + deadcode.Func(tmpfn) + + ir.CurFunc = oldcurfn + + used := usedLocals(tmpfn.Body) + + for _, name := range tmpfn.Dcl { + if name.Class != ir.PAUTO || used.Has(name) { + name.Curfn = fn + fn.Inl.Dcl = append(fn.Inl.Dcl, name) + } + } + fn.Inl.Body = tmpfn.Body + + // Double check that we didn't change fn.Dcl by accident. + assert(fndcls == len(fn.Dcl)) + + // typecheck.Stmts may have added function literals to + // typecheck.Target.Decls. Remove them again so we don't risk trying + // to compile them multiple times. + typecheck.Target.Decls = typecheck.Target.Decls[:topdcls] +} + +// usedLocals returns a set of local variables that are used within body. +func usedLocals(body []ir.Node) ir.NameSet { + var used ir.NameSet + ir.VisitList(body, func(n ir.Node) { + if n, ok := n.(*ir.Name); ok && n.Op() == ir.ONAME && n.Class == ir.PAUTO { + used.Add(n) + } + }) + return used +} diff --git a/src/cmd/compile/internal/noder/reader2.go b/src/cmd/compile/internal/noder/reader2.go new file mode 100644 index 00000000000..174bd3f5bdb --- /dev/null +++ b/src/cmd/compile/internal/noder/reader2.go @@ -0,0 +1,463 @@ +// UNREVIEWED + +// Copyright 2021 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 noder + +import ( + "go/constant" + + "cmd/compile/internal/base" + "cmd/compile/internal/syntax" + "cmd/compile/internal/types2" + "cmd/internal/src" +) + +type pkgReader2 struct { + pkgDecoder + + check *types2.Checker + imports map[string]*types2.Package + + posBases []*syntax.PosBase + pkgs []*types2.Package + typs []types2.Type +} + +func readPackage2(check *types2.Checker, imports map[string]*types2.Package, input pkgDecoder) *types2.Package { + pr := pkgReader2{ + pkgDecoder: input, + + check: check, + imports: imports, + + posBases: make([]*syntax.PosBase, input.numElems(relocPosBase)), + pkgs: make([]*types2.Package, input.numElems(relocPkg)), + typs: make([]types2.Type, input.numElems(relocType)), + } + + r := pr.newReader(relocMeta, publicRootIdx, syncPublic) + pkg := r.pkg() + r.bool() // has init + + for i, n := 0, r.len(); i < n; i++ { + r.obj() + } + + r.sync(syncEOF) + + pkg.MarkComplete() + return pkg +} + +type reader2 struct { + decoder + + p *pkgReader2 + + tparams []*types2.TypeName +} + +func (pr *pkgReader2) newReader(k reloc, idx int, marker syncMarker) *reader2 { + return &reader2{ + decoder: pr.newDecoder(k, idx, marker), + p: pr, + } +} + +// @@@ Positions + +func (r *reader2) pos() syntax.Pos { + r.sync(syncPos) + if !r.bool() { + return syntax.Pos{} + } + + // TODO(mdempsky): Delta encoding. + posBase := r.posBase() + line := r.uint() + col := r.uint() + return syntax.MakePos(posBase, line, col) +} + +func (r *reader2) posBase() *syntax.PosBase { + return r.p.posBaseIdx(r.reloc(relocPosBase)) +} + +func (pr *pkgReader2) posBaseIdx(idx int) *syntax.PosBase { + if b := pr.posBases[idx]; b != nil { + return b + } + + r := pr.newReader(relocPosBase, idx, syncPosBase) + var b *syntax.PosBase + + filename := r.string() + _ = r.string() // absolute file name + + if r.bool() { + b = syntax.NewFileBase(filename) + } else { + pos := r.pos() + line := r.uint() + col := r.uint() + b = syntax.NewLineBase(pos, filename, line, col) + } + + pr.posBases[idx] = b + return b +} + +// @@@ Packages + +func (r *reader2) pkg() *types2.Package { + r.sync(syncPkg) + return r.p.pkgIdx(r.reloc(relocPkg)) +} + +func (pr *pkgReader2) pkgIdx(idx int) *types2.Package { + // TODO(mdempsky): Consider using some non-nil pointer to indicate + // the universe scope, so we don't need to keep re-reading it. + if pkg := pr.pkgs[idx]; pkg != nil { + return pkg + } + + pkg := pr.newReader(relocPkg, idx, syncPkgDef).doPkg() + pr.pkgs[idx] = pkg + return pkg +} + +func (r *reader2) doPkg() *types2.Package { + path := r.string() + if path == "builtin" { + return nil // universe + } + if path == "" { + path = r.p.pkgPath + } + + if pkg := r.p.imports[path]; pkg != nil { + return pkg + } + + name := r.string() + height := r.len() + + pkg := types2.NewPackageHeight(path, name, height) + r.p.imports[path] = pkg + + // TODO(mdempsky): The list of imported packages is important for + // go/types, but we could probably skip populating it for types2. + imports := make([]*types2.Package, r.len()) + for i := range imports { + imports[i] = r.pkg() + } + pkg.SetImports(imports) + + return pkg +} + +// @@@ Types + +func (r *reader2) typ() types2.Type { + r.sync(syncType) + return r.p.typIdx(r.reloc(relocType), r.tparams) +} + +func (pr *pkgReader2) typIdx(idx int, tparams []*types2.TypeName) types2.Type { + if typ := pr.typs[idx]; typ != nil { + return typ + } + + r := pr.newReader(relocType, idx, syncTypeIdx) + r.tparams = tparams + typ := r.doTyp() + assert(typ != nil) + + if pr.typs[idx] != nil { + // See comment in pkgReader.typIdx. + return pr.typs[idx] + } + + if len(tparams) == 0 { + pr.typs[idx] = typ + } + + return typ +} + +func (r *reader2) doTyp() (res types2.Type) { + switch tag := codeType(r.code(syncType)); tag { + default: + base.FatalfAt(src.NoXPos, "unhandled type tag: %v", tag) + panic("unreachable") + + case typeBasic: + return types2.Typ[r.len()] + + case typeNamed: + obj, targs := r.obj() + name := obj.(*types2.TypeName) + if len(targs) != 0 { + return r.p.check.InstantiateLazy(syntax.Pos{}, name.Type(), targs) + } + return name.Type() + + case typeTypeParam: + idx := r.len() + return r.tparams[idx].Type().(*types2.TypeParam) + + case typeArray: + len := int64(r.uint64()) + return types2.NewArray(r.typ(), len) + case typeChan: + dir := types2.ChanDir(r.len()) + return types2.NewChan(dir, r.typ()) + case typeMap: + return types2.NewMap(r.typ(), r.typ()) + case typePointer: + return types2.NewPointer(r.typ()) + case typeSignature: + return r.signature(nil) + case typeSlice: + return types2.NewSlice(r.typ()) + case typeStruct: + return r.structType() + case typeInterface: + return r.interfaceType() + case typeUnion: + return r.unionType() + } +} + +func (r *reader2) structType() *types2.Struct { + fields := make([]*types2.Var, r.len()) + var tags []string + for i := range fields { + pos := r.pos() + pkg, name := r.selector() + ftyp := r.typ() + tag := r.string() + embedded := r.bool() + + fields[i] = types2.NewField(pos, pkg, name, ftyp, embedded) + if tag != "" { + for len(tags) < i { + tags = append(tags, "") + } + tags = append(tags, tag) + } + } + return types2.NewStruct(fields, tags) +} + +func (r *reader2) unionType() *types2.Union { + terms := make([]types2.Type, r.len()) + tildes := make([]bool, len(terms)) + for i := range terms { + terms[i] = r.typ() + tildes[i] = r.bool() + } + return types2.NewUnion(terms, tildes) +} + +func (r *reader2) interfaceType() *types2.Interface { + methods := make([]*types2.Func, r.len()) + embeddeds := make([]types2.Type, r.len()) + + for i := range methods { + pos := r.pos() + pkg, name := r.selector() + mtyp := r.signature(nil) + methods[i] = types2.NewFunc(pos, pkg, name, mtyp) + } + + for i := range embeddeds { + embeddeds[i] = r.typ() + } + + typ := types2.NewInterfaceType(methods, embeddeds) + typ.Complete() + return typ +} + +func (r *reader2) signature(recv *types2.Var) *types2.Signature { + r.sync(syncSignature) + + params := r.params() + results := r.params() + variadic := r.bool() + + return types2.NewSignature(recv, params, results, variadic) +} + +func (r *reader2) params() *types2.Tuple { + r.sync(syncParams) + params := make([]*types2.Var, r.len()) + for i := range params { + params[i] = r.param() + } + return types2.NewTuple(params...) +} + +func (r *reader2) param() *types2.Var { + r.sync(syncParam) + + pos := r.pos() + pkg, name := r.localIdent() + typ := r.typ() + + return types2.NewParam(pos, pkg, name, typ) +} + +// @@@ Objects + +func (r *reader2) obj() (types2.Object, []types2.Type) { + r.sync(syncObject) + + pkg, name := r.p.objIdx(r.reloc(relocObj)) + obj := pkg.Scope().Lookup(name) + + targs := make([]types2.Type, r.len()) + for i := range targs { + targs[i] = r.typ() + } + + return obj, targs +} + +func (pr *pkgReader2) objIdx(idx int) (*types2.Package, string) { + r := pr.newReader(relocObj, idx, syncObject1) + objPkg, objName := r.qualifiedIdent() + assert(objName != "") + + bounds := r.typeParamBounds() + tag := codeObj(r.code(syncCodeObj)) + + if tag == objStub { + assert(objPkg == nil) + return objPkg, objName + } + + objPkg.Scope().InsertLazy(objName, func() types2.Object { + switch tag { + default: + panic("weird") + + case objAlias: + pos := r.pos() + typ := r.typ() + return types2.NewTypeName(pos, objPkg, objName, typ) + + case objConst: + pos := r.pos() + typ, val := r.value() + return types2.NewConst(pos, objPkg, objName, typ, val) + + case objFunc: + pos := r.pos() + r.typeParamNames(bounds) + sig := r.signature(nil) + if len(r.tparams) != 0 { + sig.SetTParams(r.tparams) + } + return types2.NewFunc(pos, objPkg, objName, sig) + + case objType: + pos := r.pos() + + return types2.NewTypeNameLazy(pos, objPkg, objName, func(named *types2.Named) (tparams []*types2.TypeName, underlying types2.Type, methods []*types2.Func) { + r.typeParamNames(bounds) + if len(r.tparams) != 0 { + tparams = r.tparams + } + + // TODO(mdempsky): Rewrite receiver types to underlying is an + // Interface? The go/types importer does this (I think because + // unit tests expected that), but cmd/compile doesn't care + // about it, so maybe we can avoid worrying about that here. + underlying = r.typ().Underlying() + + methods = make([]*types2.Func, r.len()) + for i := range methods { + methods[i] = r.method(bounds) + } + + return + }) + + case objVar: + pos := r.pos() + typ := r.typ() + return types2.NewVar(pos, objPkg, objName, typ) + } + }) + + return objPkg, objName +} + +func (r *reader2) value() (types2.Type, constant.Value) { + r.sync(syncValue) + return r.typ(), r.rawValue() +} + +func (r *reader2) typeParamBounds() []int { + r.sync(syncTypeParamBounds) + + // exported types never have implicit type parameters + // TODO(mdempsky): Hide this from public importer. + assert(r.len() == 0) + + bounds := make([]int, r.len()) + for i := range bounds { + r.sync(syncType) + bounds[i] = r.reloc(relocType) + } + return bounds +} + +func (r *reader2) typeParamNames(bounds []int) { + r.sync(syncTypeParamNames) + + r.tparams = make([]*types2.TypeName, len(bounds)) + + for i := range r.tparams { + pos := r.pos() + pkg, name := r.localIdent() + + obj := types2.NewTypeName(pos, pkg, name, nil) + r.p.check.NewTypeParam(obj, i, nil) + r.tparams[i] = obj + } + + for i, tparam := range r.tparams { + bound := r.p.typIdx(bounds[i], r.tparams) + tparam.Type().(*types2.TypeParam).SetBound(bound) + } +} + +func (r *reader2) method(bounds []int) *types2.Func { + r.sync(syncMethod) + pos := r.pos() + pkg, name := r.selector() + + r.typeParamNames(bounds) + sig := r.signature(r.param()) + if len(r.tparams) != 0 { + sig.SetRParams(r.tparams) + } + + _ = r.pos() // TODO(mdempsky): Remove; this is a hacker for linker.go. + return types2.NewFunc(pos, pkg, name, sig) +} + +func (r *reader2) qualifiedIdent() (*types2.Package, string) { return r.ident(syncSym) } +func (r *reader2) localIdent() (*types2.Package, string) { return r.ident(syncLocalIdent) } +func (r *reader2) selector() (*types2.Package, string) { return r.ident(syncSelector) } + +func (r *reader2) ident(marker syncMarker) (*types2.Package, string) { + r.sync(marker) + return r.pkg(), r.string() +} diff --git a/src/cmd/compile/internal/noder/reloc.go b/src/cmd/compile/internal/noder/reloc.go new file mode 100644 index 00000000000..961de494199 --- /dev/null +++ b/src/cmd/compile/internal/noder/reloc.go @@ -0,0 +1,40 @@ +// UNREVIEWED + +// Copyright 2021 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 noder + +// A reloc indicates a particular section within a unified IR export. +// +// TODO(mdempsky): Rename to "section" or something similar? +type reloc int + +// A relocEnt (relocation entry) is an entry in an atom's local +// reference table. +// +// TODO(mdempsky): Rename this too. +type relocEnt struct { + kind reloc + idx int +} + +// Reserved indices within the meta relocation section. +const ( + publicRootIdx = 0 + privateRootIdx = 1 +) + +const ( + relocString reloc = iota + relocMeta + relocPosBase + relocPkg + relocType + relocObj + relocObjExt + relocBody + + numRelocs = iota +) diff --git a/src/cmd/compile/internal/noder/sync.go b/src/cmd/compile/internal/noder/sync.go new file mode 100644 index 00000000000..d77a7844798 --- /dev/null +++ b/src/cmd/compile/internal/noder/sync.go @@ -0,0 +1,154 @@ +// UNREVIEWED + +// Copyright 2021 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 noder + +const debug = true + +type syncMarker int + +//go:generate stringer -type=syncMarker -trimprefix=sync + +// TODO(mdempsky): Cleanup unneeded sync markers. + +// TODO(mdempsky): Split these markers into public/stable markers, and +// private ones. Also, trim unused ones. +const ( + _ syncMarker = iota + syncNode + syncBool + syncInt64 + syncUint64 + syncString + syncPos + syncPkg + syncSym + syncSelector + syncKind + syncType + syncTypePkg + syncSignature + syncParam + syncOp + syncObject + syncExpr + syncStmt + syncDecl + syncConstDecl + syncFuncDecl + syncTypeDecl + syncVarDecl + syncPragma + syncValue + syncEOF + syncMethod + syncFuncBody + syncUse + syncUseObj + syncObjectIdx + syncTypeIdx + syncBOF + syncEntry + syncOpenScope + syncCloseScope + syncGlobal + syncLocal + syncDefine + syncDefLocal + syncUseLocal + syncDefGlobal + syncUseGlobal + syncTypeParams + syncUseLabel + syncDefLabel + syncFuncLit + syncCommonFunc + syncBodyRef + syncLinksymExt + syncHack + syncSetlineno + syncName + syncImportDecl + syncDeclNames + syncDeclName + syncExprList + syncExprs + syncWrapname + syncTypeExpr + syncTypeExprOrNil + syncChanDir + syncParams + syncCloseAnotherScope + syncSum + syncUnOp + syncBinOp + syncStructType + syncInterfaceType + syncPackname + syncEmbedded + syncStmts + syncStmtsFall + syncStmtFall + syncBlockStmt + syncIfStmt + syncForStmt + syncSwitchStmt + syncRangeStmt + syncCaseClause + syncCommClause + syncSelectStmt + syncDecls + syncLabeledStmt + syncCompLit + + sync1 + sync2 + sync3 + sync4 + + syncN + syncDefImplicit + syncUseName + syncUseObjLocal + syncAddLocal + syncBothSignature + syncSetUnderlying + syncLinkname + syncStmt1 + syncStmtsEnd + syncDeclare + syncTopDecls + syncTopConstDecl + syncTopFuncDecl + syncTopTypeDecl + syncTopVarDecl + syncObject1 + syncAddBody + syncLabel + syncFuncExt + syncMethExt + syncOptLabel + syncScalar + syncStmtDecls + syncDeclLocal + syncObjLocal + syncObjLocal1 + syncDeclareLocal + syncPublic + syncPrivate + syncRelocs + syncReloc + syncUseReloc + syncVarExt + syncPkgDef + syncTypeExt + syncVal + syncCodeObj + syncPosBase + syncLocalIdent + syncTypeParamNames + syncTypeParamBounds +) diff --git a/src/cmd/compile/internal/noder/syncmarker_string.go b/src/cmd/compile/internal/noder/syncmarker_string.go new file mode 100644 index 00000000000..3eb88fb9118 --- /dev/null +++ b/src/cmd/compile/internal/noder/syncmarker_string.go @@ -0,0 +1,152 @@ +// Code generated by "stringer -type=syncMarker -trimprefix=sync"; DO NOT EDIT. + +package noder + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[syncNode-1] + _ = x[syncBool-2] + _ = x[syncInt64-3] + _ = x[syncUint64-4] + _ = x[syncString-5] + _ = x[syncPos-6] + _ = x[syncPkg-7] + _ = x[syncSym-8] + _ = x[syncSelector-9] + _ = x[syncKind-10] + _ = x[syncType-11] + _ = x[syncTypePkg-12] + _ = x[syncSignature-13] + _ = x[syncParam-14] + _ = x[syncOp-15] + _ = x[syncObject-16] + _ = x[syncExpr-17] + _ = x[syncStmt-18] + _ = x[syncDecl-19] + _ = x[syncConstDecl-20] + _ = x[syncFuncDecl-21] + _ = x[syncTypeDecl-22] + _ = x[syncVarDecl-23] + _ = x[syncPragma-24] + _ = x[syncValue-25] + _ = x[syncEOF-26] + _ = x[syncMethod-27] + _ = x[syncFuncBody-28] + _ = x[syncUse-29] + _ = x[syncUseObj-30] + _ = x[syncObjectIdx-31] + _ = x[syncTypeIdx-32] + _ = x[syncBOF-33] + _ = x[syncEntry-34] + _ = x[syncOpenScope-35] + _ = x[syncCloseScope-36] + _ = x[syncGlobal-37] + _ = x[syncLocal-38] + _ = x[syncDefine-39] + _ = x[syncDefLocal-40] + _ = x[syncUseLocal-41] + _ = x[syncDefGlobal-42] + _ = x[syncUseGlobal-43] + _ = x[syncTypeParams-44] + _ = x[syncUseLabel-45] + _ = x[syncDefLabel-46] + _ = x[syncFuncLit-47] + _ = x[syncCommonFunc-48] + _ = x[syncBodyRef-49] + _ = x[syncLinksymExt-50] + _ = x[syncHack-51] + _ = x[syncSetlineno-52] + _ = x[syncName-53] + _ = x[syncImportDecl-54] + _ = x[syncDeclNames-55] + _ = x[syncDeclName-56] + _ = x[syncExprList-57] + _ = x[syncExprs-58] + _ = x[syncWrapname-59] + _ = x[syncTypeExpr-60] + _ = x[syncTypeExprOrNil-61] + _ = x[syncChanDir-62] + _ = x[syncParams-63] + _ = x[syncCloseAnotherScope-64] + _ = x[syncSum-65] + _ = x[syncUnOp-66] + _ = x[syncBinOp-67] + _ = x[syncStructType-68] + _ = x[syncInterfaceType-69] + _ = x[syncPackname-70] + _ = x[syncEmbedded-71] + _ = x[syncStmts-72] + _ = x[syncStmtsFall-73] + _ = x[syncStmtFall-74] + _ = x[syncBlockStmt-75] + _ = x[syncIfStmt-76] + _ = x[syncForStmt-77] + _ = x[syncSwitchStmt-78] + _ = x[syncRangeStmt-79] + _ = x[syncCaseClause-80] + _ = x[syncCommClause-81] + _ = x[syncSelectStmt-82] + _ = x[syncDecls-83] + _ = x[syncLabeledStmt-84] + _ = x[syncCompLit-85] + _ = x[sync1-86] + _ = x[sync2-87] + _ = x[sync3-88] + _ = x[sync4-89] + _ = x[syncN-90] + _ = x[syncDefImplicit-91] + _ = x[syncUseName-92] + _ = x[syncUseObjLocal-93] + _ = x[syncAddLocal-94] + _ = x[syncBothSignature-95] + _ = x[syncSetUnderlying-96] + _ = x[syncLinkname-97] + _ = x[syncStmt1-98] + _ = x[syncStmtsEnd-99] + _ = x[syncDeclare-100] + _ = x[syncTopDecls-101] + _ = x[syncTopConstDecl-102] + _ = x[syncTopFuncDecl-103] + _ = x[syncTopTypeDecl-104] + _ = x[syncTopVarDecl-105] + _ = x[syncObject1-106] + _ = x[syncAddBody-107] + _ = x[syncLabel-108] + _ = x[syncFuncExt-109] + _ = x[syncMethExt-110] + _ = x[syncOptLabel-111] + _ = x[syncScalar-112] + _ = x[syncStmtDecls-113] + _ = x[syncDeclLocal-114] + _ = x[syncObjLocal-115] + _ = x[syncObjLocal1-116] + _ = x[syncDeclareLocal-117] + _ = x[syncPublic-118] + _ = x[syncPrivate-119] + _ = x[syncRelocs-120] + _ = x[syncReloc-121] + _ = x[syncUseReloc-122] + _ = x[syncVarExt-123] + _ = x[syncPkgDef-124] + _ = x[syncTypeExt-125] + _ = x[syncVal-126] + _ = x[syncCodeObj-127] + _ = x[syncPosBase-128] + _ = x[syncLocalIdent-129] +} + +const _syncMarker_name = "NodeBoolInt64Uint64StringPosPkgSymSelectorKindTypeTypePkgSignatureParamOpObjectExprStmtDeclConstDeclFuncDeclTypeDeclVarDeclPragmaValueEOFMethodFuncBodyUseUseObjObjectIdxTypeIdxBOFEntryOpenScopeCloseScopeGlobalLocalDefineDefLocalUseLocalDefGlobalUseGlobalTypeParamsUseLabelDefLabelFuncLitCommonFuncBodyRefLinksymExtHackSetlinenoNameImportDeclDeclNamesDeclNameExprListExprsWrapnameTypeExprTypeExprOrNilChanDirParamsCloseAnotherScopeSumUnOpBinOpStructTypeInterfaceTypePacknameEmbeddedStmtsStmtsFallStmtFallBlockStmtIfStmtForStmtSwitchStmtRangeStmtCaseClauseCommClauseSelectStmtDeclsLabeledStmtCompLit1234NDefImplicitUseNameUseObjLocalAddLocalBothSignatureSetUnderlyingLinknameStmt1StmtsEndDeclareTopDeclsTopConstDeclTopFuncDeclTopTypeDeclTopVarDeclObject1AddBodyLabelFuncExtMethExtOptLabelScalarStmtDeclsDeclLocalObjLocalObjLocal1DeclareLocalPublicPrivateRelocsRelocUseRelocVarExtPkgDefTypeExtValCodeObjPosBaseLocalIdent" + +var _syncMarker_index = [...]uint16{0, 4, 8, 13, 19, 25, 28, 31, 34, 42, 46, 50, 57, 66, 71, 73, 79, 83, 87, 91, 100, 108, 116, 123, 129, 134, 137, 143, 151, 154, 160, 169, 176, 179, 184, 193, 203, 209, 214, 220, 228, 236, 245, 254, 264, 272, 280, 287, 297, 304, 314, 318, 327, 331, 341, 350, 358, 366, 371, 379, 387, 400, 407, 413, 430, 433, 437, 442, 452, 465, 473, 481, 486, 495, 503, 512, 518, 525, 535, 544, 554, 564, 574, 579, 590, 597, 598, 599, 600, 601, 602, 613, 620, 631, 639, 652, 665, 673, 678, 686, 693, 701, 713, 724, 735, 745, 752, 759, 764, 771, 778, 786, 792, 801, 810, 818, 827, 839, 845, 852, 858, 863, 871, 877, 883, 890, 893, 900, 907, 917} + +func (i syncMarker) String() string { + i -= 1 + if i < 0 || i >= syncMarker(len(_syncMarker_index)-1) { + return "syncMarker(" + strconv.FormatInt(int64(i+1), 10) + ")" + } + return _syncMarker_name[_syncMarker_index[i]:_syncMarker_index[i+1]] +} diff --git a/src/cmd/compile/internal/noder/unified.go b/src/cmd/compile/internal/noder/unified.go new file mode 100644 index 00000000000..9a41ea9dfe4 --- /dev/null +++ b/src/cmd/compile/internal/noder/unified.go @@ -0,0 +1,276 @@ +// UNREVIEWED + +// Copyright 2021 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 noder + +import ( + "bytes" + "fmt" + "internal/goversion" + "io" + "runtime" + "sort" + + "cmd/compile/internal/base" + "cmd/compile/internal/inline" + "cmd/compile/internal/ir" + "cmd/compile/internal/typecheck" + "cmd/compile/internal/types" + "cmd/compile/internal/types2" + "cmd/internal/src" +) + +// localPkgReader holds the package reader used for reading the local +// package. It exists so the unified IR linker can refer back to it +// later. +var localPkgReader *pkgReader + +// useUnifiedIR reports whether the unified IR frontend should be +// used; and if so, uses it to construct the local package's IR. +func useUnifiedIR(noders []*noder) { + inline.NewInline = InlineCall + + if !quirksMode() { + writeNewExportFunc = writeNewExport + } + + newReadImportFunc = func(data string, pkg1 *types.Pkg, check *types2.Checker, packages map[string]*types2.Package) (pkg2 *types2.Package, err error) { + pr := newPkgDecoder(pkg1.Path, data) + + // Read package descriptors for both types2 and compiler backend. + readPackage(newPkgReader(pr), pkg1) + pkg2 = readPackage2(check, packages, pr) + return + } + + data := writePkgStub(noders) + + // We already passed base.Flag.Lang to types2 to handle validating + // the user's source code. Bump it up now to the current version and + // re-parse, so typecheck doesn't complain if we construct IR that + // utilizes newer Go features. + base.Flag.Lang = fmt.Sprintf("go1.%d", goversion.Version) + types.ParseLangFlag() + + assert(types.LocalPkg.Path == "") + types.LocalPkg.Height = 0 // reset so pkgReader.pkgIdx doesn't complain + target := typecheck.Target + + typecheck.TypecheckAllowed = true + + localPkgReader = newPkgReader(newPkgDecoder(types.LocalPkg.Path, data)) + readPackage(localPkgReader, types.LocalPkg) + + r := localPkgReader.newReader(relocMeta, privateRootIdx, syncPrivate) + r.ext = r + r.pkgInit(types.LocalPkg, target) + + // Don't use range--bodyIdx can add closures to todoBodies. + for len(todoBodies) > 0 { + // The order we expand bodies doesn't matter, so pop from the end + // to reduce todoBodies reallocations if it grows further. + fn := todoBodies[len(todoBodies)-1] + todoBodies = todoBodies[:len(todoBodies)-1] + + pri, ok := bodyReader[fn] + assert(ok) + pri.funcBody(fn) + + // Instantiated generic function: add to Decls for typechecking + // and compilation. + if len(pri.implicits) != 0 && fn.OClosure == nil { + target.Decls = append(target.Decls, fn) + } + } + todoBodies = nil + + // Don't use range--typecheck can add closures to Target.Decls. + for i := 0; i < len(target.Decls); i++ { + target.Decls[i] = typecheck.Stmt(target.Decls[i]) + } + + // Don't use range--typecheck can add closures to Target.Decls. + for i := 0; i < len(target.Decls); i++ { + if fn, ok := target.Decls[i].(*ir.Func); ok { + if base.Flag.W > 1 { + s := fmt.Sprintf("\nbefore typecheck %v", fn) + ir.Dump(s, fn) + } + ir.CurFunc = fn + typecheck.Stmts(fn.Body) + if base.Flag.W > 1 { + s := fmt.Sprintf("\nafter typecheck %v", fn) + ir.Dump(s, fn) + } + } + } + + base.ExitIfErrors() // just in case +} + +// writePkgStub type checks the given parsed source files and then +// returns +func writePkgStub(noders []*noder) string { + m, pkg, info := checkFiles(noders) + + pw := newPkgWriter(m, pkg, info) + + pw.collectDecls(noders) + + publicRootWriter := pw.newWriter(relocMeta, syncPublic) + privateRootWriter := pw.newWriter(relocMeta, syncPrivate) + + assert(publicRootWriter.idx == publicRootIdx) + assert(privateRootWriter.idx == privateRootIdx) + + { + w := publicRootWriter + w.pkg(pkg) + w.bool(false) // has init; XXX + + scope := pkg.Scope() + names := scope.Names() + w.len(len(names)) + for _, name := range scope.Names() { + w.obj(scope.Lookup(name), nil) + } + + w.sync(syncEOF) + w.flush() + } + + { + w := privateRootWriter + w.ext = w + w.pkgInit(noders) + w.flush() + } + + var sb bytes.Buffer // TODO(mdempsky): strings.Builder after #44505 is resolved + pw.dump(&sb) + + // At this point, we're done with types2. Make sure the package is + // garbage collected. + freePackage(pkg) + + return sb.String() +} + +// freePackage ensures the given package is garbage collected. +func freePackage(pkg *types2.Package) { + // Set a finalizer on pkg so we can detect if/when it's collected. + done := make(chan struct{}) + runtime.SetFinalizer(pkg, func(*types2.Package) { close(done) }) + + // Important: objects involved in cycles are not finalized, so zero + // out pkg to break its cycles and allow the finalizer to run. + *pkg = types2.Package{} + + // It typically takes just 1 or 2 cycles to release pkg, but it + // doesn't hurt to try a few more times. + for i := 0; i < 10; i++ { + select { + case <-done: + return + default: + runtime.GC() + } + } + + base.Fatalf("package never finalized") +} + +func readPackage(pr *pkgReader, importpkg *types.Pkg) { + r := pr.newReader(relocMeta, publicRootIdx, syncPublic) + + pkg := r.pkg() + assert(pkg == importpkg) + + if r.bool() { + sym := pkg.Lookup(".inittask") + task := ir.NewNameAt(src.NoXPos, sym) + task.Class = ir.PEXTERN + sym.Def = task + } + + for i, n := 0, r.len(); i < n; i++ { + r.sync(syncObject) + idx := r.reloc(relocObj) + assert(r.len() == 0) + + path, name, code, _ := r.p.peekObj(idx) + if code != objStub { + objReader[types.NewPkg(path, "").Lookup(name)] = pkgReaderIndex{pr, idx, nil} + } + } +} + +func writeNewExport(out io.Writer) { + l := linker{ + pw: newPkgEncoder(), + + pkgs: make(map[string]int), + decls: make(map[*types.Sym]int), + } + + publicRootWriter := l.pw.newEncoder(relocMeta, syncPublic) + assert(publicRootWriter.idx == publicRootIdx) + + var selfPkgIdx int + + { + pr := localPkgReader + r := pr.newDecoder(relocMeta, publicRootIdx, syncPublic) + + r.sync(syncPkg) + selfPkgIdx = l.relocIdx(pr, relocPkg, r.reloc(relocPkg)) + + r.bool() // has init + + for i, n := 0, r.len(); i < n; i++ { + r.sync(syncObject) + idx := r.reloc(relocObj) + assert(r.len() == 0) + + xpath, xname, xtag, _ := pr.peekObj(idx) + assert(xpath == pr.pkgPath) + assert(xtag != objStub) + + if types.IsExported(xname) { + l.relocIdx(pr, relocObj, idx) + } + } + + r.sync(syncEOF) + } + + { + var idxs []int + for _, idx := range l.decls { + idxs = append(idxs, idx) + } + sort.Ints(idxs) + + w := publicRootWriter + + w.sync(syncPkg) + w.reloc(relocPkg, selfPkgIdx) + + w.bool(typecheck.Lookup(".inittask").Def != nil) + + w.len(len(idxs)) + for _, idx := range idxs { + w.sync(syncObject) + w.reloc(relocObj, idx) + w.len(0) + } + + w.sync(syncEOF) + w.flush() + } + + l.pw.dump(out) +} diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go new file mode 100644 index 00000000000..b39dd8651b3 --- /dev/null +++ b/src/cmd/compile/internal/noder/writer.go @@ -0,0 +1,1746 @@ +// UNREVIEWED + +// Copyright 2021 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 noder + +import ( + "fmt" + "go/constant" + + "cmd/compile/internal/base" + "cmd/compile/internal/ir" + "cmd/compile/internal/syntax" + "cmd/compile/internal/types2" +) + +type pkgWriter struct { + pkgEncoder + + m posMap + curpkg *types2.Package + info *types2.Info + + posBasesIdx map[*syntax.PosBase]int + pkgsIdx map[*types2.Package]int + typsIdx map[types2.Type]int + globalsIdx map[types2.Object]int + + funDecls map[*types2.Func]*syntax.FuncDecl + typDecls map[*types2.TypeName]typeDeclGen + + linknames map[types2.Object]string + cgoPragmas [][]string + + dups dupTypes +} + +func newPkgWriter(m posMap, pkg *types2.Package, info *types2.Info) *pkgWriter { + return &pkgWriter{ + pkgEncoder: newPkgEncoder(), + + m: m, + curpkg: pkg, + info: info, + + pkgsIdx: make(map[*types2.Package]int), + globalsIdx: make(map[types2.Object]int), + typsIdx: make(map[types2.Type]int), + + posBasesIdx: make(map[*syntax.PosBase]int), + + funDecls: make(map[*types2.Func]*syntax.FuncDecl), + typDecls: make(map[*types2.TypeName]typeDeclGen), + + linknames: make(map[types2.Object]string), + } +} + +func (pw *pkgWriter) errorf(p poser, msg string, args ...interface{}) { + base.ErrorfAt(pw.m.pos(p), msg, args...) +} + +func (pw *pkgWriter) fatalf(p poser, msg string, args ...interface{}) { + base.FatalfAt(pw.m.pos(p), msg, args...) +} + +func (pw *pkgWriter) unexpected(what string, p poser) { + pw.fatalf(p, "unexpected %s: %v (%T)", what, p, p) +} + +type writer struct { + p *pkgWriter + + encoder + + // For writing out object descriptions, ext points to the extension + // writer for where we can write the compiler's private extension + // details for the object. + // + // TODO(mdempsky): This is a little hacky, but works easiest with + // the way things are currently. + ext *writer + + // TODO(mdempsky): We should be able to prune localsIdx whenever a + // scope closes, and then maybe we can just use the same map for + // storing the TypeParams too (as their TypeName instead). + + // type parameters. explicitIdx has the type parameters declared on + // the current object, while implicitIdx has the type parameters + // declared on the enclosing object (if any). + // + // TODO(mdempsky): Merge these back together, now that I've got them + // working. + implicitIdx map[*types2.TypeParam]int + explicitIdx map[*types2.TypeParam]int + + // variables declared within this function + localsIdx map[types2.Object]int +} + +func (pw *pkgWriter) newWriter(k reloc, marker syncMarker) *writer { + return &writer{ + encoder: pw.newEncoder(k, marker), + p: pw, + } +} + +// @@@ Positions + +func (w *writer) pos(p poser) { + w.sync(syncPos) + pos := p.Pos() + + // TODO(mdempsky): Track down the remaining cases here and fix them. + if !w.bool(pos.IsKnown()) { + return + } + + // TODO(mdempsky): Delta encoding. Also, if there's a b-side, update + // its position base too (but not vice versa!). + w.posBase(pos.Base()) + w.uint(pos.Line()) + w.uint(pos.Col()) +} + +func (w *writer) posBase(b *syntax.PosBase) { + w.reloc(relocPosBase, w.p.posBaseIdx(b)) +} + +func (pw *pkgWriter) posBaseIdx(b *syntax.PosBase) int { + if idx, ok := pw.posBasesIdx[b]; ok { + return idx + } + + w := pw.newWriter(relocPosBase, syncPosBase) + w.p.posBasesIdx[b] = w.idx + + // TODO(mdempsky): What exactly does "fileh" do anyway? Is writing + // out both of these strings really the right thing to do here? + fn := b.Filename() + w.string(fn) + w.string(fileh(fn)) + + if !w.bool(b.IsFileBase()) { + w.pos(b) + w.uint(b.Line()) + w.uint(b.Col()) + } + + return w.flush() +} + +// @@@ Packages + +func (w *writer) pkg(pkg *types2.Package) { + w.sync(syncPkg) + w.reloc(relocPkg, w.p.pkgIdx(pkg)) +} + +func (pw *pkgWriter) pkgIdx(pkg *types2.Package) int { + if idx, ok := pw.pkgsIdx[pkg]; ok { + return idx + } + + w := pw.newWriter(relocPkg, syncPkgDef) + pw.pkgsIdx[pkg] = w.idx + + if pkg == nil { + w.string("builtin") + } else { + var path string + if pkg != w.p.curpkg { + path = pkg.Path() + } + w.string(path) + w.string(pkg.Name()) + w.len(pkg.Height()) + + w.len(len(pkg.Imports())) + for _, imp := range pkg.Imports() { + w.pkg(imp) + } + } + + return w.flush() +} + +// @@@ Types + +func (w *writer) typ(typ types2.Type) { + w.sync(syncType) + + if quirksMode() { + typ = w.p.dups.orig(typ) + } + + w.reloc(relocType, w.p.typIdx(typ, w.implicitIdx, w.explicitIdx)) +} + +func (pw *pkgWriter) typIdx(typ types2.Type, implicitIdx, explicitIdx map[*types2.TypeParam]int) int { + if idx, ok := pw.typsIdx[typ]; ok { + return idx + } + + w := pw.newWriter(relocType, syncTypeIdx) + w.implicitIdx = implicitIdx + w.explicitIdx = explicitIdx + + pw.typsIdx[typ] = w.idx // handle cycles + w.doTyp(typ) + return w.flush() +} + +func (w *writer) doTyp(typ types2.Type) { + switch typ := typ.(type) { + default: + base.Fatalf("unexpected type: %v (%T)", typ, typ) + + case *types2.Basic: + if kind := typ.Kind(); types2.Typ[kind] == typ { + w.code(typeBasic) + w.len(int(kind)) + break + } + + // Handle "byte" and "rune" as references to their TypeName. + obj := types2.Universe.Lookup(typ.Name()) + assert(obj.Type() == typ) + + w.code(typeNamed) + w.obj(obj, nil) + + case *types2.Named: + // Type aliases can refer to uninstantiated generic types, so we + // might see len(TParams) != 0 && len(TArgs) == 0 here. + // TODO(mdempsky): Revisit after #46477 is resolved. + assert(len(typ.TParams()) == len(typ.TArgs()) || len(typ.TArgs()) == 0) + + // TODO(mdempsky): Why do we need to loop here? + orig := typ + for orig.TArgs() != nil { + orig = orig.Orig() + } + + w.code(typeNamed) + w.obj(orig.Obj(), typ.TArgs()) + + case *types2.TypeParam: + w.code(typeTypeParam) + if idx, ok := w.implicitIdx[typ]; ok { + w.len(idx) + } else if idx, ok := w.explicitIdx[typ]; ok { + w.len(len(w.implicitIdx) + idx) + } else { + w.p.fatalf(typ.Obj(), "%v not in %v or %v", typ, w.implicitIdx, w.explicitIdx) + } + + case *types2.Array: + w.code(typeArray) + w.uint64(uint64(typ.Len())) + w.typ(typ.Elem()) + + case *types2.Chan: + w.code(typeChan) + w.len(int(typ.Dir())) + w.typ(typ.Elem()) + + case *types2.Map: + w.code(typeMap) + w.typ(typ.Key()) + w.typ(typ.Elem()) + + case *types2.Pointer: + w.code(typePointer) + w.typ(typ.Elem()) + + case *types2.Signature: + assert(typ.TParams() == nil) + w.code(typeSignature) + w.signature(typ) + + case *types2.Slice: + w.code(typeSlice) + w.typ(typ.Elem()) + + case *types2.Struct: + w.code(typeStruct) + w.structType(typ) + + case *types2.Interface: + w.code(typeInterface) + w.interfaceType(typ) + + case *types2.Union: + w.code(typeUnion) + w.unionType(typ) + } +} + +func (w *writer) structType(typ *types2.Struct) { + w.len(typ.NumFields()) + for i := 0; i < typ.NumFields(); i++ { + f := typ.Field(i) + w.pos(f) + w.selector(f) + w.typ(f.Type()) + w.string(typ.Tag(i)) + w.bool(f.Embedded()) + } +} + +func (w *writer) unionType(typ *types2.Union) { + w.len(typ.NumTerms()) + for i := 0; i < typ.NumTerms(); i++ { + term, tilde := typ.Term(i) + w.typ(term) + w.bool(tilde) + } +} + +func (w *writer) interfaceType(typ *types2.Interface) { + w.len(typ.NumExplicitMethods()) + w.len(typ.NumEmbeddeds()) + + for i := 0; i < typ.NumExplicitMethods(); i++ { + m := typ.ExplicitMethod(i) + sig := m.Type().(*types2.Signature) + assert(sig.TParams() == nil) + + w.pos(m) + w.selector(m) + w.signature(sig) + } + + for i := 0; i < typ.NumEmbeddeds(); i++ { + w.typ(typ.EmbeddedType(i)) + } +} + +func (w *writer) signature(sig *types2.Signature) { + w.sync(syncSignature) + w.params(sig.Params()) + w.params(sig.Results()) + w.bool(sig.Variadic()) +} + +func (w *writer) params(typ *types2.Tuple) { + w.sync(syncParams) + w.len(typ.Len()) + for i := 0; i < typ.Len(); i++ { + w.param(typ.At(i)) + } +} + +func (w *writer) param(param *types2.Var) { + w.sync(syncParam) + w.pos(param) + w.localIdent(param) + w.typ(param.Type()) +} + +// @@@ Objects + +func (w *writer) obj(obj types2.Object, explicits []types2.Type) { + w.sync(syncObject) + + var implicitIdx map[*types2.TypeParam]int + if isDefinedType(obj) && !isGlobal(obj) { + implicitIdx = w.implicitIdx + } + w.reloc(relocObj, w.p.objIdx(obj, implicitIdx)) + + w.len(len(explicits)) + for _, explicit := range explicits { + w.typ(explicit) + } +} + +func (pw *pkgWriter) objIdx(obj types2.Object, implicitIdx map[*types2.TypeParam]int) int { + if idx, ok := pw.globalsIdx[obj]; ok { + return idx + } + + w := pw.newWriter(relocObj, syncObject1) + w.ext = pw.newWriter(relocObjExt, syncObject1) + assert(w.ext.idx == w.idx) + + pw.globalsIdx[obj] = w.idx + + w.implicitIdx = implicitIdx + w.ext.implicitIdx = implicitIdx + + w.doObj(obj) + + w.flush() + w.ext.flush() + + return w.idx +} + +func (w *writer) doObj(obj types2.Object) { + // Ident goes first so importer can avoid unnecessary work if + // they've already resolved this object. + w.qualifiedIdent(obj) + + tparams := objTypeParams(obj) + w.setTypeParams(tparams) + w.typeParamBounds(tparams) + + if obj.Pkg() != w.p.curpkg { + w.code(objStub) + return + } + + switch obj := obj.(type) { + default: + w.p.unexpected("object", obj) + + case *types2.Const: + w.code(objConst) + w.pos(obj) + w.value(obj.Type(), obj.Val()) + + case *types2.Func: + decl, ok := w.p.funDecls[obj] + assert(ok) + sig := obj.Type().(*types2.Signature) + + // Rewrite blank methods into blank functions. + // They aren't included in the receiver type's method set, + // and we still want to write them out to be compiled + // for regression tests. + // TODO(mdempsky): Change regress tests to avoid relying + // on blank functions/methods, so we can just ignore them + // altogether. + if recv := sig.Recv(); recv != nil { + assert(obj.Name() == "_") + assert(sig.TParams() == nil) + + params := make([]*types2.Var, 1+sig.Params().Len()) + params[0] = recv + for i := 0; i < sig.Params().Len(); i++ { + params[1+i] = sig.Params().At(i) + } + sig = types2.NewSignature(nil, types2.NewTuple(params...), sig.Results(), sig.Variadic()) + } + + w.code(objFunc) + w.pos(obj) + w.typeParamNames(sig.TParams()) + w.signature(sig) + w.pos(decl) + w.ext.funcExt(obj) + + case *types2.TypeName: + decl, ok := w.p.typDecls[obj] + assert(ok) + + if obj.IsAlias() { + w.code(objAlias) + w.pos(obj) + w.typ(obj.Type()) + break + } + + named := obj.Type().(*types2.Named) + assert(named.TArgs() == nil) + + w.code(objType) + w.pos(obj) + w.typeParamNames(named.TParams()) + w.ext.typeExt(obj) + w.typExpr(decl.Type) + + w.len(named.NumMethods()) + for i := 0; i < named.NumMethods(); i++ { + w.method(named.Method(i)) + } + + case *types2.Var: + w.code(objVar) + w.pos(obj) + w.typ(obj.Type()) + w.ext.varExt(obj) + } +} + +// typExpr writes the type represented by the given expression. +func (w *writer) typExpr(expr syntax.Expr) { + tv, ok := w.p.info.Types[expr] + assert(ok) + assert(tv.IsType()) + w.typ(tv.Type) +} + +func (w *writer) value(typ types2.Type, val constant.Value) { + w.sync(syncValue) + w.typ(typ) + w.rawValue(val) +} + +func (w *writer) setTypeParams(tparams []*types2.TypeName) { + if len(tparams) == 0 { + return + } + + explicitIdx := make(map[*types2.TypeParam]int) + for _, tparam := range tparams { + explicitIdx[tparam.Type().(*types2.TypeParam)] = len(explicitIdx) + } + + w.explicitIdx = explicitIdx + w.ext.explicitIdx = explicitIdx +} + +func (w *writer) typeParamBounds(tparams []*types2.TypeName) { + w.sync(syncTypeParamBounds) + + // TODO(mdempsky): Remove. It's useful for debugging at the moment, + // but it doesn't belong here. + w.len(len(w.implicitIdx)) + w.len(len(w.explicitIdx)) + assert(len(w.explicitIdx) == len(tparams)) + + for _, tparam := range tparams { + w.typ(tparam.Type().(*types2.TypeParam).Bound()) + } +} + +func (w *writer) typeParamNames(tparams []*types2.TypeName) { + w.sync(syncTypeParamNames) + + for _, tparam := range tparams { + w.pos(tparam) + w.localIdent(tparam) + } +} + +func (w *writer) method(meth *types2.Func) { + decl, ok := w.p.funDecls[meth] + assert(ok) + sig := meth.Type().(*types2.Signature) + + assert(len(w.explicitIdx) == len(sig.RParams())) + w.setTypeParams(sig.RParams()) + + w.sync(syncMethod) + w.pos(meth) + w.selector(meth) + w.typeParamNames(sig.RParams()) + w.param(sig.Recv()) + w.signature(sig) + + w.pos(decl) // XXX: Hack to workaround linker limitations. + w.ext.funcExt(meth) +} + +// qualifiedIdent writes out the name of an object declared at package +// scope. (For now, it's also used to refer to local defined types.) +func (w *writer) qualifiedIdent(obj types2.Object) { + w.sync(syncSym) + + name := obj.Name() + if isDefinedType(obj) && !isGlobal(obj) { + // TODO(mdempsky): Find a better solution, this is terrible. + decl, ok := w.p.typDecls[obj.(*types2.TypeName)] + assert(ok) + name = fmt.Sprintf("%s·%v", name, decl.gen) + } + + w.pkg(obj.Pkg()) + w.string(name) +} + +// TODO(mdempsky): We should be able to omit pkg from both localIdent +// and selector, because they should always be known from context. +// However, past frustrations with this optimization in iexport make +// me a little nervous to try it again. + +// localIdent writes the name of a locally declared object (i.e., +// objects that can only be accessed by name, within the context of a +// particular function). +func (w *writer) localIdent(obj types2.Object) { + assert(!isGlobal(obj)) + w.sync(syncLocalIdent) + w.pkg(obj.Pkg()) + w.string(obj.Name()) +} + +// selector writes the name of a field or method (i.e., objects that +// can only be accessed using selector expressions). +func (w *writer) selector(obj types2.Object) { + w.sync(syncSelector) + w.pkg(obj.Pkg()) + w.string(obj.Name()) +} + +// @@@ Compiler extensions + +func (w *writer) funcExt(obj *types2.Func) { + decl, ok := w.p.funDecls[obj] + assert(ok) + + // TODO(mdempsky): Extend these pragma validation flags to account + // for generics. E.g., linkname probably doesn't make sense at + // least. + + pragma := asPragmaFlag(decl.Pragma) + if pragma&ir.Systemstack != 0 && pragma&ir.Nosplit != 0 { + w.p.errorf(decl, "go:nosplit and go:systemstack cannot be combined") + } + + if decl.Body != nil { + if pragma&ir.Noescape != 0 { + w.p.errorf(decl, "can only use //go:noescape with external func implementations") + } + } else { + if base.Flag.Complete || decl.Name.Value == "init" { + // Linknamed functions are allowed to have no body. Hopefully + // the linkname target has a body. See issue 23311. + if _, ok := w.p.linknames[obj]; !ok { + w.p.errorf(decl, "missing function body") + } + } + } + + w.sync(syncFuncExt) + w.pragmaFlag(pragma) + w.linkname(obj) + w.bool(false) // stub extension + w.addBody(obj.Type().(*types2.Signature), decl.Body, make(map[types2.Object]int)) + w.sync(syncEOF) +} + +func (w *writer) typeExt(obj *types2.TypeName) { + decl, ok := w.p.typDecls[obj] + assert(ok) + + w.sync(syncTypeExt) + + w.pragmaFlag(asPragmaFlag(decl.Pragma)) + + // No LSym.SymIdx info yet. + w.int64(-1) + w.int64(-1) +} + +func (w *writer) varExt(obj *types2.Var) { + w.sync(syncVarExt) + w.linkname(obj) +} + +func (w *writer) linkname(obj types2.Object) { + w.sync(syncLinkname) + w.int64(-1) + w.string(w.p.linknames[obj]) +} + +func (w *writer) pragmaFlag(p ir.PragmaFlag) { + w.sync(syncPragma) + w.int(int(p)) +} + +// @@@ Function bodies + +func (w *writer) addBody(sig *types2.Signature, block *syntax.BlockStmt, localsIdx map[types2.Object]int) { + // TODO(mdempsky): Theoretically, I think at this point we want to + // extend the implicit type parameters list with any new explicit + // type parameters. + // + // However, I believe that's moot: declared functions and methods + // have explicit type parameters, but are always declared at package + // scope (which has no implicit type parameters); and function + // literals can appear within a type-parameterized function (i.e., + // implicit type parameters), but cannot have explicit type + // parameters of their own. + // + // So I think it's safe to just use whichever is non-empty. + implicitIdx := w.implicitIdx + if len(implicitIdx) == 0 { + implicitIdx = w.explicitIdx + } else { + assert(len(w.explicitIdx) == 0) + } + + w.sync(syncAddBody) + w.reloc(relocBody, w.p.bodyIdx(w.p.curpkg, sig, block, implicitIdx, localsIdx)) +} + +func (pw *pkgWriter) bodyIdx(pkg *types2.Package, sig *types2.Signature, block *syntax.BlockStmt, implicitIdx map[*types2.TypeParam]int, localsIdx map[types2.Object]int) int { + w := pw.newWriter(relocBody, syncFuncBody) + w.implicitIdx = implicitIdx + w.localsIdx = localsIdx + + w.funcargs(sig) + if w.bool(block != nil) { + w.stmts(block.List) + w.pos(block.Rbrace) + } + + return w.flush() +} + +func (w *writer) funcargs(sig *types2.Signature) { + do := func(params *types2.Tuple, result bool) { + for i := 0; i < params.Len(); i++ { + w.funcarg(params.At(i), result) + } + } + + if recv := sig.Recv(); recv != nil { + w.funcarg(recv, false) + } + do(sig.Params(), false) + do(sig.Results(), true) +} + +func (w *writer) funcarg(param *types2.Var, result bool) { + if param.Name() != "" || result { + w.addLocal(param) + } +} + +func (w *writer) addLocal(obj types2.Object) { + w.sync(syncAddLocal) + idx := len(w.localsIdx) + if debug { + w.int(idx) + } + w.localsIdx[obj] = idx +} + +func (w *writer) useLocal(obj types2.Object) { + w.sync(syncUseObjLocal) + idx, ok := w.localsIdx[obj] + assert(ok) + w.len(idx) +} + +func (w *writer) openScope(pos syntax.Pos) { + w.sync(syncOpenScope) + w.pos(pos) +} + +func (w *writer) closeScope(pos syntax.Pos) { + w.sync(syncCloseScope) + w.pos(pos) + w.closeAnotherScope() +} + +func (w *writer) closeAnotherScope() { + w.sync(syncCloseAnotherScope) +} + +// @@@ Statements + +func (w *writer) stmt(stmt syntax.Stmt) { + var stmts []syntax.Stmt + if stmt != nil { + stmts = []syntax.Stmt{stmt} + } + w.stmts(stmts) +} + +func (w *writer) stmts(stmts []syntax.Stmt) { + w.sync(syncStmts) + for _, stmt := range stmts { + w.stmt1(stmt) + } + w.code(stmtEnd) + w.sync(syncStmtsEnd) +} + +func (w *writer) stmt1(stmt syntax.Stmt) { + switch stmt := stmt.(type) { + default: + w.p.unexpected("statement", stmt) + + case nil, *syntax.EmptyStmt: + return + + case *syntax.AssignStmt: + switch { + case stmt.Rhs == nil: + w.code(stmtIncDec) + w.op(binOps[stmt.Op]) + w.expr(stmt.Lhs) + w.pos(stmt) + + case stmt.Op != 0 && stmt.Op != syntax.Def: + w.code(stmtAssignOp) + w.op(binOps[stmt.Op]) + w.expr(stmt.Lhs) + w.pos(stmt) + w.expr(stmt.Rhs) + + default: + w.code(stmtAssign) + w.pos(stmt) + w.assignList(stmt.Lhs) + w.exprList(stmt.Rhs) + } + + case *syntax.BlockStmt: + w.code(stmtBlock) + w.blockStmt(stmt) + + case *syntax.BranchStmt: + w.code(stmtBranch) + w.pos(stmt) + w.op(branchOps[stmt.Tok]) + w.optLabel(stmt.Label) + + case *syntax.CallStmt: + w.code(stmtCall) + w.pos(stmt) + w.op(callOps[stmt.Tok]) + w.expr(stmt.Call) + + case *syntax.DeclStmt: + for _, decl := range stmt.DeclList { + w.declStmt(decl) + } + + case *syntax.ExprStmt: + w.code(stmtExpr) + w.expr(stmt.X) + + case *syntax.ForStmt: + w.code(stmtFor) + w.forStmt(stmt) + + case *syntax.IfStmt: + w.code(stmtIf) + w.ifStmt(stmt) + + case *syntax.LabeledStmt: + w.code(stmtLabel) + w.pos(stmt) + w.label(stmt.Label) + w.stmt1(stmt.Stmt) + + case *syntax.ReturnStmt: + w.code(stmtReturn) + w.pos(stmt) + w.exprList(stmt.Results) + + case *syntax.SelectStmt: + w.code(stmtSelect) + w.selectStmt(stmt) + + case *syntax.SendStmt: + w.code(stmtSend) + w.pos(stmt) + w.expr(stmt.Chan) + w.expr(stmt.Value) + + case *syntax.SwitchStmt: + w.code(stmtSwitch) + w.switchStmt(stmt) + } +} + +func (w *writer) assignList(expr syntax.Expr) { + exprs := unpackListExpr(expr) + w.len(len(exprs)) + + for _, expr := range exprs { + if name, ok := expr.(*syntax.Name); ok && name.Value != "_" { + if obj, ok := w.p.info.Defs[name]; ok { + w.bool(true) + w.pos(obj) + w.localIdent(obj) + w.typ(obj.Type()) + + // TODO(mdempsky): Minimize locals index size by deferring + // this until the variables actually come into scope. + w.addLocal(obj) + continue + } + } + + w.bool(false) + w.expr(expr) + } +} + +func (w *writer) declStmt(decl syntax.Decl) { + switch decl := decl.(type) { + default: + w.p.unexpected("declaration", decl) + + case *syntax.ConstDecl: + + case *syntax.TypeDecl: + // Quirk: The legacy inliner doesn't support inlining functions + // with type declarations. Unified IR doesn't have any need to + // write out type declarations explicitly (they're always looked + // up via global index tables instead), so we just write out a + // marker so the reader knows to synthesize a fake declaration to + // prevent inlining. + if quirksMode() { + w.code(stmtTypeDeclHack) + } + + case *syntax.VarDecl: + values := unpackListExpr(decl.Values) + + // Quirk: When N variables are declared with N initialization + // values, we need to decompose that into N interleaved + // declarations+initializations, because it leads to different + // (albeit semantically equivalent) code generation. + if quirksMode() && len(decl.NameList) == len(values) { + for i, name := range decl.NameList { + w.code(stmtAssign) + w.pos(decl) + w.assignList(name) + w.exprList(values[i]) + } + break + } + + w.code(stmtAssign) + w.pos(decl) + w.assignList(namesAsExpr(decl.NameList)) + w.exprList(decl.Values) + } +} + +func (w *writer) blockStmt(stmt *syntax.BlockStmt) { + w.sync(syncBlockStmt) + w.openScope(stmt.Pos()) + w.stmts(stmt.List) + w.closeScope(stmt.Rbrace) +} + +func (w *writer) forStmt(stmt *syntax.ForStmt) { + w.sync(syncForStmt) + w.openScope(stmt.Pos()) + + if rang, ok := stmt.Init.(*syntax.RangeClause); w.bool(ok) { + w.pos(rang) + w.assignList(rang.Lhs) + w.expr(rang.X) + } else { + w.pos(stmt) + w.stmt(stmt.Init) + w.expr(stmt.Cond) + w.stmt(stmt.Post) + } + + w.blockStmt(stmt.Body) + w.closeAnotherScope() +} + +func (w *writer) ifStmt(stmt *syntax.IfStmt) { + w.sync(syncIfStmt) + w.openScope(stmt.Pos()) + w.pos(stmt) + w.stmt(stmt.Init) + w.expr(stmt.Cond) + w.blockStmt(stmt.Then) + w.stmt(stmt.Else) + w.closeAnotherScope() +} + +func (w *writer) selectStmt(stmt *syntax.SelectStmt) { + w.sync(syncSelectStmt) + + w.pos(stmt) + w.len(len(stmt.Body)) + for i, clause := range stmt.Body { + if i > 0 { + w.closeScope(clause.Pos()) + } + w.openScope(clause.Pos()) + + w.pos(clause) + w.stmt(clause.Comm) + w.stmts(clause.Body) + } + if len(stmt.Body) > 0 { + w.closeScope(stmt.Rbrace) + } +} + +func (w *writer) switchStmt(stmt *syntax.SwitchStmt) { + w.sync(syncSwitchStmt) + + w.openScope(stmt.Pos()) + w.pos(stmt) + w.stmt(stmt.Init) + w.expr(stmt.Tag) + + w.len(len(stmt.Body)) + for i, clause := range stmt.Body { + if i > 0 { + w.closeScope(clause.Pos()) + } + w.openScope(clause.Pos()) + + w.pos(clause) + w.exprList(clause.Cases) + + if obj, ok := w.p.info.Implicits[clause]; ok { + // TODO(mdempsky): These pos details are quirkish, but also + // necessary so the variable's position is correct for DWARF + // scope assignment later. It would probably be better for us to + // instead just set the variable's DWARF scoping info earlier so + // we can give it the correct position information. + pos := clause.Pos() + if typs := unpackListExpr(clause.Cases); len(typs) != 0 { + pos = typeExprEndPos(typs[len(typs)-1]) + } + w.pos(pos) + + obj := obj.(*types2.Var) + w.typ(obj.Type()) + w.addLocal(obj) + } + + w.stmts(clause.Body) + } + if len(stmt.Body) > 0 { + w.closeScope(stmt.Rbrace) + } + + w.closeScope(stmt.Rbrace) +} + +func (w *writer) label(label *syntax.Name) { + w.sync(syncLabel) + + // TODO(mdempsky): Replace label strings with dense indices. + w.string(label.Value) +} + +func (w *writer) optLabel(label *syntax.Name) { + w.sync(syncOptLabel) + if w.bool(label != nil) { + w.label(label) + } +} + +// @@@ Expressions + +func (w *writer) expr(expr syntax.Expr) { + expr = unparen(expr) // skip parens; unneeded after typecheck + + obj, targs := lookupObj(w.p.info, expr) + + if tv, ok := w.p.info.Types[expr]; ok { + if tv.IsType() { + w.code(exprType) + w.typ(tv.Type) + return + } + + if tv.Value != nil { + pos := expr.Pos() + if quirksMode() { + if obj != nil { + // Quirk: IR (and thus iexport) doesn't track position + // information for uses of declared objects. + pos = syntax.Pos{} + } else if tv.Value.Kind() == constant.String { + // Quirk: noder.sum picks a particular position for certain + // string concatenations. + pos = sumPos(expr) + } + } + + w.code(exprConst) + w.pos(pos) + w.value(tv.Type, tv.Value) + + // TODO(mdempsky): These details are only important for backend + // diagnostics. Explore writing them out separately. + w.op(constExprOp(expr)) + w.string(syntax.String(expr)) + return + } + } + + if obj != nil { + if _, ok := w.localsIdx[obj]; ok { + assert(len(targs) == 0) + w.code(exprLocal) + w.useLocal(obj) + return + } + + w.code(exprName) + w.obj(obj, targs) + return + } + + switch expr := expr.(type) { + default: + w.p.unexpected("expression", expr) + + case nil: // absent slice index, for condition, or switch tag + w.code(exprNone) + + case *syntax.Name: + assert(expr.Value == "_") + w.code(exprBlank) + + case *syntax.CompositeLit: + w.code(exprCompLit) + w.compLit(expr) + + case *syntax.FuncLit: + w.code(exprFuncLit) + w.funcLit(expr) + + case *syntax.SelectorExpr: + sel, ok := w.p.info.Selections[expr] + assert(ok) + + w.code(exprSelector) + w.expr(expr.X) + w.pos(expr) + w.selector(sel.Obj()) + + case *syntax.IndexExpr: + tv, ok := w.p.info.Types[expr.Index] + assert(ok && tv.IsValue()) + + w.code(exprIndex) + w.expr(expr.X) + w.pos(expr) + w.expr(expr.Index) + + case *syntax.SliceExpr: + w.code(exprSlice) + w.expr(expr.X) + w.pos(expr) + for _, n := range &expr.Index { + w.expr(n) + } + + case *syntax.AssertExpr: + w.code(exprAssert) + w.expr(expr.X) + w.pos(expr) + w.expr(expr.Type) + + case *syntax.Operation: + if expr.Y == nil { + w.code(exprUnaryOp) + w.op(unOps[expr.Op]) + w.pos(expr) + w.expr(expr.X) + break + } + + w.code(exprBinaryOp) + w.op(binOps[expr.Op]) + w.expr(expr.X) + w.pos(expr) + w.expr(expr.Y) + + case *syntax.CallExpr: + w.code(exprCall) + + if inf, ok := w.p.info.Inferred[expr]; ok { + obj, _ := lookupObj(w.p.info, expr.Fun) + assert(obj != nil) + + // As if w.expr(expr.Fun), but using inf.TArgs instead. + w.code(exprName) + w.obj(obj, inf.TArgs) + } else { + w.expr(expr.Fun) + } + + w.pos(expr) + w.exprs(expr.ArgList) + w.bool(expr.HasDots) + + case *syntax.TypeSwitchGuard: + w.code(exprTypeSwitchGuard) + w.pos(expr) + if tag := expr.Lhs; w.bool(tag != nil) { + w.pos(tag) + w.string(tag.Value) + } + w.expr(expr.X) + } +} + +func (w *writer) compLit(lit *syntax.CompositeLit) { + tv, ok := w.p.info.Types[lit] + assert(ok) + + w.sync(syncCompLit) + w.pos(lit) + w.typ(tv.Type) + + typ := tv.Type + if ptr, ok := typ.Underlying().(*types2.Pointer); ok { + typ = ptr.Elem() + } + str, isStruct := typ.Underlying().(*types2.Struct) + + w.len(len(lit.ElemList)) + for i, elem := range lit.ElemList { + if isStruct { + if kv, ok := elem.(*syntax.KeyValueExpr); ok { + // use position of expr.Key rather than of elem (which has position of ':') + w.pos(kv.Key) + w.len(fieldIndex(w.p.info, str, kv.Key.(*syntax.Name))) + elem = kv.Value + } else { + w.pos(elem) + w.len(i) + } + } else { + if kv, ok := elem.(*syntax.KeyValueExpr); w.bool(ok) { + // use position of expr.Key rather than of elem (which has position of ':') + w.pos(kv.Key) + w.expr(kv.Key) + elem = kv.Value + } + } + w.pos(elem) + w.expr(elem) + } +} + +func (w *writer) funcLit(expr *syntax.FuncLit) { + tv, ok := w.p.info.Types[expr] + assert(ok) + sig := tv.Type.(*types2.Signature) + + w.sync(syncFuncLit) + w.pos(expr) + w.pos(expr.Type) // for QuirksMode + w.signature(sig) + + closureVars, localsIdx := w.captureVars(expr) + w.len(len(closureVars)) + for _, closureVar := range closureVars { + w.pos(closureVar.pos) + w.useLocal(closureVar.obj) + } + + w.addBody(sig, expr.Body, localsIdx) +} + +type posObj struct { + pos syntax.Pos + obj types2.Object +} + +// captureVars returns the free variables used by the given function +// literal. +func (w *writer) captureVars(expr *syntax.FuncLit) (closureVars []posObj, localsIdx map[types2.Object]int) { + scope, ok := w.p.info.Scopes[expr.Type] + assert(ok) + + localsIdx = make(map[types2.Object]int) + + // TODO(mdempsky): This code needs to be cleaned up (e.g., to avoid + // traversing nested function literals multiple times). This will be + // easier after we drop quirks mode. + + var rbracePos syntax.Pos + + var visitor func(n syntax.Node) bool + visitor = func(n syntax.Node) bool { + + // Constant expressions don't count towards capturing. + if n, ok := n.(syntax.Expr); ok { + if tv, ok := w.p.info.Types[n]; ok && tv.Value != nil { + return true + } + } + + switch n := n.(type) { + case *syntax.Name: + if obj, ok := w.p.info.Uses[n].(*types2.Var); ok && !obj.IsField() && obj.Pkg() == w.p.curpkg && obj.Parent() != obj.Pkg().Scope() { + // Found a local variable. See if it chains up to scope. + parent := obj.Parent() + for { + if parent == scope { + break + } + if parent == obj.Pkg().Scope() { + if _, present := localsIdx[obj]; !present { + pos := rbracePos + if pos == (syntax.Pos{}) { + pos = n.Pos() + } + + idx := len(closureVars) + closureVars = append(closureVars, posObj{pos, obj}) + localsIdx[obj] = idx + } + break + } + parent = parent.Parent() + } + } + + case *syntax.FuncLit: + // Quirk: typecheck uses the rbrace position position of the + // function literal as the position of the intermediary capture. + if quirksMode() && rbracePos == (syntax.Pos{}) { + rbracePos = n.Body.Rbrace + syntax.Walk(n.Body, visitor) + rbracePos = syntax.Pos{} + return true + } + + case *syntax.AssignStmt: + // Quirk: typecheck visits (and thus captures) the RHS of + // assignment statements before the LHS. + if quirksMode() && (n.Op == 0 || n.Op == syntax.Def) { + syntax.Walk(n.Rhs, visitor) + syntax.Walk(n.Lhs, visitor) + return true + } + case *syntax.RangeClause: + // Quirk: Similarly, it visits the expression to be iterated + // over before the iteration variables. + if quirksMode() { + syntax.Walk(n.X, visitor) + if n.Lhs != nil { + syntax.Walk(n.Lhs, visitor) + } + return true + } + } + + return false + } + syntax.Walk(expr.Body, visitor) + + return +} + +func (w *writer) exprList(expr syntax.Expr) { + w.sync(syncExprList) + w.exprs(unpackListExpr(expr)) +} + +func (w *writer) exprs(exprs []syntax.Expr) { + if len(exprs) == 0 { + assert(exprs == nil) + } + + w.sync(syncExprs) + w.len(len(exprs)) + for _, expr := range exprs { + w.expr(expr) + } +} + +func (w *writer) op(op ir.Op) { + // TODO(mdempsky): Remove in favor of explicit codes? Would make + // export data more stable against internal refactorings, but low + // priority at the moment. + assert(op != 0) + w.sync(syncOp) + w.len(int(op)) +} + +// @@@ Package initialization + +// Caution: This code is still clumsy, because toolstash -cmp is +// particularly sensitive to it. + +type typeDeclGen struct { + *syntax.TypeDecl + gen int +} + +func (pw *pkgWriter) collectDecls(noders []*noder) { + var typegen int + + for _, p := range noders { + var importedEmbed, importedUnsafe bool + + syntax.Walk(p.file, func(n syntax.Node) bool { + switch n := n.(type) { + case *syntax.File: + pw.checkPragmas(n.Pragma, ir.GoBuildPragma, false) + + case *syntax.ImportDecl: + pw.checkPragmas(n.Pragma, 0, false) + + switch pkgNameOf(pw.info, n).Imported().Path() { + case "embed": + importedEmbed = true + case "unsafe": + importedUnsafe = true + } + + case *syntax.ConstDecl: + pw.checkPragmas(n.Pragma, 0, false) + + case *syntax.FuncDecl: + pw.checkPragmas(n.Pragma, funcPragmas, false) + + obj := pw.info.Defs[n.Name].(*types2.Func) + pw.funDecls[obj] = n + + case *syntax.TypeDecl: + obj := pw.info.Defs[n.Name].(*types2.TypeName) + d := typeDeclGen{TypeDecl: n} + + if n.Alias { + pw.checkPragmas(n.Pragma, 0, false) + } else { + pw.checkPragmas(n.Pragma, typePragmas, false) + + // Assign a unique ID to function-scoped defined types. + if !isGlobal(obj) { + typegen++ + d.gen = typegen + } + } + + pw.typDecls[obj] = d + + case *syntax.VarDecl: + pw.checkPragmas(n.Pragma, 0, true) + + if p, ok := n.Pragma.(*pragmas); ok && len(p.Embeds) > 0 { + obj := pw.info.Defs[n.NameList[0]].(*types2.Var) + // TODO(mdempsky): isGlobal(obj) gives false positive errors + // for //go:embed directives on package-scope blank + // variables. + if err := checkEmbed(n, importedEmbed, !isGlobal(obj)); err != nil { + pw.errorf(p.Embeds[0].Pos, "%s", err) + } + } + + // Workaround for #46208. For variable declarations that + // declare multiple variables and have an explicit type + // expression, the type expression is evaluated multiple + // times. This affects toolstash -cmp, because iexport is + // sensitive to *types.Type pointer identity. + if quirksMode() && n.Type != nil { + tv, ok := pw.info.Types[n.Type] + assert(ok) + assert(tv.IsType()) + for _, name := range n.NameList { + obj := pw.info.Defs[name].(*types2.Var) + pw.dups.add(obj.Type(), tv.Type) + } + } + } + return false + }) + + pw.cgoPragmas = append(pw.cgoPragmas, p.pragcgobuf...) + + for _, l := range p.linknames { + if !importedUnsafe { + pw.errorf(l.pos, "//go:linkname only allowed in Go files that import \"unsafe\"") + continue + } + + switch obj := pw.curpkg.Scope().Lookup(l.local).(type) { + case *types2.Func, *types2.Var: + if _, ok := pw.linknames[obj]; !ok { + pw.linknames[obj] = l.remote + } else { + pw.errorf(l.pos, "duplicate //go:linkname for %s", l.local) + } + + default: + // TODO(mdempsky): Enable after #42938 is fixed. + if false { + pw.errorf(l.pos, "//go:linkname must refer to declared function or variable") + } + } + } + } +} + +func (pw *pkgWriter) checkPragmas(p syntax.Pragma, allowed ir.PragmaFlag, embedOK bool) { + if p == nil { + return + } + pragma := p.(*pragmas) + + for _, pos := range pragma.Pos { + if pos.Flag&^allowed != 0 { + pw.errorf(pos.Pos, "misplaced compiler directive") + } + } + + if !embedOK { + for _, e := range pragma.Embeds { + pw.errorf(e.Pos, "misplaced go:embed directive") + } + } +} + +func (w *writer) pkgInit(noders []*noder) { + if quirksMode() { + posBases := posBasesOf(noders) + w.len(len(posBases)) + for _, posBase := range posBases { + w.posBase(posBase) + } + + objs := importedObjsOf(w.p.curpkg, w.p.info, noders) + w.len(len(objs)) + for _, obj := range objs { + w.qualifiedIdent(obj) + } + } + + w.len(len(w.p.cgoPragmas)) + for _, cgoPragma := range w.p.cgoPragmas { + w.strings(cgoPragma) + } + + w.sync(syncDecls) + for _, p := range noders { + for _, decl := range p.file.DeclList { + w.pkgDecl(decl) + } + } + w.code(declEnd) + + w.sync(syncEOF) +} + +func (w *writer) pkgDecl(decl syntax.Decl) { + switch decl := decl.(type) { + default: + w.p.unexpected("declaration", decl) + + case *syntax.ImportDecl: + + case *syntax.ConstDecl: + w.code(declOther) + w.pkgObjs(decl.NameList...) + + case *syntax.FuncDecl: + obj := w.p.info.Defs[decl.Name].(*types2.Func) + sig := obj.Type().(*types2.Signature) + + if sig.RParams() != nil || sig.TParams() != nil { + break // skip generic functions + } + + if recv := sig.Recv(); recv != nil && obj.Name() != "_" { + w.code(declMethod) + w.typ(recvBase(recv)) + w.selector(obj) + break + } + + w.code(declFunc) + w.pkgObjs(decl.Name) + + case *syntax.TypeDecl: + if len(decl.TParamList) != 0 { + break // skip generic type decls + } + + name := w.p.info.Defs[decl.Name].(*types2.TypeName) + + // Skip type declarations for interfaces that are only usable as + // type parameter bounds. + if iface, ok := name.Type().Underlying().(*types2.Interface); ok && iface.IsConstraint() { + break + } + + // Skip aliases to uninstantiated generic types. + // TODO(mdempsky): Revisit after #46477 is resolved. + if name.IsAlias() { + named, ok := name.Type().(*types2.Named) + if ok && len(named.TParams()) != 0 && len(named.TArgs()) == 0 { + break + } + } + + w.code(declOther) + w.pkgObjs(decl.Name) + + case *syntax.VarDecl: + w.code(declVar) + w.pos(decl) + w.pkgObjs(decl.NameList...) + w.exprList(decl.Values) + + var embeds []pragmaEmbed + if p, ok := decl.Pragma.(*pragmas); ok { + embeds = p.Embeds + } + w.len(len(embeds)) + for _, embed := range embeds { + w.pos(embed.Pos) + w.strings(embed.Patterns) + } + } +} + +func (w *writer) pkgObjs(names ...*syntax.Name) { + w.sync(syncDeclNames) + w.len(len(names)) + + for _, name := range names { + obj, ok := w.p.info.Defs[name] + assert(ok) + + w.sync(syncDeclName) + w.obj(obj, nil) + } +} + +// @@@ Helpers + +// isDefinedType reports whether obj is a defined type. +func isDefinedType(obj types2.Object) bool { + if obj, ok := obj.(*types2.TypeName); ok { + return !obj.IsAlias() + } + return false +} + +// isGlobal reports whether obj was declared at package scope. +// +// Caveat: blank objects are not declared. +func isGlobal(obj types2.Object) bool { + return obj.Parent() == obj.Pkg().Scope() +} + +// lookupObj returns the object that expr refers to, if any. If expr +// is an explicit instantiation of a generic object, then the type +// arguments are returned as well. +func lookupObj(info *types2.Info, expr syntax.Expr) (obj types2.Object, targs []types2.Type) { + if index, ok := expr.(*syntax.IndexExpr); ok { + if inf, ok := info.Inferred[index]; ok { + targs = inf.TArgs + } else { + args := unpackListExpr(index.Index) + + if len(args) == 1 { + tv, ok := info.Types[args[0]] + assert(ok) + if tv.IsValue() { + return // normal index expression + } + } + + targs = make([]types2.Type, len(args)) + for i, arg := range args { + tv, ok := info.Types[arg] + assert(ok) + assert(tv.IsType()) + targs[i] = tv.Type + } + } + + expr = index.X + } + + // Strip package qualifier, if present. + if sel, ok := expr.(*syntax.SelectorExpr); ok { + if !isPkgQual(info, sel) { + return // normal selector expression + } + expr = sel.Sel + } + + if name, ok := expr.(*syntax.Name); ok { + obj, _ = info.Uses[name] + } + return +} + +// isPkgQual reports whether the given selector expression is a +// package-qualified identifier. +func isPkgQual(info *types2.Info, sel *syntax.SelectorExpr) bool { + if name, ok := sel.X.(*syntax.Name); ok { + _, isPkgName := info.Uses[name].(*types2.PkgName) + return isPkgName + } + return false +} + +// recvBase returns the base type for the given receiver parameter. +func recvBase(recv *types2.Var) *types2.Named { + typ := recv.Type() + if ptr, ok := typ.(*types2.Pointer); ok { + typ = ptr.Elem() + } + return typ.(*types2.Named) +} + +// namesAsExpr returns a list of names as a syntax.Expr. +func namesAsExpr(names []*syntax.Name) syntax.Expr { + if len(names) == 1 { + return names[0] + } + + exprs := make([]syntax.Expr, len(names)) + for i, name := range names { + exprs[i] = name + } + return &syntax.ListExpr{ElemList: exprs} +} + +// fieldIndex returns the index of the struct field named by key. +func fieldIndex(info *types2.Info, str *types2.Struct, key *syntax.Name) int { + field := info.Uses[key].(*types2.Var) + + for i := 0; i < str.NumFields(); i++ { + if str.Field(i) == field { + return i + } + } + + panic(fmt.Sprintf("%s: %v is not a field of %v", key.Pos(), field, str)) +} + +// objTypeParams returns the type parameters on the given object. +func objTypeParams(obj types2.Object) []*types2.TypeName { + switch obj := obj.(type) { + case *types2.Func: + return obj.Type().(*types2.Signature).TParams() + case *types2.TypeName: + if !obj.IsAlias() { + return obj.Type().(*types2.Named).TParams() + } + } + return nil +} + +func asPragmaFlag(p syntax.Pragma) ir.PragmaFlag { + if p == nil { + return 0 + } + return p.(*pragmas).Flag +} From d77f4c0c5c966c37960cd691656fba184ae770ff Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Thu, 9 Jul 2020 18:49:05 -0400 Subject: [PATCH 415/940] net/http: improve some server docs Change-Id: I04662a08e07c49f629f9067a89bf453e697d44dd Reviewed-on: https://go-review.googlesource.com/c/go/+/327813 Trust: Filippo Valsorda Run-TryBot: Filippo Valsorda TryBot-Result: Go Bot Reviewed-by: Damien Neil --- src/net/http/server.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/net/http/server.go b/src/net/http/server.go index 50fab4520dd..5b113cff970 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -333,7 +333,7 @@ func (c *conn) hijackLocked() (rwc net.Conn, buf *bufio.ReadWriter, err error) { const bufferBeforeChunkingSize = 2048 // chunkWriter writes to a response's conn buffer, and is the writer -// wrapped by the response.bufw buffered writer. +// wrapped by the response.w buffered writer. // // chunkWriter also is responsible for finalizing the Header, including // conditionally setting the Content-Type and setting a Content-Length @@ -1529,12 +1529,12 @@ func (w *response) bodyAllowed() bool { // The Writers are wired together like: // // 1. *response (the ResponseWriter) -> -// 2. (*response).w, a *bufio.Writer of bufferBeforeChunkingSize bytes +// 2. (*response).w, a *bufio.Writer of bufferBeforeChunkingSize bytes -> // 3. chunkWriter.Writer (whose writeHeader finalizes Content-Length/Type) -// and which writes the chunk headers, if needed. -// 4. conn.buf, a bufio.Writer of default (4kB) bytes, writing to -> +// and which writes the chunk headers, if needed -> +// 4. conn.bufw, a *bufio.Writer of default (4kB) bytes, writing to -> // 5. checkConnErrorWriter{c}, which notes any non-nil error on Write -// and populates c.werr with it if so. but otherwise writes to: +// and populates c.werr with it if so, but otherwise writes to -> // 6. the rwc, the net.Conn. // // TODO(bradfitz): short-circuit some of the buffering when the From cf1ae5fc364eb7f2ee5203e4c5e30411c3cfe01f Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 11 Jun 2021 03:54:25 -0700 Subject: [PATCH 416/940] [dev.typeparams] cmd/compile: add -d=unified flag to enable unified IR This CL adds a new -d=unified debug flag, which controls whether unified IR mode is used. Change-Id: Iaa5f3cc0a24b9881aeec5317cd6b462b4a7b6fc9 Reviewed-on: https://go-review.googlesource.com/c/go/+/327054 Trust: Matthew Dempsky Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/base/debug.go | 1 + src/cmd/compile/internal/noder/noder.go | 5 +++++ src/cmd/compile/internal/reflectdata/reflect.go | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/src/cmd/compile/internal/base/debug.go b/src/cmd/compile/internal/base/debug.go index 71712ab1a56..824a8baa832 100644 --- a/src/cmd/compile/internal/base/debug.go +++ b/src/cmd/compile/internal/base/debug.go @@ -46,6 +46,7 @@ type DebugFlags struct { SoftFloat int `help:"force compiler to emit soft-float code"` TypeAssert int `help:"print information about type assertion inlining"` TypecheckInl int `help:"eager typechecking of inline function bodies"` + Unified int `help:"enable unified IR construction"` WB int `help:"print information about write barriers"` ABIWrap int `help:"print information about ABI wrapper generation"` diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go index d417edcbd52..c7970396f8d 100644 --- a/src/cmd/compile/internal/noder/noder.go +++ b/src/cmd/compile/internal/noder/noder.go @@ -76,6 +76,11 @@ func LoadPackage(filenames []string) { } base.Timer.AddEvent(int64(lines), "lines") + if base.Debug.Unified != 0 { + useUnifiedIR(noders) + return + } + if base.Flag.G != 0 { // Use types2 to type-check and possibly generate IR. check2(noders) diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index f16034ea708..5516f707fa9 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -1780,6 +1780,10 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy // TODO: check that we do the right thing when rcvr.IsInterface(). generic = true } + if base.Debug.Unified != 0 { + // TODO(mdempsky): Support dictionaries for unified IR. + generic = false + } newnam := ir.MethodSym(rcvr, method.Sym) lsym := newnam.Linksym() if newnam.Siggen() { From a752bc07462f01a4c1ee1940c3ea316b270af146 Mon Sep 17 00:00:00 2001 From: Rahul Bajaj Date: Tue, 15 Jun 2021 13:23:10 +0000 Subject: [PATCH 417/940] syscall: fix TestGroupCleanupUserNamespace test failure on Fedora Fixes #46752 Change-Id: I2eaa9d15fac4e859e18191fcf1372e5be94899df GitHub-Last-Rev: 8a2672d8dc6713ec6cbd207d870e893062c8fe5b GitHub-Pull-Request: golang/go#46753 Reviewed-on: https://go-review.googlesource.com/c/go/+/328109 Run-TryBot: Tobias Klauser TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor Reviewed-by: Tobias Klauser --- src/syscall/exec_linux_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/syscall/exec_linux_test.go b/src/syscall/exec_linux_test.go index 7d89eaae63a..85b59ad00d9 100644 --- a/src/syscall/exec_linux_test.go +++ b/src/syscall/exec_linux_test.go @@ -318,6 +318,7 @@ func TestGroupCleanupUserNamespace(t *testing.T) { "uid=0(root) gid=0(root) groups=0(root),65534", "uid=0(root) gid=0(root) groups=0(root),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody)", // Alpine; see https://golang.org/issue/19938 "uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023", // CentOS with SELinux context, see https://golang.org/issue/34547 + "uid=0(root) gid=0(root) groups=0(root),65534(nobody) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023", // Fedora with SElinux context, see https://golang.org/issue/46752 } for _, e := range expected { if strOut == e { From 785a8f677fbba9432ee67b14d41004ba7fd35ddb Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Tue, 15 Jun 2021 21:40:49 +0700 Subject: [PATCH 418/940] cmd/compile: better error message for invalid untyped operation For typed vs un-typed operation, the compiler do the conversion un-conditionally, so if the operation is invalid, the error report is pointed to the conversion, instead of the invalid operation itself. To fix this, only do the conversion when the operations are valid for both types. Fixes #46749 Change-Id: Ib71c7bcd3ed5454e6df55b6a8db4e0f189259ba7 Reviewed-on: https://go-review.googlesource.com/c/go/+/328050 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/typecheck/const.go | 20 ++++++----- test/fixedbugs/issue46749.go | 37 +++++++++++++++++++++ test/run.go | 1 + 3 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 test/fixedbugs/issue46749.go diff --git a/src/cmd/compile/internal/typecheck/const.go b/src/cmd/compile/internal/typecheck/const.go index 5a35eeade9f..761b0437940 100644 --- a/src/cmd/compile/internal/typecheck/const.go +++ b/src/cmd/compile/internal/typecheck/const.go @@ -633,6 +633,17 @@ func defaultlit2(l ir.Node, r ir.Node, force bool) (ir.Node, ir.Node) { if l.Type() == nil || r.Type() == nil { return l, r } + + if !l.Type().IsInterface() && !r.Type().IsInterface() { + // Can't mix bool with non-bool, string with non-string. + if l.Type().IsBoolean() != r.Type().IsBoolean() { + return l, r + } + if l.Type().IsString() != r.Type().IsString() { + return l, r + } + } + if !l.Type().IsUntyped() { r = convlit(r, l.Type()) return l, r @@ -647,17 +658,10 @@ func defaultlit2(l ir.Node, r ir.Node, force bool) (ir.Node, ir.Node) { return l, r } - // Can't mix bool with non-bool, string with non-string, or nil with anything (untyped). - if l.Type().IsBoolean() != r.Type().IsBoolean() { - return l, r - } - if l.Type().IsString() != r.Type().IsString() { - return l, r - } + // Can't mix nil with anything untyped. if ir.IsNil(l) || ir.IsNil(r) { return l, r } - t := defaultType(mixUntyped(l.Type(), r.Type())) l = convlit(l, t) r = convlit(r, t) diff --git a/test/fixedbugs/issue46749.go b/test/fixedbugs/issue46749.go new file mode 100644 index 00000000000..63ed19795e5 --- /dev/null +++ b/test/fixedbugs/issue46749.go @@ -0,0 +1,37 @@ +// errorcheck + +// Copyright 2021 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 + +var s string +var b bool +var i int +var iface interface{} + +var ( + _ = "" + b // ERROR "invalid operation.*mismatched types.*untyped string and bool" + _ = "" + i // ERROR "invalid operation.*mismatched types.*untyped string and int" + _ = "" + nil // ERROR "invalid operation.*mismatched types.*untyped string and nil" +) + +var ( + _ = s + false // ERROR "invalid operation.*mismatched types.*string and untyped bool" + _ = s + 1 // ERROR "invalid operation.*mismatched types.*string and untyped int" + _ = s + nil // ERROR "invalid operation.*mismatched types.*string and nil" +) + +var ( + _ = "" + false // ERROR "invalid operation.*mismatched types.*untyped string and untyped bool" + _ = "" + 1 // ERROR "invalid operation.*mismatched types.*untyped string and untyped int" +) + +var ( + _ = b + 1 // ERROR "invalid operation.*mismatched types.*bool and untyped int" + _ = i + false // ERROR "invalid operation.*mismatched types.*int and untyped bool" + _ = iface + 1 // ERROR "invalid operation.*mismatched types.*interface {} and int" + _ = iface + 1.0 // ERROR "invalid operation.*mismatched types.*interface {} and float64" + _ = iface + false // ERROR "invalid operation.*mismatched types.*interface {} and bool" +) diff --git a/test/run.go b/test/run.go index 5e60de76248..d7f5d02391b 100644 --- a/test/run.go +++ b/test/run.go @@ -2002,4 +2002,5 @@ var excluded = map[string]bool{ "fixedbugs/issue7525c.go": true, // types2 reports init cycle error on different line - ok otherwise "fixedbugs/issue7525d.go": true, // types2 reports init cycle error on different line - ok otherwise "fixedbugs/issue7525e.go": true, // types2 reports init cycle error on different line - ok otherwise + "fixedbugs/issue46749.go": true, // types2 reports can not convert error instead of type mismatched } From ee0420d3b56982cb1600dc141dfd4be155adddfe Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Wed, 16 Jun 2021 10:29:21 +0700 Subject: [PATCH 419/940] [dev.typeparams] cmd/compile: factor out implicit/explicit handling The logic for handling them must keep in sync between reader/writer, so factoring them out from addBody make it's easier to refer later. Change-Id: I26447065867d79f4f47cc678a398b9e7bf5d2403 Reviewed-on: https://go-review.googlesource.com/c/go/+/328051 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/noder/reader.go | 15 +++++++++++---- src/cmd/compile/internal/noder/sync.go | 1 + src/cmd/compile/internal/noder/writer.go | 11 +++++++++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 18ecbff3ccf..803acaa88dc 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -789,18 +789,25 @@ var bodyReader = map[*ir.Func]pkgReaderIndex{} // constructed. var todoBodies []*ir.Func -func (r *reader) addBody(fn *ir.Func) { - r.sync(syncAddBody) +// Keep in sync with writer.implicitTypes +// Also see comment there for why r.implicits and r.explicits should +// never both be non-empty. +func (r *reader) implicitTypes() []*types.Type { + r.sync(syncImplicitTypes) - // See commont in writer.addBody for why r.implicits and r.explicits - // should never both be non-empty. implicits := r.implicits if len(implicits) == 0 { implicits = r.explicits } else { assert(len(r.explicits) == 0) } + return implicits +} +func (r *reader) addBody(fn *ir.Func) { + r.sync(syncAddBody) + + implicits := r.implicitTypes() pri := pkgReaderIndex{r.p, r.reloc(relocBody), implicits} bodyReader[fn] = pri diff --git a/src/cmd/compile/internal/noder/sync.go b/src/cmd/compile/internal/noder/sync.go index d77a7844798..7326a6edbef 100644 --- a/src/cmd/compile/internal/noder/sync.go +++ b/src/cmd/compile/internal/noder/sync.go @@ -151,4 +151,5 @@ const ( syncLocalIdent syncTypeParamNames syncTypeParamBounds + syncImplicitTypes ) diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go index b39dd8651b3..1475540d84c 100644 --- a/src/cmd/compile/internal/noder/writer.go +++ b/src/cmd/compile/internal/noder/writer.go @@ -665,7 +665,9 @@ func (w *writer) pragmaFlag(p ir.PragmaFlag) { // @@@ Function bodies -func (w *writer) addBody(sig *types2.Signature, block *syntax.BlockStmt, localsIdx map[types2.Object]int) { +func (w *writer) implicitTypes() map[*types2.TypeParam]int { + w.sync(syncImplicitTypes) + // TODO(mdempsky): Theoretically, I think at this point we want to // extend the implicit type parameters list with any new explicit // type parameters. @@ -684,9 +686,14 @@ func (w *writer) addBody(sig *types2.Signature, block *syntax.BlockStmt, localsI } else { assert(len(w.explicitIdx) == 0) } + return implicitIdx +} +func (w *writer) addBody(sig *types2.Signature, block *syntax.BlockStmt, localsIdx map[types2.Object]int) { w.sync(syncAddBody) - w.reloc(relocBody, w.p.bodyIdx(w.p.curpkg, sig, block, implicitIdx, localsIdx)) + + implicits := w.implicitTypes() + w.reloc(relocBody, w.p.bodyIdx(w.p.curpkg, sig, block, implicits, localsIdx)) } func (pw *pkgWriter) bodyIdx(pkg *types2.Package, sig *types2.Signature, block *syntax.BlockStmt, implicitIdx map[*types2.TypeParam]int, localsIdx map[types2.Object]int) int { From a6a853f94cf00d8f581d0e6fbcc28898e39557b2 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 15 Jun 2021 12:47:57 -0400 Subject: [PATCH 420/940] cmd/asm: restore supporting of *1 scaling on ARM64 On ARM64, instruction like "MOVD (R1)(R2*1), R3" is accepted and assembles correctly with Go 1.16, but errors out on tip with "arm64 doesn't support scaled register format", since CL 289589. "MOVD (R1)(R2), R3" is the preferred form. But the *1 form works before and assembles correctly. Keep supporting it. Fixes #46766. Change-Id: I0f7fd71fa87ea698919a936b6c68aa5a91afd486 Reviewed-on: https://go-review.googlesource.com/c/go/+/328229 Trust: Cherry Mui Trust: Cuong Manh Le Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: eric fang --- src/cmd/asm/internal/asm/parse.go | 3 ++- src/cmd/asm/internal/asm/testdata/arm64.s | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cmd/asm/internal/asm/parse.go b/src/cmd/asm/internal/asm/parse.go index ab48632a44b..4cddcf48a46 100644 --- a/src/cmd/asm/internal/asm/parse.go +++ b/src/cmd/asm/internal/asm/parse.go @@ -1003,7 +1003,8 @@ func (p *Parser) registerIndirect(a *obj.Addr, prefix rune) { p.errorf("unimplemented two-register form") } a.Index = r1 - if scale != 0 && p.arch.Family == sys.ARM64 { + if scale != 0 && scale != 1 && p.arch.Family == sys.ARM64 { + // Support (R1)(R2) (no scaling) and (R1)(R2*1). p.errorf("arm64 doesn't support scaled register format") } else { a.Scale = int16(scale) diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s index 1146c1a7898..5f1e68545ba 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64.s +++ b/src/cmd/asm/internal/asm/testdata/arm64.s @@ -547,6 +547,7 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8 // shifted or extended register offset. MOVD (R2)(R6.SXTW), R4 // 44c866f8 MOVD (R3)(R6), R5 // 656866f8 + MOVD (R3)(R6*1), R5 // 656866f8 MOVD (R2)(R6), R4 // 446866f8 MOVWU (R19)(R20<<2), R20 // 747a74b8 MOVD (R2)(R6<<3), R4 // 447866f8 @@ -579,6 +580,7 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8 MOVB R4, (R2)(R6.SXTX) // 44e82638 MOVB R8, (R3)(R9.UXTW) // 68482938 MOVB R10, (R5)(R8) // aa682838 + MOVB R10, (R5)(R8*1) // aa682838 MOVH R11, (R2)(R7.SXTW<<1) // 4bd82778 MOVH R5, (R1)(R2<<1) // 25782278 MOVH R7, (R2)(R5.SXTX<<1) // 47f82578 From a4121d7dd66b0bca91cc1619721f69e9027af041 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Mon, 14 Jun 2021 12:39:14 -0400 Subject: [PATCH 421/940] [dev.typeparams] Revert "[dev.typeparams] runtime: make deferproc take a func() argument" Temprary revert CL 325918. Delve relies on the _defer.fn.fn field to get defer frames. CL 325918 changes the type of _defer.fn to func(), which no longer has an fn field. Change-Id: If6c71b15a27bac579593f5273c9a49715e6e35b2 Reviewed-on: https://go-review.googlesource.com/c/go/+/327775 Trust: Cherry Mui Trust: Dan Scales Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/runtime/heapdump.go | 7 +++---- src/runtime/panic.go | 25 +++++++++++++++++-------- src/runtime/runtime2.go | 8 ++++---- src/runtime/stubs.go | 2 +- 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go index 47e4b6b0d1d..934e55f4952 100644 --- a/src/runtime/heapdump.go +++ b/src/runtime/heapdump.go @@ -381,13 +381,12 @@ func dumpgoroutine(gp *g) { dumpint(uint64(uintptr(unsafe.Pointer(gp)))) dumpint(uint64(d.sp)) dumpint(uint64(d.pc)) - fn := *(**funcval)(unsafe.Pointer(&d.fn)) - dumpint(uint64(uintptr(unsafe.Pointer(fn)))) - if fn == nil { + dumpint(uint64(uintptr(unsafe.Pointer(d.fn)))) + if d.fn == nil { // d.fn can be nil for open-coded defers dumpint(uint64(0)) } else { - dumpint(uint64(uintptr(unsafe.Pointer(fn.fn)))) + dumpint(uint64(uintptr(unsafe.Pointer(d.fn.fn)))) } dumpint(uint64(uintptr(unsafe.Pointer(d.link)))) } diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 86d41c4e1c5..04b95e51e53 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -226,7 +226,7 @@ func panicmemAddr(addr uintptr) { // Create a new deferred function fn, which has no arguments and results. // The compiler turns a defer statement into a call to this. -func deferproc(fn func()) { +func deferproc(fn *funcval) { // TODO: Make deferproc just take a func(). gp := getg() if gp.m.curg != gp { // go code on the system stack can't defer @@ -302,6 +302,16 @@ func deferprocStack(d *_defer) { // been set and must not be clobbered. } +// deferFunc returns d's deferred function. This is temporary while we +// support both modes of GOEXPERIMENT=regabidefer. Once we commit to +// that experiment, we should change the type of d.fn. +//go:nosplit +func deferFunc(d *_defer) func() { + var fn func() + *(**funcval)(unsafe.Pointer(&fn)) = d.fn + return fn +} + // Each P holds a pool for defers. // Allocate a Defer, usually using per-P pool. @@ -461,9 +471,7 @@ func deferreturn() { // called with a callback on an LR architecture and jmpdefer is on the // stack, because the stack trace can be incorrect in that case - see // issue #8153). - if fn == nil { - fn() - } + _ = fn.fn jmpdefer(fn, argp) } @@ -527,7 +535,7 @@ func Goexit() { } else { // Save the pc/sp in deferCallSave(), so we can "recover" back to this // loop if necessary. - deferCallSave(&p, d.fn) + deferCallSave(&p, deferFunc(d)) } if p.aborted { // We had a recursive panic in the defer d we started, and @@ -719,12 +727,12 @@ func runOpenDeferFrame(gp *g, d *_defer) bool { if deferBits&(1< Date: Wed, 16 Jun 2021 23:00:23 +0700 Subject: [PATCH 422/940] [dev.typeparams] cmd/compile: fix missing sync implicit types CL 328051 introduced new syncImplicitTypes, but forgot to add a sync after syncAddBody in linker.relocFuncExt, cause the compiler crashes when reading in package data. Adding missing w.sync(syncImplicitTypes) call fixes this. While at it, also run go generate to update code generated for syncImplicitTypes, which is also missed in CL 328051. Change-Id: Ic65092f69f8d8e63de15989c7f15b6e5633d8f9e Reviewed-on: https://go-review.googlesource.com/c/go/+/328054 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le Reviewed-by: Matthew Dempsky TryBot-Result: Go Bot --- src/cmd/compile/internal/noder/linker.go | 1 + src/cmd/compile/internal/noder/syncmarker_string.go | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/noder/linker.go b/src/cmd/compile/internal/noder/linker.go index 324902d246e..72911381605 100644 --- a/src/cmd/compile/internal/noder/linker.go +++ b/src/cmd/compile/internal/noder/linker.go @@ -210,6 +210,7 @@ func (l *linker) relocFuncExt(w *encoder, name *ir.Name) { pri, ok := bodyReader[name.Func] assert(ok) w.sync(syncAddBody) + w.sync(syncImplicitTypes) w.reloc(relocBody, l.relocIdx(pri.pr, relocBody, pri.idx)) } diff --git a/src/cmd/compile/internal/noder/syncmarker_string.go b/src/cmd/compile/internal/noder/syncmarker_string.go index 3eb88fb9118..14747b7c106 100644 --- a/src/cmd/compile/internal/noder/syncmarker_string.go +++ b/src/cmd/compile/internal/noder/syncmarker_string.go @@ -137,11 +137,14 @@ func _() { _ = x[syncCodeObj-127] _ = x[syncPosBase-128] _ = x[syncLocalIdent-129] + _ = x[syncTypeParamNames-130] + _ = x[syncTypeParamBounds-131] + _ = x[syncImplicitTypes-132] } -const _syncMarker_name = "NodeBoolInt64Uint64StringPosPkgSymSelectorKindTypeTypePkgSignatureParamOpObjectExprStmtDeclConstDeclFuncDeclTypeDeclVarDeclPragmaValueEOFMethodFuncBodyUseUseObjObjectIdxTypeIdxBOFEntryOpenScopeCloseScopeGlobalLocalDefineDefLocalUseLocalDefGlobalUseGlobalTypeParamsUseLabelDefLabelFuncLitCommonFuncBodyRefLinksymExtHackSetlinenoNameImportDeclDeclNamesDeclNameExprListExprsWrapnameTypeExprTypeExprOrNilChanDirParamsCloseAnotherScopeSumUnOpBinOpStructTypeInterfaceTypePacknameEmbeddedStmtsStmtsFallStmtFallBlockStmtIfStmtForStmtSwitchStmtRangeStmtCaseClauseCommClauseSelectStmtDeclsLabeledStmtCompLit1234NDefImplicitUseNameUseObjLocalAddLocalBothSignatureSetUnderlyingLinknameStmt1StmtsEndDeclareTopDeclsTopConstDeclTopFuncDeclTopTypeDeclTopVarDeclObject1AddBodyLabelFuncExtMethExtOptLabelScalarStmtDeclsDeclLocalObjLocalObjLocal1DeclareLocalPublicPrivateRelocsRelocUseRelocVarExtPkgDefTypeExtValCodeObjPosBaseLocalIdent" +const _syncMarker_name = "NodeBoolInt64Uint64StringPosPkgSymSelectorKindTypeTypePkgSignatureParamOpObjectExprStmtDeclConstDeclFuncDeclTypeDeclVarDeclPragmaValueEOFMethodFuncBodyUseUseObjObjectIdxTypeIdxBOFEntryOpenScopeCloseScopeGlobalLocalDefineDefLocalUseLocalDefGlobalUseGlobalTypeParamsUseLabelDefLabelFuncLitCommonFuncBodyRefLinksymExtHackSetlinenoNameImportDeclDeclNamesDeclNameExprListExprsWrapnameTypeExprTypeExprOrNilChanDirParamsCloseAnotherScopeSumUnOpBinOpStructTypeInterfaceTypePacknameEmbeddedStmtsStmtsFallStmtFallBlockStmtIfStmtForStmtSwitchStmtRangeStmtCaseClauseCommClauseSelectStmtDeclsLabeledStmtCompLit1234NDefImplicitUseNameUseObjLocalAddLocalBothSignatureSetUnderlyingLinknameStmt1StmtsEndDeclareTopDeclsTopConstDeclTopFuncDeclTopTypeDeclTopVarDeclObject1AddBodyLabelFuncExtMethExtOptLabelScalarStmtDeclsDeclLocalObjLocalObjLocal1DeclareLocalPublicPrivateRelocsRelocUseRelocVarExtPkgDefTypeExtValCodeObjPosBaseLocalIdentTypeParamNamesTypeParamBoundsImplicitTypes" -var _syncMarker_index = [...]uint16{0, 4, 8, 13, 19, 25, 28, 31, 34, 42, 46, 50, 57, 66, 71, 73, 79, 83, 87, 91, 100, 108, 116, 123, 129, 134, 137, 143, 151, 154, 160, 169, 176, 179, 184, 193, 203, 209, 214, 220, 228, 236, 245, 254, 264, 272, 280, 287, 297, 304, 314, 318, 327, 331, 341, 350, 358, 366, 371, 379, 387, 400, 407, 413, 430, 433, 437, 442, 452, 465, 473, 481, 486, 495, 503, 512, 518, 525, 535, 544, 554, 564, 574, 579, 590, 597, 598, 599, 600, 601, 602, 613, 620, 631, 639, 652, 665, 673, 678, 686, 693, 701, 713, 724, 735, 745, 752, 759, 764, 771, 778, 786, 792, 801, 810, 818, 827, 839, 845, 852, 858, 863, 871, 877, 883, 890, 893, 900, 907, 917} +var _syncMarker_index = [...]uint16{0, 4, 8, 13, 19, 25, 28, 31, 34, 42, 46, 50, 57, 66, 71, 73, 79, 83, 87, 91, 100, 108, 116, 123, 129, 134, 137, 143, 151, 154, 160, 169, 176, 179, 184, 193, 203, 209, 214, 220, 228, 236, 245, 254, 264, 272, 280, 287, 297, 304, 314, 318, 327, 331, 341, 350, 358, 366, 371, 379, 387, 400, 407, 413, 430, 433, 437, 442, 452, 465, 473, 481, 486, 495, 503, 512, 518, 525, 535, 544, 554, 564, 574, 579, 590, 597, 598, 599, 600, 601, 602, 613, 620, 631, 639, 652, 665, 673, 678, 686, 693, 701, 713, 724, 735, 745, 752, 759, 764, 771, 778, 786, 792, 801, 810, 818, 827, 839, 845, 852, 858, 863, 871, 877, 883, 890, 893, 900, 907, 917, 931, 946, 959} func (i syncMarker) String() string { i -= 1 From a294e4e798d75ee9cf167a75189b1b0dff3664f1 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 15 Jun 2021 12:46:11 -0400 Subject: [PATCH 423/940] math/rand: mention half-open intervals explicitly If someone sees "in [0,n)" it might look like a typo. Saying "in the half-open interval [0,n)" will give people something to search the web for (half-open interval). Change-Id: I3c343f0a7171891e106e709ca77ab9db5daa5c84 Reviewed-on: https://go-review.googlesource.com/c/go/+/328210 Trust: Russ Cox Run-TryBot: Russ Cox Reviewed-by: Ian Lance Taylor TryBot-Result: Go Bot --- src/math/rand/rand.go | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/math/rand/rand.go b/src/math/rand/rand.go index 8179d9f4649..13f20ca5efb 100644 --- a/src/math/rand/rand.go +++ b/src/math/rand/rand.go @@ -12,9 +12,6 @@ // The default Source is safe for concurrent use by multiple goroutines, but // Sources created by NewSource are not. // -// Mathematical interval notation such as [0, n) is used throughout the -// documentation for this package. -// // This package's outputs might be easily predictable regardless of how it's // seeded. For random numbers suitable for security-sensitive work, see the // crypto/rand package. @@ -106,7 +103,7 @@ func (r *Rand) Int() int { return int(u << 1 >> 1) // clear sign bit if int == int32 } -// Int63n returns, as an int64, a non-negative pseudo-random number in [0,n). +// Int63n returns, as an int64, a non-negative pseudo-random number in the half-open interval [0,n). // It panics if n <= 0. func (r *Rand) Int63n(n int64) int64 { if n <= 0 { @@ -123,7 +120,7 @@ func (r *Rand) Int63n(n int64) int64 { return v % n } -// Int31n returns, as an int32, a non-negative pseudo-random number in [0,n). +// Int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n). // It panics if n <= 0. func (r *Rand) Int31n(n int32) int32 { if n <= 0 { @@ -140,7 +137,7 @@ func (r *Rand) Int31n(n int32) int32 { return v % n } -// int31n returns, as an int32, a non-negative pseudo-random number in [0,n). +// int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n). // n must be > 0, but int31n does not check this; the caller must ensure it. // int31n exists because Int31n is inefficient, but Go 1 compatibility // requires that the stream of values produced by math/rand remain unchanged. @@ -164,7 +161,7 @@ func (r *Rand) int31n(n int32) int32 { return int32(prod >> 32) } -// Intn returns, as an int, a non-negative pseudo-random number in [0,n). +// Intn returns, as an int, a non-negative pseudo-random number in the half-open interval [0,n). // It panics if n <= 0. func (r *Rand) Intn(n int) int { if n <= 0 { @@ -176,7 +173,7 @@ func (r *Rand) Intn(n int) int { return int(r.Int63n(int64(n))) } -// Float64 returns, as a float64, a pseudo-random number in [0.0,1.0). +// Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0). func (r *Rand) Float64() float64 { // A clearer, simpler implementation would be: // return float64(r.Int63n(1<<53)) / (1<<53) @@ -202,7 +199,7 @@ again: return f } -// Float32 returns, as a float32, a pseudo-random number in [0.0,1.0). +// Float32 returns, as a float32, a pseudo-random number in the half-open interval [0.0,1.0). func (r *Rand) Float32() float32 { // Same rationale as in Float64: we want to preserve the Go 1 value // stream except we want to fix it not to return 1.0 @@ -215,7 +212,8 @@ again: return f } -// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n). +// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers +// in the half-open interval [0,n). func (r *Rand) Perm(n int) []int { m := make([]int, n) // In the following loop, the iteration when i=0 always swaps m[0] with m[0]. @@ -323,31 +321,31 @@ func Int31() int32 { return globalRand.Int31() } // Int returns a non-negative pseudo-random int from the default Source. func Int() int { return globalRand.Int() } -// Int63n returns, as an int64, a non-negative pseudo-random number in [0,n) +// Int63n returns, as an int64, a non-negative pseudo-random number in the half-open interval [0,n) // from the default Source. // It panics if n <= 0. func Int63n(n int64) int64 { return globalRand.Int63n(n) } -// Int31n returns, as an int32, a non-negative pseudo-random number in [0,n) +// Int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n) // from the default Source. // It panics if n <= 0. func Int31n(n int32) int32 { return globalRand.Int31n(n) } -// Intn returns, as an int, a non-negative pseudo-random number in [0,n) +// Intn returns, as an int, a non-negative pseudo-random number in the half-open interval [0,n) // from the default Source. // It panics if n <= 0. func Intn(n int) int { return globalRand.Intn(n) } -// Float64 returns, as a float64, a pseudo-random number in [0.0,1.0) +// Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0) // from the default Source. func Float64() float64 { return globalRand.Float64() } -// Float32 returns, as a float32, a pseudo-random number in [0.0,1.0) +// Float32 returns, as a float32, a pseudo-random number in the half-open interval [0.0,1.0) // from the default Source. func Float32() float32 { return globalRand.Float32() } -// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n) -// from the default Source. +// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers +// in the half-open interval [0,n) from the default Source. func Perm(n int) []int { return globalRand.Perm(n) } // Shuffle pseudo-randomizes the order of elements using the default Source. From 132ea56d292eac0226eef4bc32d784b0300c3bce Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 14 Jun 2021 19:21:14 -0700 Subject: [PATCH 424/940] [dev.typeparams] cmd/compile: fix crawling of embeddable types In reflectdata, we have a hack to only apply inlining for (*T).M wrappers generated around T.M. This was a hack because I didn't understand at the time why other cases were failing. But I understand now: during export, we generally skip exporting the inline bodies for unexported methods (unless they're reachable through some other exported method). But it doesn't take into account that embedding a type requires generating wrappers for promoted methods, including imported, unexported methods. For example: package a type T struct{} func (T) m() {} // previously omitted by exported package b import "./a" type U struct { a.T } // needs U.m -> T.m wrapper This CL adds extra logic to the crawler to recognize that T is an exported type directly reachable by the user, so *all* of its methods need to be re-exported. This finally allows simplifying reflectdata.methodWrapper to always call inline.InlineCalls. Change-Id: I25031d41fd6b6cd69d31c6a864b5329cdb5780e2 Reviewed-on: https://go-review.googlesource.com/c/go/+/327872 Trust: Matthew Dempsky Reviewed-by: Cuong Manh Le --- .../compile/internal/reflectdata/reflect.go | 41 ++++++++----- src/cmd/compile/internal/typecheck/crawler.go | 58 ++++++++++++++++++- 2 files changed, 81 insertions(+), 18 deletions(-) diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index 5516f707fa9..f4a06199353 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -1795,20 +1795,24 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy return lsym } - // Only generate (*T).M wrappers for T.M in T's own package, except for - // instantiated methods. - if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type && - rcvr.Elem().Sym() != nil && rcvr.Elem().Sym().Pkg != types.LocalPkg && - !rcvr.Elem().IsFullyInstantiated() { - return lsym + // imported reports whether typ is a defined type that was declared + // in an imported package, and therefore must have been compiled in + // that package. + importedType := func(typ *types.Type) bool { + return typ.Sym() != nil && typ.Sym().Pkg != types.LocalPkg && + + // Exception: need wrapper for error.Error (#29304). + // TODO(mdempsky): Put this in package runtime, like we do for + // the type descriptors for predeclared types. + typ != types.ErrorType && + + // Exception: parameterized types may have been instantiated + // with new type arguments, so we don't assume they've been + // compiled before. + !typ.IsFullyInstantiated() } - // Only generate I.M wrappers for I in I's own package - // but keep doing it for error.Error (was issue #29304) - // and methods of instantiated interfaces. - if rcvr.IsInterface() && rcvr != types.ErrorType && - rcvr.Sym() != nil && rcvr.Sym().Pkg != types.LocalPkg && - !rcvr.IsFullyInstantiated() { + if importedType(rcvr) || rcvr.IsPtr() && importedType(rcvr.Elem()) { return lsym } @@ -1922,9 +1926,16 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy ir.CurFunc = fn typecheck.Stmts(fn.Body) - // Inline calls within (*T).M wrappers. This is safe because we only - // generate those wrappers within the same compilation unit as (T).M. - // TODO(mdempsky): Investigate why we can't enable this more generally. + // TODO(mdempsky): Make this unconditional. The exporter now + // includes all of the inline bodies we need, and the "importedType" + // logic above now correctly suppresses compiling out-of-package + // types that we might not have inline bodies for. The only problem + // now is that the extra inlining can now introduce further new + // itabs, and gc.dumpdata's ad hoc compile loop doesn't handle this. + // + // CL 327871 will address this by writing itabs and generating + // wrappers as part of the loop, so we won't have to worry about + // "itabs changed after compile functions loop" errors anymore. if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type && rcvr.Elem().Sym() != nil { inline.InlineCalls(fn) } diff --git a/src/cmd/compile/internal/typecheck/crawler.go b/src/cmd/compile/internal/typecheck/crawler.go index c78a604a8d2..655ac6e4654 100644 --- a/src/cmd/compile/internal/typecheck/crawler.go +++ b/src/cmd/compile/internal/typecheck/crawler.go @@ -15,14 +15,18 @@ import ( // callable by importers are marked with ExportInline so that // iexport.go knows to re-export their inline body. func crawlExports(exports []*ir.Name) { - p := crawler{marked: make(map[*types.Type]bool)} + p := crawler{ + marked: make(map[*types.Type]bool), + embedded: make(map[*types.Type]bool), + } for _, n := range exports { p.markObject(n) } } type crawler struct { - marked map[*types.Type]bool // types already seen by markType + marked map[*types.Type]bool // types already seen by markType + embedded map[*types.Type]bool // types already seen by markEmbed } // markObject visits a reachable object. @@ -31,6 +35,12 @@ func (p *crawler) markObject(n *ir.Name) { p.markInlBody(n) } + // If a declared type name is reachable, users can embed it in their + // own types, which makes even its unexported methods reachable. + if n.Op() == ir.OTYPE { + p.markEmbed(n.Type()) + } + p.markType(n.Type()) } @@ -46,7 +56,7 @@ func (p *crawler) markType(t *types.Type) { } p.marked[t] = true - // If this is a named type, mark all of its associated + // If this is a defined type, mark all of its associated // methods. Skip interface types because t.Methods contains // only their unexpanded method set (i.e., exclusive of // interface embeddings), and the switch statement below @@ -107,6 +117,48 @@ func (p *crawler) markType(t *types.Type) { } } +// markEmbed is similar to markType, but handles finding methods that +// need to be re-exported because t can be embedded in user code +// (possibly transitively). +func (p *crawler) markEmbed(t *types.Type) { + if t.IsPtr() { + // Defined pointer type; not allowed to embed anyway. + if t.Sym() != nil { + return + } + t = t.Elem() + } + + if t.IsInstantiatedGeneric() { + // Re-instantiated types don't add anything new, so don't follow them. + return + } + + if p.embedded[t] { + return + } + p.embedded[t] = true + + // If t is a defined type, then re-export all of its methods. Unlike + // in markType, we include even unexported methods here, because we + // still need to generate wrappers for them, even if the user can't + // refer to them directly. + if t.Sym() != nil && t.Kind() != types.TINTER { + for _, m := range t.Methods().Slice() { + p.markObject(m.Nname.(*ir.Name)) + } + } + + // If t is a struct, recursively visit its embedded fields. + if t.IsStruct() { + for _, f := range t.FieldSlice() { + if f.Embedded != 0 { + p.markEmbed(f.Type) + } + } + } +} + // markInlBody marks n's inline body for export and recursively // ensures all called functions are marked too. func (p *crawler) markInlBody(n *ir.Name) { From 6ea2af0890260fec6cc951b5f426c0464e43266d Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Fri, 11 Jun 2021 16:39:54 -0400 Subject: [PATCH 425/940] cmd/go: add a regression test for #45979 Change-Id: Id7f83b2e6a99af798e55b272b04880ebb588351f Reviewed-on: https://go-review.googlesource.com/c/go/+/328230 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Michael Matloob --- .../testdata/script/mod_get_lazy_indirect.txt | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/cmd/go/testdata/script/mod_get_lazy_indirect.txt diff --git a/src/cmd/go/testdata/script/mod_get_lazy_indirect.txt b/src/cmd/go/testdata/script/mod_get_lazy_indirect.txt new file mode 100644 index 00000000000..60548e8429e --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_lazy_indirect.txt @@ -0,0 +1,38 @@ +# https://golang.org/issue/45979: after 'go get' on a package, +# that package should be importable without error. + + +# We start out with an unresolved dependency. +# 'go list' suggests that we run 'go get' on that dependency. + +! go list -deps . +stderr '^m.go:3:8: no required module provides package rsc\.io/quote; to add it:\n\tgo get rsc.io/quote$' + + +# Unfortunately, the suggested 'go get' command leaves us with another problem. +# +# TODO(#45979): After 'go get', the 'go list' command from above should succeed. + +go get rsc.io/quote + +! go list -deps . +stderr '^go: updates to go.mod needed; to update it:\n\tgo mod tidy' +[!short] ! go build . +stderr '^go: updates to go.mod needed; to update it:\n\tgo mod tidy' + + +# After running the suggested 'go mod tidy' command, the build +# should succeed. +go mod tidy +go list -deps . +[!short] go build . + + +-- go.mod -- +module example.com/m + +go 1.17 +-- m.go -- +package m + +import _ "rsc.io/quote" From 0e67ce3d28320e816dd8e7cf7d701c1804fb977e Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Tue, 15 Jun 2021 12:05:01 -0400 Subject: [PATCH 426/940] cmd/go: in lazy modules, add transitive imports for 'go get' arguments I needed to also update TestScript/mod_sumdb_golang. It had been relying on 'go list -mod=mod' to add both the go.mod and go.sum entries for the named package, but when 'go get' actually adds all of the needed dependencies, lazy loading kicks in and 'go list' doesn't end up needing the checksums for go.mod files. We didn't detect the skew before because the 'go list' command was (unexpectedly) also adding the missing dependencies, which triggered a deep scan of the complete module graph. For #45979 Change-Id: Ica917dee22c83ffa71c6ad0f2e189f911b73edf4 Reviewed-on: https://go-review.googlesource.com/c/go/+/328231 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Michael Matloob --- src/cmd/go/internal/modget/get.go | 1 + src/cmd/go/internal/modload/buildlist.go | 12 ++++--- src/cmd/go/internal/modload/init.go | 2 +- src/cmd/go/internal/modload/load.go | 25 +++++++++++-- .../testdata/script/mod_get_lazy_indirect.txt | 26 ++++++++------ .../go/testdata/script/mod_sumdb_golang.txt | 36 ++++++++++++++++--- 6 files changed, 79 insertions(+), 23 deletions(-) diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go index 8eee723f89b..ea5c4e229a5 100644 --- a/src/cmd/go/internal/modget/get.go +++ b/src/cmd/go/internal/modget/get.go @@ -1153,6 +1153,7 @@ func (r *resolver) loadPackages(ctx context.Context, patterns []string, findPack Tags: imports.AnyTags(), VendorModulesInGOROOTSrc: true, LoadTests: *getT, + AssumeRootsImported: true, // After 'go get foo', imports of foo should build. SilencePackageErrors: true, // May be fixed by subsequent upgrades or downgrades. } diff --git a/src/cmd/go/internal/modload/buildlist.go b/src/cmd/go/internal/modload/buildlist.go index e5db41c7486..64eaa16e8b1 100644 --- a/src/cmd/go/internal/modload/buildlist.go +++ b/src/cmd/go/internal/modload/buildlist.go @@ -443,7 +443,7 @@ func expandGraph(ctx context.Context, rs *Requirements) (*Requirements, *ModuleG // roots — but in a lazy module it may pull in previously-irrelevant // transitive dependencies. - newRS, rsErr := updateRoots(ctx, rs.direct, rs, nil, nil) + newRS, rsErr := updateRoots(ctx, rs.direct, rs, nil, nil, false) if rsErr != nil { // Failed to update roots, perhaps because of an error in a transitive // dependency needed for the update. Return the original Requirements @@ -517,11 +517,11 @@ func tidyRoots(ctx context.Context, rs *Requirements, pkgs []*loadPkg) (*Require return tidyLazyRoots(ctx, rs.direct, pkgs) } -func updateRoots(ctx context.Context, direct map[string]bool, rs *Requirements, pkgs []*loadPkg, add []module.Version) (*Requirements, error) { +func updateRoots(ctx context.Context, direct map[string]bool, rs *Requirements, pkgs []*loadPkg, add []module.Version, rootsImported bool) (*Requirements, error) { if rs.depth == eager { return updateEagerRoots(ctx, direct, rs, add) } - return updateLazyRoots(ctx, direct, rs, pkgs, add) + return updateLazyRoots(ctx, direct, rs, pkgs, add, rootsImported) } // tidyLazyRoots returns a minimal set of root requirements that maintains the @@ -661,7 +661,7 @@ func tidyLazyRoots(ctx context.Context, direct map[string]bool, pkgs []*loadPkg) // // (See https://golang.org/design/36460-lazy-module-loading#invariants for more // detail.) -func updateLazyRoots(ctx context.Context, direct map[string]bool, rs *Requirements, pkgs []*loadPkg, add []module.Version) (*Requirements, error) { +func updateLazyRoots(ctx context.Context, direct map[string]bool, rs *Requirements, pkgs []*loadPkg, add []module.Version, rootsImported bool) (*Requirements, error) { roots := rs.rootModules rootsUpgraded := false @@ -688,6 +688,10 @@ func updateLazyRoots(ctx context.Context, direct map[string]bool, rs *Requiremen // // (This is the “import invariant” that makes lazy loading possible.) + case rootsImported && pkg.flags.has(pkgFromRoot): + // pkg is a transitive dependency of some root, and we are treating the + // roots as if they are imported by the main module (as in 'go get'). + case pkg.flags.has(pkgIsRoot): // pkg is a root of the package-import graph. (Generally this means that // it matches a command-line argument.) We want future invocations of the diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go index eb9cfe629b3..cbc7289afa5 100644 --- a/src/cmd/go/internal/modload/init.go +++ b/src/cmd/go/internal/modload/init.go @@ -661,7 +661,7 @@ func requirementsFromModFile(ctx context.Context) *Requirements { for _, n := range mPathCount { if n > 1 { var err error - rs, err = updateRoots(ctx, rs.direct, rs, nil, nil) + rs, err = updateRoots(ctx, rs.direct, rs, nil, nil, false) if err != nil { base.Fatalf("go: %v", err) } diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go index a9d1777125e..a3a8021c049 100644 --- a/src/cmd/go/internal/modload/load.go +++ b/src/cmd/go/internal/modload/load.go @@ -171,6 +171,11 @@ type PackageOpts struct { // if the flag is set to "readonly" (the default) or "vendor". ResolveMissingImports bool + // AssumeRootsImported indicates that the transitive dependencies of the root + // packages should be treated as if those roots will be imported by the main + // module. + AssumeRootsImported bool + // AllowPackage, if non-nil, is called after identifying the module providing // each package. If AllowPackage returns a non-nil error, that error is set // for the package, and the imports and test of that package will not be @@ -875,6 +880,11 @@ const ( // are also roots (and must be marked pkgIsRoot). pkgIsRoot + // pkgFromRoot indicates that the package is in the transitive closure of + // imports starting at the roots. (Note that every package marked as pkgIsRoot + // is also trivially marked pkgFromRoot.) + pkgFromRoot + // pkgImportsLoaded indicates that the imports and testImports fields of a // loadPkg have been populated. pkgImportsLoaded @@ -1068,7 +1078,7 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader { // iteration so we don't need to also update it here. (That would waste time // computing a "direct" map that we'll have to recompute later anyway.) direct := ld.requirements.direct - rs, err := updateRoots(ctx, direct, ld.requirements, noPkgs, toAdd) + rs, err := updateRoots(ctx, direct, ld.requirements, noPkgs, toAdd, ld.AssumeRootsImported) if err != nil { // If an error was found in a newly added module, report the package // import stack instead of the module requirement stack. Packages @@ -1274,7 +1284,7 @@ func (ld *loader) updateRequirements(ctx context.Context) (changed bool, err err addRoots = tidy.rootModules } - rs, err = updateRoots(ctx, direct, rs, ld.pkgs, addRoots) + rs, err = updateRoots(ctx, direct, rs, ld.pkgs, addRoots, ld.AssumeRootsImported) if err != nil { // We don't actually know what even the root requirements are supposed to be, // so we can't proceed with loading. Return the error to the caller @@ -1433,6 +1443,9 @@ func (ld *loader) applyPkgFlags(ctx context.Context, pkg *loadPkg, flags loadPkg // This package matches a root pattern by virtue of being in "all". flags |= pkgIsRoot } + if flags.has(pkgIsRoot) { + flags |= pkgFromRoot + } old := pkg.flags.update(flags) new := old | flags @@ -1487,6 +1500,12 @@ func (ld *loader) applyPkgFlags(ctx context.Context, pkg *loadPkg, flags loadPkg ld.applyPkgFlags(ctx, dep, pkgInAll) } } + + if new.has(pkgFromRoot) && !old.has(pkgFromRoot|pkgImportsLoaded) { + for _, dep := range pkg.imports { + ld.applyPkgFlags(ctx, dep, pkgFromRoot) + } + } } // preloadRootModules loads the module requirements needed to identify the @@ -1549,7 +1568,7 @@ func (ld *loader) preloadRootModules(ctx context.Context, rootPkgs []string) (ch } module.Sort(toAdd) - rs, err := updateRoots(ctx, ld.requirements.direct, ld.requirements, nil, toAdd) + rs, err := updateRoots(ctx, ld.requirements.direct, ld.requirements, nil, toAdd, ld.AssumeRootsImported) if err != nil { // We are missing some root dependency, and for some reason we can't load // enough of the module dependency graph to add the missing root. Package diff --git a/src/cmd/go/testdata/script/mod_get_lazy_indirect.txt b/src/cmd/go/testdata/script/mod_get_lazy_indirect.txt index 60548e8429e..13640cbc235 100644 --- a/src/cmd/go/testdata/script/mod_get_lazy_indirect.txt +++ b/src/cmd/go/testdata/script/mod_get_lazy_indirect.txt @@ -9,23 +9,27 @@ stderr '^m.go:3:8: no required module provides package rsc\.io/quote; to add it:\n\tgo get rsc.io/quote$' -# Unfortunately, the suggested 'go get' command leaves us with another problem. +# When we run the suggested 'go get' command, the new dependency can be used +# immediately, even though 'go get' marks it as 'indirect'. # -# TODO(#45979): After 'go get', the 'go list' command from above should succeed. +# TODO(#45979): Should we swap this default state, so that new dependencies +# are added as direct unless otherwise noted? go get rsc.io/quote +grep 'rsc.io/quote v\d+\.\d+\.\d+ // indirect$' go.mod +! grep 'rsc.io/quote v\d+\.\d+\.\d+$' go.mod -! go list -deps . -stderr '^go: updates to go.mod needed; to update it:\n\tgo mod tidy' -[!short] ! go build . -stderr '^go: updates to go.mod needed; to update it:\n\tgo mod tidy' - - -# After running the suggested 'go mod tidy' command, the build -# should succeed. -go mod tidy go list -deps . +! stderr . [!short] go build . +[!short] ! stderr . + + +# 'go get .' (or 'go mod tidy') removes the indirect mark. + +go get . +grep 'rsc.io/quote v\d+\.\d+\.\d+$' go.mod +! grep 'rsc.io/quote v\d+\.\d+\.\d+ // indirect$' go.mod -- go.mod -- diff --git a/src/cmd/go/testdata/script/mod_sumdb_golang.txt b/src/cmd/go/testdata/script/mod_sumdb_golang.txt index cc0b0da474a..becd88b52e7 100644 --- a/src/cmd/go/testdata/script/mod_sumdb_golang.txt +++ b/src/cmd/go/testdata/script/mod_sumdb_golang.txt @@ -10,45 +10,73 @@ go env GOSUMDB stdout '^sum.golang.org$' # Download direct from github. + [!net] skip [!exec:git] skip env GOSUMDB=sum.golang.org env GOPROXY=direct + go get -d rsc.io/quote@v1.5.2 cp go.sum saved.sum + # Download from proxy.golang.org with go.sum entry already. # Use 'go list' instead of 'go get' since the latter may download extra go.mod # files not listed in go.sum. + go clean -modcache env GOSUMDB= env GOPROXY= -go list -x -deps rsc.io/quote + +go list -x -m all # Download go.mod files. ! stderr github stderr proxy.golang.org/rsc.io/quote ! stderr sum.golang.org/tile ! stderr sum.golang.org/lookup/rsc.io/quote + +go list -x -deps rsc.io/quote # Download module source. +! stderr github +stderr proxy.golang.org/rsc.io/quote +! stderr sum.golang.org/tile +! stderr sum.golang.org/lookup/rsc.io/quote + cmp go.sum saved.sum + # Download again. # Should use the checksum database to validate new go.sum lines, # but not need to fetch any new data from the proxy. + rm go.sum -go list -mod=mod -x rsc.io/quote + +go list -mod=mod -x -m all # Add checksums for go.mod files. +stderr sum.golang.org/tile ! stderr github ! stderr proxy.golang.org/rsc.io/quote -stderr sum.golang.org/tile stderr sum.golang.org/lookup/rsc.io/quote + +go list -mod=mod -x rsc.io/quote # Add checksums for module source. +! stderr . # Adds checksums, but for entities already in the module cache. + cmp go.sum saved.sum + # test fallback to direct + env TESTGOPROXY404=1 go clean -modcache rm go.sum -go list -mod=mod -x rsc.io/quote + +go list -mod=mod -x -m all # Download go.mod files stderr 'proxy.golang.org.*404 testing' stderr github.com/rsc + +go list -mod=mod -x rsc.io/quote # Download module source. +stderr 'proxy.golang.org.*404 testing' +stderr github.com/rsc + cmp go.sum saved.sum + -- go.mod -- module m From dd95a4e3dbe1e060b59840efd7311e8d5e82c08c Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 14 Jun 2021 16:26:26 -0700 Subject: [PATCH 427/940] [dev.typeparams] cmd/compile: simplify SSA devirtualization This CL implements a few improvements to SSA devirtualization to make it simpler and more general: 1. Change reflectdata.ITabAddr to now immediately generate the wrapper functions and write out the itab symbol data. Previously, these were each handled by separate phases later on. 2. Removes the hack in typecheck where we marked itabs that we expected to need later. Instead, the calls to ITabAddr in walk now handle generating the wrappers. 3. Changes the SSA interface call devirtualization algorithm to just use the itab symbol data (namely, its relocations) to figure out what pointer is available in memory at the given offset. This decouples it somewhat from reflectdata. Change-Id: I8fe06922af8f8a1e7c93f5aff2b60ff59b8e7114 Reviewed-on: https://go-review.googlesource.com/c/go/+/327871 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Trust: Matthew Dempsky Reviewed-by: Cherry Mui --- src/cmd/compile/internal/escape/escape.go | 2 +- src/cmd/compile/internal/gc/main.go | 21 +- src/cmd/compile/internal/gc/obj.go | 7 +- .../compile/internal/reflectdata/reflect.go | 196 ++++++------------ src/cmd/compile/internal/ssa/config.go | 6 - src/cmd/compile/internal/ssa/rewrite.go | 36 ++-- src/cmd/compile/internal/ssagen/ssa.go | 4 - src/cmd/compile/internal/typecheck/subr.go | 8 - .../compile/internal/typecheck/typecheck.go | 1 - 9 files changed, 92 insertions(+), 189 deletions(-) diff --git a/src/cmd/compile/internal/escape/escape.go b/src/cmd/compile/internal/escape/escape.go index 842b0f4a7e0..e3727bca27c 100644 --- a/src/cmd/compile/internal/escape/escape.go +++ b/src/cmd/compile/internal/escape/escape.go @@ -673,7 +673,7 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) { n := n.(*ir.BinaryExpr) // Note: n.X is not needed because it can never point to memory that might escape. e.expr(k, n.Y) - case ir.OIDATA: + case ir.OIDATA, ir.OSPTR: n := n.(*ir.UnaryExpr) e.expr(k, n.X) case ir.OSLICE2ARRPTR: diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index ce50cbb4c2e..c0346c02065 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -181,7 +181,6 @@ func Main(archInit func(*ssagen.ArchInfo)) { typecheck.Target = new(ir.Package) - typecheck.NeedITab = func(t, iface *types.Type) { reflectdata.ITabAddr(t, iface) } typecheck.NeedRuntimeType = reflectdata.NeedRuntimeType // TODO(rsc): TypeSym for lock? base.AutogeneratedPos = makePos(src.NewFileBase("", ""), 1, 0) @@ -193,6 +192,11 @@ func Main(archInit func(*ssagen.ArchInfo)) { dwarfgen.RecordPackageName() + // Prepare for backend processing. This must happen before pkginit, + // because it generates itabs for initializing global variables. + typecheck.InitRuntime() + ssagen.InitConfig() + // Build init task. if initTask := pkginit.Task(); initTask != nil { typecheck.Export(initTask) @@ -252,6 +256,11 @@ func Main(archInit func(*ssagen.ArchInfo)) { base.Timer.Start("fe", "escapes") escape.Funcs(typecheck.Target.Decls) + // TODO(mdempsky): This is a hack. We need a proper, global work + // queue for scheduling function compilation so components don't + // need to adjust their behavior depending on when they're called. + reflectdata.AfterGlobalEscapeAnalysis = true + // Collect information for go:nowritebarrierrec // checking. This must happen before transforming closures during Walk // We'll do the final check after write barriers are @@ -260,17 +269,7 @@ func Main(archInit func(*ssagen.ArchInfo)) { ssagen.EnableNoWriteBarrierRecCheck() } - // Prepare for SSA compilation. - // This must be before CompileITabs, because CompileITabs - // can trigger function compilation. - typecheck.InitRuntime() - ssagen.InitConfig() - - // Just before compilation, compile itabs found on - // the right side of OCONVIFACE so that methods - // can be de-virtualized during compilation. ir.CurFunc = nil - reflectdata.CompileITabs() // Compile top level functions. // Don't use range--walk can add functions to Target.Decls. diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go index 8a2ff75583b..440f898211f 100644 --- a/src/cmd/compile/internal/gc/obj.go +++ b/src/cmd/compile/internal/gc/obj.go @@ -117,7 +117,7 @@ func dumpdata() { addsignats(typecheck.Target.Externs) reflectdata.WriteRuntimeTypes() reflectdata.WriteTabs() - numPTabs, numITabs := reflectdata.CountTabs() + numPTabs := reflectdata.CountPTabs() reflectdata.WriteImportStrings() reflectdata.WriteBasicTypes() dumpembeds() @@ -158,13 +158,10 @@ func dumpdata() { if numExports != len(typecheck.Target.Exports) { base.Fatalf("Target.Exports changed after compile functions loop") } - newNumPTabs, newNumITabs := reflectdata.CountTabs() + newNumPTabs := reflectdata.CountPTabs() if newNumPTabs != numPTabs { base.Fatalf("ptabs changed after compile functions loop") } - if newNumITabs != numITabs { - base.Fatalf("itabs changed after compile functions loop") - } } func dumpLinkerObj(bout *bio.Writer) { diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index f4a06199353..9e070895a0b 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -28,23 +28,13 @@ import ( "cmd/internal/src" ) -type itabEntry struct { - t, itype *types.Type - lsym *obj.LSym // symbol of the itab itself - - // symbols of each method in - // the itab, sorted by byte offset; - // filled in by CompileITabs - entries []*obj.LSym -} - type ptabEntry struct { s *types.Sym t *types.Type } -func CountTabs() (numPTabs, numITabs int) { - return len(ptabs), len(itabs) +func CountPTabs() int { + return len(ptabs) } // runtime interface and reflection data structures @@ -56,7 +46,6 @@ var ( gcsymmu sync.Mutex // protects gcsymset and gcsymslice gcsymset = make(map[*types.Type]struct{}) - itabs []itabEntry ptabs []*ir.Name ) @@ -841,16 +830,16 @@ func TypePtr(t *types.Type) *ir.AddrExpr { return typecheck.Expr(typecheck.NodAddr(n)).(*ir.AddrExpr) } -func ITabAddr(t, itype *types.Type) *ir.AddrExpr { - if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() || !itype.IsInterface() || itype.IsEmptyInterface() { - base.Fatalf("ITabAddr(%v, %v)", t, itype) - } - s, existed := ir.Pkgs.Itab.LookupOK(t.ShortString() + "," + itype.ShortString()) +// ITabAddr returns an expression representing a pointer to the itab +// for concrete type typ implementing interface iface. +func ITabAddr(typ, iface *types.Type) *ir.AddrExpr { + s, existed := ir.Pkgs.Itab.LookupOK(typ.ShortString() + "," + iface.ShortString()) + lsym := s.Linksym() + if !existed { - itabs = append(itabs, itabEntry{t: t, itype: itype, lsym: s.Linksym()}) + writeITab(lsym, typ, iface) } - lsym := s.Linksym() n := ir.NewLinksymExpr(base.Pos, lsym, types.Types[types.TUINT8]) return typecheck.Expr(typecheck.NodAddr(n)).(*ir.AddrExpr) } @@ -1223,83 +1212,6 @@ func InterfaceMethodOffset(ityp *types.Type, i int64) int64 { return int64(commonSize()+4*types.PtrSize+uncommonSize(ityp)) + i*8 } -// for each itabEntry, gather the methods on -// the concrete type that implement the interface -func CompileITabs() { - for i := range itabs { - tab := &itabs[i] - methods := genfun(tab.t, tab.itype) - if len(methods) == 0 { - continue - } - tab.entries = methods - } -} - -// for the given concrete type and interface -// type, return the (sorted) set of methods -// on the concrete type that implement the interface -func genfun(t, it *types.Type) []*obj.LSym { - if t == nil || it == nil { - return nil - } - sigs := imethods(it) - methods := methods(t) - out := make([]*obj.LSym, 0, len(sigs)) - // TODO(mdempsky): Short circuit before calling methods(t)? - // See discussion on CL 105039. - if len(sigs) == 0 { - return nil - } - - // both sigs and methods are sorted by name, - // so we can find the intersect in a single pass - for _, m := range methods { - if m.name == sigs[0].name { - out = append(out, m.isym) - sigs = sigs[1:] - if len(sigs) == 0 { - break - } - } - } - - if len(sigs) != 0 { - base.Fatalf("incomplete itab") - } - - return out -} - -// ITabSym uses the information gathered in -// CompileITabs to de-virtualize interface methods. -// Since this is called by the SSA backend, it shouldn't -// generate additional Nodes, Syms, etc. -func ITabSym(it *obj.LSym, offset int64) *obj.LSym { - var syms []*obj.LSym - if it == nil { - return nil - } - - for i := range itabs { - e := &itabs[i] - if e.lsym == it { - syms = e.entries - break - } - } - if syms == nil { - return nil - } - - // keep this arithmetic in sync with *itab layout - methodnum := int((offset - 2*int64(types.PtrSize) - 8) / int64(types.PtrSize)) - if methodnum >= len(syms) { - return nil - } - return syms[methodnum] -} - // NeedRuntimeType ensures that a runtime type descriptor is emitted for t. func NeedRuntimeType(t *types.Type) { if t.HasTParam() { @@ -1346,29 +1258,57 @@ func WriteRuntimeTypes() { } } -func WriteTabs() { - // process itabs - for _, i := range itabs { - // dump empty itab symbol into i.sym - // type itab struct { - // inter *interfacetype - // _type *_type - // hash uint32 - // _ [4]byte - // fun [1]uintptr // variable sized - // } - o := objw.SymPtr(i.lsym, 0, writeType(i.itype), 0) - o = objw.SymPtr(i.lsym, o, writeType(i.t), 0) - o = objw.Uint32(i.lsym, o, types.TypeHash(i.t)) // copy of type hash - o += 4 // skip unused field - for _, fn := range genfun(i.t, i.itype) { - o = objw.SymPtrWeak(i.lsym, o, fn, 0) // method pointer for each method - } - // Nothing writes static itabs, so they are read only. - objw.Global(i.lsym, int32(o), int16(obj.DUPOK|obj.RODATA)) - i.lsym.Set(obj.AttrContentAddressable, true) +// writeITab writes the itab for concrete type typ implementing +// interface iface. +func writeITab(lsym *obj.LSym, typ, iface *types.Type) { + // TODO(mdempsky): Fix methodWrapper, geneq, and genhash (and maybe + // others) to stop clobbering these. + oldpos, oldfn := base.Pos, ir.CurFunc + defer func() { base.Pos, ir.CurFunc = oldpos, oldfn }() + + if typ == nil || (typ.IsPtr() && typ.Elem() == nil) || typ.IsUntyped() || iface == nil || !iface.IsInterface() || iface.IsEmptyInterface() { + base.Fatalf("writeITab(%v, %v)", typ, iface) } + sigs := iface.AllMethods().Slice() + entries := make([]*obj.LSym, 0, len(sigs)) + + // both sigs and methods are sorted by name, + // so we can find the intersection in a single pass + for _, m := range methods(typ) { + if m.name == sigs[0].Sym { + entries = append(entries, m.isym) + sigs = sigs[1:] + if len(sigs) == 0 { + break + } + } + } + if len(sigs) != 0 { + base.Fatalf("incomplete itab") + } + + // dump empty itab symbol into i.sym + // type itab struct { + // inter *interfacetype + // _type *_type + // hash uint32 + // _ [4]byte + // fun [1]uintptr // variable sized + // } + o := objw.SymPtr(lsym, 0, writeType(iface), 0) + o = objw.SymPtr(lsym, o, writeType(typ), 0) + o = objw.Uint32(lsym, o, types.TypeHash(typ)) // copy of type hash + o += 4 // skip unused field + for _, fn := range entries { + o = objw.SymPtrWeak(lsym, o, fn, 0) // method pointer for each method + } + // Nothing writes static itabs, so they are read only. + objw.Global(lsym, int32(o), int16(obj.DUPOK|obj.RODATA)) + lsym.Set(obj.AttrContentAddressable, true) +} + +func WriteTabs() { // process ptabs if types.LocalPkg.Name == "main" && len(ptabs) > 0 { ot := 0 @@ -1926,20 +1866,10 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy ir.CurFunc = fn typecheck.Stmts(fn.Body) - // TODO(mdempsky): Make this unconditional. The exporter now - // includes all of the inline bodies we need, and the "importedType" - // logic above now correctly suppresses compiling out-of-package - // types that we might not have inline bodies for. The only problem - // now is that the extra inlining can now introduce further new - // itabs, and gc.dumpdata's ad hoc compile loop doesn't handle this. - // - // CL 327871 will address this by writing itabs and generating - // wrappers as part of the loop, so we won't have to worry about - // "itabs changed after compile functions loop" errors anymore. - if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type && rcvr.Elem().Sym() != nil { + if AfterGlobalEscapeAnalysis { inline.InlineCalls(fn) + escape.Batch([]*ir.Func{fn}, false) } - escape.Batch([]*ir.Func{fn}, false) ir.CurFunc = nil typecheck.Target.Decls = append(typecheck.Target.Decls, fn) @@ -1947,6 +1877,12 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy return lsym } +// AfterGlobalEscapeAnalysis tracks whether package gc has already +// performed the main, global escape analysis pass. If so, +// methodWrapper takes responsibility for escape analyzing any +// generated wrappers. +var AfterGlobalEscapeAnalysis bool + var ZeroSize int64 // MarkTypeUsedInInterface marks that type t is converted to an interface. diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index 61c65f9e54c..b08a3943686 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -149,12 +149,6 @@ type Frontend interface { // for the parts of that compound type. SplitSlot(parent *LocalSlot, suffix string, offset int64, t *types.Type) LocalSlot - // DerefItab dereferences an itab function - // entry, given the symbol of the itab and - // the byte offset of the function pointer. - // It may return nil. - DerefItab(sym *obj.LSym, offset int64) *obj.LSym - // Line returns a string describing the given position. Line(src.XPos) string diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index 375c4d5a560..115d5639333 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -745,27 +745,21 @@ func uaddOvf(a, b int64) bool { return uint64(a)+uint64(b) < uint64(a) } -// de-virtualize an InterCall -// 'sym' is the symbol for the itab -func devirt(v *Value, aux Aux, sym Sym, offset int64) *AuxCall { - f := v.Block.Func - n, ok := sym.(*obj.LSym) - if !ok { +// loadLSymOffset simulates reading a word at an offset into a +// read-only symbol's runtime memory. If it would read a pointer to +// another symbol, that symbol is returned. Otherwise, it returns nil. +func loadLSymOffset(lsym *obj.LSym, offset int64) *obj.LSym { + if lsym.Type != objabi.SRODATA { return nil } - lsym := f.fe.DerefItab(n, offset) - if f.pass.debug > 0 { - if lsym != nil { - f.Warnl(v.Pos, "de-virtualizing call") - } else { - f.Warnl(v.Pos, "couldn't de-virtualize call") + + for _, r := range lsym.R { + if int64(r.Off) == offset && r.Type&^objabi.R_WEAK == objabi.R_ADDR && r.Add == 0 { + return r.Sym } } - if lsym == nil { - return nil - } - va := aux.(*AuxCall) - return StaticAuxCall(lsym, va.abiInfo) + + return nil } // de-virtualize an InterLECall @@ -776,18 +770,14 @@ func devirtLESym(v *Value, aux Aux, sym Sym, offset int64) *obj.LSym { return nil } - f := v.Block.Func - lsym := f.fe.DerefItab(n, offset) - if f.pass.debug > 0 { + lsym := loadLSymOffset(n, offset) + if f := v.Block.Func; f.pass.debug > 0 { if lsym != nil { f.Warnl(v.Pos, "de-virtualizing call") } else { f.Warnl(v.Pos, "couldn't de-virtualize call") } } - if lsym == nil { - return nil - } return lsym } diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 0fbb39cfbb0..7a6bf878e1b 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -7401,10 +7401,6 @@ func (e *ssafn) Auto(pos src.XPos, t *types.Type) *ir.Name { return typecheck.TempAt(pos, e.curfn, t) // Note: adds new auto to e.curfn.Func.Dcl list } -func (e *ssafn) DerefItab(it *obj.LSym, offset int64) *obj.LSym { - return reflectdata.ITabSym(it, offset) -} - // SplitSlot returns a slot representing the data of parent starting at offset. func (e *ssafn) SplitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t *types.Type) ssa.LocalSlot { node := parent.N diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index 0e306eaea83..79b2402fe70 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -379,14 +379,6 @@ func Assignop(src, dst *types.Type) (ir.Op, string) { var missing, have *types.Field var ptr int if implements(src, dst, &missing, &have, &ptr) { - // Call NeedITab/ITabAddr so that (src, dst) - // gets added to itabs early, which allows - // us to de-virtualize calls through this - // type/interface pair later. See CompileITabs in reflect.go - if types.IsDirectIface(src) && !dst.IsEmptyInterface() { - NeedITab(src, dst) - } - return ir.OCONVIFACE, "" } diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go index 8454b8d5b34..b1a4e193d63 100644 --- a/src/cmd/compile/internal/typecheck/typecheck.go +++ b/src/cmd/compile/internal/typecheck/typecheck.go @@ -24,7 +24,6 @@ var inimport bool // set during import var TypecheckAllowed bool var ( - NeedITab = func(t, itype *types.Type) {} NeedRuntimeType = func(*types.Type) {} ) From 1ba2074440a9b82b6e39c42f40b9d04858aa6c75 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 11 Jun 2021 01:09:47 -0700 Subject: [PATCH 428/940] [dev.typeparams] cmd/compile/internal/types2: support local defined types This CL changes types2's instance hashing logic to include position information for function-scope defined types as disambiguation. This isn't ideal, but it worked for getting nested.go passing. Updates #46592. Change-Id: Id83ba0001f44af69b81260306cc8b05e44fc4f09 Reviewed-on: https://go-review.googlesource.com/c/go/+/327170 Run-TryBot: Matthew Dempsky Trust: Matthew Dempsky Trust: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/subst.go | 5 + src/cmd/compile/internal/types2/typestring.go | 36 +++-- test/typeparam/nested.go | 134 ++++++++++++++++++ test/typeparam/nested.out | 4 + 4 files changed, 169 insertions(+), 10 deletions(-) create mode 100644 test/typeparam/nested.go create mode 100644 test/typeparam/nested.out diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index dd8dd74161e..3ef65c2e923 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -425,14 +425,19 @@ func (subst *subster) typ(typ Type) Type { return typ } +var instanceHashing = 0 + // TODO(gri) Eventually, this should be more sophisticated. // It won't work correctly for locally declared types. func instantiatedHash(typ *Named, targs []Type) string { + assert(instanceHashing == 0) + instanceHashing++ var buf bytes.Buffer writeTypeName(&buf, typ.obj, nil) buf.WriteByte('[') writeTypeList(&buf, targs, nil, nil) buf.WriteByte(']') + instanceHashing-- // With respect to the represented type, whether a // type is fully expanded or stored as instance diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go index 07ed510d118..f08c41c2a35 100644 --- a/src/cmd/compile/internal/types2/typestring.go +++ b/src/cmd/compile/internal/types2/typestring.go @@ -350,17 +350,33 @@ func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited } func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) { - s := "" - if obj != nil { - if obj.pkg != nil { - writePackage(buf, obj.pkg, qf) - } - // TODO(gri): function-local named types should be displayed - // differently from named types at package level to avoid - // ambiguity. - s = obj.name + if obj == nil { + buf.WriteString("") + return + } + if obj.pkg != nil { + writePackage(buf, obj.pkg, qf) + } + buf.WriteString(obj.name) + + if instanceHashing != 0 { + // For local defined types, use the (original!) TypeName's position + // to disambiguate. This is overkill, and could probably instead + // just be the pointer value (if we assume a non-moving GC) or + // a unique ID (like cmd/compile uses). But this works for now, + // and is convenient for debugging. + + // TODO(mdempsky): I still don't fully understand why typ.orig.orig + // can differ from typ.orig, or whether looping more than twice is + // ever necessary. + typ := obj.typ.(*Named) + for typ.orig != typ { + typ = typ.orig + } + if orig := typ.obj; orig.pkg != nil && orig.parent != orig.pkg.scope { + fmt.Fprintf(buf, "@%q", orig.pos) + } } - buf.WriteString(s) } func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visited []Type) { diff --git a/test/typeparam/nested.go b/test/typeparam/nested.go new file mode 100644 index 00000000000..6512b3fc8fe --- /dev/null +++ b/test/typeparam/nested.go @@ -0,0 +1,134 @@ +// run -gcflags=all="-d=unified -G" + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This test case stress tests a number of subtle cases involving +// nested type-parameterized declarations. At a high-level, it +// declares a generic function that contains a generic type +// declaration: +// +// func F[A intish]() { +// type T[B intish] struct{} +// +// // store reflect.Type tuple (A, B, F[A].T[B]) in tests +// } +// +// It then instantiates this function with a variety of type arguments +// for A and B. Particularly tricky things like shadowed types. +// +// From this data it tests two things: +// +// 1. Given tuples (A, B, F[A].T[B]) and (A', B', F[A'].T[B']), +// F[A].T[B] should be identical to F[A'].T[B'] iff (A, B) is +// identical to (A', B'). +// +// 2. A few of the instantiations are constructed to be identical, and +// it tests that exactly these pairs are duplicated (by golden +// output comparison to nested.out). +// +// In both cases, we're effectively using the compiler's existing +// runtime.Type handling (which is well tested) of type identity of A +// and B as a way to help bootstrap testing and validate its new +// runtime.Type handling of F[A].T[B]. +// +// This isn't perfect, but it smoked out a handful of issues in +// gotypes2 and unified IR. + +package main + +import ( + "fmt" + "reflect" +) + +type test struct { + TArgs [2]reflect.Type + Instance reflect.Type +} + +var tests []test + +type intish interface{ ~int } + +type Int int +type GlobalInt = Int // allow access to global Int, even when shadowed + +func F[A intish]() { + add := func(B, T interface{}) { + tests = append(tests, test{ + TArgs: [2]reflect.Type{ + reflect.TypeOf(A(0)), + reflect.TypeOf(B), + }, + Instance: reflect.TypeOf(T), + }) + } + + type Int int + + type T[B intish] struct{} + + add(int(0), T[int]{}) + add(Int(0), T[Int]{}) + add(GlobalInt(0), T[GlobalInt]{}) + add(A(0), T[A]{}) // NOTE: intentionally dups with int and GlobalInt + + type U[_ any] int + type V U[int] + type W V + + add(U[int](0), T[U[int]]{}) + add(U[Int](0), T[U[Int]]{}) + add(U[GlobalInt](0), T[U[GlobalInt]]{}) + add(U[A](0), T[U[A]]{}) // NOTE: intentionally dups with U[int] and U[GlobalInt] + add(V(0), T[V]{}) + add(W(0), T[W]{}) +} + +func main() { + type Int int + + F[int]() + F[Int]() + F[GlobalInt]() + + type U[_ any] int + type V U[int] + type W V + + F[U[int]]() + F[U[Int]]() + F[U[GlobalInt]]() + F[V]() + F[W]() + + type X[A any] U[X[A]] + + F[X[int]]() + F[X[Int]]() + F[X[GlobalInt]]() + + for j, tj := range tests { + for i, ti := range tests[:j+1] { + if (ti.TArgs == tj.TArgs) != (ti.Instance == tj.Instance) { + fmt.Printf("FAIL: %d,%d: %s, but %s\n", i, j, eq(ti.TArgs, tj.TArgs), eq(ti.Instance, tj.Instance)) + } + + // The test is constructed so we should see a few identical types. + // See "NOTE" comments above. + if i != j && ti.Instance == tj.Instance { + fmt.Printf("%d,%d: %v\n", i, j, ti.Instance) + } + } + } +} + +func eq(a, b interface{}) string { + op := "==" + if a != b { + op = "!=" + } + return fmt.Sprintf("%v %s %v", a, op, b) +} diff --git a/test/typeparam/nested.out b/test/typeparam/nested.out new file mode 100644 index 00000000000..91105182482 --- /dev/null +++ b/test/typeparam/nested.out @@ -0,0 +1,4 @@ +0,3: main.T·2[int;int] +4,7: main.T·2[int;"".U·3[int;int]] +22,23: main.T·2["".Int;"".Int] +26,27: main.T·2["".Int;"".U·3["".Int;"".Int]] From ad59efb02705a9f33a1eb9a9c04740da721a8cc4 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Mon, 7 Jun 2021 10:29:44 -0400 Subject: [PATCH 429/940] [dev.typeparams] go/ast: remove the typeparams build constraint This CL removes the typeparams build constraint guarding changes to the go/ast and go/types APIs. Notably it does not remove all indirection added to hide the type parameter API: the go/internal/typeparams package is not yet deleted, nor have go/parser or go/types been updated to access type parameter data directly. This will be done in a follow-up CL; the intent of this CL is to make it easier to support the new type set syntax, and to experiment with different AST APIs. Change-Id: I13ea0285752991b87b3aead1d1371e1f3f817b1a Reviewed-on: https://go-review.googlesource.com/c/go/+/325689 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/ast/ast.go | 62 +++++++++--- src/go/ast/ast_notypeparams.go | 28 ------ src/go/ast/ast_typeparams.go | 51 ---------- src/go/ast/walk.go | 17 +++- src/go/ast/walk_notypeparams.go | 17 ---- src/go/ast/walk_typeparams.go | 36 ------- src/go/internal/typeparams/notypeparams.go | 40 -------- src/go/internal/typeparams/typeparams.go | 3 - src/go/types/api_notypeparams.go | 104 --------------------- src/go/types/api_typeparams.go | 3 - src/go/types/api_typeparams_test.go | 3 - 11 files changed, 64 insertions(+), 300 deletions(-) delete mode 100644 src/go/ast/ast_notypeparams.go delete mode 100644 src/go/ast/ast_typeparams.go delete mode 100644 src/go/ast/walk_notypeparams.go delete mode 100644 src/go/ast/walk_typeparams.go delete mode 100644 src/go/internal/typeparams/notypeparams.go delete mode 100644 src/go/types/api_notypeparams.go diff --git a/src/go/ast/ast.go b/src/go/ast/ast.go index 337c87fd797..a34cafcb4e7 100644 --- a/src/go/ast/ast.go +++ b/src/go/ast/ast.go @@ -374,6 +374,13 @@ type ( Rparen token.Pos // position of ")" } + // A ListExpr node represents a list of expressions separated by commas. + // ListExpr nodes are used as index in IndexExpr nodes representing type + // or function instantiations with more than one type argument. + ListExpr struct { + ElemList []Expr + } + // A StarExpr node represents an expression of the form "*" Expression. // Semantically it could be a unary "*" expression, or a pointer type. // @@ -440,6 +447,14 @@ type ( // Pointer types are represented via StarExpr nodes. + // A FuncType node represents a function type. + FuncType struct { + Func token.Pos // position of "func" keyword (token.NoPos if there is no "func") + TParams *FieldList // type parameters; or nil + Params *FieldList // (incoming) parameters; non-nil + Results *FieldList // (outgoing) results; or nil + } + // An InterfaceType node represents an interface type. InterfaceType struct { Interface token.Pos // position of "interface" keyword @@ -482,12 +497,18 @@ func (x *IndexExpr) Pos() token.Pos { return x.X.Pos() } func (x *SliceExpr) Pos() token.Pos { return x.X.Pos() } func (x *TypeAssertExpr) Pos() token.Pos { return x.X.Pos() } func (x *CallExpr) Pos() token.Pos { return x.Fun.Pos() } -func (x *StarExpr) Pos() token.Pos { return x.Star } -func (x *UnaryExpr) Pos() token.Pos { return x.OpPos } -func (x *BinaryExpr) Pos() token.Pos { return x.X.Pos() } -func (x *KeyValueExpr) Pos() token.Pos { return x.Key.Pos() } -func (x *ArrayType) Pos() token.Pos { return x.Lbrack } -func (x *StructType) Pos() token.Pos { return x.Struct } +func (x *ListExpr) Pos() token.Pos { + if len(x.ElemList) > 0 { + return x.ElemList[0].Pos() + } + return token.NoPos +} +func (x *StarExpr) Pos() token.Pos { return x.Star } +func (x *UnaryExpr) Pos() token.Pos { return x.OpPos } +func (x *BinaryExpr) Pos() token.Pos { return x.X.Pos() } +func (x *KeyValueExpr) Pos() token.Pos { return x.Key.Pos() } +func (x *ArrayType) Pos() token.Pos { return x.Lbrack } +func (x *StructType) Pos() token.Pos { return x.Struct } func (x *FuncType) Pos() token.Pos { if x.Func.IsValid() || x.Params == nil { // see issue 3870 return x.Func @@ -515,12 +536,18 @@ func (x *IndexExpr) End() token.Pos { return x.Rbrack + 1 } func (x *SliceExpr) End() token.Pos { return x.Rbrack + 1 } func (x *TypeAssertExpr) End() token.Pos { return x.Rparen + 1 } func (x *CallExpr) End() token.Pos { return x.Rparen + 1 } -func (x *StarExpr) End() token.Pos { return x.X.End() } -func (x *UnaryExpr) End() token.Pos { return x.X.End() } -func (x *BinaryExpr) End() token.Pos { return x.Y.End() } -func (x *KeyValueExpr) End() token.Pos { return x.Value.End() } -func (x *ArrayType) End() token.Pos { return x.Elt.End() } -func (x *StructType) End() token.Pos { return x.Fields.End() } +func (x *ListExpr) End() token.Pos { + if len(x.ElemList) > 0 { + return x.ElemList[len(x.ElemList)-1].End() + } + return token.NoPos +} +func (x *StarExpr) End() token.Pos { return x.X.End() } +func (x *UnaryExpr) End() token.Pos { return x.X.End() } +func (x *BinaryExpr) End() token.Pos { return x.Y.End() } +func (x *KeyValueExpr) End() token.Pos { return x.Value.End() } +func (x *ArrayType) End() token.Pos { return x.Elt.End() } +func (x *StructType) End() token.Pos { return x.Fields.End() } func (x *FuncType) End() token.Pos { if x.Results != nil { return x.Results.End() @@ -546,6 +573,7 @@ func (*IndexExpr) exprNode() {} func (*SliceExpr) exprNode() {} func (*TypeAssertExpr) exprNode() {} func (*CallExpr) exprNode() {} +func (*ListExpr) exprNode() {} func (*StarExpr) exprNode() {} func (*UnaryExpr) exprNode() {} func (*BinaryExpr) exprNode() {} @@ -892,6 +920,16 @@ type ( Values []Expr // initial values; or nil Comment *CommentGroup // line comments; or nil } + + // A TypeSpec node represents a type declaration (TypeSpec production). + TypeSpec struct { + Doc *CommentGroup // associated documentation; or nil + Name *Ident // type name + TParams *FieldList // type parameters; or nil + Assign token.Pos // position of '=', if any + Type Expr // *Ident, *ParenExpr, *SelectorExpr, *StarExpr, or any of the *XxxTypes + Comment *CommentGroup // line comments; or nil + } ) // Pos and End implementations for spec nodes. diff --git a/src/go/ast/ast_notypeparams.go b/src/go/ast/ast_notypeparams.go deleted file mode 100644 index fa132fba858..00000000000 --- a/src/go/ast/ast_notypeparams.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2021 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 !typeparams -// +build !typeparams - -package ast - -import "go/token" - -type ( - // A FuncType node represents a function type. - FuncType struct { - Func token.Pos // position of "func" keyword (token.NoPos if there is no "func") - Params *FieldList // (incoming) parameters; non-nil - Results *FieldList // (outgoing) results; or nil - } - - // A TypeSpec node represents a type declaration (TypeSpec production). - TypeSpec struct { - Doc *CommentGroup // associated documentation; or nil - Name *Ident // type name - Assign token.Pos // position of '=', if any - Type Expr // *Ident, *ParenExpr, *SelectorExpr, *StarExpr, or any of the *XxxTypes - Comment *CommentGroup // line comments; or nil - } -) diff --git a/src/go/ast/ast_typeparams.go b/src/go/ast/ast_typeparams.go deleted file mode 100644 index 24fdc5f1317..00000000000 --- a/src/go/ast/ast_typeparams.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2021 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 typeparams -// +build typeparams - -package ast - -import "go/token" - -type ( - // A FuncType node represents a function type. - FuncType struct { - Func token.Pos // position of "func" keyword (token.NoPos if there is no "func") - TParams *FieldList // type parameters; or nil - Params *FieldList // (incoming) parameters; non-nil - Results *FieldList // (outgoing) results; or nil - } - - // A TypeSpec node represents a type declaration (TypeSpec production). - TypeSpec struct { - Doc *CommentGroup // associated documentation; or nil - Name *Ident // type name - TParams *FieldList // type parameters; or nil - Assign token.Pos // position of '=', if any - Type Expr // *Ident, *ParenExpr, *SelectorExpr, *StarExpr, or any of the *XxxTypes - Comment *CommentGroup // line comments; or nil - } - - // A ListExpr node represents a list of expressions separated by commas. - // ListExpr nodes are used as index in IndexExpr nodes representing type - // or function instantiations with more than one type argument. - ListExpr struct { - ElemList []Expr - } -) - -func (*ListExpr) exprNode() {} -func (x *ListExpr) Pos() token.Pos { - if len(x.ElemList) > 0 { - return x.ElemList[0].Pos() - } - return token.NoPos -} -func (x *ListExpr) End() token.Pos { - if len(x.ElemList) > 0 { - return x.ElemList[len(x.ElemList)-1].End() - } - return token.NoPos -} diff --git a/src/go/ast/walk.go b/src/go/ast/walk.go index 9224264e291..02fef5901dd 100644 --- a/src/go/ast/walk.go +++ b/src/go/ast/walk.go @@ -4,6 +4,8 @@ package ast +import "fmt" + // A Visitor's Visit method is invoked for each node encountered by Walk. // If the result visitor w is not nil, Walk visits each of the children // of node with the visitor w, followed by a call of w.Visit(nil). @@ -136,6 +138,11 @@ func Walk(v Visitor, node Node) { Walk(v, n.Fun) walkExprList(v, n.Args) + case *ListExpr: + for _, elem := range n.ElemList { + Walk(v, elem) + } + case *StarExpr: Walk(v, n.X) @@ -161,7 +168,9 @@ func Walk(v Visitor, node Node) { Walk(v, n.Fields) case *FuncType: - walkFuncTypeParams(v, n) + if n.TParams != nil { + Walk(v, n.TParams) + } if n.Params != nil { Walk(v, n.Params) } @@ -316,7 +325,9 @@ func Walk(v Visitor, node Node) { Walk(v, n.Doc) } Walk(v, n.Name) - walkTypeSpecParams(v, n) + if n.TParams != nil { + Walk(v, n.TParams) + } Walk(v, n.Type) if n.Comment != nil { Walk(v, n.Comment) @@ -363,7 +374,7 @@ func Walk(v Visitor, node Node) { } default: - walkOtherNodes(v, n) + panic(fmt.Sprintf("ast.Walk: unexpected node type %T", n)) } v.Visit(nil) diff --git a/src/go/ast/walk_notypeparams.go b/src/go/ast/walk_notypeparams.go deleted file mode 100644 index d43e13dd11a..00000000000 --- a/src/go/ast/walk_notypeparams.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2021 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 !typeparams -// +build !typeparams - -package ast - -import "fmt" - -func walkFuncTypeParams(v Visitor, n *FuncType) {} -func walkTypeSpecParams(v Visitor, n *TypeSpec) {} - -func walkOtherNodes(v Visitor, n Node) { - panic(fmt.Sprintf("ast.Walk: unexpected node type %T", n)) -} diff --git a/src/go/ast/walk_typeparams.go b/src/go/ast/walk_typeparams.go deleted file mode 100644 index b6621335b8e..00000000000 --- a/src/go/ast/walk_typeparams.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2021 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 typeparams -// +build typeparams - -package ast - -import ( - "fmt" -) - -func walkFuncTypeParams(v Visitor, n *FuncType) { - if n.TParams != nil { - Walk(v, n.TParams) - } -} - -func walkTypeSpecParams(v Visitor, n *TypeSpec) { - if n.TParams != nil { - Walk(v, n.TParams) - } -} - -func walkOtherNodes(v Visitor, n Node) { - if e, ok := n.(*ListExpr); ok { - if e != nil { - for _, elem := range e.ElemList { - Walk(v, elem) - } - } - } else { - panic(fmt.Sprintf("ast.Walk: unexpected node type %T", n)) - } -} diff --git a/src/go/internal/typeparams/notypeparams.go b/src/go/internal/typeparams/notypeparams.go deleted file mode 100644 index 2ceafaac1c3..00000000000 --- a/src/go/internal/typeparams/notypeparams.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2021 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 !typeparams -// +build !typeparams - -package typeparams - -import ( - "go/ast" -) - -const Enabled = false - -func PackExpr(list []ast.Expr) ast.Expr { - switch len(list) { - case 1: - return list[0] - default: - // The parser should not attempt to pack multiple expressions into an - // IndexExpr if type params are disabled. - panic("multiple index expressions are unsupported without type params") - } -} - -func UnpackExpr(expr ast.Expr) []ast.Expr { - return []ast.Expr{expr} -} - -func IsListExpr(n ast.Node) bool { - return false -} - -func Get(ast.Node) *ast.FieldList { - return nil -} - -func Set(node ast.Node, params *ast.FieldList) { -} diff --git a/src/go/internal/typeparams/typeparams.go b/src/go/internal/typeparams/typeparams.go index 871e95d9984..b4251bda7e3 100644 --- a/src/go/internal/typeparams/typeparams.go +++ b/src/go/internal/typeparams/typeparams.go @@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build typeparams -// +build typeparams - package typeparams import ( diff --git a/src/go/types/api_notypeparams.go b/src/go/types/api_notypeparams.go deleted file mode 100644 index 9f7cb7eccf2..00000000000 --- a/src/go/types/api_notypeparams.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2021 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 !typeparams -// +build !typeparams - -package types - -import "go/ast" - -// Info holds result type information for a type-checked package. -// Only the information for which a map is provided is collected. -// If the package has type errors, the collected information may -// be incomplete. -type Info struct { - // Types maps expressions to their types, and for constant - // expressions, also their values. Invalid expressions are - // omitted. - // - // For (possibly parenthesized) identifiers denoting built-in - // functions, the recorded signatures are call-site specific: - // if the call result is not a constant, the recorded type is - // an argument-specific signature. Otherwise, the recorded type - // is invalid. - // - // The Types map does not record the type of every identifier, - // only those that appear where an arbitrary expression is - // permitted. For instance, the identifier f in a selector - // expression x.f is found only in the Selections map, the - // identifier z in a variable declaration 'var z int' is found - // only in the Defs map, and identifiers denoting packages in - // qualified identifiers are collected in the Uses map. - Types map[ast.Expr]TypeAndValue - - // Defs maps identifiers to the objects they define (including - // package names, dots "." of dot-imports, and blank "_" identifiers). - // For identifiers that do not denote objects (e.g., the package name - // in package clauses, or symbolic variables t in t := x.(type) of - // type switch headers), the corresponding objects are nil. - // - // For an embedded field, Defs returns the field *Var it defines. - // - // Invariant: Defs[id] == nil || Defs[id].Pos() == id.Pos() - Defs map[*ast.Ident]Object - - // Uses maps identifiers to the objects they denote. - // - // For an embedded field, Uses returns the *TypeName it denotes. - // - // Invariant: Uses[id].Pos() != id.Pos() - Uses map[*ast.Ident]Object - - // Implicits maps nodes to their implicitly declared objects, if any. - // The following node and object types may appear: - // - // node declared object - // - // *ast.ImportSpec *PkgName for imports without renames - // *ast.CaseClause type-specific *Var for each type switch case clause (incl. default) - // *ast.Field anonymous parameter *Var (incl. unnamed results) - // - Implicits map[ast.Node]Object - - // Selections maps selector expressions (excluding qualified identifiers) - // to their corresponding selections. - Selections map[*ast.SelectorExpr]*Selection - - // Scopes maps ast.Nodes to the scopes they define. Package scopes are not - // associated with a specific node but with all files belonging to a package. - // Thus, the package scope can be found in the type-checked Package object. - // Scopes nest, with the Universe scope being the outermost scope, enclosing - // the package scope, which contains (one or more) files scopes, which enclose - // function scopes which in turn enclose statement and function literal scopes. - // Note that even though package-level functions are declared in the package - // scope, the function scopes are embedded in the file scope of the file - // containing the function declaration. - // - // The following node types may appear in Scopes: - // - // *ast.File - // *ast.FuncType - // *ast.BlockStmt - // *ast.IfStmt - // *ast.SwitchStmt - // *ast.TypeSwitchStmt - // *ast.CaseClause - // *ast.CommClause - // *ast.ForStmt - // *ast.RangeStmt - // - Scopes map[ast.Node]*Scope - - // InitOrder is the list of package-level initializers in the order in which - // they must be executed. Initializers referring to variables related by an - // initialization dependency appear in topological order, the others appear - // in source order. Variables without an initialization expression do not - // appear in this list. - InitOrder []*Initializer -} - -func getInferred(info *Info) map[ast.Expr]_Inferred { - return nil -} diff --git a/src/go/types/api_typeparams.go b/src/go/types/api_typeparams.go index ae2c5a7fd09..25fb3fa7818 100644 --- a/src/go/types/api_typeparams.go +++ b/src/go/types/api_typeparams.go @@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build typeparams -// +build typeparams - package types import ( diff --git a/src/go/types/api_typeparams_test.go b/src/go/types/api_typeparams_test.go index 517c58505b5..4a2adce9a29 100644 --- a/src/go/types/api_typeparams_test.go +++ b/src/go/types/api_typeparams_test.go @@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build typeparams -// +build typeparams - package types_test import ( From 7c5d7a4caffdb72ce252fb465ff4f7fd62a46c8a Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 3 Jun 2021 22:07:36 -0400 Subject: [PATCH 430/940] [dev.typeparams] go/token, go/scanner: add the "~" operator This is an approximate port of CL 307370 to go/token and go/scanner. Change-Id: I5b789408f825f7e39f569322cb67802117b9d734 Reviewed-on: https://go-review.googlesource.com/c/go/+/324992 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/scanner/scanner.go | 2 ++ src/go/scanner/scanner_test.go | 3 ++- src/go/token/token.go | 11 ++++++++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/go/scanner/scanner.go b/src/go/scanner/scanner.go index 29cbf39721f..f8bcf4d8642 100644 --- a/src/go/scanner/scanner.go +++ b/src/go/scanner/scanner.go @@ -969,6 +969,8 @@ scanAgain: } case '|': tok = s.switch3(token.OR, token.OR_ASSIGN, '|', token.LOR) + case '~': + tok = token.TILDE default: // next reports unexpected BOMs - don't repeat if ch != bom { diff --git a/src/go/scanner/scanner_test.go b/src/go/scanner/scanner_test.go index ac8d2577169..dd3c7cf8385 100644 --- a/src/go/scanner/scanner_test.go +++ b/src/go/scanner/scanner_test.go @@ -40,7 +40,7 @@ type elt struct { class int } -var tokens = [...]elt{ +var tokens = []elt{ // Special tokens {token.COMMENT, "/* a comment */", special}, {token.COMMENT, "// a comment \n", special}, @@ -149,6 +149,7 @@ var tokens = [...]elt{ {token.RBRACE, "}", operator}, {token.SEMICOLON, ";", operator}, {token.COLON, ":", operator}, + {token.TILDE, "~", operator}, // Keywords {token.BREAK, "break", keyword}, diff --git a/src/go/token/token.go b/src/go/token/token.go index 96a1079ec37..d22e575661a 100644 --- a/src/go/token/token.go +++ b/src/go/token/token.go @@ -125,6 +125,11 @@ const ( TYPE VAR keyword_end + + additional_beg + // additional tokens, handled in an ad-hoc manner + TILDE + additional_end ) var tokens = [...]string{ @@ -225,6 +230,8 @@ var tokens = [...]string{ SWITCH: "switch", TYPE: "type", VAR: "var", + + TILDE: "~", } // String returns the string corresponding to the token tok. @@ -304,7 +311,9 @@ func (tok Token) IsLiteral() bool { return literal_beg < tok && tok < literal_en // IsOperator returns true for tokens corresponding to operators and // delimiters; it returns false otherwise. // -func (tok Token) IsOperator() bool { return operator_beg < tok && tok < operator_end } +func (tok Token) IsOperator() bool { + return (operator_beg < tok && tok < operator_end) || tok == TILDE +} // IsKeyword returns true for tokens corresponding to keywords; // it returns false otherwise. From ab4b3c4b15838e3eb5888b96c7965e31973b25cd Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Mon, 7 Jun 2021 10:04:12 -0400 Subject: [PATCH 431/940] [dev.typeparams] go/parser: accept "~" and "|" interface elements This is a port of CL 307371 to go/parser, adding support for the new embedded type expressions. As in that CL, type lists continue to be accepted. This CL also revealed a pre-existing bug related to embedded instances: the parser was failing to parse embedded instances with multiple type arguments, due to not consuming the initial ','. This is fixed, and along the way TestErrors is modified to use subtests. Several missing tests cases were added to exprstring_test.go. These must have been missed in an earlier CL. Change-Id: I452769536998cddb1618bebdba675fc09d48a12f Reviewed-on: https://go-review.googlesource.com/c/go/+/325690 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/parser/error_test.go | 20 ++++---- src/go/parser/parser.go | 74 +++++++++++++++++++++++++--- src/go/parser/testdata/interface.go2 | 37 ++++++++++++++ src/go/types/exprstring_test.go | 34 +++++++++++++ 4 files changed, 149 insertions(+), 16 deletions(-) create mode 100644 src/go/parser/testdata/interface.go2 diff --git a/src/go/parser/error_test.go b/src/go/parser/error_test.go index f4f0a5240ac..e22ab124510 100644 --- a/src/go/parser/error_test.go +++ b/src/go/parser/error_test.go @@ -186,16 +186,18 @@ func TestErrors(t *testing.T) { } for _, d := range list { name := d.Name() - if !d.IsDir() && !strings.HasPrefix(name, ".") && (strings.HasSuffix(name, ".src") || strings.HasSuffix(name, ".go2")) { - mode := DeclarationErrors | AllErrors - if strings.HasSuffix(name, ".go2") { - if !typeparams.Enabled { - continue + t.Run(name, func(t *testing.T) { + if !d.IsDir() && !strings.HasPrefix(name, ".") && (strings.HasSuffix(name, ".src") || strings.HasSuffix(name, ".go2")) { + mode := DeclarationErrors | AllErrors + if strings.HasSuffix(name, ".go2") { + if !typeparams.Enabled { + return + } + } else { + mode |= typeparams.DisallowParsing } - } else { - mode |= typeparams.DisallowParsing + checkErrors(t, filepath.Join(testdata, name), nil, mode, true) } - checkErrors(t, filepath.Join(testdata, name), nil, mode, true) - } + }) } } diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go index 3965641713a..5ccba02e5ca 100644 --- a/src/go/parser/parser.go +++ b/src/go/parser/parser.go @@ -980,6 +980,7 @@ func (p *parser) parseMethodSpec() *ast.Field { list := []ast.Expr{x} if p.atComma("type argument list", token.RBRACK) { p.exprLev++ + p.next() for p.tok != token.RBRACK && p.tok != token.EOF { list = append(list, p.parseType()) if !p.atComma("type argument list", token.RBRACK) { @@ -1011,11 +1012,56 @@ func (p *parser) parseMethodSpec() *ast.Field { typ = p.parseTypeInstance(typ) } } - p.expectSemi() // call before accessing p.linecomment - spec := &ast.Field{Doc: doc, Names: idents, Type: typ, Comment: p.lineComment} + // Comment is added at the callsite: the field below may joined with + // additional type specs using '|'. + // TODO(rfindley) this should be refactored. + // TODO(rfindley) add more tests for comment handling. + return &ast.Field{Doc: doc, Names: idents, Type: typ} +} - return spec +func (p *parser) embeddedElem(f *ast.Field) *ast.Field { + if p.trace { + defer un(trace(p, "EmbeddedElem")) + } + if f == nil { + f = new(ast.Field) + f.Type = p.embeddedTerm() + } + for p.tok == token.OR { + t := new(ast.BinaryExpr) + t.OpPos = p.pos + t.Op = token.OR + p.next() + t.X = f.Type + t.Y = p.embeddedTerm() + f.Type = t + } + return f +} + +func (p *parser) embeddedTerm() ast.Expr { + if p.trace { + defer un(trace(p, "EmbeddedTerm")) + } + if p.tok == token.TILDE { + t := new(ast.UnaryExpr) + t.OpPos = p.pos + t.Op = token.TILDE + p.next() + t.X = p.parseType() + return t + } + + t := p.tryIdentOrType() + if t == nil { + pos := p.pos + p.errorExpected(pos, "~ term or type") + p.advance(exprEnd) + return &ast.BadExpr{From: pos, To: p.pos} + } + + return t } func (p *parser) parseInterfaceType() *ast.InterfaceType { @@ -1026,10 +1072,24 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType { pos := p.expect(token.INTERFACE) lbrace := p.expect(token.LBRACE) var list []*ast.Field - for p.tok == token.IDENT || p.parseTypeParams() && p.tok == token.TYPE { - if p.tok == token.IDENT { - list = append(list, p.parseMethodSpec()) - } else { + for p.tok == token.IDENT || p.parseTypeParams() && (p.tok == token.TYPE || p.tok == token.TILDE) { + switch p.tok { + case token.IDENT: + f := p.parseMethodSpec() + if f.Names == nil && p.parseTypeParams() { + f = p.embeddedElem(f) + } + p.expectSemi() + f.Comment = p.lineComment + list = append(list, f) + case token.TILDE: + f := p.embeddedElem(nil) + p.expectSemi() + f.Comment = p.lineComment + list = append(list, f) + case token.TYPE: + // TODO(rfindley): remove TypeList syntax and refactor the clauses above. + // all types in a type list share the same field name "type" // (since type is a keyword, a Go program cannot have that field name) name := []*ast.Ident{{NamePos: p.pos, Name: "type"}} diff --git a/src/go/parser/testdata/interface.go2 b/src/go/parser/testdata/interface.go2 new file mode 100644 index 00000000000..c631055202b --- /dev/null +++ b/src/go/parser/testdata/interface.go2 @@ -0,0 +1,37 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains test cases for interfaces containing +// constraint elements. +// +// For now, we accept both ordinary type lists and the +// more complex constraint elements. + +package p + +type _ interface { + m() + type int + type int, string + E +} + +type _ interface { + m() + ~int + int | string + int | ~string + ~int | ~string +} + + +type _ interface { + m() + ~int + T[int, string] | string + int | ~T[string, struct{}] + ~int | ~string + type bool, int, float64 +} + diff --git a/src/go/types/exprstring_test.go b/src/go/types/exprstring_test.go index 51102881c9f..a67f6a978a9 100644 --- a/src/go/types/exprstring_test.go +++ b/src/go/types/exprstring_test.go @@ -27,6 +27,40 @@ var testExprs = []testEntry{ {"func(x int) complex128 {}", "(func(x int) complex128 literal)"}, {"[]int{1, 2, 3}", "([]int literal)"}, + // type expressions + dup("[1 << 10]byte"), + dup("[]int"), + dup("*int"), + dup("struct{x int}"), + dup("func()"), + dup("func(int, float32) string"), + dup("interface{m()}"), + dup("interface{m() string; n(x int)}"), + dup("interface{type int}"), + + // The following exprs do not get formatted correctly: each element in the + // type list is printed on a separate line. This is left as a placeholder + // until type lists are removed. + // TODO(rfindley): remove this once type lists are gone. + // dup("interface{type int, float64, string}"), + // dup("interface{type int; m()}"), + // dup("interface{type int, float64, string; m() string; n(x int)}"), + dup("map[string]int"), + dup("chan E"), + dup("<-chan E"), + dup("chan<- E"), + + // new interfaces + dup("interface{int}"), + dup("interface{~int}"), + dup("interface{~int}"), + dup("interface{int | string}"), + dup("interface{~int | ~string; float64; m()}"), + + // See above. + // dup("interface{type a, b, c; ~int | ~string; float64; m()}"), + dup("interface{~T[int, string] | string}"), + // non-type expressions dup("(x)"), dup("x.f"), From 54f854fb4150dfe5bc156abf57c46e9931d55ee5 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Mon, 7 Jun 2021 19:50:15 -0400 Subject: [PATCH 432/940] [dev.typeparams] go/parser: accept embedded type literals This is an approximate port of CL 321109 to go/parser, though go/parser does not have the same internal APIs as cmd/compile/internal/syntax, so this CL required some refactoring. Change-Id: I146ef530c969d61bab99f98f4de94b862e103ddc Reviewed-on: https://go-review.googlesource.com/c/go/+/325703 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/parser/parser.go | 27 +++++++++++++---- src/go/parser/short_test.go | 8 +++-- src/go/parser/testdata/interface.go2 | 45 +++++++++++++++++++++++++++- 3 files changed, 71 insertions(+), 9 deletions(-) diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go index 5ccba02e5ca..869d14c2c13 100644 --- a/src/go/parser/parser.go +++ b/src/go/parser/parser.go @@ -1071,10 +1071,13 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType { pos := p.expect(token.INTERFACE) lbrace := p.expect(token.LBRACE) + var list []*ast.Field - for p.tok == token.IDENT || p.parseTypeParams() && (p.tok == token.TYPE || p.tok == token.TILDE) { - switch p.tok { - case token.IDENT: + +parseElements: + for { + switch { + case p.tok == token.IDENT: f := p.parseMethodSpec() if f.Names == nil && p.parseTypeParams() { f = p.embeddedElem(f) @@ -1082,12 +1085,12 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType { p.expectSemi() f.Comment = p.lineComment list = append(list, f) - case token.TILDE: + case p.tok == token.TILDE && p.parseTypeParams(): f := p.embeddedElem(nil) p.expectSemi() f.Comment = p.lineComment list = append(list, f) - case token.TYPE: + case p.tok == token.TYPE && p.parseTypeParams(): // TODO(rfindley): remove TypeList syntax and refactor the clauses above. // all types in a type list share the same field name "type" @@ -1099,8 +1102,22 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType { list = append(list, &ast.Field{Names: name, Type: typ}) } p.expectSemi() + case p.parseTypeParams(): + if t := p.tryIdentOrType(); t != nil { + f := new(ast.Field) + f.Type = t + f = p.embeddedElem(f) + p.expectSemi() + f.Comment = p.lineComment + list = append(list, f) + } else { + break parseElements + } + default: + break parseElements } } + // TODO(rfindley): the error produced here could be improved, since we could // accept a identifier, 'type', or a '}' at this point. rbrace := p.expect(token.RBRACE) diff --git a/src/go/parser/short_test.go b/src/go/parser/short_test.go index 67fef156655..2467ccb4a77 100644 --- a/src/go/parser/short_test.go +++ b/src/go/parser/short_test.go @@ -200,10 +200,12 @@ var invalids = []string{ `package p; func (type /* ERROR "found 'type'" */ T)(T) _()`, `package p; type _[A+B, /* ERROR "expected ']'" */ ] int`, - // TODO: this error should be positioned on the ':' + // TODO(rfindley): this error should be positioned on the ':' `package p; var a = a[[]int:[ /* ERROR "expected expression" */ ]int];`, - // TODO: the compiler error is better here: "cannot parenthesize embedded type" - `package p; type I1 interface{}; type I2 interface{ (/* ERROR "expected '}', found '\('" */ I1) }`, + + // TODO(rfindley): the compiler error is better here: "cannot parenthesize embedded type" + // TODO(rfindley): confirm that parenthesized types should now be accepted. + // `package p; type I1 interface{}; type I2 interface{ (/* ERROR "expected '}', found '\('" */ I1) }`, // issue 8656 `package p; func f() (a b string /* ERROR "missing ','" */ , ok bool)`, diff --git a/src/go/parser/testdata/interface.go2 b/src/go/parser/testdata/interface.go2 index c631055202b..b399d751488 100644 --- a/src/go/parser/testdata/interface.go2 +++ b/src/go/parser/testdata/interface.go2 @@ -25,7 +25,6 @@ type _ interface { ~int | ~string } - type _ interface { m() ~int @@ -35,3 +34,47 @@ type _ interface { type bool, int, float64 } +type _ interface { + int + []byte + [10]int + struct{} + *int + func() + interface{} + map[string]int + chan T + chan<- T + <-chan T + T[int] +} + +type _ interface { + int | string + []byte | string + [10]int | string + struct{} | string + *int | string + func() | string + interface{} | string + map[string]int | string + chan T | string + chan<- T | string + <-chan T | string + T[int] | string +} + +type _ interface { + ~int | string + ~[]byte | string + ~[10]int | string + ~struct{} | string + ~*int | string + ~func() | string + ~interface{} | string + ~map[string]int | string + ~chan T | string + ~chan<- T | string + ~<-chan T | string + ~T[int] | string +} From e7451f661665e406889094b9d1471c7991dfefaa Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Tue, 8 Jun 2021 10:21:51 -0400 Subject: [PATCH 433/940] [dev.typeparams] go/types: accept embedded interface elements This is a port of CL 321689 to go/types. It differs from that CL in the uses of the position, AST and error APIs, and in not factoring out an unimplemented() helper (this helper didn't already exist in go/types, so it seemed cleaner to defer adding it). Change-Id: I577a57297caf35eb7a23f63f3f52037a7bb528ea Reviewed-on: https://go-review.googlesource.com/c/go/+/326069 Trust: Robert Findley Run-TryBot: Robert Findley Reviewed-by: Robert Griesemer --- src/go/types/builtins.go | 2 +- src/go/types/errorcodes.go | 11 +- src/go/types/infer.go | 5 +- src/go/types/interface.go | 224 +++++++++--------- src/go/types/predicates.go | 3 + src/go/types/sanitize.go | 6 +- src/go/types/sizeof_test.go | 3 +- src/go/types/sizes.go | 2 + src/go/types/subst.go | 16 +- src/go/types/testdata/check/decls0.src | 2 +- src/go/types/testdata/check/issues.src | 2 +- src/go/types/testdata/check/typeinst2.go2 | 6 +- .../types/testdata/examples/constraints.go2 | 25 ++ .../types/testdata/fixedbugs/issue39634.go2 | 2 +- .../types/testdata/fixedbugs/issue39693.go2 | 17 +- .../types/testdata/fixedbugs/issue39711.go2 | 4 +- .../types/testdata/fixedbugs/issue39723.go2 | 2 +- .../types/testdata/fixedbugs/issue39948.go2 | 8 +- src/go/types/type.go | 1 - src/go/types/typestring.go | 21 +- src/go/types/typestring_test.go | 3 + src/go/types/unify.go | 4 + src/go/types/union.go | 108 +++++++++ 23 files changed, 316 insertions(+), 161 deletions(-) create mode 100644 src/go/types/testdata/examples/constraints.go2 create mode 100644 src/go/types/union.go diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index 2a2d54da882..99122dfe7c9 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -783,7 +783,7 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { tpar := NewTypeName(token.NoPos, nil /* = Universe pkg */, "", nil) ptyp := check.newTypeParam(tpar, 0, &emptyInterface) // assigns type to tpar as a side-effect tsum := _NewSum(rtypes) - ptyp.bound = &Interface{types: tsum, allMethods: markComplete, allTypes: tsum} + ptyp.bound = &Interface{allMethods: markComplete, allTypes: tsum} return ptyp } diff --git a/src/go/types/errorcodes.go b/src/go/types/errorcodes.go index 3d24da7b533..2afb6a383c9 100644 --- a/src/go/types/errorcodes.go +++ b/src/go/types/errorcodes.go @@ -281,16 +281,7 @@ const ( _IncomparableMapKey // _InvalidIfaceEmbed occurs when a non-interface type is embedded in an - // interface. - // - // Example: - // type T struct {} - // - // func (T) m() - // - // type I interface { - // T - // } + // interface (for go 1.17 or earlier). _InvalidIfaceEmbed // _InvalidPtrEmbed occurs when an embedded field is of the pointer form *T, diff --git a/src/go/types/infer.go b/src/go/types/infer.go index 5d49351e1f0..951c6b8cbd4 100644 --- a/src/go/types/infer.go +++ b/src/go/types/infer.go @@ -315,6 +315,9 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { // Thus, we only need to look at the input and result parameters. return w.isParameterized(t.params) || w.isParameterized(t.results) + case *Union: + panic("unimplemented") + case *Interface: if t.allMethods != nil { // TODO(rFindley) at some point we should enforce completeness here @@ -332,7 +335,7 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { return true } } - return w.isParameterizedList(unpackType(t.types)) + return w.isParameterizedList(t.embeddeds) }, nil) case *Map: diff --git a/src/go/types/interface.go b/src/go/types/interface.go index fd3fe0ef91e..611f3870466 100644 --- a/src/go/types/interface.go +++ b/src/go/types/interface.go @@ -13,74 +13,84 @@ import ( ) func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, def *Named) { - var tlist *ast.Ident // "type" name of first entry in a type list declaration - var types []ast.Expr + var tlist []ast.Expr + var tname *ast.Ident // "type" name of first entry in a type list declaration + for _, f := range iface.Methods.List { - if len(f.Names) > 0 { - // We have a method with name f.Names[0], or a type - // of a type list (name.Name == "type"). - // (The parser ensures that there's only one method - // and we don't care if a constructed AST has more.) - name := f.Names[0] - if name.Name == "_" { - check.errorf(name, _BlankIfaceMethod, "invalid method name _") - continue // ignore - } - - if name.Name == "type" { - // Always collect all type list entries, even from - // different type lists, under the assumption that - // the author intended to include all types. - types = append(types, f.Type) - if tlist != nil && tlist != name { - check.errorf(name, _Todo, "cannot have multiple type lists in an interface") - } - tlist = name - continue - } - - typ := check.typ(f.Type) - sig, _ := typ.(*Signature) - if sig == nil { - if typ != Typ[Invalid] { - check.invalidAST(f.Type, "%s is not a method signature", typ) - } - continue // ignore - } - - // Always type-check method type parameters but complain if they are not enabled. - // (This extra check is needed here because interface method signatures don't have - // a receiver specification.) - if sig.tparams != nil { - var at positioner = f.Type - if tparams := typeparams.Get(f.Type); tparams != nil { - at = tparams - } - check.errorf(at, _Todo, "methods cannot have type parameters") - } - - // use named receiver type if available (for better error messages) - var recvTyp Type = ityp - if def != nil { - recvTyp = def - } - sig.recv = NewVar(name.Pos(), check.pkg, "", recvTyp) - - m := NewFunc(name.Pos(), check.pkg, name.Name, sig) - check.recordDef(name, m) - ityp.methods = append(ityp.methods, m) - } else { - // We have an embedded type. completeInterface will - // eventually verify that we have an interface. - ityp.embeddeds = append(ityp.embeddeds, check.typ(f.Type)) + if len(f.Names) == 0 { + // We have an embedded type; possibly a union of types. + ityp.embeddeds = append(ityp.embeddeds, parseUnion(check, flattenUnion(nil, f.Type))) check.posMap[ityp] = append(check.posMap[ityp], f.Type.Pos()) + continue } + + // We have a method with name f.Names[0], or a type + // of a type list (name.Name == "type"). + // (The parser ensures that there's only one method + // and we don't care if a constructed AST has more.) + name := f.Names[0] + if name.Name == "_" { + check.errorf(name, _BlankIfaceMethod, "invalid method name _") + continue // ignore + } + + if name.Name == "type" { + // For now, collect all type list entries as if it + // were a single union, where each union element is + // of the form ~T. + // TODO(rfindley) remove once we disallow type lists + op := new(ast.UnaryExpr) + op.Op = token.TILDE + op.X = f.Type + tlist = append(tlist, op) + if tname != nil && tname != name { + check.errorf(name, _Todo, "cannot have multiple type lists in an interface") + } + tname = name + continue + } + + typ := check.typ(f.Type) + sig, _ := typ.(*Signature) + if sig == nil { + if typ != Typ[Invalid] { + check.invalidAST(f.Type, "%s is not a method signature", typ) + } + continue // ignore + } + + // Always type-check method type parameters but complain if they are not enabled. + // (This extra check is needed here because interface method signatures don't have + // a receiver specification.) + if sig.tparams != nil { + var at positioner = f.Type + if tparams := typeparams.Get(f.Type); tparams != nil { + at = tparams + } + check.errorf(at, _Todo, "methods cannot have type parameters") + } + + // use named receiver type if available (for better error messages) + var recvTyp Type = ityp + if def != nil { + recvTyp = def + } + sig.recv = NewVar(name.Pos(), check.pkg, "", recvTyp) + + m := NewFunc(name.Pos(), check.pkg, name.Name, sig) + check.recordDef(name, m) + ityp.methods = append(ityp.methods, m) } // type constraints - ityp.types = _NewSum(check.collectTypeConstraints(iface.Pos(), types)) + if tlist != nil { + ityp.embeddeds = append(ityp.embeddeds, parseUnion(check, tlist)) + // Types T in a type list are added as ~T expressions but we don't + // have the position of the '~'. Use the first type position instead. + check.posMap[ityp] = append(check.posMap[ityp], tlist[0].(*ast.UnaryExpr).X.Pos()) + } - if len(ityp.methods) == 0 && ityp.types == nil && len(ityp.embeddeds) == 0 { + if len(ityp.methods) == 0 && len(ityp.embeddeds) == 0 { // empty interface ityp.allMethods = markComplete return @@ -93,32 +103,12 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d check.later(func() { check.completeInterface(iface.Pos(), ityp) }) } -func (check *Checker) collectTypeConstraints(pos token.Pos, types []ast.Expr) []Type { - list := make([]Type, 0, len(types)) // assume all types are correct - for _, texpr := range types { - if texpr == nil { - check.invalidAST(atPos(pos), "missing type constraint") - continue - } - list = append(list, check.varType(texpr)) +func flattenUnion(list []ast.Expr, x ast.Expr) []ast.Expr { + if o, _ := x.(*ast.BinaryExpr); o != nil && o.Op == token.OR { + list = flattenUnion(list, o.X) + x = o.Y } - - // Ensure that each type is only present once in the type list. Types may be - // interfaces, which may not be complete yet. It's ok to do this check at the - // end because it's not a requirement for correctness of the code. - // Note: This is a quadratic algorithm, but type lists tend to be short. - check.later(func() { - for i, t := range list { - if t := asInterface(t); t != nil { - check.completeInterface(types[i].Pos(), t) - } - if includes(list[:i], t) { - check.softErrorf(types[i], _Todo, "duplicate type %s in type list", t) - } - } - }) - - return list + return append(list, x) } // includes reports whether typ is in list. @@ -146,6 +136,7 @@ func (check *Checker) completeInterface(pos token.Pos, ityp *Interface) { completeInterface(check, pos, ityp) } +// completeInterface may be called with check == nil. func completeInterface(check *Checker, pos token.Pos, ityp *Interface) { assert(ityp.allMethods == nil) @@ -198,6 +189,7 @@ func completeInterface(check *Checker, pos token.Pos, ityp *Interface) { if check == nil { panic(fmt.Sprintf("%v: duplicate method %s", m.pos, m.name)) } + // check != nil check.errorf(atPos(pos), _DuplicateDecl, "duplicate method %s", m.name) check.errorf(atPos(mpos[other.(*Func)]), _DuplicateDecl, "\tother declaration of %s", m.name) // secondary error, \t indented default: @@ -211,6 +203,7 @@ func completeInterface(check *Checker, pos token.Pos, ityp *Interface) { todo = append(todo, m, other.(*Func)) break } + // check != nil check.later(func() { if !check.allowVersion(m.pkg, 1, 14) || !check.identical(m.typ, other.Type()) { check.errorf(atPos(pos), _DuplicateDecl, "duplicate method %s", m.name) @@ -224,9 +217,8 @@ func completeInterface(check *Checker, pos token.Pos, ityp *Interface) { addMethod(m.pos, m, true) } - // collect types - allTypes := ityp.types - + // collect embedded elements + var allTypes Type var posList []token.Pos if check != nil { posList = check.posMap[ityp] @@ -236,32 +228,36 @@ func completeInterface(check *Checker, pos token.Pos, ityp *Interface) { if posList != nil { pos = posList[i] } - utyp := under(typ) - etyp := asInterface(utyp) - if etyp == nil { - if utyp != Typ[Invalid] { - var format string - if _, ok := utyp.(*_TypeParam); ok { - format = "%s is a type parameter, not an interface" - } else { - format = "%s is not an interface" - } - if check != nil { - // TODO: correct error code. - check.errorf(atPos(pos), _InvalidIfaceEmbed, format, typ) - } else { - panic(fmt.Sprintf(format, typ)) - } + var types Type + switch t := under(typ).(type) { + case *Interface: + if t.allMethods == nil { + completeInterface(check, pos, t) } - continue + for _, m := range t.allMethods { + addMethod(pos, m, false) // use embedding position pos rather than m.pos + + } + types = t.allTypes + case *Union: + types = NewSum(t.terms) + case *TypeParam: + if check != nil && !check.allowVersion(check.pkg, 1, 18) { + check.errorf(atPos(pos), _InvalidIfaceEmbed, "%s is a type parameter, not an interface", typ) + continue + } + types = t + default: + if t == Typ[Invalid] { + continue + } + if check != nil && !check.allowVersion(check.pkg, 1, 18) { + check.errorf(atPos(pos), _InvalidIfaceEmbed, "%s is not an interface", typ) + continue + } + types = t } - if etyp.allMethods == nil { - completeInterface(check, pos, etyp) - } - for _, m := range etyp.allMethods { - addMethod(pos, m, false) // use embedding position pos rather than m.pos - } - allTypes = intersect(allTypes, etyp.allTypes) + allTypes = intersect(allTypes, types) } // process todo's (this only happens if check == nil) @@ -281,7 +277,7 @@ func completeInterface(check *Checker, pos token.Pos, ityp *Interface) { } // intersect computes the intersection of the types x and y. -// Note: A incomming nil type stands for the top type. A top +// Note: An incomming nil type stands for the top type. A top // type result is returned as nil. func intersect(x, y Type) (r Type) { defer func() { diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index 7bb026414f8..a72c0dc1fd8 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -288,6 +288,9 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { return true } + case *Union: + panic("identical0 not implemented for union types") + case *Interface: // Two interface types are identical if they have the same set of methods with // the same names and identical function types. Lower-case method names from diff --git a/src/go/types/sanitize.go b/src/go/types/sanitize.go index 88fc3f83772..b9fd56001d4 100644 --- a/src/go/types/sanitize.go +++ b/src/go/types/sanitize.go @@ -110,11 +110,11 @@ func (s sanitizer) typ(typ Type) Type { case *_Sum: s.typeList(t.types) + case *Union: + s.typeList(t.terms) + case *Interface: s.funcList(t.methods) - if types := s.typ(t.types); types != t.types { - t.types = types - } s.typeList(t.embeddeds) s.funcList(t.allMethods) if allTypes := s.typ(t.allTypes); allTypes != t.allTypes { diff --git a/src/go/types/sizeof_test.go b/src/go/types/sizeof_test.go index 3af9079a85c..7454831843d 100644 --- a/src/go/types/sizeof_test.go +++ b/src/go/types/sizeof_test.go @@ -27,7 +27,8 @@ func TestSizeof(t *testing.T) { {Tuple{}, 12, 24}, {Signature{}, 44, 88}, {_Sum{}, 12, 24}, - {Interface{}, 60, 120}, + {Union{}, 24, 48}, + {Interface{}, 52, 104}, {Map{}, 16, 32}, {Chan{}, 12, 24}, {Named{}, 68, 136}, diff --git a/src/go/types/sizes.go b/src/go/types/sizes.go index 67052bb816e..ae5d765a89c 100644 --- a/src/go/types/sizes.go +++ b/src/go/types/sizes.go @@ -150,6 +150,8 @@ func (s *StdSizes) Sizeof(T Type) int64 { return offsets[n-1] + s.Sizeof(t.fields[n-1].typ) case *_Sum: panic("Sizeof unimplemented for type sum") + case *Union: + panic("Sizeof unimplemented for type union") case *Interface: return s.WordSize * 2 } diff --git a/src/go/types/subst.go b/src/go/types/subst.go index 47b0c279db6..d79c07a2fc8 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -311,15 +311,19 @@ func (subst *subster) typ(typ Type) Type { return _NewSum(types) } + case *Union: + terms, copied := subst.typeList(t.terms) + if copied { + // TODO(gri) Do we need to remove duplicates that may have + // crept in after substitution? It may not matter. + return newUnion(terms, t.tilde) + } + case *Interface: methods, mcopied := subst.funcList(t.methods) - types := t.types - if t.types != nil { - types = subst.typ(t.types) - } embeddeds, ecopied := subst.typeList(t.embeddeds) - if mcopied || types != t.types || ecopied { - iface := &Interface{methods: methods, types: types, embeddeds: embeddeds} + if mcopied || ecopied { + iface := &Interface{methods: methods, embeddeds: embeddeds} if subst.check == nil { panic("internal error: cannot instantiate interfaces yet") } diff --git a/src/go/types/testdata/check/decls0.src b/src/go/types/testdata/check/decls0.src index 09904bb3030..1224e46377a 100644 --- a/src/go/types/testdata/check/decls0.src +++ b/src/go/types/testdata/check/decls0.src @@ -4,7 +4,7 @@ // type declarations -package decls0 +package go1_17 // don't permit non-interface elements in interfaces import "unsafe" diff --git a/src/go/types/testdata/check/issues.src b/src/go/types/testdata/check/issues.src index e2ac06759ba..9d9fc7862f1 100644 --- a/src/go/types/testdata/check/issues.src +++ b/src/go/types/testdata/check/issues.src @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package issues +package go1_17 // don't permit non-interface elements in interfaces import ( "fmt" diff --git a/src/go/types/testdata/check/typeinst2.go2 b/src/go/types/testdata/check/typeinst2.go2 index 6e2104a5150..1096bb42eb7 100644 --- a/src/go/types/testdata/check/typeinst2.go2 +++ b/src/go/types/testdata/check/typeinst2.go2 @@ -164,12 +164,12 @@ type _ interface { // for them to be all in a single list, and we report the error // as well.) type _ interface { - type int, int /* ERROR duplicate type int */ - type /* ERROR multiple type lists */ int /* ERROR duplicate type int */ + type int, int /* ERROR duplicate term int */ + type /* ERROR multiple type lists */ int /* ERROR duplicate term int */ } type _ interface { - type struct{f int}, struct{g int}, struct /* ERROR duplicate type */ {f int} + type struct{f int}, struct{g int}, struct /* ERROR duplicate term */ {f int} } // Interface type lists can contain any type, incl. *Named types. diff --git a/src/go/types/testdata/examples/constraints.go2 b/src/go/types/testdata/examples/constraints.go2 new file mode 100644 index 00000000000..e8b3912884c --- /dev/null +++ b/src/go/types/testdata/examples/constraints.go2 @@ -0,0 +1,25 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file shows some examples of generic constraint interfaces. + +package p + +type ( + // Arbitrary types may be embedded like interfaces. + _ interface{int} + _ interface{~int} + + // Types may be combined into a union. + _ interface{int|~string} + + // Union terms must be unique independent of whether they are ~ or not. + _ interface{int|int /* ERROR duplicate term int */ } + _ interface{int|~ /* ERROR duplicate term int */ int } + _ interface{~int|~ /* ERROR duplicate term int */ int } + + // For now we do not permit interfaces with ~ or in unions. + _ interface{~ /* ERROR cannot use interface */ interface{}} + _ interface{int|interface /* ERROR cannot use interface */ {}} +) diff --git a/src/go/types/testdata/fixedbugs/issue39634.go2 b/src/go/types/testdata/fixedbugs/issue39634.go2 index a13ed13ce5f..c759be0d93f 100644 --- a/src/go/types/testdata/fixedbugs/issue39634.go2 +++ b/src/go/types/testdata/fixedbugs/issue39634.go2 @@ -36,7 +36,7 @@ func bar8[A foo8[A]](a A) {} func main8() {} // crash 9 -type foo9[A any] interface { type foo9 /* ERROR interface contains type constraints */ [A] } +type foo9[A any] interface { type foo9 /* ERROR cannot use interface */ [A] } func _() { var _ = new(foo9 /* ERROR interface contains type constraints */ [int]) } // crash 12 diff --git a/src/go/types/testdata/fixedbugs/issue39693.go2 b/src/go/types/testdata/fixedbugs/issue39693.go2 index 316ab1982e8..ec7641902a1 100644 --- a/src/go/types/testdata/fixedbugs/issue39693.go2 +++ b/src/go/types/testdata/fixedbugs/issue39693.go2 @@ -4,11 +4,20 @@ package p -type Number interface { - int /* ERROR int is not an interface */ - float64 /* ERROR float64 is not an interface */ +type Number1 interface { + // embedding non-interface types is permitted + int + float64 } -func Add[T Number](a, b T) T { +func Add[T Number1](a, b T) T { return a /* ERROR not defined */ + b } + +type Number2 interface { + int|float64 +} + +func Add2[T Number2](a, b T) T { + return a + b +} diff --git a/src/go/types/testdata/fixedbugs/issue39711.go2 b/src/go/types/testdata/fixedbugs/issue39711.go2 index df621a4c173..cf1f90545f6 100644 --- a/src/go/types/testdata/fixedbugs/issue39711.go2 +++ b/src/go/types/testdata/fixedbugs/issue39711.go2 @@ -7,5 +7,7 @@ package p // Do not report a duplicate type error for this type list. // (Check types after interfaces have been completed.) type _ interface { - type interface{ Error() string }, interface{ String() string } + // TODO(rfindley) Once we have full type sets we can enable this again. + // Fow now we don't permit interfaces in type lists. + // type interface{ Error() string }, interface{ String() string } } diff --git a/src/go/types/testdata/fixedbugs/issue39723.go2 b/src/go/types/testdata/fixedbugs/issue39723.go2 index 55464e6b775..61bc6067892 100644 --- a/src/go/types/testdata/fixedbugs/issue39723.go2 +++ b/src/go/types/testdata/fixedbugs/issue39723.go2 @@ -6,4 +6,4 @@ package p // A constraint must be an interface; it cannot // be a type parameter, for instance. -func _[A interface{ type interface{} }, B A /* ERROR not an interface */ ]() +func _[A interface{ type int }, B A /* ERROR not an interface */ ]() diff --git a/src/go/types/testdata/fixedbugs/issue39948.go2 b/src/go/types/testdata/fixedbugs/issue39948.go2 index c2b460902cc..d83084b52a7 100644 --- a/src/go/types/testdata/fixedbugs/issue39948.go2 +++ b/src/go/types/testdata/fixedbugs/issue39948.go2 @@ -2,7 +2,13 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package p +// TODO(rfindley) Eventually, once we disallow type lists, we need to +// adjust this code: for 1.17 we don't accept type parameters, +// and for 1.18 this code is valid. +// Leaving for now so we can see that existing errors +// are being reported. + +package go1_17 // don't permit non-interface elements in interfaces type T[P any] interface{ P // ERROR P is a type parameter, not an interface diff --git a/src/go/types/type.go b/src/go/types/type.go index 4a394999058..d487bf66f9e 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -305,7 +305,6 @@ func (s *_Sum) is(pred func(Type) bool) bool { // An Interface represents an interface type. type Interface struct { methods []*Func // ordered list of explicitly declared methods - types Type // (possibly a Sum) type declared with a type list (TODO(gri) need better field name) embeddeds []Type // ordered list of explicitly embedded types allMethods []*Func // ordered list of methods declared with or embedded in this interface (TODO(gri): replace with mset) diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go index ff93f3b3c31..9e860dda22c 100644 --- a/src/go/types/typestring.go +++ b/src/go/types/typestring.go @@ -159,11 +159,17 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { writeSignature(buf, t, qf, visited) case *_Sum: - for i, t := range t.types { + writeTypeList(buf, t.types, qf, visited) + + case *Union: + for i, e := range t.terms { if i > 0 { - buf.WriteString(", ") + buf.WriteString("|") } - writeType(buf, t, qf, visited) + if t.tilde[i] { + buf.WriteByte('~') + } + writeType(buf, e, qf, visited) } case *Interface: @@ -208,14 +214,6 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { writeSignature(buf, m.typ.(*Signature), qf, visited) empty = false } - if !empty && t.types != nil { - buf.WriteString("; ") - } - if t.types != nil { - buf.WriteString("type ") - writeType(buf, t.types, qf, visited) - empty = false - } if !empty && len(t.embeddeds) > 0 { buf.WriteString("; ") } @@ -301,6 +299,7 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { default: // For externally defined implementations of Type. + // Note: In this case cycles won't be caught. buf.WriteString(t.String()) } } diff --git a/src/go/types/typestring_test.go b/src/go/types/typestring_test.go index 55ee4b987f7..0e35a3dbf1c 100644 --- a/src/go/types/typestring_test.go +++ b/src/go/types/typestring_test.go @@ -95,6 +95,9 @@ var independentTestTypes = []testEntry{ dup("interface{}"), dup("interface{m()}"), dup(`interface{String() string; m(int) float32}`), + {"interface{type int, float32, complex128}", "interface{~int|~float32|~complex128}"}, + dup("interface{int|float32|complex128}"), + dup("interface{int|~float32|~complex128}"), // TODO(rFindley) uncomment this once this AST is accepted, and add more test // cases. diff --git a/src/go/types/unify.go b/src/go/types/unify.go index db06e21cf72..4b541df4cd1 100644 --- a/src/go/types/unify.go +++ b/src/go/types/unify.go @@ -356,6 +356,10 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool { // This should not happen with the current internal use of sum types. panic("type inference across sum types not implemented") + case *Union: + // This should not happen with the current internal use of union types. + panic("type inference across union types not implemented") + case *Interface: // Two interface types are identical if they have the same set of methods with // the same names and identical function types. Lower-case method names from diff --git a/src/go/types/union.go b/src/go/types/union.go new file mode 100644 index 00000000000..0df200c67bc --- /dev/null +++ b/src/go/types/union.go @@ -0,0 +1,108 @@ +// Copyright 2021 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 types + +import ( + "go/ast" + "go/token" +) + +// ---------------------------------------------------------------------------- +// API + +// A Union represents a union of terms. +// A term is a type, possibly with a ~ (tilde) indication. +type Union struct { + terms []Type // terms are unique + tilde []bool // if tilde[i] is set, terms[i] is of the form ~T +} + +func NewUnion(terms []Type, tilde []bool) Type { return newUnion(terms, tilde) } + +func (u *Union) NumTerms() int { return len(u.terms) } +func (u *Union) Term(i int) (Type, bool) { return u.terms[i], u.tilde[i] } + +func (u *Union) Underlying() Type { return u } +func (u *Union) String() string { return TypeString(u, nil) } + +// ---------------------------------------------------------------------------- +// Implementation + +func newUnion(terms []Type, tilde []bool) Type { + assert(len(terms) == len(tilde)) + if terms == nil { + return nil + } + t := new(Union) + t.terms = terms + t.tilde = tilde + return t +} + +func parseUnion(check *Checker, tlist []ast.Expr) Type { + var terms []Type + var tilde []bool + for _, x := range tlist { + t, d := parseTilde(check, x) + if len(tlist) == 1 && !d { + return t // single type + } + terms = append(terms, t) + tilde = append(tilde, d) + } + + // Ensure that each type is only present once in the type list. + // It's ok to do this check at the end because it's not a requirement + // for correctness of the code. + // Note: This is a quadratic algorithm, but unions tend to be short. + check.later(func() { + for i, t := range terms { + t := expand(t) + if t == Typ[Invalid] { + continue + } + + x := tlist[i] + pos := x.Pos() + // We may not know the position of x if it was a typechecker- + // introduced ~T type of a type list entry T. Use the position + // of T instead. + // TODO(rfindley) remove this test once we don't support type lists anymore + if !pos.IsValid() { + if op, _ := x.(*ast.UnaryExpr); op != nil { + pos = op.X.Pos() + } + } + + u := under(t) + if tilde[i] { + // TODO(rfindley) enable this check once we have converted tests + // if !Identical(u, t) { + // check.errorf(x, "invalid use of ~ (underlying type of %s is %s)", t, u) + // } + } + if _, ok := u.(*Interface); ok { + check.errorf(atPos(pos), _Todo, "cannot use interface %s with ~ or inside a union (implementation restriction)", t) + } + + // Complain about duplicate entries a|a, but also a|~a, and ~a|~a. + if includes(terms[:i], t) { + // TODO(rfindley) this currently doesn't print the ~ if present + check.softErrorf(atPos(pos), _Todo, "duplicate term %s in union element", t) + } + } + }) + + return newUnion(terms, tilde) +} + +func parseTilde(check *Checker, x ast.Expr) (Type, bool) { + tilde := false + if op, _ := x.(*ast.UnaryExpr); op != nil && op.Op == token.TILDE { + x = op.X + tilde = true + } + return check.anyType(x), tilde +} From c7a460526eb20752d92fef0456852a3e64bc47a0 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Wed, 9 Jun 2021 18:15:10 -0400 Subject: [PATCH 434/940] [dev.typeparams] go/types: replace Sum type with Union type This is a straightforward port of CL 323274 to go/types. Change-Id: Ica769d90fd482703f260f105199d2f2229498e95 Reviewed-on: https://go-review.googlesource.com/c/go/+/326677 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/api_typeparams.go | 3 - src/go/types/builtins.go | 16 +++-- src/go/types/expr.go | 4 +- src/go/types/index.go | 18 +++--- src/go/types/infer.go | 5 +- src/go/types/interface.go | 50 +++------------ src/go/types/operand.go | 19 +++++- src/go/types/predicates.go | 35 +++++------ src/go/types/sanitize.go | 5 +- src/go/types/sizeof_test.go | 1 - src/go/types/sizes.go | 4 +- src/go/types/stmt.go | 6 +- src/go/types/subst.go | 18 ++---- src/go/types/type.go | 72 +++++---------------- src/go/types/typestring.go | 5 +- src/go/types/unify.go | 4 -- src/go/types/union.go | 111 ++++++++++++++++++++++++++++----- 17 files changed, 185 insertions(+), 191 deletions(-) diff --git a/src/go/types/api_typeparams.go b/src/go/types/api_typeparams.go index 25fb3fa7818..6aaefbb6b29 100644 --- a/src/go/types/api_typeparams.go +++ b/src/go/types/api_typeparams.go @@ -10,12 +10,9 @@ import ( type ( Inferred = _Inferred - Sum = _Sum TypeParam = _TypeParam ) -func NewSum(types []Type) Type { return _NewSum(types) } - // NewTypeParam returns a new TypeParam. func NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam { return (*Checker)(nil).newTypeParam(obj, index, bound) diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index 99122dfe7c9..92807ed44a1 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -179,9 +179,9 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b mode = value } - case *_Sum: - if t.is(func(t Type) bool { - switch t := under(t).(type) { + case *Union: + if t.underIs(func(t Type) bool { + switch t := t.(type) { case *Basic: if isString(t) && id == _Len { return true @@ -469,8 +469,8 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b m = 2 case *Map, *Chan: m = 1 - case *_Sum: - return t.is(valid) + case *Union: + return t.underIs(valid) default: return false } @@ -768,10 +768,14 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { if tp := asTypeParam(x); tp != nil { // Test if t satisfies the requirements for the argument // type and collect possible result types at the same time. + // TODO(gri) This needs to consider the ~ information if we + // have a union type. var rtypes []Type + var tilde []bool if !tp.Bound().is(func(x Type) bool { if r := f(x); r != nil { rtypes = append(rtypes, r) + tilde = append(tilde, true) return true } return false @@ -782,7 +786,7 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { // construct a suitable new type parameter tpar := NewTypeName(token.NoPos, nil /* = Universe pkg */, "", nil) ptyp := check.newTypeParam(tpar, 0, &emptyInterface) // assigns type to tpar as a side-effect - tsum := _NewSum(rtypes) + tsum := newUnion(rtypes, tilde) ptyp.bound = &Interface{allMethods: markComplete, allTypes: tsum} return ptyp diff --git a/src/go/types/expr.go b/src/go/types/expr.go index 5c65fad4479..b7cc6e8ae7b 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -661,8 +661,8 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const default: return nil, nil, _InvalidUntypedConversion } - case *_Sum: - ok := t.is(func(t Type) bool { + case *Union: + ok := t.underIs(func(t Type) bool { target, _, _ := check.implicitTypeAndValue(x, t) return target != nil }) diff --git a/src/go/types/index.go b/src/go/types/index.go index 2ba3475f897..5bc1d0af8da 100644 --- a/src/go/types/index.go +++ b/src/go/types/index.go @@ -91,15 +91,15 @@ func (check *Checker) indexExpr(x *operand, e *ast.IndexExpr) (isFuncInst bool) x.expr = e return - case *_Sum: - // A sum type can be indexed if all of the sum's types + case *Union: + // A union type can be indexed if all of the union's terms // support indexing and have the same index and element - // type. Special rules apply for maps in the sum type. + // type. Special rules apply for maps in the union type. var tkey, telem Type // key is for map types only - nmaps := 0 // number of map types in sum type - if typ.is(func(t Type) bool { + nmaps := 0 // number of map types in union type + if typ.underIs(func(t Type) bool { var e Type - switch t := under(t).(type) { + switch t := t.(type) { case *Basic: if isString(t) { e = universeByte @@ -113,7 +113,7 @@ func (check *Checker) indexExpr(x *operand, e *ast.IndexExpr) (isFuncInst bool) case *Slice: e = t.elem case *Map: - // If there are multiple maps in the sum type, + // If there are multiple maps in the union type, // they must have identical key types. // TODO(gri) We may be able to relax this rule // but it becomes complicated very quickly. @@ -148,7 +148,7 @@ func (check *Checker) indexExpr(x *operand, e *ast.IndexExpr) (isFuncInst bool) // ok to continue even if indexing failed - map element type is known // If there are only maps, we are done. - if nmaps == len(typ.types) { + if nmaps == typ.NumTerms() { x.mode = mapindex x.typ = telem x.expr = e @@ -246,7 +246,7 @@ func (check *Checker) sliceExpr(x *operand, e *ast.SliceExpr) { valid = true // x.typ doesn't change - case *_Sum, *_TypeParam: + case *Union, *_TypeParam: check.errorf(x, 0, "generic slice expressions not yet implemented") x.mode = invalid return diff --git a/src/go/types/infer.go b/src/go/types/infer.go index 951c6b8cbd4..ddf02a3942a 100644 --- a/src/go/types/infer.go +++ b/src/go/types/infer.go @@ -302,7 +302,7 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { } } - case *_Sum: + case *Union: return w.isParameterizedList(t.types) case *Signature: @@ -315,9 +315,6 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { // Thus, we only need to look at the input and result parameters. return w.isParameterized(t.params) || w.isParameterized(t.results) - case *Union: - panic("unimplemented") - case *Interface: if t.allMethods != nil { // TODO(rFindley) at some point we should enforce completeness here diff --git a/src/go/types/interface.go b/src/go/types/interface.go index 611f3870466..2bbd2f135de 100644 --- a/src/go/types/interface.go +++ b/src/go/types/interface.go @@ -240,22 +240,26 @@ func completeInterface(check *Checker, pos token.Pos, ityp *Interface) { } types = t.allTypes case *Union: - types = NewSum(t.terms) + // TODO(gri) combine with default case once we have + // converted all tests to new notation and we + // can report an error when we don't have an + // interface before go1.18. + types = typ case *TypeParam: if check != nil && !check.allowVersion(check.pkg, 1, 18) { check.errorf(atPos(pos), _InvalidIfaceEmbed, "%s is a type parameter, not an interface", typ) continue } - types = t + types = typ default: - if t == Typ[Invalid] { + if typ == Typ[Invalid] { continue } if check != nil && !check.allowVersion(check.pkg, 1, 18) { check.errorf(atPos(pos), _InvalidIfaceEmbed, "%s is not an interface", typ) continue } - types = t + types = typ } allTypes = intersect(allTypes, types) } @@ -276,44 +280,6 @@ func completeInterface(check *Checker, pos token.Pos, ityp *Interface) { ityp.allTypes = allTypes } -// intersect computes the intersection of the types x and y. -// Note: An incomming nil type stands for the top type. A top -// type result is returned as nil. -func intersect(x, y Type) (r Type) { - defer func() { - if r == theTop { - r = nil - } - }() - - switch { - case x == theBottom || y == theBottom: - return theBottom - case x == nil || x == theTop: - return y - case y == nil || x == theTop: - return x - } - - xtypes := unpackType(x) - ytypes := unpackType(y) - // Compute the list rtypes which includes only - // types that are in both xtypes and ytypes. - // Quadratic algorithm, but good enough for now. - // TODO(gri) fix this - var rtypes []Type - for _, x := range xtypes { - if includes(ytypes, x) { - rtypes = append(rtypes, x) - } - } - - if rtypes == nil { - return theBottom - } - return _NewSum(rtypes) -} - func sortTypes(list []Type) { sort.Stable(byUniqueTypeName(list)) } diff --git a/src/go/types/operand.go b/src/go/types/operand.go index 6463728cec6..81dc66e800e 100644 --- a/src/go/types/operand.go +++ b/src/go/types/operand.go @@ -233,6 +233,12 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er V := x.typ + const debugAssignableTo = false + if debugAssignableTo && check != nil { + check.dump("V = %s", V) + check.dump("T = %s", T) + } + // x's type is identical to T if check.identical(V, T) { return true, 0 @@ -241,11 +247,20 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er Vu := optype(V) Tu := optype(T) + if debugAssignableTo && check != nil { + check.dump("Vu = %s", Vu) + check.dump("Tu = %s", Tu) + } + // x is an untyped value representable by a value of type T. if isUntyped(Vu) { - if t, ok := Tu.(*_Sum); ok { - return t.is(func(t Type) bool { + if t, ok := Tu.(*Union); ok { + return t.is(func(t Type, tilde bool) bool { // TODO(gri) this could probably be more efficient + if tilde { + // TODO(gri) We need to check assignability + // for the underlying type of x. + } ok, _ := x.assignableTo(check, t, reason) return ok }), _IncompatibleAssign diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index a72c0dc1fd8..78dba6d3e03 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -32,8 +32,8 @@ func is(typ Type, what BasicInfo) bool { switch t := optype(typ).(type) { case *Basic: return t.info&what != 0 - case *_Sum: - return t.is(func(typ Type) bool { return is(typ, what) }) + case *Union: + return t.underIs(func(typ Type) bool { return is(typ, what) }) } return false } @@ -128,11 +128,10 @@ func comparable(T Type, seen map[Type]bool) bool { return true case *Array: return comparable(t.elem, seen) - case *_Sum: - pred := func(t Type) bool { + case *Union: + return t.underIs(func(t Type) bool { return comparable(t, seen) - } - return t.is(pred) + }) case *_TypeParam: return t.Bound()._IsComparable() } @@ -146,8 +145,8 @@ func hasNil(typ Type) bool { return t.kind == UnsafePointer case *Slice, *Pointer, *Signature, *Interface, *Map, *Chan: return true - case *_Sum: - return t.is(hasNil) + case *Union: + return t.underIs(hasNil) } return false } @@ -265,21 +264,20 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { check.identical0(x.results, y.results, cmpTags, p) } - case *_Sum: - // Two sum types are identical if they contain the same types. - // (Sum types always consist of at least two types. Also, the - // the set (list) of types in a sum type consists of unique - // types - each type appears exactly once. Thus, two sum types + case *Union: + // Two union types are identical if they contain the same terms. + // The set (list) of types in a union type consists of unique + // types - each type appears exactly once. Thus, two union types // must contain the same number of types to have chance of // being equal. - if y, ok := y.(*_Sum); ok && len(x.types) == len(y.types) { + if y, ok := y.(*Union); ok && x.NumTerms() == y.NumTerms() { // Every type in x.types must be in y.types. // Quadratic algorithm, but probably good enough for now. // TODO(gri) we need a fast quick type ID/hash for all types. L: - for _, x := range x.types { - for _, y := range y.types { - if Identical(x, y) { + for i, xt := range x.types { + for j, yt := range y.types { + if Identical(xt, yt) && x.tilde[i] == y.tilde[j] { continue L // x is in y.types } } @@ -288,9 +286,6 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { return true } - case *Union: - panic("identical0 not implemented for union types") - case *Interface: // Two interface types are identical if they have the same set of methods with // the same names and identical function types. Lower-case method names from diff --git a/src/go/types/sanitize.go b/src/go/types/sanitize.go index b9fd56001d4..2d700608990 100644 --- a/src/go/types/sanitize.go +++ b/src/go/types/sanitize.go @@ -107,11 +107,8 @@ func (s sanitizer) typ(typ Type) Type { s.tuple(t.params) s.tuple(t.results) - case *_Sum: - s.typeList(t.types) - case *Union: - s.typeList(t.terms) + s.typeList(t.types) case *Interface: s.funcList(t.methods) diff --git a/src/go/types/sizeof_test.go b/src/go/types/sizeof_test.go index 7454831843d..3e79499ea5a 100644 --- a/src/go/types/sizeof_test.go +++ b/src/go/types/sizeof_test.go @@ -26,7 +26,6 @@ func TestSizeof(t *testing.T) { {Pointer{}, 8, 16}, {Tuple{}, 12, 24}, {Signature{}, 44, 88}, - {_Sum{}, 12, 24}, {Union{}, 24, 48}, {Interface{}, 52, 104}, {Map{}, 16, 32}, diff --git a/src/go/types/sizes.go b/src/go/types/sizes.go index ae5d765a89c..35219836ecf 100644 --- a/src/go/types/sizes.go +++ b/src/go/types/sizes.go @@ -148,10 +148,8 @@ func (s *StdSizes) Sizeof(T Type) int64 { } offsets := s.Offsetsof(t.fields) return offsets[n-1] + s.Sizeof(t.fields[n-1].typ) - case *_Sum: - panic("Sizeof unimplemented for type sum") case *Union: - panic("Sizeof unimplemented for type union") + panic("Sizeof unimplemented for union") case *Interface: return s.WordSize * 2 } diff --git a/src/go/types/stmt.go b/src/go/types/stmt.go index 47f6dcfbd1c..9dcaceaca77 100644 --- a/src/go/types/stmt.go +++ b/src/go/types/stmt.go @@ -911,12 +911,12 @@ func rangeKeyVal(typ Type, wantKey, wantVal bool) (Type, Type, string) { msg = "send-only channel" } return typ.elem, Typ[Invalid], msg - case *_Sum: + case *Union: first := true var key, val Type var msg string - typ.is(func(t Type) bool { - k, v, m := rangeKeyVal(under(t), wantKey, wantVal) + typ.underIs(func(t Type) bool { + k, v, m := rangeKeyVal(t, wantKey, wantVal) if k == nil || m != "" { key, val, msg = k, v, m return false diff --git a/src/go/types/subst.go b/src/go/types/subst.go index d79c07a2fc8..8cd8d0719b7 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -302,21 +302,13 @@ func (subst *subster) typ(typ Type) Type { } } - case *_Sum: + case *Union: types, copied := subst.typeList(t.types) if copied { - // Don't do it manually, with a Sum literal: the new - // types list may not be unique and NewSum may remove - // duplicates. - return _NewSum(types) - } - - case *Union: - terms, copied := subst.typeList(t.terms) - if copied { - // TODO(gri) Do we need to remove duplicates that may have - // crept in after substitution? It may not matter. - return newUnion(terms, t.tilde) + // TODO(gri) Remove duplicates that may have crept in after substitution + // (unlikely but possible). This matters for the Identical + // predicate on unions. + return newUnion(types, t.tilde) } case *Interface: diff --git a/src/go/types/type.go b/src/go/types/type.go index d487bf66f9e..3b10fabbf84 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -255,53 +255,6 @@ func (s *Signature) Results() *Tuple { return s.results } // Variadic reports whether the signature s is variadic. func (s *Signature) Variadic() bool { return s.variadic } -// A _Sum represents a set of possible types. -// Sums are currently used to represent type lists of interfaces -// and thus the underlying types of type parameters; they are not -// first class types of Go. -type _Sum struct { - types []Type // types are unique -} - -// _NewSum returns a new Sum type consisting of the provided -// types if there are more than one. If there is exactly one -// type, it returns that type. If the list of types is empty -// the result is nil. -func _NewSum(types []Type) Type { - if len(types) == 0 { - return nil - } - - // What should happen if types contains a sum type? - // Do we flatten the types list? For now we check - // and panic. This should not be possible for the - // current use case of type lists. - // TODO(gri) Come up with the rules for sum types. - for _, t := range types { - if _, ok := t.(*_Sum); ok { - panic("sum type contains sum type - unimplemented") - } - } - - if len(types) == 1 { - return types[0] - } - return &_Sum{types: types} -} - -// is reports whether all types in t satisfy pred. -func (s *_Sum) is(pred func(Type) bool) bool { - if s == nil { - return false - } - for _, t := range s.types { - if !pred(t) { - return false - } - } - return true -} - // An Interface represents an interface type. type Interface struct { methods []*Func // ordered list of explicitly declared methods @@ -319,8 +272,8 @@ func unpackType(typ Type) []Type { if typ == nil { return nil } - if sum := asSum(typ); sum != nil { - return sum.types + if u := asUnion(typ); u != nil { + return u.types } return []Type{typ} } @@ -709,9 +662,16 @@ func optype(typ Type) Type { // for a type parameter list of the form: // (type T interface { type T }). // See also issue #39680. - if u := t.Bound().allTypes; u != nil && u != typ { - // u != typ and u is a type parameter => under(u) != typ, so this is ok - return under(u) + if a := t.Bound().allTypes; a != nil && a != typ { + // If we have a union with a single entry, ignore + // any tilde because under(~t) == under(t). + if u, _ := a.(*Union); u != nil && u.NumTerms() == 1 { + a = u.types[0] + } + if a != typ { + // a != typ and a is a type parameter => under(a) != typ, so this is ok + return under(a) + } } return theTop } @@ -793,7 +753,6 @@ func (t *Struct) Underlying() Type { return t } func (t *Pointer) Underlying() Type { return t } func (t *Tuple) Underlying() Type { return t } func (t *Signature) Underlying() Type { return t } -func (t *_Sum) Underlying() Type { return t } func (t *Interface) Underlying() Type { return t } func (t *Map) Underlying() Type { return t } func (t *Chan) Underlying() Type { return t } @@ -811,7 +770,6 @@ func (t *Struct) String() string { return TypeString(t, nil) } func (t *Pointer) String() string { return TypeString(t, nil) } func (t *Tuple) String() string { return TypeString(t, nil) } func (t *Signature) String() string { return TypeString(t, nil) } -func (t *_Sum) String() string { return TypeString(t, nil) } func (t *Interface) String() string { return TypeString(t, nil) } func (t *Map) String() string { return TypeString(t, nil) } func (t *Chan) String() string { return TypeString(t, nil) } @@ -826,7 +784,7 @@ func (t *top) String() string { return TypeString(t, nil) } // under must only be called when a type is known // to be fully set up. func under(t Type) Type { - // TODO(gri) is this correct for *Sum? + // TODO(gri) is this correct for *Union? if n := asNamed(t); n != nil { return n.under() } @@ -876,8 +834,8 @@ func asSignature(t Type) *Signature { return op } -func asSum(t Type) *_Sum { - op, _ := optype(t).(*_Sum) +func asUnion(t Type) *Union { + op, _ := optype(t).(*Union) return op } diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go index 9e860dda22c..52c22f25d88 100644 --- a/src/go/types/typestring.go +++ b/src/go/types/typestring.go @@ -158,11 +158,8 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { buf.WriteString("func") writeSignature(buf, t, qf, visited) - case *_Sum: - writeTypeList(buf, t.types, qf, visited) - case *Union: - for i, e := range t.terms { + for i, e := range t.types { if i > 0 { buf.WriteString("|") } diff --git a/src/go/types/unify.go b/src/go/types/unify.go index 4b541df4cd1..7c58c6c5128 100644 --- a/src/go/types/unify.go +++ b/src/go/types/unify.go @@ -352,10 +352,6 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool { u.nify(x.results, y.results, p) } - case *_Sum: - // This should not happen with the current internal use of sum types. - panic("type inference across sum types not implemented") - case *Union: // This should not happen with the current internal use of union types. panic("type inference across union types not implemented") diff --git a/src/go/types/union.go b/src/go/types/union.go index 0df200c67bc..aa46b8ab9c5 100644 --- a/src/go/types/union.go +++ b/src/go/types/union.go @@ -13,16 +13,16 @@ import ( // API // A Union represents a union of terms. -// A term is a type, possibly with a ~ (tilde) indication. +// A term is a type, possibly with a ~ (tilde) flag. type Union struct { - terms []Type // terms are unique + types []Type // types are unique tilde []bool // if tilde[i] is set, terms[i] is of the form ~T } -func NewUnion(terms []Type, tilde []bool) Type { return newUnion(terms, tilde) } +func NewUnion(types []Type, tilde []bool) Type { return newUnion(types, tilde) } -func (u *Union) NumTerms() int { return len(u.terms) } -func (u *Union) Term(i int) (Type, bool) { return u.terms[i], u.tilde[i] } +func (u *Union) NumTerms() int { return len(u.types) } +func (u *Union) Term(i int) (Type, bool) { return u.types[i], u.tilde[i] } func (u *Union) Underlying() Type { return u } func (u *Union) String() string { return TypeString(u, nil) } @@ -30,26 +30,52 @@ func (u *Union) String() string { return TypeString(u, nil) } // ---------------------------------------------------------------------------- // Implementation -func newUnion(terms []Type, tilde []bool) Type { - assert(len(terms) == len(tilde)) - if terms == nil { +func newUnion(types []Type, tilde []bool) Type { + assert(len(types) == len(tilde)) + if types == nil { return nil } t := new(Union) - t.terms = terms + t.types = types t.tilde = tilde return t } +// is reports whether f returned true for all terms (type, tilde) of u. +func (u *Union) is(f func(Type, bool) bool) bool { + if u == nil { + return false + } + for i, t := range u.types { + if !f(t, u.tilde[i]) { + return false + } + } + return true +} + +// is reports whether f returned true for the underlying types of all terms of u. +func (u *Union) underIs(f func(Type) bool) bool { + if u == nil { + return false + } + for _, t := range u.types { + if !f(under(t)) { + return false + } + } + return true +} + func parseUnion(check *Checker, tlist []ast.Expr) Type { - var terms []Type + var types []Type var tilde []bool for _, x := range tlist { t, d := parseTilde(check, x) if len(tlist) == 1 && !d { return t // single type } - terms = append(terms, t) + types = append(types, t) tilde = append(tilde, d) } @@ -58,7 +84,7 @@ func parseUnion(check *Checker, tlist []ast.Expr) Type { // for correctness of the code. // Note: This is a quadratic algorithm, but unions tend to be short. check.later(func() { - for i, t := range terms { + for i, t := range types { t := expand(t) if t == Typ[Invalid] { continue @@ -88,14 +114,14 @@ func parseUnion(check *Checker, tlist []ast.Expr) Type { } // Complain about duplicate entries a|a, but also a|~a, and ~a|~a. - if includes(terms[:i], t) { + if includes(types[:i], t) { // TODO(rfindley) this currently doesn't print the ~ if present check.softErrorf(atPos(pos), _Todo, "duplicate term %s in union element", t) } } }) - return newUnion(terms, tilde) + return newUnion(types, tilde) } func parseTilde(check *Checker, x ast.Expr) (Type, bool) { @@ -106,3 +132,60 @@ func parseTilde(check *Checker, x ast.Expr) (Type, bool) { } return check.anyType(x), tilde } + +// intersect computes the intersection of the types x and y. +// Note: An incomming nil type stands for the top type. A top +// type result is returned as nil. +func intersect(x, y Type) (r Type) { + defer func() { + if r == theTop { + r = nil + } + }() + + switch { + case x == theBottom || y == theBottom: + return theBottom + case x == nil || x == theTop: + return y + case y == nil || x == theTop: + return x + } + + // Compute the terms which are in both x and y. + xu, _ := x.(*Union) + yu, _ := y.(*Union) + switch { + case xu != nil && yu != nil: + // Quadratic algorithm, but good enough for now. + // TODO(gri) fix asymptotic performance + var types []Type + var tilde []bool + for _, y := range yu.types { + if includes(xu.types, y) { + types = append(types, y) + tilde = append(tilde, true) // TODO(gri) fix this + } + } + if types != nil { + return newUnion(types, tilde) + } + + case xu != nil: + if includes(xu.types, y) { + return y + } + + case yu != nil: + if includes(yu.types, x) { + return x + } + + default: // xu == nil && yu == nil + if Identical(x, y) { + return x + } + } + + return theBottom +} From aecfd5c29e3d8cb168c180f4e14e981c58eb599c Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Wed, 9 Jun 2021 18:31:55 -0400 Subject: [PATCH 435/940] [dev.typeparams] go/types: clean up type set/union intersection This is a straightforward port of CL 323354 to go/types. Change-Id: I53512540cc35df6e88b2b66e144e1be7ccc9a6f0 Reviewed-on: https://go-review.googlesource.com/c/go/+/326678 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/interface.go | 10 -- src/go/types/predicates.go | 11 +- src/go/types/sanitize.go | 2 +- src/go/types/sizeof_test.go | 1 - src/go/types/subst.go | 4 +- src/go/types/testdata/check/issues.go2 | 2 +- .../types/testdata/examples/constraints.go2 | 14 +++ src/go/types/type.go | 40 +++---- src/go/types/typestring.go | 7 +- src/go/types/union.go | 107 +++++++++++++----- 10 files changed, 119 insertions(+), 79 deletions(-) diff --git a/src/go/types/interface.go b/src/go/types/interface.go index 2bbd2f135de..9b4d080c813 100644 --- a/src/go/types/interface.go +++ b/src/go/types/interface.go @@ -111,16 +111,6 @@ func flattenUnion(list []ast.Expr, x ast.Expr) []ast.Expr { return append(list, x) } -// includes reports whether typ is in list. -func includes(list []Type, typ Type) bool { - for _, e := range list { - if Identical(typ, e) { - return true - } - } - return false -} - func (check *Checker) completeInterface(pos token.Pos, ityp *Interface) { if ityp.allMethods != nil { return diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index 78dba6d3e03..6aa58259431 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -101,9 +101,9 @@ func comparable(T Type, seen map[Type]bool) bool { seen[T] = true // If T is a type parameter not constrained by any type - // list (i.e., it's underlying type is the top type), + // list (i.e., it's operational type is the top type), // T is comparable if it has the == method. Otherwise, - // the underlying type "wins". For instance + // the operational type "wins". For instance // // interface{ comparable; type []byte } // @@ -374,10 +374,9 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { // case *instance: // unreachable since types are expanded - case *bottom, *top: - // Either both types are theBottom, or both are theTop in which - // case the initial x == y check will have caught them. Otherwise - // they are not identical. + case *top: + // Either both types are theTop in which case the initial x == y check + // will have caught them. Otherwise they are not identical. case nil: // avoid a crash in case of nil type diff --git a/src/go/types/sanitize.go b/src/go/types/sanitize.go index 2d700608990..05e7d8b4bfe 100644 --- a/src/go/types/sanitize.go +++ b/src/go/types/sanitize.go @@ -78,7 +78,7 @@ func (s sanitizer) typ(typ Type) Type { s[typ] = typ switch t := typ.(type) { - case *Basic, *bottom, *top: + case *Basic, *top: // nothing to do case *Array: diff --git a/src/go/types/sizeof_test.go b/src/go/types/sizeof_test.go index 3e79499ea5a..9459f677697 100644 --- a/src/go/types/sizeof_test.go +++ b/src/go/types/sizeof_test.go @@ -33,7 +33,6 @@ func TestSizeof(t *testing.T) { {Named{}, 68, 136}, {_TypeParam{}, 28, 48}, {instance{}, 44, 88}, - {bottom{}, 0, 0}, {top{}, 0, 0}, // Objects diff --git a/src/go/types/subst.go b/src/go/types/subst.go index 8cd8d0719b7..24108993efa 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -210,7 +210,7 @@ func (check *Checker) satisfies(pos token.Pos, targ Type, tpar *_TypeParam, smap // Otherwise, targ's type or underlying type must also be one of the interface types listed, if any. if !iface.isSatisfiedBy(targ) { - check.softErrorf(atPos(pos), _Todo, "%s does not satisfy %s (%s not found in %s)", targ, tpar.bound, under(targ), iface.allTypes) + check.softErrorf(atPos(pos), _Todo, "%s does not satisfy %s (%s not found in %s)", targ, tpar.bound, targ, iface.allTypes) return false } @@ -253,7 +253,7 @@ func (subst *subster) typ(typ Type) Type { // Call typOrNil if it's possible that typ is nil. panic("nil typ") - case *Basic, *bottom, *top: + case *Basic, *top: // nothing to do case *Array: diff --git a/src/go/types/testdata/check/issues.go2 b/src/go/types/testdata/check/issues.go2 index 8994164eacf..0a7648cba17 100644 --- a/src/go/types/testdata/check/issues.go2 +++ b/src/go/types/testdata/check/issues.go2 @@ -241,7 +241,7 @@ func _[T interface{ type func() }](f T) { type sliceOf[E any] interface{ type []E } -func append[T interface{}, S sliceOf[T], T2 interface{ type T }](s S, t ...T2) S +func append[T interface{}, S sliceOf[T], T2 interface{ T }](s S, t ...T2) S var f func() var cancelSlice []context.CancelFunc diff --git a/src/go/types/testdata/examples/constraints.go2 b/src/go/types/testdata/examples/constraints.go2 index e8b3912884c..f6291ccf7dd 100644 --- a/src/go/types/testdata/examples/constraints.go2 +++ b/src/go/types/testdata/examples/constraints.go2 @@ -23,3 +23,17 @@ type ( _ interface{~ /* ERROR cannot use interface */ interface{}} _ interface{int|interface /* ERROR cannot use interface */ {}} ) + +// Multiple embedded union elements are intersected. The order in which they +// appear in the interface doesn't matter since intersection is a symmetric +// operation. + +type myInt1 int +type myInt2 int + +func _[T interface{ myInt1|myInt2; ~int }]() T { return T(0) } +func _[T interface{ ~int; myInt1|myInt2 }]() T { return T(0) } + +// Here the intersections are empty - there's no type that's in the type set of T. +func _[T interface{ myInt1|myInt2; int }]() T { return T(0 /* ERROR cannot convert */ ) } +func _[T interface{ int; myInt1|myInt2 }]() T { return T(0 /* ERROR cannot convert */ ) } diff --git a/src/go/types/type.go b/src/go/types/type.go index 3b10fabbf84..8a4544e4971 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -383,7 +383,6 @@ func (t *Interface) Method(i int) *Func { t.Complete(); return t.allMethods[i] } // Empty reports whether t is the empty interface. func (t *Interface) Empty() bool { t.Complete() - // A non-nil allTypes may still have length 0 but represents the bottom type. return len(t.allMethods) == 0 && t.allTypes == nil } @@ -438,11 +437,15 @@ func (t *Interface) iterate(f func(*Interface) bool, seen map[*Interface]bool) b // "implements" predicate. func (t *Interface) isSatisfiedBy(typ Type) bool { t.Complete() - if t.allTypes == nil { - return true + switch t := t.allTypes.(type) { + case nil: + return true // no type restrictions + case *Union: + r, _ := t.intersect(typ, false) + return r != nil + default: + return Identical(t, typ) } - types := unpackType(t.allTypes) - return includes(types, typ) || includes(types, under(typ)) } // Complete computes the interface's method set. It must be called by users of @@ -647,13 +650,11 @@ func (t *_TypeParam) Bound() *Interface { return iface } -// optype returns a type's operational type. Except for -// type parameters, the operational type is the same -// as the underlying type (as returned by under). For -// Type parameters, the operational type is determined -// by the corresponding type bound's type list. The -// result may be the bottom or top type, but it is never -// the incoming type parameter. +// optype returns a type's operational type. Except for type parameters, +// the operational type is the same as the underlying type (as returned +// by under). For Type parameters, the operational type is determined +// by the corresponding type constraint. The result may be the top type, +// but it is never the incoming type parameter. func optype(typ Type) Type { if t := asTypeParam(typ); t != nil { // If the optype is typ, return the top type as we have @@ -726,20 +727,11 @@ var expandf func(Type) Type func init() { expandf = expand } -// bottom represents the bottom of the type lattice. -// It is the underlying type of a type parameter that -// cannot be satisfied by any type, usually because -// the intersection of type constraints left nothing). -type bottom struct{} - -// theBottom is the singleton bottom type. -var theBottom = &bottom{} - // top represents the top of the type lattice. // It is the underlying type of a type parameter that // can be satisfied by any type (ignoring methods), -// usually because the type constraint has no type -// list. +// because its type constraint contains no restrictions +// besides methods. type top struct{} // theTop is the singleton top type. @@ -759,7 +751,6 @@ func (t *Chan) Underlying() Type { return t } func (t *Named) Underlying() Type { return t.underlying } func (t *_TypeParam) Underlying() Type { return t } func (t *instance) Underlying() Type { return t } -func (t *bottom) Underlying() Type { return t } func (t *top) Underlying() Type { return t } // Type-specific implementations of String. @@ -776,7 +767,6 @@ func (t *Chan) String() string { return TypeString(t, nil) } func (t *Named) String() string { return TypeString(t, nil) } func (t *_TypeParam) String() string { return TypeString(t, nil) } func (t *instance) String() string { return TypeString(t, nil) } -func (t *bottom) String() string { return TypeString(t, nil) } func (t *top) String() string { return TypeString(t, nil) } // under returns the true expanded underlying type. diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go index 52c22f25d88..73465a35b77 100644 --- a/src/go/types/typestring.go +++ b/src/go/types/typestring.go @@ -159,6 +159,10 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { writeSignature(buf, t, qf, visited) case *Union: + if t.IsEmpty() { + buf.WriteString("⊥") + break + } for i, e := range t.types { if i > 0 { buf.WriteString("|") @@ -288,9 +292,6 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { writeTypeList(buf, t.targs, qf, visited) buf.WriteByte(']') - case *bottom: - buf.WriteString("⊥") - case *top: buf.WriteString("⊤") diff --git a/src/go/types/union.go b/src/go/types/union.go index aa46b8ab9c5..4eda874eb8a 100644 --- a/src/go/types/union.go +++ b/src/go/types/union.go @@ -13,14 +13,18 @@ import ( // API // A Union represents a union of terms. -// A term is a type, possibly with a ~ (tilde) flag. +// A term is a type with a ~ (tilde) flag. type Union struct { types []Type // types are unique tilde []bool // if tilde[i] is set, terms[i] is of the form ~T } -func NewUnion(types []Type, tilde []bool) Type { return newUnion(types, tilde) } +// NewUnion returns a new Union type with the given terms (types[i], tilde[i]). +// The lengths of both arguments must match. An empty union represents the set +// of no types. +func NewUnion(types []Type, tilde []bool) *Union { return newUnion(types, tilde) } +func (u *Union) IsEmpty() bool { return len(u.types) == 0 } func (u *Union) NumTerms() int { return len(u.types) } func (u *Union) Term(i int) (Type, bool) { return u.types[i], u.tilde[i] } @@ -30,10 +34,12 @@ func (u *Union) String() string { return TypeString(u, nil) } // ---------------------------------------------------------------------------- // Implementation -func newUnion(types []Type, tilde []bool) Type { +var emptyUnion = new(Union) + +func newUnion(types []Type, tilde []bool) *Union { assert(len(types) == len(tilde)) - if types == nil { - return nil + if len(types) == 0 { + return emptyUnion } t := new(Union) t.types = types @@ -43,7 +49,7 @@ func newUnion(types []Type, tilde []bool) Type { // is reports whether f returned true for all terms (type, tilde) of u. func (u *Union) is(f func(Type, bool) bool) bool { - if u == nil { + if u.IsEmpty() { return false } for i, t := range u.types { @@ -56,7 +62,7 @@ func (u *Union) is(f func(Type, bool) bool) bool { // is reports whether f returned true for the underlying types of all terms of u. func (u *Union) underIs(f func(Type) bool) bool { - if u == nil { + if u.IsEmpty() { return false } for _, t := range u.types { @@ -133,26 +139,24 @@ func parseTilde(check *Checker, x ast.Expr) (Type, bool) { return check.anyType(x), tilde } -// intersect computes the intersection of the types x and y. -// Note: An incomming nil type stands for the top type. A top -// type result is returned as nil. +// intersect computes the intersection of the types x and y, +// A nil type stands for the set of all types; an empty union +// stands for the set of no types. func intersect(x, y Type) (r Type) { - defer func() { - if r == theTop { - r = nil - } - }() - + // If one of the types is nil (no restrictions) + // the result is the other type. switch { - case x == theBottom || y == theBottom: - return theBottom - case x == nil || x == theTop: + case x == nil: return y - case y == nil || x == theTop: + case y == nil: return x } // Compute the terms which are in both x and y. + // TODO(gri) This is not correct as it may not always compute + // the "largest" intersection. For instance, for + // x = myInt|~int, y = ~int + // we get the result myInt but we should get ~int. xu, _ := x.(*Union) yu, _ := y.(*Union) switch { @@ -161,23 +165,29 @@ func intersect(x, y Type) (r Type) { // TODO(gri) fix asymptotic performance var types []Type var tilde []bool - for _, y := range yu.types { - if includes(xu.types, y) { - types = append(types, y) - tilde = append(tilde, true) // TODO(gri) fix this + for j, y := range yu.types { + yt := yu.tilde[j] + if r, rt := xu.intersect(y, yt); r != nil { + // Terms x[i] and y[j] match: Select the one that + // is not a ~t because that is the intersection + // type. If both are ~t, they are identical: + // T ∩ T = T + // T ∩ ~t = T + // ~t ∩ T = T + // ~t ∩ ~t = ~t + types = append(types, r) + tilde = append(tilde, rt) } } - if types != nil { - return newUnion(types, tilde) - } + return newUnion(types, tilde) case xu != nil: - if includes(xu.types, y) { + if r, _ := xu.intersect(y, false); r != nil { return y } case yu != nil: - if includes(yu.types, x) { + if r, _ := yu.intersect(x, false); r != nil { return x } @@ -187,5 +197,42 @@ func intersect(x, y Type) (r Type) { } } - return theBottom + return emptyUnion +} + +// includes reports whether typ is in list. +func includes(list []Type, typ Type) bool { + for _, e := range list { + if Identical(typ, e) { + return true + } + } + return false +} + +// intersect computes the intersection of the union u and term (y, yt) +// and returns the intersection term, if any. Otherwise the result is +// (nil, false). +func (u *Union) intersect(y Type, yt bool) (Type, bool) { + under_y := under(y) + for i, x := range u.types { + xt := u.tilde[i] + // determine which types xx, yy to compare + xx := x + if yt { + xx = under(x) + } + yy := y + if xt { + yy = under_y + } + if Identical(xx, yy) { + // T ∩ T = T + // T ∩ ~t = T + // ~t ∩ T = T + // ~t ∩ ~t = ~t + return xx, xt && yt + } + } + return nil, false } From 8e14a9cf04fd2a215871f7f68abaa926d8435173 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Wed, 9 Jun 2021 18:41:19 -0400 Subject: [PATCH 436/940] [dev.typeparams] go/types: eliminate need for unpack and asUnion functions This is a straightforward port of CL 323355 to go/types, adjusted for the different error reporting API in go/types. Change-Id: I0f9d7ca0e0959e1e214ecd61eb85cc311e6409a2 Reviewed-on: https://go-review.googlesource.com/c/go/+/326679 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/builtins.go | 12 +++++------- src/go/types/infer.go | 15 +++++++++------ src/go/types/subst.go | 11 ++++++----- src/go/types/type.go | 35 +++++++++-------------------------- 4 files changed, 29 insertions(+), 44 deletions(-) diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index 92807ed44a1..cfaeab611b0 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -768,14 +768,12 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { if tp := asTypeParam(x); tp != nil { // Test if t satisfies the requirements for the argument // type and collect possible result types at the same time. - // TODO(gri) This needs to consider the ~ information if we - // have a union type. var rtypes []Type - var tilde []bool - if !tp.Bound().is(func(x Type) bool { - if r := f(x); r != nil { + var tildes []bool + if !tp.Bound().is(func(typ Type, tilde bool) bool { + if r := f(typ); r != nil { rtypes = append(rtypes, r) - tilde = append(tilde, true) + tildes = append(tildes, tilde) return true } return false @@ -786,7 +784,7 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { // construct a suitable new type parameter tpar := NewTypeName(token.NoPos, nil /* = Universe pkg */, "", nil) ptyp := check.newTypeParam(tpar, 0, &emptyInterface) // assigns type to tpar as a side-effect - tsum := newUnion(rtypes, tilde) + tsum := newUnion(rtypes, tildes) ptyp.bound = &Interface{allMethods: markComplete, allTypes: tsum} return ptyp diff --git a/src/go/types/infer.go b/src/go/types/infer.go index ddf02a3942a..5a4f939bb13 100644 --- a/src/go/types/infer.go +++ b/src/go/types/infer.go @@ -323,7 +323,7 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { return true } } - return w.isParameterizedList(unpackType(t.allTypes)) + return w.isParameterized(t.allTypes) } return t.iterate(func(t *Interface) bool { @@ -472,11 +472,14 @@ func (check *Checker) inferB(tparams []*TypeName, targs []Type, report bool) (ty func (check *Checker) structuralType(constraint Type) Type { if iface, _ := under(constraint).(*Interface); iface != nil { check.completeInterface(token.NoPos, iface) - types := unpackType(iface.allTypes) - if len(types) == 1 { - return types[0] + if u, _ := iface.allTypes.(*Union); u != nil { + if u.NumTerms() == 1 { + // TODO(gri) do we need to respect tilde? + return u.types[0] + } + return nil } - return nil + return iface.allTypes } - return constraint + return nil } diff --git a/src/go/types/subst.go b/src/go/types/subst.go index 24108993efa..025eba0f8c3 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -198,14 +198,15 @@ func (check *Checker) satisfies(pos token.Pos, targ Type, tpar *_TypeParam, smap check.softErrorf(atPos(pos), _Todo, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ) return false } - for _, t := range unpackType(targBound.allTypes) { - if !iface.isSatisfiedBy(t) { + return iface.is(func(typ Type, tilde bool) bool { + // TODO(gri) incorporate tilde information! + if !iface.isSatisfiedBy(typ) { // TODO(gri) match this error message with the one below (or vice versa) - check.softErrorf(atPos(pos), 0, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, t, iface.allTypes) + check.softErrorf(atPos(pos), 0, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, typ, iface.allTypes) return false } - } - return false + return true + }) } // Otherwise, targ's type or underlying type must also be one of the interface types listed, if any. diff --git a/src/go/types/type.go b/src/go/types/type.go index 8a4544e4971..7429056865e 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -266,29 +266,17 @@ type Interface struct { obj Object // type declaration defining this interface; or nil (for better error messages) } -// unpack unpacks a type into a list of types. -// TODO(gri) Try to eliminate the need for this function. -func unpackType(typ Type) []Type { - if typ == nil { - return nil - } - if u := asUnion(typ); u != nil { - return u.types - } - return []Type{typ} -} - -// is reports whether interface t represents types that all satisfy pred. -func (t *Interface) is(pred func(Type) bool) bool { - if t.allTypes == nil { +// is reports whether interface t represents types that all satisfy f. +func (t *Interface) is(f func(Type, bool) bool) bool { + switch t := t.allTypes.(type) { + case nil, *top: + // TODO(gri) should settle on top or nil to represent this case return false // we must have at least one type! (was bug) + case *Union: + return t.is(func(typ Type, tilde bool) bool { return f(typ, tilde) }) + default: + return f(t, false) } - for _, t := range unpackType(t.allTypes) { - if !pred(t) { - return false - } - } - return true } // emptyInterface represents the empty (completed) interface @@ -824,11 +812,6 @@ func asSignature(t Type) *Signature { return op } -func asUnion(t Type) *Union { - op, _ := optype(t).(*Union) - return op -} - func asInterface(t Type) *Interface { op, _ := optype(t).(*Interface) return op From 795f4475e58ff7adaeaf949f8e79470a7c43f501 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Wed, 9 Jun 2021 18:46:30 -0400 Subject: [PATCH 437/940] [dev.typeparams] go/types: convert testdata/examples tests to type set sytax This is a straightforward port of CL 324529 to go/types. Change-Id: I788b1ac3d4e40060038a134c525c81624add8e81 Reviewed-on: https://go-review.googlesource.com/c/go/+/326680 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/testdata/examples/functions.go2 | 2 +- src/go/types/testdata/examples/inference.go2 | 6 +++--- src/go/types/testdata/examples/types.go2 | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/go/types/testdata/examples/functions.go2 b/src/go/types/testdata/examples/functions.go2 index fb74ae7ae25..f15c709ce44 100644 --- a/src/go/types/testdata/examples/functions.go2 +++ b/src/go/types/testdata/examples/functions.go2 @@ -98,7 +98,7 @@ func g2b[P, Q any](x P, y Q) { // Here's an example of a recursive function call with variadic // arguments and type inference inferring the type parameter of // the caller (i.e., itself). -func max[T interface{ type int }](x ...T) T { +func max[T interface{ ~int }](x ...T) T { var x0 T if len(x) > 0 { x0 = x[0] diff --git a/src/go/types/testdata/examples/inference.go2 b/src/go/types/testdata/examples/inference.go2 index b4f3369aa0c..1142e569b47 100644 --- a/src/go/types/testdata/examples/inference.go2 +++ b/src/go/types/testdata/examples/inference.go2 @@ -7,7 +7,7 @@ package p type Ordered interface { - type int, float64, string + ~int|~float64|~string } func min[T Ordered](x, y T) T @@ -54,7 +54,7 @@ func _() { mixed[int, string](1.1 /* ERROR cannot use 1.1 */ , "", false) } -func related1[Slice interface{type []Elem}, Elem any](s Slice, e Elem) +func related1[Slice interface{~[]Elem}, Elem any](s Slice, e Elem) func _() { // related1 can be called with explicit instantiation. @@ -78,7 +78,7 @@ func _() { related1(si, "foo" /* ERROR cannot use "foo" */ ) } -func related2[Elem any, Slice interface{type []Elem}](e Elem, s Slice) +func related2[Elem any, Slice interface{~[]Elem}](e Elem, s Slice) func _() { // related2 can be called with explicit instantiation. diff --git a/src/go/types/testdata/examples/types.go2 b/src/go/types/testdata/examples/types.go2 index 59c8804ad27..8cdd7f2fd27 100644 --- a/src/go/types/testdata/examples/types.go2 +++ b/src/go/types/testdata/examples/types.go2 @@ -165,7 +165,7 @@ type _ struct { // are type parameters. As with ordinary type definitions, the // types underlying properties are "inherited" but the methods // are not. -func _[T interface{ m(); type int }]() { +func _[T interface{ m(); ~int }]() { type L T var x L @@ -238,11 +238,11 @@ func _[A Adder[A], B Adder[B], C Adder[A]]() { // The type of variables (incl. parameters and return values) cannot // be an interface with type constraints or be/embed comparable. type I interface { - type int + ~int } var ( - _ interface /* ERROR contains type constraints */ {type int} + _ interface /* ERROR contains type constraints */ {~int} _ I /* ERROR contains type constraints */ ) @@ -273,7 +273,7 @@ func _() { // (If a type list contains just a single const type, we could // allow it, but such type lists don't make much sense in the // first place.) -func _[T interface { type int, float64 }]() { +func _[T interface {~int|~float64}]() { // not valid const _ = T /* ERROR not constant */ (0) const _ T /* ERROR invalid constant type T */ = 1 From b6fc4d01a8d9cefe180fde97ace36588d1d31417 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Wed, 9 Jun 2021 18:51:24 -0400 Subject: [PATCH 438/940] [dev.typeparams] go/types: convert testdata/fixedbugs tests to type set sytax This is a port of CL 324530 to go/types. One error position in issue39634.go2 was adjusted by a character, to account for go/types' positioning. Change-Id: Ie06974ea9ee81d3ae66ef58dba522936ab4ce2d1 Reviewed-on: https://go-review.googlesource.com/c/go/+/326681 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/testdata/fixedbugs/issue39634.go2 | 4 ++-- src/go/types/testdata/fixedbugs/issue39680.go2 | 4 ++-- src/go/types/testdata/fixedbugs/issue39699.go2 | 2 +- src/go/types/testdata/fixedbugs/issue39723.go2 | 2 +- src/go/types/testdata/fixedbugs/issue39755.go2 | 4 ++-- src/go/types/testdata/fixedbugs/issue41124.go2 | 4 ++-- src/go/types/testdata/fixedbugs/issue42758.go2 | 2 +- src/go/types/testdata/fixedbugs/issue45548.go2 | 2 +- src/go/types/testdata/fixedbugs/issue45635.go2 | 2 +- src/go/types/testdata/fixedbugs/issue45985.go2 | 2 +- 10 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/go/types/testdata/fixedbugs/issue39634.go2 b/src/go/types/testdata/fixedbugs/issue39634.go2 index c759be0d93f..8decff5291e 100644 --- a/src/go/types/testdata/fixedbugs/issue39634.go2 +++ b/src/go/types/testdata/fixedbugs/issue39634.go2 @@ -31,12 +31,12 @@ type x7[A any] struct{ foo7 } func main7() { var _ foo7 = x7[int]{} } // crash 8 -type foo8[A any] interface { type A } +type foo8[A any] interface { ~A } func bar8[A foo8[A]](a A) {} func main8() {} // crash 9 -type foo9[A any] interface { type foo9 /* ERROR cannot use interface */ [A] } +type foo9[A any] interface { ~ /* ERROR cannot use interface */ foo9 [A] } func _() { var _ = new(foo9 /* ERROR interface contains type constraints */ [int]) } // crash 12 diff --git a/src/go/types/testdata/fixedbugs/issue39680.go2 b/src/go/types/testdata/fixedbugs/issue39680.go2 index 9bc26f35461..01eadd2dbf9 100644 --- a/src/go/types/testdata/fixedbugs/issue39680.go2 +++ b/src/go/types/testdata/fixedbugs/issue39680.go2 @@ -7,13 +7,13 @@ package p import "fmt" // Minimal test case. -func _[T interface{type T}](x T) T{ +func _[T interface{~T}](x T) T{ return x } // Test case from issue. type constr[T any] interface { - type T + ~T } func Print[T constr[T]](s []T) { diff --git a/src/go/types/testdata/fixedbugs/issue39699.go2 b/src/go/types/testdata/fixedbugs/issue39699.go2 index 75491e7e26f..72f83997c24 100644 --- a/src/go/types/testdata/fixedbugs/issue39699.go2 +++ b/src/go/types/testdata/fixedbugs/issue39699.go2 @@ -8,7 +8,7 @@ type T0 interface{ } type T1 interface{ - type int + ~int } type T2 interface{ diff --git a/src/go/types/testdata/fixedbugs/issue39723.go2 b/src/go/types/testdata/fixedbugs/issue39723.go2 index 61bc6067892..367b3f1360f 100644 --- a/src/go/types/testdata/fixedbugs/issue39723.go2 +++ b/src/go/types/testdata/fixedbugs/issue39723.go2 @@ -6,4 +6,4 @@ package p // A constraint must be an interface; it cannot // be a type parameter, for instance. -func _[A interface{ type int }, B A /* ERROR not an interface */ ]() +func _[A interface{ ~int }, B A /* ERROR not an interface */ ]() diff --git a/src/go/types/testdata/fixedbugs/issue39755.go2 b/src/go/types/testdata/fixedbugs/issue39755.go2 index b7ab68818e9..257b73a2fbe 100644 --- a/src/go/types/testdata/fixedbugs/issue39755.go2 +++ b/src/go/types/testdata/fixedbugs/issue39755.go2 @@ -4,14 +4,14 @@ package p -func _[T interface{type map[string]int}](x T) { +func _[T interface{~map[string]int}](x T) { _ = x == nil } // simplified test case from issue type PathParamsConstraint interface { - type map[string]string, []struct{key, value string} + ~map[string]string | ~[]struct{key, value string} } type PathParams[T PathParamsConstraint] struct { diff --git a/src/go/types/testdata/fixedbugs/issue41124.go2 b/src/go/types/testdata/fixedbugs/issue41124.go2 index 61f766bcbd7..ab535049dd7 100644 --- a/src/go/types/testdata/fixedbugs/issue41124.go2 +++ b/src/go/types/testdata/fixedbugs/issue41124.go2 @@ -7,7 +7,7 @@ package p // Test case from issue. type Nat interface { - type Zero, Succ + Zero|Succ } type Zero struct{} @@ -22,7 +22,7 @@ type I1 interface { } type I2 interface { - type int + ~int } type I3 interface { diff --git a/src/go/types/testdata/fixedbugs/issue42758.go2 b/src/go/types/testdata/fixedbugs/issue42758.go2 index 698cb8a16ba..bf0031f5d24 100644 --- a/src/go/types/testdata/fixedbugs/issue42758.go2 +++ b/src/go/types/testdata/fixedbugs/issue42758.go2 @@ -17,7 +17,7 @@ func _[T any](x interface{}){ } type constraint interface { - type int + ~int } func _[T constraint](x interface{}){ diff --git a/src/go/types/testdata/fixedbugs/issue45548.go2 b/src/go/types/testdata/fixedbugs/issue45548.go2 index b1e42497e85..b8ba0ad4a70 100644 --- a/src/go/types/testdata/fixedbugs/issue45548.go2 +++ b/src/go/types/testdata/fixedbugs/issue45548.go2 @@ -4,7 +4,7 @@ package p -func f[F interface{type *Q}, G interface{type *R}, Q, R any](q Q, r R) {} +func f[F interface{~*Q}, G interface{~*R}, Q, R any](q Q, r R) {} func _() { f[*float64, *int](1, 2) diff --git a/src/go/types/testdata/fixedbugs/issue45635.go2 b/src/go/types/testdata/fixedbugs/issue45635.go2 index 3e2cceca2d4..0f629803434 100644 --- a/src/go/types/testdata/fixedbugs/issue45635.go2 +++ b/src/go/types/testdata/fixedbugs/issue45635.go2 @@ -13,7 +13,7 @@ type N[T any] struct{} var _ N /* ERROR "0 arguments but 1 type parameters" */ [] type I interface { - type map[int]int, []int + ~map[int]int | ~[]int } func _[T I](i, j int) { diff --git a/src/go/types/testdata/fixedbugs/issue45985.go2 b/src/go/types/testdata/fixedbugs/issue45985.go2 index 550b9c67127..6e42dbb6339 100644 --- a/src/go/types/testdata/fixedbugs/issue45985.go2 +++ b/src/go/types/testdata/fixedbugs/issue45985.go2 @@ -5,7 +5,7 @@ package issue45985 // TODO(rFindley): this error should be on app[int] below. -func app[S /* ERROR "type S = S does not match" */ interface{ type []T }, T any](s S, e T) S { +func app[S /* ERROR "type S = S does not match" */ interface{ ~[]T }, T any](s S, e T) S { return append(s, e) } From 6e50f4f11166d5bfa2fba2f28bf4d43e3a713930 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 10 Jun 2021 09:27:44 -0400 Subject: [PATCH 439/940] [dev.typeparams] go/types: convert testdata/check tests to type set syntax This is a port of CL 324569 to go/types, with some error positions adjusted: go/types puts errors related to terms on the '~', not type name. Change-Id: I92e8443ce27a5ecae0e3e0dac4811eaf3eee07ff Reviewed-on: https://go-review.googlesource.com/c/go/+/326682 Trust: Robert Findley Run-TryBot: Robert Findley Reviewed-by: Robert Griesemer --- src/go/types/testdata/check/builtins.go2 | 8 +-- src/go/types/testdata/check/issues.go2 | 26 +++---- src/go/types/testdata/check/linalg.go2 | 16 ++--- src/go/types/testdata/check/tinference.go2 | 20 +++--- src/go/types/testdata/check/typeinst2.go2 | 29 ++++---- src/go/types/testdata/check/typeparams.go2 | 80 +++++++++++----------- 6 files changed, 90 insertions(+), 89 deletions(-) diff --git a/src/go/types/testdata/check/builtins.go2 b/src/go/types/testdata/check/builtins.go2 index 3918d836b52..5bb67efec9d 100644 --- a/src/go/types/testdata/check/builtins.go2 +++ b/src/go/types/testdata/check/builtins.go2 @@ -7,19 +7,19 @@ package builtins type Bmc interface { - type map[rune]string, chan int + ~map[rune]string | ~chan int } type Bms interface { - type map[string]int, []int + ~map[string]int | ~[]int } type Bcs interface { - type chan bool, []float64 + ~chan bool | ~[]float64 } type Bss interface { - type []int, []string + ~[]int | ~[]string } func _[T any] () { diff --git a/src/go/types/testdata/check/issues.go2 b/src/go/types/testdata/check/issues.go2 index 0a7648cba17..c655fb99a4f 100644 --- a/src/go/types/testdata/check/issues.go2 +++ b/src/go/types/testdata/check/issues.go2 @@ -64,7 +64,7 @@ func _() { // type with a type list constraint, all of the type argument's types in its // bound, but at least one (!), must be in the type list of the bound of the // corresponding parameterized type's type parameter. -type T1[P interface{type uint}] struct{} +type T1[P interface{~uint}] struct{} func _[P any]() { _ = T1[P /* ERROR P has no type constraints */ ]{} @@ -72,7 +72,7 @@ func _[P any]() { // This is the original (simplified) program causing the same issue. type Unsigned interface { - type uint + ~uint } type T2[U Unsigned] struct { @@ -163,7 +163,7 @@ type inf2[T any] struct{ inf2 /* ERROR illegal cycle */ [T] } // predicate disjunction in the implementation was wrong because if a type list // contains both an integer and a floating-point type, the type parameter is // neither an integer or a floating-point number. -func convert[T1, T2 interface{type int, uint, float32}](v T1) T2 { +func convert[T1, T2 interface{~int | ~uint | ~float32}](v T1) T2 { return T2(v) } @@ -175,12 +175,12 @@ func _() { // both numeric, or both strings. The implementation had the same problem // with this check as the conversion issue above (issue #39623). -func issue39623[T interface{type int, string}](x, y T) T { +func issue39623[T interface{~int | ~string}](x, y T) T { return x + y } // Simplified, from https://go2goplay.golang.org/p/efS6x6s-9NI: -func Sum[T interface{type int, string}](s []T) (sum T) { +func Sum[T interface{~int | ~string}](s []T) (sum T) { for _, v := range s { sum += v } @@ -189,19 +189,19 @@ func Sum[T interface{type int, string}](s []T) (sum T) { // Assignability of an unnamed pointer type to a type parameter that // has a matching underlying type. -func _[T interface{}, PT interface{type *T}] (x T) PT { +func _[T interface{}, PT interface{~*T}] (x T) PT { return &x } // Indexing of generic types containing type parameters in their type list: -func at[T interface{ type []E }, E interface{}](x T, i int) E { +func at[T interface{ ~[]E }, E interface{}](x T, i int) E { return x[i] } // A generic type inside a function acts like a named type. Its underlying // type is itself, its "operational type" is defined by the type list in // the tybe bound, if any. -func _[T interface{type int}](x T) { +func _[T interface{~int}](x T) { type myint int var _ int = int(x) var _ T = 42 @@ -210,24 +210,24 @@ func _[T interface{type int}](x T) { // Indexing a generic type with an array type bound checks length. // (Example by mdempsky@.) -func _[T interface { type [10]int }](x T) { +func _[T interface { ~[10]int }](x T) { _ = x[9] // ok _ = x[20 /* ERROR out of bounds */ ] } // Pointer indirection of a generic type. -func _[T interface{ type *int }](p T) int { +func _[T interface{ ~*int }](p T) int { return *p } // Channel sends and receives on generic types. -func _[T interface{ type chan int }](ch T) int { +func _[T interface{ ~chan int }](ch T) int { ch <- 0 return <- ch } // Calling of a generic variable. -func _[T interface{ type func() }](f T) { +func _[T interface{ ~func() }](f T) { f() go f() } @@ -239,7 +239,7 @@ func _[T interface{ type func() }](f T) { // type parameter that was substituted with a defined type. // Test case from an (originally) failing example. -type sliceOf[E any] interface{ type []E } +type sliceOf[E any] interface{ ~[]E } func append[T interface{}, S sliceOf[T], T2 interface{ T }](s S, t ...T2) S diff --git a/src/go/types/testdata/check/linalg.go2 b/src/go/types/testdata/check/linalg.go2 index 0d27603a583..efc090a1d1f 100644 --- a/src/go/types/testdata/check/linalg.go2 +++ b/src/go/types/testdata/check/linalg.go2 @@ -9,10 +9,10 @@ import "math" // Numeric is type bound that matches any numeric type. // It would likely be in a constraints package in the standard library. type Numeric interface { - type int, int8, int16, int32, int64, - uint, uint8, uint16, uint32, uint64, uintptr, - float32, float64, - complex64, complex128 + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~complex64 | ~complex128 } func DotProduct[T Numeric](s1, s2 []T) T { @@ -42,14 +42,14 @@ func AbsDifference[T NumericAbs[T]](a, b T) T { // OrderedNumeric is a type bound that matches numeric types that support the < operator. type OrderedNumeric interface { - type int, int8, int16, int32, int64, - uint, uint8, uint16, uint32, uint64, uintptr, - float32, float64 + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 } // Complex is a type bound that matches the two complex types, which do not have a < operator. type Complex interface { - type complex64, complex128 + ~complex64 | ~complex128 } // OrderedAbs is a helper type that defines an Abs method for diff --git a/src/go/types/testdata/check/tinference.go2 b/src/go/types/testdata/check/tinference.go2 index 31338b33ad6..7ed358e0784 100644 --- a/src/go/types/testdata/check/tinference.go2 +++ b/src/go/types/testdata/check/tinference.go2 @@ -11,28 +11,28 @@ type any interface{} // TODO(rFindley) the below partially applied function types should probably // not be permitted (spec question). -func f0[A any, B interface{type C}, C interface{type D}, D interface{type A}](A, B, C, D) +func f0[A any, B interface{~C}, C interface{~D}, D interface{~A}](A, B, C, D) func _() { f := f0[string] f("a", "b", "c", "d") f0("a", "b", "c", "d") } -func f1[A any, B interface{type A}](A, B) +func f1[A any, B interface{~A}](A, B) func _() { f := f1[int] f(int(0), int(0)) f1(int(0), int(0)) } -func f2[A any, B interface{type []A}](A, B) +func f2[A any, B interface{~[]A}](A, B) func _() { f := f2[byte] f(byte(0), []byte{}) f2(byte(0), []byte{}) } -func f3[A any, B interface{type C}, C interface{type *A}](A, B, C) +func f3[A any, B interface{~C}, C interface{~*A}](A, B, C) func _() { f := f3[int] var x int @@ -40,7 +40,7 @@ func _() { f3(x, &x, &x) } -func f4[A any, B interface{type []C}, C interface{type *A}](A, B, C) +func f4[A any, B interface{~[]C}, C interface{~*A}](A, B, C) func _() { f := f4[int] var x int @@ -48,14 +48,14 @@ func _() { f4(x, []*int{}, &x) } -func f5[A interface{type struct{b B; c C}}, B any, C interface{type *B}](x B) A +func f5[A interface{~struct{b B; c C}}, B any, C interface{~*B}](x B) A func _() { x := f5(1.2) var _ float64 = x.b var _ float64 = *x.c } -func f6[A any, B interface{type struct{f []A}}](B) A +func f6[A any, B interface{~struct{f []A}}](B) A func _() { x := f6(struct{f []string}{}) var _ string = x @@ -63,11 +63,11 @@ func _() { // TODO(gri) Need to flag invalid recursive constraints. At the // moment these cause infinite recursions and stack overflow. -// func f7[A interface{type B}, B interface{type A}]() +// func f7[A interface{type B}, B interface{~A}]() // More realistic examples -func Double[S interface{ type []E }, E interface{ type int, int8, int16, int32, int64 }](s S) S { +func Double[S interface{ ~[]E }, E interface{ ~int | ~int8 | ~int16 | ~int32 | ~int64 }](s S) S { r := make(S, len(s)) for i, v := range s { r[i] = v + v @@ -83,7 +83,7 @@ var _ = Double(MySlice{1}) type Setter[B any] interface { Set(string) - type *B + ~*B } func FromStrings[T interface{}, PT Setter[T]](s []string) []T { diff --git a/src/go/types/testdata/check/typeinst2.go2 b/src/go/types/testdata/check/typeinst2.go2 index 1096bb42eb7..a4c9f58c097 100644 --- a/src/go/types/testdata/check/typeinst2.go2 +++ b/src/go/types/testdata/check/typeinst2.go2 @@ -148,15 +148,15 @@ func _[T any](r R2[T, int], p *R2[string, T]) { p.pm() } -// An interface can (explicitly) declare at most one type list. +// It is ok to have multiple embedded unions. type _ interface { m0() - type int, string, bool - type /* ERROR multiple type lists */ float32, float64 + ~int | ~string | ~bool + ~float32 | ~float64 m1() m2() - type /* ERROR multiple type lists */ complex64, complex128 - type /* ERROR multiple type lists */ rune + ~complex64 | ~complex128 + ~rune } // Interface type lists may contain each type at most once. @@ -164,23 +164,24 @@ type _ interface { // for them to be all in a single list, and we report the error // as well.) type _ interface { - type int, int /* ERROR duplicate term int */ - type /* ERROR multiple type lists */ int /* ERROR duplicate term int */ + ~int|~ /* ERROR duplicate term int */ int + ~int|int /* ERROR duplicate term int */ + int|int /* ERROR duplicate term int */ } type _ interface { - type struct{f int}, struct{g int}, struct /* ERROR duplicate term */ {f int} + ~struct{f int} | ~struct{g int} | ~ /* ERROR duplicate term */ struct{f int} } // Interface type lists can contain any type, incl. *Named types. // Verify that we use the underlying type to compute the operational type. type MyInt int -func add1[T interface{type MyInt}](x T) T { +func add1[T interface{~MyInt}](x T) T { return x + 1 } type MyString string -func double[T interface{type MyInt, MyString}](x T) T { +func double[T interface{~MyInt | ~MyString}](x T) T { return x + x } @@ -189,15 +190,15 @@ func double[T interface{type MyInt, MyString}](x T) T { // type lists. type E0 interface { - type int, bool, string + ~int | ~bool | ~string } type E1 interface { - type int, float64, string + ~int | ~float64 | ~string } type E2 interface { - type float64 + ~float64 } type I0 interface { @@ -246,7 +247,7 @@ var _ = f12[float64] type I0_ interface { E0 - type int + ~int } func f0_[T I0_]() diff --git a/src/go/types/testdata/check/typeparams.go2 b/src/go/types/testdata/check/typeparams.go2 index d95e02e4432..5b4361d2791 100644 --- a/src/go/types/testdata/check/typeparams.go2 +++ b/src/go/types/testdata/check/typeparams.go2 @@ -52,22 +52,22 @@ func swapswap[A, B any](a A, b B) (A, B) { type F[A, B any] func(A, B) (B, A) -func min[T interface{ type int }](x, y T) T { +func min[T interface{ ~int }](x, y T) T { if x < y { return x } return y } -func _[T interface{type int, float32}](x, y T) bool { return x < y } +func _[T interface{~int | ~float32}](x, y T) bool { return x < y } func _[T any](x, y T) bool { return x /* ERROR cannot compare */ < y } -func _[T interface{type int, float32, bool}](x, y T) bool { return x /* ERROR cannot compare */ < y } +func _[T interface{~int | ~float32 | ~bool}](x, y T) bool { return x /* ERROR cannot compare */ < y } func _[T C1[T]](x, y T) bool { return x /* ERROR cannot compare */ < y } func _[T C2[T]](x, y T) bool { return x < y } type C1[T any] interface{} -type C2[T any] interface{ type int, float32 } +type C2[T any] interface{ ~int | ~float32 } func new[T any]() *T { var x T @@ -95,48 +95,48 @@ var _ = f3[int, rune, bool](1, struct{x rune}{}, nil) // indexing func _[T any] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } -func _[T interface{ type int }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } -func _[T interface{ type string }] (x T, i int) { _ = x[i] } -func _[T interface{ type []int }] (x T, i int) { _ = x[i] } -func _[T interface{ type [10]int, *[20]int, map[int]int }] (x T, i int) { _ = x[i] } -func _[T interface{ type string, []byte }] (x T, i int) { _ = x[i] } -func _[T interface{ type []int, [1]rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } -func _[T interface{ type string, []rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } +func _[T interface{ ~int }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } +func _[T interface{ ~string }] (x T, i int) { _ = x[i] } +func _[T interface{ ~[]int }] (x T, i int) { _ = x[i] } +func _[T interface{ ~[10]int | ~*[20]int | ~map[int]int }] (x T, i int) { _ = x[i] } +func _[T interface{ ~string | ~[]byte }] (x T, i int) { _ = x[i] } +func _[T interface{ ~[]int | ~[1]rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } +func _[T interface{ ~string | ~[]rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } // indexing with various combinations of map types in type lists (see issue #42616) -func _[T interface{ type []E, map[int]E }, E any](x T, i int) { _ = x[i] } -func _[T interface{ type []E }, E any](x T, i int) { _ = &x[i] } -func _[T interface{ type map[int]E }, E any](x T, i int) { _, _ = x[i] } // comma-ok permitted -func _[T interface{ type []E, map[int]E }, E any](x T, i int) { _ = &x /* ERROR cannot take address */ [i] } -func _[T interface{ type []E, map[int]E, map[uint]E }, E any](x T, i int) { _ = x /* ERROR cannot index */ [i] } // different map element types -func _[T interface{ type []E, map[string]E }, E any](x T, i int) { _ = x[i /* ERROR cannot use i */ ] } +func _[T interface{ ~[]E | ~map[int]E }, E any](x T, i int) { _ = x[i] } +func _[T interface{ ~[]E }, E any](x T, i int) { _ = &x[i] } +func _[T interface{ ~map[int]E }, E any](x T, i int) { _, _ = x[i] } // comma-ok permitted +func _[T interface{ ~[]E | ~map[int]E }, E any](x T, i int) { _ = &x /* ERROR cannot take address */ [i] } +func _[T interface{ ~[]E | ~map[int]E | ~map[uint]E }, E any](x T, i int) { _ = x /* ERROR cannot index */ [i] } // different map element types +func _[T interface{ ~[]E | ~map[string]E }, E any](x T, i int) { _ = x[i /* ERROR cannot use i */ ] } // slicing // TODO(gri) implement this -func _[T interface{ type string }] (x T, i, j, k int) { _ = x /* ERROR invalid operation */ [i:j:k] } +func _[T interface{ ~string }] (x T, i, j, k int) { _ = x /* ERROR invalid operation */ [i:j:k] } // len/cap built-ins func _[T any](x T) { _ = len(x /* ERROR invalid argument */ ) } -func _[T interface{ type int }](x T) { _ = len(x /* ERROR invalid argument */ ) } -func _[T interface{ type string, []byte, int }](x T) { _ = len(x /* ERROR invalid argument */ ) } -func _[T interface{ type string }](x T) { _ = len(x) } -func _[T interface{ type [10]int }](x T) { _ = len(x) } -func _[T interface{ type []byte }](x T) { _ = len(x) } -func _[T interface{ type map[int]int }](x T) { _ = len(x) } -func _[T interface{ type chan int }](x T) { _ = len(x) } -func _[T interface{ type string, []byte, chan int }](x T) { _ = len(x) } +func _[T interface{ ~int }](x T) { _ = len(x /* ERROR invalid argument */ ) } +func _[T interface{ ~string | ~[]byte | ~int }](x T) { _ = len(x /* ERROR invalid argument */ ) } +func _[T interface{ ~string }](x T) { _ = len(x) } +func _[T interface{ ~[10]int }](x T) { _ = len(x) } +func _[T interface{ ~[]byte }](x T) { _ = len(x) } +func _[T interface{ ~map[int]int }](x T) { _ = len(x) } +func _[T interface{ ~chan int }](x T) { _ = len(x) } +func _[T interface{ ~string | ~[]byte | ~chan int }](x T) { _ = len(x) } func _[T any](x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _[T interface{ type int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _[T interface{ type string, []byte, int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _[T interface{ type string }](x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _[T interface{ type [10]int }](x T) { _ = cap(x) } -func _[T interface{ type []byte }](x T) { _ = cap(x) } -func _[T interface{ type map[int]int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _[T interface{ type chan int }](x T) { _ = cap(x) } -func _[T interface{ type []byte, chan int }](x T) { _ = cap(x) } +func _[T interface{ ~int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } +func _[T interface{ ~string | ~[]byte | ~int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } +func _[T interface{ ~string }](x T) { _ = cap(x /* ERROR invalid argument */ ) } +func _[T interface{ ~[10]int }](x T) { _ = cap(x) } +func _[T interface{ ~[]byte }](x T) { _ = cap(x) } +func _[T interface{ ~map[int]int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } +func _[T interface{ ~chan int }](x T) { _ = cap(x) } +func _[T interface{ ~[]byte | ~chan int }](x T) { _ = cap(x) } // range iteration @@ -144,7 +144,7 @@ func _[T interface{}](x T) { for range x /* ERROR cannot range */ {} } -func _[T interface{ type string, []string }](x T) { +func _[T interface{ ~string | ~[]string }](x T) { for range x {} for i := range x { _ = i } for i, _ := range x { _ = i } @@ -156,23 +156,23 @@ func _[T interface{ type string, []string }](x T) { } -func _[T interface{ type string, []rune, map[int]rune }](x T) { +func _[T interface{ ~string | ~[]rune | ~map[int]rune }](x T) { for _, e := range x { _ = e } for i, e := range x { _ = i; _ = e } } -func _[T interface{ type string, []rune, map[string]rune }](x T) { +func _[T interface{ ~string | ~[]rune | ~map[string]rune }](x T) { for _, e := range x { _ = e } for i, e := range x /* ERROR must have the same key type */ { _ = e } } -func _[T interface{ type string, chan int }](x T) { +func _[T interface{ ~string | ~chan int }](x T) { for range x {} for i := range x { _ = i } for i, _ := range x { _ = i } // TODO(gri) should get an error here: channels only return one value } -func _[T interface{ type string, chan<-int }](x T) { +func _[T interface{ ~string | ~chan<-int }](x T) { for i := range x /* ERROR send-only channel */ { _ = i } } @@ -399,7 +399,7 @@ func _[T any](x T) { } } -func _[T interface{type int}](x T) { +func _[T interface{~int}](x T) { _ = x /* ERROR not an interface */ .(int) switch x /* ERROR not an interface */ .(type) { } From 6237e441bca7f3429abde413bf71c7840fec9bf2 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 10 Jun 2021 11:26:08 -0400 Subject: [PATCH 440/940] [dev.typeparams] go/types: disallow type list handling This is a port of CL 324571 to go/types, though type list handling is guarded by a const rather than a config option. Change-Id: I91c940fead048980603e0bb56fcc896dbef4f94c Reviewed-on: https://go-review.googlesource.com/c/go/+/326683 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/api.go | 2 ++ src/go/types/api_test.go | 2 +- src/go/types/api_typeparams_test.go | 14 +++++++------- src/go/types/interface.go | 10 +++++++++- src/go/types/testdata/examples/constraints.go2 | 12 ++++++++++++ src/go/types/typestring_test.go | 1 - 6 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/go/types/api.go b/src/go/types/api.go index 30f8ded744a..d3a95bc9910 100644 --- a/src/go/types/api.go +++ b/src/go/types/api.go @@ -34,6 +34,8 @@ import ( "go/token" ) +const allowTypeLists = false + // An Error describes a type-checking error; it implements the error interface. // A "soft" error is an error that still permits a valid interpretation of a // package (such as "unused variable"); "hard" errors may lead to unpredictable diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go index 5a2d4a4ca38..6a7218d90f4 100644 --- a/src/go/types/api_test.go +++ b/src/go/types/api_test.go @@ -349,7 +349,7 @@ func TestTypesInfo(t *testing.T) { {genericPkg + `g0; type t[P any] int; var x struct{ f t[int] }; var _ = x.f`, `x.f`, `generic_g0.t[int]`}, // issue 45096 - {genericPkg + `issue45096; func _[T interface{ type int8, int16, int32 }](x T) { _ = x < 0 }`, `0`, `T₁`}, + {genericPkg + `issue45096; func _[T interface{ ~int8 | ~int16 | ~int32 }](x T) { _ = x < 0 }`, `0`, `T₁`}, } for _, test := range tests { diff --git a/src/go/types/api_typeparams_test.go b/src/go/types/api_typeparams_test.go index 4a2adce9a29..d9117b84129 100644 --- a/src/go/types/api_typeparams_test.go +++ b/src/go/types/api_typeparams_test.go @@ -45,38 +45,38 @@ func TestInferredInfo(t *testing.T) { `func(float64, *byte, ...[]byte)`, }, - {genericPkg + `s1; func f[T any, P interface{type *T}](x T); func _(x string) { f(x) }`, + {genericPkg + `s1; func f[T any, P interface{~*T}](x T); func _(x string) { f(x) }`, `f`, []string{`string`, `*string`}, `func(x string)`, }, - {genericPkg + `s2; func f[T any, P interface{type *T}](x []T); func _(x []int) { f(x) }`, + {genericPkg + `s2; func f[T any, P interface{~*T}](x []T); func _(x []int) { f(x) }`, `f`, []string{`int`, `*int`}, `func(x []int)`, }, - {genericPkg + `s3; type C[T any] interface{type chan<- T}; func f[T any, P C[T]](x []T); func _(x []int) { f(x) }`, + {genericPkg + `s3; type C[T any] interface{~chan<- T}; func f[T any, P C[T]](x []T); func _(x []int) { f(x) }`, `f`, []string{`int`, `chan<- int`}, `func(x []int)`, }, - {genericPkg + `s4; type C[T any] interface{type chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T); func _(x []int) { f(x) }`, + {genericPkg + `s4; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T); func _(x []int) { f(x) }`, `f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func(x []int)`, }, - {genericPkg + `t1; func f[T any, P interface{type *T}]() T; func _() { _ = f[string] }`, + {genericPkg + `t1; func f[T any, P interface{~*T}]() T; func _() { _ = f[string] }`, `f`, []string{`string`, `*string`}, `func() string`, }, - {genericPkg + `t2; type C[T any] interface{type chan<- T}; func f[T any, P C[T]]() []T; func _() { _ = f[int] }`, + {genericPkg + `t2; type C[T any] interface{~chan<- T}; func f[T any, P C[T]]() []T; func _() { _ = f[int] }`, `f`, []string{`int`, `chan<- int`}, `func() []int`, }, - {genericPkg + `t3; type C[T any] interface{type chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T; func _() { _ = f[int] }`, + {genericPkg + `t3; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T; func _() { _ = f[int] }`, `f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func() []int`, diff --git a/src/go/types/interface.go b/src/go/types/interface.go index 9b4d080c813..947e76dc17e 100644 --- a/src/go/types/interface.go +++ b/src/go/types/interface.go @@ -34,7 +34,13 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d continue // ignore } + // TODO(rfindley) Remove type list handling once the parser doesn't accept type lists anymore. if name.Name == "type" { + // Report an error for the first type list per interface + // if we don't allow type lists, but continue. + if !allowTypeLists && tlist == nil { + check.softErrorf(name, _Todo, "use generalized embedding syntax instead of a type list") + } // For now, collect all type list entries as if it // were a single union, where each union element is // of the form ~T. @@ -43,7 +49,9 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d op.Op = token.TILDE op.X = f.Type tlist = append(tlist, op) - if tname != nil && tname != name { + // Report an error if we have multiple type lists in an + // interface, but only if they are permitted in the first place. + if allowTypeLists && tname != nil && tname != name { check.errorf(name, _Todo, "cannot have multiple type lists in an interface") } tname = name diff --git a/src/go/types/testdata/examples/constraints.go2 b/src/go/types/testdata/examples/constraints.go2 index f6291ccf7dd..61992e4c2a8 100644 --- a/src/go/types/testdata/examples/constraints.go2 +++ b/src/go/types/testdata/examples/constraints.go2 @@ -6,6 +6,18 @@ package p +type ( + // Type lists are processed as unions but an error is reported. + // TODO(gri) remove this once the parser doesn't accept type lists anymore. + _ interface{ + type /* ERROR use generalized embedding syntax instead of a type list */ int + } + _ interface{ + type /* ERROR use generalized embedding syntax instead of a type list */ int + type float32 + } +) + type ( // Arbitrary types may be embedded like interfaces. _ interface{int} diff --git a/src/go/types/typestring_test.go b/src/go/types/typestring_test.go index 0e35a3dbf1c..f02c0d9c18d 100644 --- a/src/go/types/typestring_test.go +++ b/src/go/types/typestring_test.go @@ -95,7 +95,6 @@ var independentTestTypes = []testEntry{ dup("interface{}"), dup("interface{m()}"), dup(`interface{String() string; m(int) float32}`), - {"interface{type int, float32, complex128}", "interface{~int|~float32|~complex128}"}, dup("interface{int|float32|complex128}"), dup("interface{int|~float32|~complex128}"), From 8115ae198d192f778a3586596c8550665f409823 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 10 Jun 2021 12:23:40 -0400 Subject: [PATCH 441/940] [dev.typeparams] go/types: disallow ~T where T is a defined type or an interface This is a straightforward port of CL 324570 to go/types. Change-Id: I1395775a1d21a903a57e0cefc4e240cfa2bb8e97 Reviewed-on: https://go-review.googlesource.com/c/go/+/326684 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/testdata/check/typeinst2.go2 | 4 ++-- src/go/types/testdata/examples/constraints.go2 | 9 +++++++++ src/go/types/testdata/fixedbugs/issue39634.go2 | 4 ++-- src/go/types/union.go | 11 ++++++----- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/go/types/testdata/check/typeinst2.go2 b/src/go/types/testdata/check/typeinst2.go2 index a4c9f58c097..ab56ccafc91 100644 --- a/src/go/types/testdata/check/typeinst2.go2 +++ b/src/go/types/testdata/check/typeinst2.go2 @@ -176,12 +176,12 @@ type _ interface { // Interface type lists can contain any type, incl. *Named types. // Verify that we use the underlying type to compute the operational type. type MyInt int -func add1[T interface{~MyInt}](x T) T { +func add1[T interface{MyInt}](x T) T { return x + 1 } type MyString string -func double[T interface{~MyInt | ~MyString}](x T) T { +func double[T interface{MyInt|MyString}](x T) T { return x + x } diff --git a/src/go/types/testdata/examples/constraints.go2 b/src/go/types/testdata/examples/constraints.go2 index 61992e4c2a8..d9805fe6940 100644 --- a/src/go/types/testdata/examples/constraints.go2 +++ b/src/go/types/testdata/examples/constraints.go2 @@ -36,6 +36,15 @@ type ( _ interface{int|interface /* ERROR cannot use interface */ {}} ) +type ( + // Tilde is not permitted on defined types or interfaces. + foo int + bar interface{} + _ interface{foo} + _ interface{~ /* ERROR invalid use of ~ */ foo } + _ interface{~ /* ERROR invalid use of ~ */ bar } +) + // Multiple embedded union elements are intersected. The order in which they // appear in the interface doesn't matter since intersection is a symmetric // operation. diff --git a/src/go/types/testdata/fixedbugs/issue39634.go2 b/src/go/types/testdata/fixedbugs/issue39634.go2 index 8decff5291e..2a1367373f5 100644 --- a/src/go/types/testdata/fixedbugs/issue39634.go2 +++ b/src/go/types/testdata/fixedbugs/issue39634.go2 @@ -36,8 +36,8 @@ func bar8[A foo8[A]](a A) {} func main8() {} // crash 9 -type foo9[A any] interface { ~ /* ERROR cannot use interface */ foo9 [A] } -func _() { var _ = new(foo9 /* ERROR interface contains type constraints */ [int]) } +type foo9[A any] interface { foo9 /* ERROR illegal cycle */ [A] } +func _() { var _ = new(foo9 /* ERROR illegal cycle */ [int]) } // crash 12 var u /* ERROR cycle */ , i [func /* ERROR used as value */ /* ERROR used as value */ (u, c /* ERROR undeclared */ /* ERROR undeclared */ ) {}(0, len /* ERROR must be called */ /* ERROR must be called */ )]c /* ERROR undeclared */ /* ERROR undeclared */ diff --git a/src/go/types/union.go b/src/go/types/union.go index 4eda874eb8a..690b734d76d 100644 --- a/src/go/types/union.go +++ b/src/go/types/union.go @@ -109,17 +109,18 @@ func parseUnion(check *Checker, tlist []ast.Expr) Type { } u := under(t) - if tilde[i] { - // TODO(rfindley) enable this check once we have converted tests - // if !Identical(u, t) { - // check.errorf(x, "invalid use of ~ (underlying type of %s is %s)", t, u) - // } + if tilde[i] && !Identical(u, t) { + check.errorf(x, _Todo, "invalid use of ~ (underlying type of %s is %s)", t, u) + continue // don't report another error for t } if _, ok := u.(*Interface); ok { + // A single type with a ~ is a single-term union. check.errorf(atPos(pos), _Todo, "cannot use interface %s with ~ or inside a union (implementation restriction)", t) + continue // don't report another error for t } // Complain about duplicate entries a|a, but also a|~a, and ~a|~a. + // TODO(gri) We should also exclude myint|~int since myint is included in ~int. if includes(types[:i], t) { // TODO(rfindley) this currently doesn't print the ~ if present check.softErrorf(atPos(pos), _Todo, "duplicate term %s in union element", t) From b14fd720a8c3822161ed85447774e38fab835f6f Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Wed, 16 Jun 2021 16:23:44 +0700 Subject: [PATCH 442/940] [dev.typeparams] cmd/compile: make types2 report better error for invalid untyped operation This ports the fix in CL 328050 for typecheck to types2. The fix is not identical, due to code structure differences between typecheck and types2, but the idea is the same. We only do the untyped conversion when both operands can be mixed. Updates #46749 Change-Id: Ib2c63ba0d5dd8bf02318b1bfdfe51dcaeeeb7f82 Reviewed-on: https://go-review.googlesource.com/c/go/+/328053 Trust: Cuong Manh Le Trust: Robert Griesemer Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types2/expr.go | 28 ++++++++++++++----- .../internal/types2/testdata/check/const0.src | 2 +- .../internal/types2/testdata/check/decls1.src | 2 +- .../internal/types2/testdata/check/expr1.src | 4 +-- .../internal/types2/testdata/check/expr2.src | 2 +- .../internal/types2/testdata/check/expr3.src | 2 +- .../internal/types2/testdata/check/stmt0.src | 12 ++++---- test/fixedbugs/issue41500.go | 8 +++--- test/fixedbugs/issue43762.go | 6 ++-- test/fixedbugs/issue46749.go | 10 +++---- test/run.go | 1 - 11 files changed, 45 insertions(+), 32 deletions(-) diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go index b223387f18e..d1cb27de160 100644 --- a/src/cmd/compile/internal/types2/expr.go +++ b/src/cmd/compile/internal/types2/expr.go @@ -972,14 +972,28 @@ func (check *Checker) binary(x *operand, e syntax.Expr, lhs, rhs syntax.Expr, op return } - check.convertUntyped(x, y.typ) - if x.mode == invalid { - return + canMix := func(x, y *operand) bool { + if IsInterface(x.typ) || IsInterface(y.typ) { + return true + } + if isBoolean(x.typ) != isBoolean(y.typ) { + return false + } + if isString(x.typ) != isString(y.typ) { + return false + } + return true } - check.convertUntyped(&y, x.typ) - if y.mode == invalid { - x.mode = invalid - return + if canMix(x, &y) { + check.convertUntyped(x, y.typ) + if x.mode == invalid { + return + } + check.convertUntyped(&y, x.typ) + if y.mode == invalid { + x.mode = invalid + return + } } if isComparison(op) { diff --git a/src/cmd/compile/internal/types2/testdata/check/const0.src b/src/cmd/compile/internal/types2/testdata/check/const0.src index 5608b1549ba..3cffdf904c8 100644 --- a/src/cmd/compile/internal/types2/testdata/check/const0.src +++ b/src/cmd/compile/internal/types2/testdata/check/const0.src @@ -27,7 +27,7 @@ const ( ub1 = true ub2 = 2 < 1 ub3 = ui1 == uf1 - ub4 = true /* ERROR "cannot convert" */ == 0 + ub4 = true /* ERROR "mismatched types untyped bool and untyped int" */ == 0 // integer values ui0 = 0 diff --git a/src/cmd/compile/internal/types2/testdata/check/decls1.src b/src/cmd/compile/internal/types2/testdata/check/decls1.src index e6beb783589..1167ced366e 100644 --- a/src/cmd/compile/internal/types2/testdata/check/decls1.src +++ b/src/cmd/compile/internal/types2/testdata/check/decls1.src @@ -83,7 +83,7 @@ var ( // Constant expression initializations var ( - v1 = 1 /* ERROR "cannot convert" */ + "foo" + v1 = 1 /* ERROR "mismatched types untyped int and untyped string" */ + "foo" v2 = c + 255 v3 = c + 256 /* ERROR "overflows" */ v4 = r + 2147483647 diff --git a/src/cmd/compile/internal/types2/testdata/check/expr1.src b/src/cmd/compile/internal/types2/testdata/check/expr1.src index 4ead815158f..85ad234bbbf 100644 --- a/src/cmd/compile/internal/types2/testdata/check/expr1.src +++ b/src/cmd/compile/internal/types2/testdata/check/expr1.src @@ -111,10 +111,10 @@ type mystring string func _(x, y string, z mystring) { x = x + "foo" x = x /* ERROR not defined */ - "foo" - x = x + 1 // ERROR cannot convert + x = x + 1 // ERROR mismatched types string and untyped int x = x + y x = x /* ERROR not defined */ - y - x = x * 10 // ERROR cannot convert + x = x * 10 // ERROR mismatched types string and untyped int } func f() (a, b int) { return } diff --git a/src/cmd/compile/internal/types2/testdata/check/expr2.src b/src/cmd/compile/internal/types2/testdata/check/expr2.src index 0c959e80119..f9726b5de53 100644 --- a/src/cmd/compile/internal/types2/testdata/check/expr2.src +++ b/src/cmd/compile/internal/types2/testdata/check/expr2.src @@ -10,7 +10,7 @@ func _bool() { const t = true == true const f = true == false _ = t /* ERROR "cannot compare" */ < f - _ = 0 /* ERROR "cannot convert" */ == t + _ = 0 /* ERROR "mismatched types untyped int and untyped bool" */ == t var b bool var x, y float32 b = x < y diff --git a/src/cmd/compile/internal/types2/testdata/check/expr3.src b/src/cmd/compile/internal/types2/testdata/check/expr3.src index eab3f72c4d5..fd28421dc89 100644 --- a/src/cmd/compile/internal/types2/testdata/check/expr3.src +++ b/src/cmd/compile/internal/types2/testdata/check/expr3.src @@ -104,7 +104,7 @@ func indexes() { var ok mybool _, ok = m["bar"] _ = ok - _ = m[0 /* ERROR "cannot use 0" */ ] + "foo" // ERROR "cannot convert" + _ = m[0 /* ERROR "cannot use 0" */ ] + "foo" // ERROR "mismatched types int and untyped string" var t string _ = t[- /* ERROR "negative" */ 1] diff --git a/src/cmd/compile/internal/types2/testdata/check/stmt0.src b/src/cmd/compile/internal/types2/testdata/check/stmt0.src index bedcbe5fce3..d744f2ba814 100644 --- a/src/cmd/compile/internal/types2/testdata/check/stmt0.src +++ b/src/cmd/compile/internal/types2/testdata/check/stmt0.src @@ -49,18 +49,18 @@ func assignments1() { b = true i += 1 - i += "foo" /* ERROR "cannot convert.*int" */ + i += "foo" /* ERROR "mismatched types int and untyped string" */ f -= 1 f /= 0 f = float32(0)/0 /* ERROR "division by zero" */ - f -= "foo" /* ERROR "cannot convert.*float64" */ + f -= "foo" /* ERROR "mismatched types float64 and untyped string" */ c *= 1 c /= 0 s += "bar" - s += 1 /* ERROR "cannot convert.*string" */ + s += 1 /* ERROR "mismatched types string and untyped int" */ var u64 uint64 u64 += 1< Date: Thu, 17 Jun 2021 07:01:16 +0800 Subject: [PATCH 443/940] doc/go1.17: fix redundant space Change-Id: I6fccab7504f928452fbe490ae83e8d4b23a59f06 Reviewed-on: https://go-review.googlesource.com/c/go/+/328849 Reviewed-by: Dmitri Shuralyov Reviewed-by: Cherry Mui --- doc/go1.17.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 75c05c9e255..f8d7aad0348 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -387,7 +387,7 @@ func Foo() bool { registers instead of the stack. This work is enabled for Linux, MacOS, and Windows on the 64-bit x86 architecture (the linux/amd64, darwin/amd64, windows/amd64 ports). For a - representative set of Go packages and programs, benchmarking has shown + representative set of Go packages and programs, benchmarking has shown performance improvements of about 5%, and a typical reduction in binary size of about 2%.

From b0355a3e72df384c82a688524c603a97c1d8e7a7 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 10 Jun 2021 15:14:01 -0400 Subject: [PATCH 444/940] time: fix receiver for Time.IsDST method Only methods that modify the time take pointer receivers; IsDST does not modify it and therefore should not. For #42102 and #46688. Change-Id: I4721ef7f4d7572236ae6e4d99a459b9ffb11999e Reviewed-on: https://go-review.googlesource.com/c/go/+/326789 Trust: Russ Cox Run-TryBot: Russ Cox TryBot-Result: Go Bot Reviewed-by: Dmitri Shuralyov Reviewed-by: Ian Lance Taylor --- api/go1.17.txt | 2 +- src/time/time.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/go1.17.txt b/api/go1.17.txt index f054458715f..257ca271d3d 100644 --- a/api/go1.17.txt +++ b/api/go1.17.txt @@ -153,7 +153,7 @@ pkg time, const Layout = "01/02 03:04:05PM '06 -0700" pkg time, const Layout ideal-string pkg time, func UnixMicro(int64) Time pkg time, func UnixMilli(int64) Time -pkg time, method (*Time) IsDST() bool +pkg time, method (Time) IsDST() bool pkg time, method (Time) GoString() string pkg time, method (Time) UnixMicro() int64 pkg time, method (Time) UnixMilli() int64 diff --git a/src/time/time.go b/src/time/time.go index cd756bbf5f2..1cf1e2bbf61 100644 --- a/src/time/time.go +++ b/src/time/time.go @@ -1340,7 +1340,7 @@ func UnixMicro(usec int64) Time { } // IsDST reports whether the time in the configured location is in Daylight Savings Time. -func (t *Time) IsDST() bool { +func (t Time) IsDST() bool { _, _, _, _, isDST := t.loc.lookup(t.Unix()) return isDST } From 97cee43c93cfccded197cd281f0a5885cdb605b4 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 8 Jun 2021 15:33:54 +0200 Subject: [PATCH 445/940] testing: drop unusual characters from TempDir directory name Only use safe characters of the test name for the os.MkdirTemp pattern. This currently includes the alphanumeric characters and ASCII punctuation characters known not to interact with globs. Fixes #46624 Change-Id: I402c34775b943fed9b97963c52f79245cc16dc1d Reviewed-on: https://go-review.googlesource.com/c/go/+/326010 Trust: Tobias Klauser Run-TryBot: Tobias Klauser TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills Reviewed-by: Ian Lance Taylor --- src/testing/testing.go | 34 ++++++++++++++++++++++------------ src/testing/testing_test.go | 10 +++++++++- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/testing/testing.go b/src/testing/testing.go index 85a7fec65f1..fdf57a39535 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -252,6 +252,8 @@ import ( "sync" "sync/atomic" "time" + "unicode" + "unicode/utf8" ) var initRan bool @@ -908,11 +910,6 @@ func (c *common) Cleanup(f func()) { c.cleanups = append(c.cleanups, fn) } -var tempDirReplacer struct { - sync.Once - r *strings.Replacer -} - // TempDir returns a temporary directory for the test to use. // The directory is automatically removed by Cleanup when the test and // all its subtests complete. @@ -936,13 +933,26 @@ func (c *common) TempDir() string { if nonExistent { c.Helper() - // os.MkdirTemp doesn't like path separators in its pattern, - // so mangle the name to accommodate subtests. - tempDirReplacer.Do(func() { - tempDirReplacer.r = strings.NewReplacer("/", "_", "\\", "_", ":", "_") - }) - pattern := tempDirReplacer.r.Replace(c.Name()) - + // Drop unusual characters (such as path separators or + // characters interacting with globs) from the directory name to + // avoid surprising os.MkdirTemp behavior. + mapper := func(r rune) rune { + if r < utf8.RuneSelf { + const allowed = "!#$%&()+,-.=@^_{}~ " + if '0' <= r && r <= '9' || + 'a' <= r && r <= 'z' || + 'A' <= r && r <= 'Z' { + return r + } + if strings.ContainsRune(allowed, r) { + return r + } + } else if unicode.IsLetter(r) || unicode.IsNumber(r) { + return r + } + return -1 + } + pattern := strings.Map(mapper, c.Name()) c.tempDir, c.tempDirErr = os.MkdirTemp("", pattern) if c.tempDirErr == nil { c.Cleanup(func() { diff --git a/src/testing/testing_test.go b/src/testing/testing_test.go index 55a4df4739e..08ae23991f1 100644 --- a/src/testing/testing_test.go +++ b/src/testing/testing_test.go @@ -58,6 +58,9 @@ func TestTempDir(t *testing.T) { t.Run("test:subtest", testTempDir) t.Run("test/..", testTempDir) t.Run("../test", testTempDir) + t.Run("test[]", testTempDir) + t.Run("test*", testTempDir) + t.Run("äöüéè", testTempDir) } func testTempDir(t *testing.T) { @@ -74,7 +77,7 @@ func testTempDir(t *testing.T) { if err != nil { t.Fatal(err) } - t.Errorf("directory %q stil exists: %v, isDir=%v", dir, fi, fi.IsDir()) + t.Errorf("directory %q still exists: %v, isDir=%v", dir, fi, fi.IsDir()) default: if !t.Failed() { t.Fatal("never received dir channel") @@ -108,6 +111,11 @@ func testTempDir(t *testing.T) { if len(files) > 0 { t.Errorf("unexpected %d files in TempDir: %v", len(files), files) } + + glob := filepath.Join(dir, "*.txt") + if _, err := filepath.Glob(glob); err != nil { + t.Error(err) + } } func TestSetenv(t *testing.T) { From 804ecc2581caf33ae347d6a1ce67436d1f74e93b Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 16 Jun 2021 21:41:28 -0700 Subject: [PATCH 446/940] [dev.typeparams] all: add GOEXPERIMENT=unified knob Setting `-gcflags=all=-d=unified` works for normal builds/tests, but seems to have trouble with the test/run.go regress tests. So add a GOEXPERIMENT knob to allow another way to turn on unified IR construction, which plays better with all.bash. While here, update two existing test expectations that currently fail during GOEXPERIMENT=unified ./all.bash: 1. misc/cgo/errors/testdata/err2.go is testing column positions, and types2 gets one case slightly better, and another case slightly worse. For now, the test case is updated to accept both. 2. fixedbugs/issue42284.go is added to the list of known failures, because it fails for unified IR. (It's an escape analysis test, and escape analysis is working as expected; but unified is formatting an imported constant value differently than the test's regexp expects.) Updates #46786. Change-Id: I40a4a70fa1b85ac87fcc85a43687f5d81e011ec0 Reviewed-on: https://go-review.googlesource.com/c/go/+/328215 Run-TryBot: Matthew Dempsky Trust: Matthew Dempsky Trust: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- misc/cgo/errors/testdata/err2.go | 12 +++- src/cmd/compile/internal/base/flag.go | 4 ++ src/internal/goexperiment/exp_unified_off.go | 9 +++ src/internal/goexperiment/exp_unified_on.go | 9 +++ src/internal/goexperiment/flags.go | 4 ++ test/run.go | 66 +++++++++++++++----- 6 files changed, 86 insertions(+), 18 deletions(-) create mode 100644 src/internal/goexperiment/exp_unified_off.go create mode 100644 src/internal/goexperiment/exp_unified_on.go diff --git a/misc/cgo/errors/testdata/err2.go b/misc/cgo/errors/testdata/err2.go index a90598fe35b..aa941584c3c 100644 --- a/misc/cgo/errors/testdata/err2.go +++ b/misc/cgo/errors/testdata/err2.go @@ -91,10 +91,18 @@ func main() { // issue 26745 _ = func(i int) int { - return C.i + 1 // ERROR HERE: 14 + // typecheck reports at column 14 ('+'), but types2 reports at + // column 10 ('C'). + // TODO(mdempsky): Investigate why, and see if types2 can be + // updated to match typecheck behavior. + return C.i + 1 // ERROR HERE: \b(10|14)\b } _ = func(i int) { - C.fi(i) // ERROR HERE: 7 + // typecheck reports at column 7 ('('), but types2 reports at + // column 8 ('i'). The types2 position is more correct, but + // updating typecheck here is fundamentally challenging because of + // IR limitations. + C.fi(i) // ERROR HERE: \b(7|8)\b } C.fi = C.fi // ERROR HERE diff --git a/src/cmd/compile/internal/base/flag.go b/src/cmd/compile/internal/base/flag.go index 42c0c1b94b5..b8b205f4127 100644 --- a/src/cmd/compile/internal/base/flag.go +++ b/src/cmd/compile/internal/base/flag.go @@ -159,7 +159,11 @@ func ParseFlags() { Flag.LinkShared = &Ctxt.Flag_linkshared Flag.Shared = &Ctxt.Flag_shared Flag.WB = true + Debug.InlFuncsWithClosures = 1 + if buildcfg.Experiment.Unified { + Debug.Unified = 1 + } Debug.Checkptr = -1 // so we can tell whether it is set explicitly diff --git a/src/internal/goexperiment/exp_unified_off.go b/src/internal/goexperiment/exp_unified_off.go new file mode 100644 index 00000000000..4c16fd85624 --- /dev/null +++ b/src/internal/goexperiment/exp_unified_off.go @@ -0,0 +1,9 @@ +// Code generated by mkconsts.go. DO NOT EDIT. + +//go:build !goexperiment.unified +// +build !goexperiment.unified + +package goexperiment + +const Unified = false +const UnifiedInt = 0 diff --git a/src/internal/goexperiment/exp_unified_on.go b/src/internal/goexperiment/exp_unified_on.go new file mode 100644 index 00000000000..2b17ba3e79b --- /dev/null +++ b/src/internal/goexperiment/exp_unified_on.go @@ -0,0 +1,9 @@ +// Code generated by mkconsts.go. DO NOT EDIT. + +//go:build goexperiment.unified +// +build goexperiment.unified + +package goexperiment + +const Unified = true +const UnifiedInt = 1 diff --git a/src/internal/goexperiment/flags.go b/src/internal/goexperiment/flags.go index 71e38cd0479..b7a62b3e268 100644 --- a/src/internal/goexperiment/flags.go +++ b/src/internal/goexperiment/flags.go @@ -59,6 +59,10 @@ type Flags struct { PreemptibleLoops bool StaticLockRanking bool + // Unified enables the compiler's unified IR construction + // experiment. + Unified bool + // Regabi is split into several sub-experiments that can be // enabled individually. Not all combinations work. // The "regabi" GOEXPERIMENT is an alias for all "working" diff --git a/test/run.go b/test/run.go index 656519e3017..f8bb8c081c7 100644 --- a/test/run.go +++ b/test/run.go @@ -58,8 +58,9 @@ func defaultAllCodeGen() bool { } var ( - goos, goarch string - cgoEnabled bool + goos, goarch string + cgoEnabled bool + unifiedEnabled bool // dirs are the directories to look for *.go files in. // TODO(bradfitz): just use all directories? @@ -95,10 +96,27 @@ func main() { goos = getenv("GOOS", runtime.GOOS) goarch = getenv("GOARCH", runtime.GOARCH) - cgoEnv, err := exec.Command(goTool(), "env", "CGO_ENABLED").Output() - if err == nil { - cgoEnabled, _ = strconv.ParseBool(strings.TrimSpace(string(cgoEnv))) + + cgoCmd := exec.Command(goTool(), "env", "CGO_ENABLED") + cgoEnv, err := cgoCmd.Output() + if err != nil { + log.Fatalf("running %v: %v", cgoCmd, err) } + cgoEnabled, _ = strconv.ParseBool(strings.TrimSpace(string(cgoEnv))) + + // TODO(mdempsky): Change this to just "go env GOEXPERIMENT" after + // CL 328751 is merged back to dev.typeparams. In the mean time, we + // infer whether the "unified" experiment is defult enabled by + // inspecting the output from `go tool compile -V`. + compileCmd := exec.Command(goTool(), "tool", "compile", "-V") + compileOutput, err := compileCmd.Output() + if err != nil { + log.Fatalf("running %v: %v", compileCmd, err) + } + // TODO(mdempsky): This will give false negatives if the unified + // experiment is enabled by default, but presumably at that point we + // won't need to disable tests for it anymore anyway. + unifiedEnabled = strings.Contains(string(compileOutput), "unified") findExecCmd() @@ -290,6 +308,10 @@ type test struct { err error } +// usesTypes2 reports whether the compiler uses types2 for this test +// configuration (irrespective of flags specified by the test itself). +func (t *test) usesTypes2() bool { return unifiedEnabled || t.glevel != 0 } + func startTests(dir, gofile string, glevels []int) []*test { tests := make([]*test, len(glevels)) for i, glevel := range glevels { @@ -519,8 +541,8 @@ func (t *test) run() { close(t.donec) }() - if t.glevel > 0 && !*force { - // Files excluded from generics testing. + if t.usesTypes2() && !*force { + // Files excluded from types2 testing. filename := strings.Replace(t.goFileName(), "\\", "/", -1) // goFileName() uses \ on Windows if excludedFiles[filename] { if *verbose { @@ -666,27 +688,35 @@ func (t *test) run() { // at the specified -G level. If so, it may update flags as // necessary to test with -G. validForGLevel := func(tool Tool) bool { - if t.glevel == 0 { - // default -G level; always valid + if !t.usesTypes2() { + // tests should always pass when run w/o types2 (i.e., using the + // legacy typechecker). return true } + hasGFlag := false for _, flag := range flags { if strings.Contains(flag, "-G") { - // test provides explicit -G flag already - if *verbose { - fmt.Printf("excl\t%s\n", t.goFileName()) - } - return false + hasGFlag = true } } + if hasGFlag && t.glevel != 0 { + // test provides explicit -G flag already; don't run again + if *verbose { + fmt.Printf("excl\t%s\n", t.goFileName()) + } + return false + } + switch tool { case Build, Run: // ok; handled in goGcflags case Compile: - flags = append(flags, fmt.Sprintf("-G=%v", t.glevel)) + if !hasGFlag { + flags = append(flags, fmt.Sprintf("-G=%v", t.glevel)) + } default: // we don't know how to add -G for this test yet @@ -2026,6 +2056,9 @@ func overlayDir(dstRoot, srcRoot string) error { // List of files that the compiler cannot errorcheck with the new typechecker (compiler -G option). // Temporary scaffolding until we pass all the tests at which point this map can be removed. +// +// TODO(mdempsky): Split exclude list to disambiguate whether the +// failure is within types2, -G=3, or unified. var excludedFiles = map[string]bool{ "directive.go": true, // misplaced compiler directive checks "float_lit3.go": true, // types2 reports extra errors @@ -2079,10 +2112,11 @@ var excludedFiles = map[string]bool{ "fixedbugs/issue33460.go": true, // types2 reports alternative positions in separate error "fixedbugs/issue42058a.go": true, // types2 doesn't report "channel element type too large" "fixedbugs/issue42058b.go": true, // types2 doesn't report "channel element type too large" - "fixedbugs/issue46725.go": true, // fix applied to typecheck needs to be ported to irgen/transform + "fixedbugs/issue42284.go": true, // unified formats important constant expression differently in diagnostics "fixedbugs/issue4232.go": true, // types2 reports (correct) extra errors "fixedbugs/issue4452.go": true, // types2 reports (correct) extra errors "fixedbugs/issue4510.go": true, // types2 reports different (but ok) line numbers + "fixedbugs/issue46725.go": true, // fix applied to typecheck needs to be ported to irgen/transform "fixedbugs/issue5609.go": true, // types2 needs a better error message "fixedbugs/issue7525b.go": true, // types2 reports init cycle error on different line - ok otherwise "fixedbugs/issue7525c.go": true, // types2 reports init cycle error on different line - ok otherwise From 4dede025507fe6476e9881b4b2bd773a3680d618 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Mon, 7 Jun 2021 13:28:09 -0400 Subject: [PATCH 447/940] cmd/pprof: make ObjAddr a no-op https://golang.org/cl/318049 replaced driver.ObjFile.Base with driver.ObjFile.ObjAddr. We don't support shared libraries, so these should be no-op, but CL 318049 accidentally failed to account from the change in no-op behavior from returning 0 to passing through addr. Fixes #46636 Change-Id: Iab82224c7db722a1e257ec6e305218e22114d0a8 Reviewed-on: https://go-review.googlesource.com/c/go/+/325809 Trust: Michael Pratt Run-TryBot: Michael Pratt TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/cmd/pprof/pprof.go | 4 +- src/cmd/pprof/pprof_test.go | 110 ++++++++++++++++++++++++++++++++++ src/cmd/pprof/testdata/cpu.go | 41 +++++++++++++ 3 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 src/cmd/pprof/pprof_test.go create mode 100644 src/cmd/pprof/testdata/cpu.go diff --git a/src/cmd/pprof/pprof.go b/src/cmd/pprof/pprof.go index 1d10a7b41f3..e72c765adc3 100644 --- a/src/cmd/pprof/pprof.go +++ b/src/cmd/pprof/pprof.go @@ -233,8 +233,8 @@ func (f *file) Name() string { } func (f *file) ObjAddr(addr uint64) (uint64, error) { - // No support for shared libraries. - return 0, nil + // No support for shared libraries, so translation is a no-op. + return addr, nil } func (f *file) BuildID() string { diff --git a/src/cmd/pprof/pprof_test.go b/src/cmd/pprof/pprof_test.go new file mode 100644 index 00000000000..170cdf3bb81 --- /dev/null +++ b/src/cmd/pprof/pprof_test.go @@ -0,0 +1,110 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "internal/testenv" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "testing" +) + +var tmp, pprofExe string // populated by buildPprof + +func TestMain(m *testing.M) { + if !testenv.HasGoBuild() { + return + } + + var exitcode int + if err := buildPprof(); err == nil { + exitcode = m.Run() + } else { + fmt.Println(err) + exitcode = 1 + } + os.RemoveAll(tmp) + os.Exit(exitcode) +} + +func buildPprof() error { + var err error + tmp, err = os.MkdirTemp("", "TestPprof") + if err != nil { + return fmt.Errorf("TempDir failed: %v", err) + } + + pprofExe = filepath.Join(tmp, "testpprof.exe") + gotool, err := testenv.GoTool() + if err != nil { + return err + } + out, err := exec.Command(gotool, "build", "-o", pprofExe, "cmd/pprof").CombinedOutput() + if err != nil { + os.RemoveAll(tmp) + return fmt.Errorf("go build -o %v cmd/pprof: %v\n%s", pprofExe, err, string(out)) + } + + return nil +} + +func mustHaveDisasm(t *testing.T) { + switch runtime.GOARCH { + case "mips", "mipsle", "mips64", "mips64le": + t.Skipf("skipping on %s, issue 12559", runtime.GOARCH) + case "riscv64": + t.Skipf("skipping on %s, issue 36738", runtime.GOARCH) + case "s390x": + t.Skipf("skipping on %s, issue 15255", runtime.GOARCH) + } + + // Skip PIE platforms, pprof can't disassemble PIE. + if runtime.GOOS == "windows" { + t.Skipf("skipping on %s, issue 46639", runtime.GOOS) + } + if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" { + t.Skipf("skipping on %s/%s, issue 46639", runtime.GOOS, runtime.GOARCH) + } +} + +// TestDisasm verifies that cmd/pprof can successfully disassemble functions. +// +// This is a regression test for issue 46636. +func TestDisasm(t *testing.T) { + mustHaveDisasm(t) + testenv.MustHaveGoBuild(t) + + tmpdir := t.TempDir() + cpuExe := filepath.Join(tmpdir, "cpu.exe") + cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", cpuExe, "cpu.go") + cmd.Dir = "testdata/" + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("build failed: %v\n%s", err, out) + } + + profile := filepath.Join(tmpdir, "cpu.pprof") + cmd = exec.Command(cpuExe, "-output", profile) + out, err = cmd.CombinedOutput() + if err != nil { + t.Fatalf("cpu failed: %v\n%s", err, out) + } + + cmd = exec.Command(pprofExe, "-disasm", "main.main", cpuExe, profile) + out, err = cmd.CombinedOutput() + if err != nil { + t.Fatalf("pprof failed: %v\n%s", err, out) + } + + sout := string(out) + want := "ROUTINE ======================== main.main" + if !strings.Contains(sout, want) { + t.Errorf("pprof disasm got %s want contains %q", sout, want) + } +} diff --git a/src/cmd/pprof/testdata/cpu.go b/src/cmd/pprof/testdata/cpu.go new file mode 100644 index 00000000000..5b682870db8 --- /dev/null +++ b/src/cmd/pprof/testdata/cpu.go @@ -0,0 +1,41 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "flag" + "fmt" + "os" + "runtime/pprof" + "time" +) + +var output = flag.String("output", "", "pprof profile output file") + +func main() { + flag.Parse() + if *output == "" { + fmt.Fprintf(os.Stderr, "usage: %s -output file.pprof\n", os.Args[0]) + os.Exit(2) + } + + f, err := os.Create(*output) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(2) + } + defer f.Close() + + if err := pprof.StartCPUProfile(f); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(2) + } + defer pprof.StopCPUProfile() + + // Spin for long enough to collect some samples. + start := time.Now() + for time.Since(start) < time.Second { + } +} From 122f5e16d690bd14ae46e9cc7e37c0c84fdc2be8 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Wed, 16 Jun 2021 20:14:22 +0000 Subject: [PATCH 448/940] [dev.typeparams] internal/goarch,internal/goos: explode runtime/internal/sys into pieces This change extracts the GOOS and GOARCH specific constants from runtime/internal/sys into packages that are available to the entire standard library. This change does not yet update the runtime and associated packages to use them, and instead adds constants to runtime/internal/sys to forward the constants defined by these new packages. Change-Id: I14d574b8d7bfe599ad25da29dc1b39716e35a734 Reviewed-on: https://go-review.googlesource.com/c/go/+/328336 Trust: Michael Knyszek Run-TryBot: Michael Knyszek Reviewed-by: Matthew Dempsky TryBot-Result: Go Bot --- src/cmd/go/internal/work/gc.go | 19 ++- src/go/build/deps_test.go | 6 +- src/internal/goarch/gengoarch.go | 59 ++++++++++ .../sys/arch.go => internal/goarch/goarch.go} | 14 ++- .../goarch/goarch_386.go} | 2 +- .../goarch/goarch_amd64.go} | 2 +- .../goarch/goarch_arm.go} | 2 +- .../goarch/goarch_arm64.go} | 2 +- .../goarch/goarch_mips.go} | 2 +- .../goarch/goarch_mips64.go} | 2 +- .../goarch/goarch_mips64le.go} | 2 +- .../goarch/goarch_mipsle.go} | 2 +- .../goarch/goarch_ppc64.go} | 2 +- .../goarch/goarch_ppc64le.go} | 2 +- .../goarch/goarch_riscv64.go} | 2 +- .../goarch/goarch_s390x.go} | 2 +- .../goarch/goarch_wasm.go} | 2 +- .../sys => internal/goarch}/zgoarch_386.go | 4 +- .../sys => internal/goarch}/zgoarch_amd64.go | 4 +- .../sys => internal/goarch}/zgoarch_arm.go | 4 +- .../sys => internal/goarch}/zgoarch_arm64.go | 4 +- .../goarch}/zgoarch_arm64be.go | 4 +- .../sys => internal/goarch}/zgoarch_armbe.go | 4 +- .../sys => internal/goarch}/zgoarch_mips.go | 4 +- .../sys => internal/goarch}/zgoarch_mips64.go | 4 +- .../goarch}/zgoarch_mips64le.go | 4 +- .../goarch}/zgoarch_mips64p32.go | 4 +- .../goarch}/zgoarch_mips64p32le.go | 4 +- .../sys => internal/goarch}/zgoarch_mipsle.go | 4 +- .../sys => internal/goarch}/zgoarch_ppc.go | 4 +- .../sys => internal/goarch}/zgoarch_ppc64.go | 4 +- .../goarch}/zgoarch_ppc64le.go | 4 +- .../sys => internal/goarch}/zgoarch_riscv.go | 4 +- .../goarch}/zgoarch_riscv64.go | 4 +- .../sys => internal/goarch}/zgoarch_s390.go | 4 +- .../sys => internal/goarch}/zgoarch_s390x.go | 4 +- .../sys => internal/goarch}/zgoarch_sparc.go | 4 +- .../goarch}/zgoarch_sparc64.go | 4 +- .../sys => internal/goarch}/zgoarch_wasm.go | 4 +- .../internal/sys => internal/goos}/gengoos.go | 41 +------ src/internal/goos/goos.go | 12 ++ .../sys => internal/goos}/zgoos_aix.go | 2 +- .../sys => internal/goos}/zgoos_android.go | 2 +- .../sys => internal/goos}/zgoos_darwin.go | 2 +- .../sys => internal/goos}/zgoos_dragonfly.go | 2 +- .../sys => internal/goos}/zgoos_freebsd.go | 2 +- .../sys => internal/goos}/zgoos_hurd.go | 2 +- .../sys => internal/goos}/zgoos_illumos.go | 2 +- .../sys => internal/goos}/zgoos_ios.go | 2 +- .../sys => internal/goos}/zgoos_js.go | 2 +- .../sys => internal/goos}/zgoos_linux.go | 2 +- .../sys => internal/goos}/zgoos_netbsd.go | 2 +- .../sys => internal/goos}/zgoos_openbsd.go | 2 +- .../sys => internal/goos}/zgoos_plan9.go | 2 +- .../sys => internal/goos}/zgoos_solaris.go | 2 +- .../sys => internal/goos}/zgoos_windows.go | 2 +- .../sys => internal/goos}/zgoos_zos.go | 2 +- src/runtime/internal/sys/consts.go | 109 ++++++++++++++++++ src/runtime/internal/sys/sys.go | 8 -- 59 files changed, 284 insertions(+), 130 deletions(-) create mode 100644 src/internal/goarch/gengoarch.go rename src/{runtime/internal/sys/arch.go => internal/goarch/goarch.go} (79%) rename src/{runtime/internal/sys/arch_386.go => internal/goarch/goarch_386.go} (95%) rename src/{runtime/internal/sys/arch_amd64.go => internal/goarch/goarch_amd64.go} (95%) rename src/{runtime/internal/sys/arch_arm.go => internal/goarch/goarch_arm.go} (95%) rename src/{runtime/internal/sys/arch_arm64.go => internal/goarch/goarch_arm64.go} (95%) rename src/{runtime/internal/sys/arch_mips.go => internal/goarch/goarch_mips.go} (95%) rename src/{runtime/internal/sys/arch_mips64le.go => internal/goarch/goarch_mips64.go} (95%) rename src/{runtime/internal/sys/arch_mips64.go => internal/goarch/goarch_mips64le.go} (95%) rename src/{runtime/internal/sys/arch_mipsle.go => internal/goarch/goarch_mipsle.go} (95%) rename src/{runtime/internal/sys/arch_ppc64.go => internal/goarch/goarch_ppc64.go} (95%) rename src/{runtime/internal/sys/arch_ppc64le.go => internal/goarch/goarch_ppc64le.go} (95%) rename src/{runtime/internal/sys/arch_riscv64.go => internal/goarch/goarch_riscv64.go} (95%) rename src/{runtime/internal/sys/arch_s390x.go => internal/goarch/goarch_s390x.go} (95%) rename src/{runtime/internal/sys/arch_wasm.go => internal/goarch/goarch_wasm.go} (95%) rename src/{runtime/internal/sys => internal/goarch}/zgoarch_386.go (87%) rename src/{runtime/internal/sys => internal/goarch}/zgoarch_amd64.go (87%) rename src/{runtime/internal/sys => internal/goarch}/zgoarch_arm.go (87%) rename src/{runtime/internal/sys => internal/goarch}/zgoarch_arm64.go (87%) rename src/{runtime/internal/sys => internal/goarch}/zgoarch_arm64be.go (87%) rename src/{runtime/internal/sys => internal/goarch}/zgoarch_armbe.go (87%) rename src/{runtime/internal/sys => internal/goarch}/zgoarch_mips.go (87%) rename src/{runtime/internal/sys => internal/goarch}/zgoarch_mips64.go (87%) rename src/{runtime/internal/sys => internal/goarch}/zgoarch_mips64le.go (87%) rename src/{runtime/internal/sys => internal/goarch}/zgoarch_mips64p32.go (87%) rename src/{runtime/internal/sys => internal/goarch}/zgoarch_mips64p32le.go (87%) rename src/{runtime/internal/sys => internal/goarch}/zgoarch_mipsle.go (87%) rename src/{runtime/internal/sys => internal/goarch}/zgoarch_ppc.go (87%) rename src/{runtime/internal/sys => internal/goarch}/zgoarch_ppc64.go (87%) rename src/{runtime/internal/sys => internal/goarch}/zgoarch_ppc64le.go (87%) rename src/{runtime/internal/sys => internal/goarch}/zgoarch_riscv.go (87%) rename src/{runtime/internal/sys => internal/goarch}/zgoarch_riscv64.go (87%) rename src/{runtime/internal/sys => internal/goarch}/zgoarch_s390.go (87%) rename src/{runtime/internal/sys => internal/goarch}/zgoarch_s390x.go (87%) rename src/{runtime/internal/sys => internal/goarch}/zgoarch_sparc.go (87%) rename src/{runtime/internal/sys => internal/goarch}/zgoarch_sparc64.go (87%) rename src/{runtime/internal/sys => internal/goarch}/zgoarch_wasm.go (87%) rename src/{runtime/internal/sys => internal/goos}/gengoos.go (59%) create mode 100644 src/internal/goos/goos.go rename src/{runtime/internal/sys => internal/goos}/zgoos_aix.go (97%) rename src/{runtime/internal/sys => internal/goos}/zgoos_android.go (97%) rename src/{runtime/internal/sys => internal/goos}/zgoos_darwin.go (97%) rename src/{runtime/internal/sys => internal/goos}/zgoos_dragonfly.go (97%) rename src/{runtime/internal/sys => internal/goos}/zgoos_freebsd.go (97%) rename src/{runtime/internal/sys => internal/goos}/zgoos_hurd.go (97%) rename src/{runtime/internal/sys => internal/goos}/zgoos_illumos.go (97%) rename src/{runtime/internal/sys => internal/goos}/zgoos_ios.go (97%) rename src/{runtime/internal/sys => internal/goos}/zgoos_js.go (97%) rename src/{runtime/internal/sys => internal/goos}/zgoos_linux.go (97%) rename src/{runtime/internal/sys => internal/goos}/zgoos_netbsd.go (97%) rename src/{runtime/internal/sys => internal/goos}/zgoos_openbsd.go (97%) rename src/{runtime/internal/sys => internal/goos}/zgoos_plan9.go (97%) rename src/{runtime/internal/sys => internal/goos}/zgoos_solaris.go (97%) rename src/{runtime/internal/sys => internal/goos}/zgoos_windows.go (97%) rename src/{runtime/internal/sys => internal/goos}/zgoos_zos.go (97%) create mode 100644 src/runtime/internal/sys/consts.go diff --git a/src/cmd/go/internal/work/gc.go b/src/cmd/go/internal/work/gc.go index 85da4f89f99..2ae908bc8fd 100644 --- a/src/cmd/go/internal/work/gc.go +++ b/src/cmd/go/internal/work/gc.go @@ -29,6 +29,18 @@ import ( // The 'path' used for GOROOT_FINAL when -trimpath is specified const trimPathGoRootFinal = "go" +var runtimePackages = map[string]struct{}{ + "internal/abi": struct{}{}, + "internal/bytealg": struct{}{}, + "internal/cpu": struct{}{}, + "internal/goarch": struct{}{}, + "internal/goos": struct{}{}, + "runtime": struct{}{}, + "runtime/internal/atomic": struct{}{}, + "runtime/internal/math": struct{}{}, + "runtime/internal/sys": struct{}{}, +} + // The Go toolchain. type gcToolchain struct{} @@ -88,11 +100,8 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg if p.Standard { gcargs = append(gcargs, "-std") } - compilingRuntime := p.Standard && (p.ImportPath == "runtime" || strings.HasPrefix(p.ImportPath, "runtime/internal")) - // The runtime package imports a couple of general internal packages. - if p.Standard && (p.ImportPath == "internal/cpu" || p.ImportPath == "internal/bytealg" || p.ImportPath == "internal/abi") { - compilingRuntime = true - } + _, compilingRuntime := runtimePackages[p.ImportPath] + compilingRuntime = compilingRuntime && p.Standard if compilingRuntime { // runtime compiles with a special gc flag to check for // memory allocations that are invalid in the runtime package, diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 45e2f25df74..b440f7d2351 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -71,7 +71,8 @@ var depsRules = ` # No dependencies allowed for any of these packages. NONE < container/list, container/ring, - internal/cfg, internal/cpu, internal/goexperiment, + internal/cfg, internal/cpu, internal/goarch, + internal/goexperiment, internal/goos, internal/goversion, internal/nettrace, unicode/utf8, unicode/utf16, unicode, unsafe; @@ -81,7 +82,8 @@ var depsRules = ` < internal/abi; # RUNTIME is the core runtime group of packages, all of them very light-weight. - internal/abi, internal/cpu, internal/goexperiment, unsafe + internal/abi, internal/cpu, internal/goarch, + internal/goexperiment, internal/goos, unsafe < internal/bytealg < internal/itoa < internal/unsafeheader diff --git a/src/internal/goarch/gengoarch.go b/src/internal/goarch/gengoarch.go new file mode 100644 index 00000000000..58c3b1104c9 --- /dev/null +++ b/src/internal/goarch/gengoarch.go @@ -0,0 +1,59 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build ignore +// +build ignore + +package main + +import ( + "bytes" + "fmt" + "log" + "os" + "strconv" + "strings" +) + +var goarches []string + +func main() { + data, err := os.ReadFile("../../go/build/syslist.go") + if err != nil { + log.Fatal(err) + } + const goarchPrefix = `const goarchList = ` + for _, line := range strings.Split(string(data), "\n") { + if strings.HasPrefix(line, goarchPrefix) { + text, err := strconv.Unquote(strings.TrimPrefix(line, goarchPrefix)) + if err != nil { + log.Fatalf("parsing goarchList: %v", err) + } + goarches = strings.Fields(text) + } + } + + for _, target := range goarches { + if target == "amd64p32" { + continue + } + var buf bytes.Buffer + fmt.Fprintf(&buf, "// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.\n\n") + fmt.Fprintf(&buf, "//go:build %s\n", target) + fmt.Fprintf(&buf, "// +build %s\n\n", target) // must explicitly include target for bootstrapping purposes + fmt.Fprintf(&buf, "package goarch\n\n") + fmt.Fprintf(&buf, "const GOARCH = `%s`\n\n", target) + for _, goarch := range goarches { + value := 0 + if goarch == target { + value = 1 + } + fmt.Fprintf(&buf, "const Goarch%s = %d\n", strings.Title(goarch), value) + } + err := os.WriteFile("zgoarch_"+target+".go", buf.Bytes(), 0666) + if err != nil { + log.Fatal(err) + } + } +} diff --git a/src/runtime/internal/sys/arch.go b/src/internal/goarch/goarch.go similarity index 79% rename from src/runtime/internal/sys/arch.go rename to src/internal/goarch/goarch.go index 3c99a2f7da0..8e240295b33 100644 --- a/src/runtime/internal/sys/arch.go +++ b/src/internal/goarch/goarch.go @@ -1,8 +1,15 @@ -// Copyright 2014 The Go Authors. All rights reserved. +// Copyright 2021 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package sys +// package goarch contains GOARCH-specific constants. +package goarch + +// The next line makes 'go generate' write the zgoarch*.go files with +// per-arch information, including constants named Goarch$GOARCH for every +// GOARCH. The constant is 1 on the current system, 0 otherwise; multiplying +// by them is useful for defining GOARCH-specific constants. +//go:generate go run gengoarch.go type ArchFamilyType int @@ -23,9 +30,6 @@ const ( // It is also the size of the machine's native word size (that is, 4 on 32-bit systems, 8 on 64-bit). const PtrSize = 4 << (^uintptr(0) >> 63) -// AIX requires a larger stack for syscalls. -const StackGuardMultiplier = StackGuardMultiplierDefault*(1-GoosAix) + 2*GoosAix - // ArchFamily is the architecture family (AMD64, ARM, ...) const ArchFamily ArchFamilyType = _ArchFamily diff --git a/src/runtime/internal/sys/arch_386.go b/src/internal/goarch/goarch_386.go similarity index 95% rename from src/runtime/internal/sys/arch_386.go rename to src/internal/goarch/goarch_386.go index 1ebce3435e4..c6214217fcf 100644 --- a/src/runtime/internal/sys/arch_386.go +++ b/src/internal/goarch/goarch_386.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package sys +package goarch const ( _ArchFamily = I386 diff --git a/src/runtime/internal/sys/arch_amd64.go b/src/internal/goarch/goarch_amd64.go similarity index 95% rename from src/runtime/internal/sys/arch_amd64.go rename to src/internal/goarch/goarch_amd64.go index 7f003d0f1d5..911e3e72421 100644 --- a/src/runtime/internal/sys/arch_amd64.go +++ b/src/internal/goarch/goarch_amd64.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package sys +package goarch const ( _ArchFamily = AMD64 diff --git a/src/runtime/internal/sys/arch_arm.go b/src/internal/goarch/goarch_arm.go similarity index 95% rename from src/runtime/internal/sys/arch_arm.go rename to src/internal/goarch/goarch_arm.go index ef2048bb71a..a6591713c82 100644 --- a/src/runtime/internal/sys/arch_arm.go +++ b/src/internal/goarch/goarch_arm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package sys +package goarch const ( _ArchFamily = ARM diff --git a/src/runtime/internal/sys/arch_arm64.go b/src/internal/goarch/goarch_arm64.go similarity index 95% rename from src/runtime/internal/sys/arch_arm64.go rename to src/internal/goarch/goarch_arm64.go index b9f2f7b1fe2..85d0b476391 100644 --- a/src/runtime/internal/sys/arch_arm64.go +++ b/src/internal/goarch/goarch_arm64.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package sys +package goarch const ( _ArchFamily = ARM64 diff --git a/src/runtime/internal/sys/arch_mips.go b/src/internal/goarch/goarch_mips.go similarity index 95% rename from src/runtime/internal/sys/arch_mips.go rename to src/internal/goarch/goarch_mips.go index 4cb0eebea7b..59f3995e2a5 100644 --- a/src/runtime/internal/sys/arch_mips.go +++ b/src/internal/goarch/goarch_mips.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package sys +package goarch const ( _ArchFamily = MIPS diff --git a/src/runtime/internal/sys/arch_mips64le.go b/src/internal/goarch/goarch_mips64.go similarity index 95% rename from src/runtime/internal/sys/arch_mips64le.go rename to src/internal/goarch/goarch_mips64.go index 57636ac4a4e..9e4f82797d4 100644 --- a/src/runtime/internal/sys/arch_mips64le.go +++ b/src/internal/goarch/goarch_mips64.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package sys +package goarch const ( _ArchFamily = MIPS64 diff --git a/src/runtime/internal/sys/arch_mips64.go b/src/internal/goarch/goarch_mips64le.go similarity index 95% rename from src/runtime/internal/sys/arch_mips64.go rename to src/internal/goarch/goarch_mips64le.go index 57636ac4a4e..9e4f82797d4 100644 --- a/src/runtime/internal/sys/arch_mips64.go +++ b/src/internal/goarch/goarch_mips64le.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package sys +package goarch const ( _ArchFamily = MIPS64 diff --git a/src/runtime/internal/sys/arch_mipsle.go b/src/internal/goarch/goarch_mipsle.go similarity index 95% rename from src/runtime/internal/sys/arch_mipsle.go rename to src/internal/goarch/goarch_mipsle.go index 4240f5ce47b..3e6642bb863 100644 --- a/src/runtime/internal/sys/arch_mipsle.go +++ b/src/internal/goarch/goarch_mipsle.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package sys +package goarch const ( _ArchFamily = MIPS diff --git a/src/runtime/internal/sys/arch_ppc64.go b/src/internal/goarch/goarch_ppc64.go similarity index 95% rename from src/runtime/internal/sys/arch_ppc64.go rename to src/internal/goarch/goarch_ppc64.go index 1869213ce24..60cc846e6a3 100644 --- a/src/runtime/internal/sys/arch_ppc64.go +++ b/src/internal/goarch/goarch_ppc64.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package sys +package goarch const ( _ArchFamily = PPC64 diff --git a/src/runtime/internal/sys/arch_ppc64le.go b/src/internal/goarch/goarch_ppc64le.go similarity index 95% rename from src/runtime/internal/sys/arch_ppc64le.go rename to src/internal/goarch/goarch_ppc64le.go index 1869213ce24..60cc846e6a3 100644 --- a/src/runtime/internal/sys/arch_ppc64le.go +++ b/src/internal/goarch/goarch_ppc64le.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package sys +package goarch const ( _ArchFamily = PPC64 diff --git a/src/runtime/internal/sys/arch_riscv64.go b/src/internal/goarch/goarch_riscv64.go similarity index 95% rename from src/runtime/internal/sys/arch_riscv64.go rename to src/internal/goarch/goarch_riscv64.go index 360d236e320..3b6da1e02fe 100644 --- a/src/runtime/internal/sys/arch_riscv64.go +++ b/src/internal/goarch/goarch_riscv64.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package sys +package goarch const ( _ArchFamily = RISCV64 diff --git a/src/runtime/internal/sys/arch_s390x.go b/src/internal/goarch/goarch_s390x.go similarity index 95% rename from src/runtime/internal/sys/arch_s390x.go rename to src/internal/goarch/goarch_s390x.go index e33e0b7f2b8..20c5705581e 100644 --- a/src/runtime/internal/sys/arch_s390x.go +++ b/src/internal/goarch/goarch_s390x.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package sys +package goarch const ( _ArchFamily = S390X diff --git a/src/runtime/internal/sys/arch_wasm.go b/src/internal/goarch/goarch_wasm.go similarity index 95% rename from src/runtime/internal/sys/arch_wasm.go rename to src/internal/goarch/goarch_wasm.go index ee919ff9e63..98618d6980e 100644 --- a/src/runtime/internal/sys/arch_wasm.go +++ b/src/internal/goarch/goarch_wasm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package sys +package goarch const ( _ArchFamily = WASM diff --git a/src/runtime/internal/sys/zgoarch_386.go b/src/internal/goarch/zgoarch_386.go similarity index 87% rename from src/runtime/internal/sys/zgoarch_386.go rename to src/internal/goarch/zgoarch_386.go index 98a2401bfe9..f424b5a6b97 100644 --- a/src/runtime/internal/sys/zgoarch_386.go +++ b/src/internal/goarch/zgoarch_386.go @@ -1,9 +1,9 @@ -// Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. //go:build 386 // +build 386 -package sys +package goarch const GOARCH = `386` diff --git a/src/runtime/internal/sys/zgoarch_amd64.go b/src/internal/goarch/zgoarch_amd64.go similarity index 87% rename from src/runtime/internal/sys/zgoarch_amd64.go rename to src/internal/goarch/zgoarch_amd64.go index d8faa5c7860..728896c367e 100644 --- a/src/runtime/internal/sys/zgoarch_amd64.go +++ b/src/internal/goarch/zgoarch_amd64.go @@ -1,9 +1,9 @@ -// Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. //go:build amd64 // +build amd64 -package sys +package goarch const GOARCH = `amd64` diff --git a/src/runtime/internal/sys/zgoarch_arm.go b/src/internal/goarch/zgoarch_arm.go similarity index 87% rename from src/runtime/internal/sys/zgoarch_arm.go rename to src/internal/goarch/zgoarch_arm.go index b64a69c9b44..9d388b0554d 100644 --- a/src/runtime/internal/sys/zgoarch_arm.go +++ b/src/internal/goarch/zgoarch_arm.go @@ -1,9 +1,9 @@ -// Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. //go:build arm // +build arm -package sys +package goarch const GOARCH = `arm` diff --git a/src/runtime/internal/sys/zgoarch_arm64.go b/src/internal/goarch/zgoarch_arm64.go similarity index 87% rename from src/runtime/internal/sys/zgoarch_arm64.go rename to src/internal/goarch/zgoarch_arm64.go index de6f85347b1..a375ac80762 100644 --- a/src/runtime/internal/sys/zgoarch_arm64.go +++ b/src/internal/goarch/zgoarch_arm64.go @@ -1,9 +1,9 @@ -// Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. //go:build arm64 // +build arm64 -package sys +package goarch const GOARCH = `arm64` diff --git a/src/runtime/internal/sys/zgoarch_arm64be.go b/src/internal/goarch/zgoarch_arm64be.go similarity index 87% rename from src/runtime/internal/sys/zgoarch_arm64be.go rename to src/internal/goarch/zgoarch_arm64be.go index b762bb069f8..6fcc4f6bfa7 100644 --- a/src/runtime/internal/sys/zgoarch_arm64be.go +++ b/src/internal/goarch/zgoarch_arm64be.go @@ -1,9 +1,9 @@ -// Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. //go:build arm64be // +build arm64be -package sys +package goarch const GOARCH = `arm64be` diff --git a/src/runtime/internal/sys/zgoarch_armbe.go b/src/internal/goarch/zgoarch_armbe.go similarity index 87% rename from src/runtime/internal/sys/zgoarch_armbe.go rename to src/internal/goarch/zgoarch_armbe.go index e5297e4b169..a3ac487d80c 100644 --- a/src/runtime/internal/sys/zgoarch_armbe.go +++ b/src/internal/goarch/zgoarch_armbe.go @@ -1,9 +1,9 @@ -// Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. //go:build armbe // +build armbe -package sys +package goarch const GOARCH = `armbe` diff --git a/src/runtime/internal/sys/zgoarch_mips.go b/src/internal/goarch/zgoarch_mips.go similarity index 87% rename from src/runtime/internal/sys/zgoarch_mips.go rename to src/internal/goarch/zgoarch_mips.go index b5f4ed390c6..00cfd90c3b7 100644 --- a/src/runtime/internal/sys/zgoarch_mips.go +++ b/src/internal/goarch/zgoarch_mips.go @@ -1,9 +1,9 @@ -// Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. //go:build mips // +build mips -package sys +package goarch const GOARCH = `mips` diff --git a/src/runtime/internal/sys/zgoarch_mips64.go b/src/internal/goarch/zgoarch_mips64.go similarity index 87% rename from src/runtime/internal/sys/zgoarch_mips64.go rename to src/internal/goarch/zgoarch_mips64.go index 73777cceb21..947db612eb0 100644 --- a/src/runtime/internal/sys/zgoarch_mips64.go +++ b/src/internal/goarch/zgoarch_mips64.go @@ -1,9 +1,9 @@ -// Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. //go:build mips64 // +build mips64 -package sys +package goarch const GOARCH = `mips64` diff --git a/src/runtime/internal/sys/zgoarch_mips64le.go b/src/internal/goarch/zgoarch_mips64le.go similarity index 87% rename from src/runtime/internal/sys/zgoarch_mips64le.go rename to src/internal/goarch/zgoarch_mips64le.go index 0c81c36c097..35ffbe2d3f3 100644 --- a/src/runtime/internal/sys/zgoarch_mips64le.go +++ b/src/internal/goarch/zgoarch_mips64le.go @@ -1,9 +1,9 @@ -// Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. //go:build mips64le // +build mips64le -package sys +package goarch const GOARCH = `mips64le` diff --git a/src/runtime/internal/sys/zgoarch_mips64p32.go b/src/internal/goarch/zgoarch_mips64p32.go similarity index 87% rename from src/runtime/internal/sys/zgoarch_mips64p32.go rename to src/internal/goarch/zgoarch_mips64p32.go index d63ce27d24d..c7c712032be 100644 --- a/src/runtime/internal/sys/zgoarch_mips64p32.go +++ b/src/internal/goarch/zgoarch_mips64p32.go @@ -1,9 +1,9 @@ -// Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. //go:build mips64p32 // +build mips64p32 -package sys +package goarch const GOARCH = `mips64p32` diff --git a/src/runtime/internal/sys/zgoarch_mips64p32le.go b/src/internal/goarch/zgoarch_mips64p32le.go similarity index 87% rename from src/runtime/internal/sys/zgoarch_mips64p32le.go rename to src/internal/goarch/zgoarch_mips64p32le.go index 2d577890b2e..f605a6ff783 100644 --- a/src/runtime/internal/sys/zgoarch_mips64p32le.go +++ b/src/internal/goarch/zgoarch_mips64p32le.go @@ -1,9 +1,9 @@ -// Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. //go:build mips64p32le // +build mips64p32le -package sys +package goarch const GOARCH = `mips64p32le` diff --git a/src/runtime/internal/sys/zgoarch_mipsle.go b/src/internal/goarch/zgoarch_mipsle.go similarity index 87% rename from src/runtime/internal/sys/zgoarch_mipsle.go rename to src/internal/goarch/zgoarch_mipsle.go index 8af919d03a3..56e24dc7b3d 100644 --- a/src/runtime/internal/sys/zgoarch_mipsle.go +++ b/src/internal/goarch/zgoarch_mipsle.go @@ -1,9 +1,9 @@ -// Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. //go:build mipsle // +build mipsle -package sys +package goarch const GOARCH = `mipsle` diff --git a/src/runtime/internal/sys/zgoarch_ppc.go b/src/internal/goarch/zgoarch_ppc.go similarity index 87% rename from src/runtime/internal/sys/zgoarch_ppc.go rename to src/internal/goarch/zgoarch_ppc.go index f6f12a5ddce..4617d127927 100644 --- a/src/runtime/internal/sys/zgoarch_ppc.go +++ b/src/internal/goarch/zgoarch_ppc.go @@ -1,9 +1,9 @@ -// Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. //go:build ppc // +build ppc -package sys +package goarch const GOARCH = `ppc` diff --git a/src/runtime/internal/sys/zgoarch_ppc64.go b/src/internal/goarch/zgoarch_ppc64.go similarity index 87% rename from src/runtime/internal/sys/zgoarch_ppc64.go rename to src/internal/goarch/zgoarch_ppc64.go index a8379601f47..f3cb16e9b64 100644 --- a/src/runtime/internal/sys/zgoarch_ppc64.go +++ b/src/internal/goarch/zgoarch_ppc64.go @@ -1,9 +1,9 @@ -// Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. //go:build ppc64 // +build ppc64 -package sys +package goarch const GOARCH = `ppc64` diff --git a/src/runtime/internal/sys/zgoarch_ppc64le.go b/src/internal/goarch/zgoarch_ppc64le.go similarity index 87% rename from src/runtime/internal/sys/zgoarch_ppc64le.go rename to src/internal/goarch/zgoarch_ppc64le.go index f2ec5dcba72..b70abfb953e 100644 --- a/src/runtime/internal/sys/zgoarch_ppc64le.go +++ b/src/internal/goarch/zgoarch_ppc64le.go @@ -1,9 +1,9 @@ -// Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. //go:build ppc64le // +build ppc64le -package sys +package goarch const GOARCH = `ppc64le` diff --git a/src/runtime/internal/sys/zgoarch_riscv.go b/src/internal/goarch/zgoarch_riscv.go similarity index 87% rename from src/runtime/internal/sys/zgoarch_riscv.go rename to src/internal/goarch/zgoarch_riscv.go index 83a3312f5f3..f72973fbc59 100644 --- a/src/runtime/internal/sys/zgoarch_riscv.go +++ b/src/internal/goarch/zgoarch_riscv.go @@ -1,9 +1,9 @@ -// Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. //go:build riscv // +build riscv -package sys +package goarch const GOARCH = `riscv` diff --git a/src/runtime/internal/sys/zgoarch_riscv64.go b/src/internal/goarch/zgoarch_riscv64.go similarity index 87% rename from src/runtime/internal/sys/zgoarch_riscv64.go rename to src/internal/goarch/zgoarch_riscv64.go index 1dfcc84997b..5d09b63a031 100644 --- a/src/runtime/internal/sys/zgoarch_riscv64.go +++ b/src/internal/goarch/zgoarch_riscv64.go @@ -1,9 +1,9 @@ -// Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. //go:build riscv64 // +build riscv64 -package sys +package goarch const GOARCH = `riscv64` diff --git a/src/runtime/internal/sys/zgoarch_s390.go b/src/internal/goarch/zgoarch_s390.go similarity index 87% rename from src/runtime/internal/sys/zgoarch_s390.go rename to src/internal/goarch/zgoarch_s390.go index 91aba5a0f6c..0ceffe6c2ec 100644 --- a/src/runtime/internal/sys/zgoarch_s390.go +++ b/src/internal/goarch/zgoarch_s390.go @@ -1,9 +1,9 @@ -// Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. //go:build s390 // +build s390 -package sys +package goarch const GOARCH = `s390` diff --git a/src/runtime/internal/sys/zgoarch_s390x.go b/src/internal/goarch/zgoarch_s390x.go similarity index 87% rename from src/runtime/internal/sys/zgoarch_s390x.go rename to src/internal/goarch/zgoarch_s390x.go index edce50234e5..142bc0f1e38 100644 --- a/src/runtime/internal/sys/zgoarch_s390x.go +++ b/src/internal/goarch/zgoarch_s390x.go @@ -1,9 +1,9 @@ -// Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. //go:build s390x // +build s390x -package sys +package goarch const GOARCH = `s390x` diff --git a/src/runtime/internal/sys/zgoarch_sparc.go b/src/internal/goarch/zgoarch_sparc.go similarity index 87% rename from src/runtime/internal/sys/zgoarch_sparc.go rename to src/internal/goarch/zgoarch_sparc.go index 5ae9560ab01..62452b9d38d 100644 --- a/src/runtime/internal/sys/zgoarch_sparc.go +++ b/src/internal/goarch/zgoarch_sparc.go @@ -1,9 +1,9 @@ -// Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. //go:build sparc // +build sparc -package sys +package goarch const GOARCH = `sparc` diff --git a/src/runtime/internal/sys/zgoarch_sparc64.go b/src/internal/goarch/zgoarch_sparc64.go similarity index 87% rename from src/runtime/internal/sys/zgoarch_sparc64.go rename to src/internal/goarch/zgoarch_sparc64.go index e2a0134affd..5149507917d 100644 --- a/src/runtime/internal/sys/zgoarch_sparc64.go +++ b/src/internal/goarch/zgoarch_sparc64.go @@ -1,9 +1,9 @@ -// Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. //go:build sparc64 // +build sparc64 -package sys +package goarch const GOARCH = `sparc64` diff --git a/src/runtime/internal/sys/zgoarch_wasm.go b/src/internal/goarch/zgoarch_wasm.go similarity index 87% rename from src/runtime/internal/sys/zgoarch_wasm.go rename to src/internal/goarch/zgoarch_wasm.go index 52e85dea371..fd25e93e747 100644 --- a/src/runtime/internal/sys/zgoarch_wasm.go +++ b/src/internal/goarch/zgoarch_wasm.go @@ -1,9 +1,9 @@ -// Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. //go:build wasm // +build wasm -package sys +package goarch const GOARCH = `wasm` diff --git a/src/runtime/internal/sys/gengoos.go b/src/internal/goos/gengoos.go similarity index 59% rename from src/runtime/internal/sys/gengoos.go rename to src/internal/goos/gengoos.go index ffe962f71df..ebcdfec3ba9 100644 --- a/src/runtime/internal/sys/gengoos.go +++ b/src/internal/goos/gengoos.go @@ -16,17 +16,14 @@ import ( "strings" ) -var gooses, goarches []string +var gooses []string func main() { - data, err := os.ReadFile("../../../go/build/syslist.go") + data, err := os.ReadFile("../../go/build/syslist.go") if err != nil { log.Fatal(err) } - const ( - goosPrefix = `const goosList = ` - goarchPrefix = `const goarchList = ` - ) + const goosPrefix = `const goosList = ` for _, line := range strings.Split(string(data), "\n") { if strings.HasPrefix(line, goosPrefix) { text, err := strconv.Unquote(strings.TrimPrefix(line, goosPrefix)) @@ -35,13 +32,6 @@ func main() { } gooses = strings.Fields(text) } - if strings.HasPrefix(line, goarchPrefix) { - text, err := strconv.Unquote(strings.TrimPrefix(line, goarchPrefix)) - if err != nil { - log.Fatalf("parsing goarchList: %v", err) - } - goarches = strings.Fields(text) - } } for _, target := range gooses { @@ -63,7 +53,7 @@ func main() { fmt.Fprintf(&buf, "// Code generated by gengoos.go using 'go generate'. DO NOT EDIT.\n\n") fmt.Fprintf(&buf, "//go:build %s\n", strings.Join(tags, " && ")) fmt.Fprintf(&buf, "// +build %s\n\n", strings.Join(tags, ",")) - fmt.Fprintf(&buf, "package sys\n\n") + fmt.Fprintf(&buf, "package goos\n\n") fmt.Fprintf(&buf, "const GOOS = `%s`\n\n", target) for _, goos := range gooses { value := 0 @@ -77,27 +67,4 @@ func main() { log.Fatal(err) } } - - for _, target := range goarches { - if target == "amd64p32" { - continue - } - var buf bytes.Buffer - fmt.Fprintf(&buf, "// Code generated by gengoos.go using 'go generate'. DO NOT EDIT.\n\n") - fmt.Fprintf(&buf, "//go:build %s\n", target) - fmt.Fprintf(&buf, "// +build %s\n\n", target) // must explicitly include target for bootstrapping purposes - fmt.Fprintf(&buf, "package sys\n\n") - fmt.Fprintf(&buf, "const GOARCH = `%s`\n\n", target) - for _, goarch := range goarches { - value := 0 - if goarch == target { - value = 1 - } - fmt.Fprintf(&buf, "const Goarch%s = %d\n", strings.Title(goarch), value) - } - err := os.WriteFile("zgoarch_"+target+".go", buf.Bytes(), 0666) - if err != nil { - log.Fatal(err) - } - } } diff --git a/src/internal/goos/goos.go b/src/internal/goos/goos.go new file mode 100644 index 00000000000..332cf51e5dc --- /dev/null +++ b/src/internal/goos/goos.go @@ -0,0 +1,12 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// package goos contains GOOS-specific constants. +package goos + +// The next line makes 'go generate' write the zgoos*.go files with +// per-OS information, including constants named Goos$GOOS for every +// known GOOS. The constant is 1 on the current system, 0 otherwise; +// multiplying by them is useful for defining GOOS-specific constants. +//go:generate go run gengoos.go diff --git a/src/runtime/internal/sys/zgoos_aix.go b/src/internal/goos/zgoos_aix.go similarity index 97% rename from src/runtime/internal/sys/zgoos_aix.go rename to src/internal/goos/zgoos_aix.go index f3b907471f6..f453a8a0a8f 100644 --- a/src/runtime/internal/sys/zgoos_aix.go +++ b/src/internal/goos/zgoos_aix.go @@ -3,7 +3,7 @@ //go:build aix // +build aix -package sys +package goos const GOOS = `aix` diff --git a/src/runtime/internal/sys/zgoos_android.go b/src/internal/goos/zgoos_android.go similarity index 97% rename from src/runtime/internal/sys/zgoos_android.go rename to src/internal/goos/zgoos_android.go index e28baf7c481..d90c04f7589 100644 --- a/src/runtime/internal/sys/zgoos_android.go +++ b/src/internal/goos/zgoos_android.go @@ -3,7 +3,7 @@ //go:build android // +build android -package sys +package goos const GOOS = `android` diff --git a/src/runtime/internal/sys/zgoos_darwin.go b/src/internal/goos/zgoos_darwin.go similarity index 97% rename from src/runtime/internal/sys/zgoos_darwin.go rename to src/internal/goos/zgoos_darwin.go index 3c7f7b543ee..18f6c28b128 100644 --- a/src/runtime/internal/sys/zgoos_darwin.go +++ b/src/internal/goos/zgoos_darwin.go @@ -3,7 +3,7 @@ //go:build !ios && darwin // +build !ios,darwin -package sys +package goos const GOOS = `darwin` diff --git a/src/runtime/internal/sys/zgoos_dragonfly.go b/src/internal/goos/zgoos_dragonfly.go similarity index 97% rename from src/runtime/internal/sys/zgoos_dragonfly.go rename to src/internal/goos/zgoos_dragonfly.go index f844d29e2a1..a658d1d07f2 100644 --- a/src/runtime/internal/sys/zgoos_dragonfly.go +++ b/src/internal/goos/zgoos_dragonfly.go @@ -3,7 +3,7 @@ //go:build dragonfly // +build dragonfly -package sys +package goos const GOOS = `dragonfly` diff --git a/src/runtime/internal/sys/zgoos_freebsd.go b/src/internal/goos/zgoos_freebsd.go similarity index 97% rename from src/runtime/internal/sys/zgoos_freebsd.go rename to src/internal/goos/zgoos_freebsd.go index 8999a2797af..2534eb8c6f8 100644 --- a/src/runtime/internal/sys/zgoos_freebsd.go +++ b/src/internal/goos/zgoos_freebsd.go @@ -3,7 +3,7 @@ //go:build freebsd // +build freebsd -package sys +package goos const GOOS = `freebsd` diff --git a/src/runtime/internal/sys/zgoos_hurd.go b/src/internal/goos/zgoos_hurd.go similarity index 97% rename from src/runtime/internal/sys/zgoos_hurd.go rename to src/internal/goos/zgoos_hurd.go index a546488bf89..3fefb1fbb18 100644 --- a/src/runtime/internal/sys/zgoos_hurd.go +++ b/src/internal/goos/zgoos_hurd.go @@ -3,7 +3,7 @@ //go:build hurd // +build hurd -package sys +package goos const GOOS = `hurd` diff --git a/src/runtime/internal/sys/zgoos_illumos.go b/src/internal/goos/zgoos_illumos.go similarity index 97% rename from src/runtime/internal/sys/zgoos_illumos.go rename to src/internal/goos/zgoos_illumos.go index 02a4ca06e82..77495a3369b 100644 --- a/src/runtime/internal/sys/zgoos_illumos.go +++ b/src/internal/goos/zgoos_illumos.go @@ -3,7 +3,7 @@ //go:build illumos // +build illumos -package sys +package goos const GOOS = `illumos` diff --git a/src/runtime/internal/sys/zgoos_ios.go b/src/internal/goos/zgoos_ios.go similarity index 97% rename from src/runtime/internal/sys/zgoos_ios.go rename to src/internal/goos/zgoos_ios.go index 033eec623df..92820fe77e8 100644 --- a/src/runtime/internal/sys/zgoos_ios.go +++ b/src/internal/goos/zgoos_ios.go @@ -3,7 +3,7 @@ //go:build ios // +build ios -package sys +package goos const GOOS = `ios` diff --git a/src/runtime/internal/sys/zgoos_js.go b/src/internal/goos/zgoos_js.go similarity index 97% rename from src/runtime/internal/sys/zgoos_js.go rename to src/internal/goos/zgoos_js.go index 28226ad60ad..6331a5c3f19 100644 --- a/src/runtime/internal/sys/zgoos_js.go +++ b/src/internal/goos/zgoos_js.go @@ -3,7 +3,7 @@ //go:build js // +build js -package sys +package goos const GOOS = `js` diff --git a/src/runtime/internal/sys/zgoos_linux.go b/src/internal/goos/zgoos_linux.go similarity index 97% rename from src/runtime/internal/sys/zgoos_linux.go rename to src/internal/goos/zgoos_linux.go index 01546e4b9f2..aa4e2d31451 100644 --- a/src/runtime/internal/sys/zgoos_linux.go +++ b/src/internal/goos/zgoos_linux.go @@ -3,7 +3,7 @@ //go:build !android && linux // +build !android,linux -package sys +package goos const GOOS = `linux` diff --git a/src/runtime/internal/sys/zgoos_netbsd.go b/src/internal/goos/zgoos_netbsd.go similarity index 97% rename from src/runtime/internal/sys/zgoos_netbsd.go rename to src/internal/goos/zgoos_netbsd.go index 9d658b20ee2..39635104c03 100644 --- a/src/runtime/internal/sys/zgoos_netbsd.go +++ b/src/internal/goos/zgoos_netbsd.go @@ -3,7 +3,7 @@ //go:build netbsd // +build netbsd -package sys +package goos const GOOS = `netbsd` diff --git a/src/runtime/internal/sys/zgoos_openbsd.go b/src/internal/goos/zgoos_openbsd.go similarity index 97% rename from src/runtime/internal/sys/zgoos_openbsd.go rename to src/internal/goos/zgoos_openbsd.go index 0f55454a953..61d4ac8bb02 100644 --- a/src/runtime/internal/sys/zgoos_openbsd.go +++ b/src/internal/goos/zgoos_openbsd.go @@ -3,7 +3,7 @@ //go:build openbsd // +build openbsd -package sys +package goos const GOOS = `openbsd` diff --git a/src/runtime/internal/sys/zgoos_plan9.go b/src/internal/goos/zgoos_plan9.go similarity index 97% rename from src/runtime/internal/sys/zgoos_plan9.go rename to src/internal/goos/zgoos_plan9.go index d0347464d6d..7f0dc2fa041 100644 --- a/src/runtime/internal/sys/zgoos_plan9.go +++ b/src/internal/goos/zgoos_plan9.go @@ -3,7 +3,7 @@ //go:build plan9 // +build plan9 -package sys +package goos const GOOS = `plan9` diff --git a/src/runtime/internal/sys/zgoos_solaris.go b/src/internal/goos/zgoos_solaris.go similarity index 97% rename from src/runtime/internal/sys/zgoos_solaris.go rename to src/internal/goos/zgoos_solaris.go index 05c3007e2c2..7497324a4f6 100644 --- a/src/runtime/internal/sys/zgoos_solaris.go +++ b/src/internal/goos/zgoos_solaris.go @@ -3,7 +3,7 @@ //go:build !illumos && solaris // +build !illumos,solaris -package sys +package goos const GOOS = `solaris` diff --git a/src/runtime/internal/sys/zgoos_windows.go b/src/internal/goos/zgoos_windows.go similarity index 97% rename from src/runtime/internal/sys/zgoos_windows.go rename to src/internal/goos/zgoos_windows.go index 7d07fa3a451..e316b80c82f 100644 --- a/src/runtime/internal/sys/zgoos_windows.go +++ b/src/internal/goos/zgoos_windows.go @@ -3,7 +3,7 @@ //go:build windows // +build windows -package sys +package goos const GOOS = `windows` diff --git a/src/runtime/internal/sys/zgoos_zos.go b/src/internal/goos/zgoos_zos.go similarity index 97% rename from src/runtime/internal/sys/zgoos_zos.go rename to src/internal/goos/zgoos_zos.go index d6e5b9b0cb2..26471f4f36e 100644 --- a/src/runtime/internal/sys/zgoos_zos.go +++ b/src/internal/goos/zgoos_zos.go @@ -3,7 +3,7 @@ //go:build zos // +build zos -package sys +package goos const GOOS = `zos` diff --git a/src/runtime/internal/sys/consts.go b/src/runtime/internal/sys/consts.go new file mode 100644 index 00000000000..815f7893808 --- /dev/null +++ b/src/runtime/internal/sys/consts.go @@ -0,0 +1,109 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sys + +import ( + "internal/goarch" + "internal/goos" +) + +type ArchFamilyType = goarch.ArchFamilyType + +const ( + AMD64 = goarch.AMD64 + ARM = goarch.ARM + ARM64 = goarch.ARM64 + I386 = goarch.I386 + MIPS = goarch.MIPS + MIPS64 = goarch.MIPS64 + PPC64 = goarch.PPC64 + RISCV64 = goarch.RISCV64 + S390X = goarch.S390X + WASM = goarch.WASM +) + +// PtrSize is the size of a pointer in bytes - unsafe.Sizeof(uintptr(0)) but as an ideal constant. +// It is also the size of the machine's native word size (that is, 4 on 32-bit systems, 8 on 64-bit). +const PtrSize = goarch.PtrSize + +// ArchFamily is the architecture family (AMD64, ARM, ...) +const ArchFamily ArchFamilyType = goarch.ArchFamily + +// AIX requires a larger stack for syscalls. +const StackGuardMultiplier = StackGuardMultiplierDefault*(1-goos.GoosAix) + 2*goos.GoosAix + +// BigEndian reports whether the architecture is big-endian. +const BigEndian = goarch.BigEndian + +// DefaultPhysPageSize is the default physical page size. +const DefaultPhysPageSize = goarch.DefaultPhysPageSize + +// PCQuantum is the minimal unit for a program counter (1 on x86, 4 on most other systems). +// The various PC tables record PC deltas pre-divided by PCQuantum. +const PCQuantum = goarch.PCQuantum + +// Int64Align is the required alignment for a 64-bit integer (4 on 32-bit systems, 8 on 64-bit). +const Int64Align = goarch.PtrSize + +// MinFrameSize is the size of the system-reserved words at the bottom +// of a frame (just above the architectural stack pointer). +// It is zero on x86 and PtrSize on most non-x86 (LR-based) systems. +// On PowerPC it is larger, to cover three more reserved words: +// the compiler word, the link editor word, and the TOC save word. +const MinFrameSize = goarch.MinFrameSize + +// StackAlign is the required alignment of the SP register. +// The stack must be at least word aligned, but some architectures require more. +const StackAlign = goarch.StackAlign + +const GOARCH = goarch.GOARCH + +const ( + Goarch386 = goarch.Goarch386 + GoarchAmd64 = goarch.GoarchAmd64 + GoarchAmd64p32 = goarch.GoarchAmd64p32 + GoarchArm = goarch.GoarchArm + GoarchArmbe = goarch.GoarchArmbe + GoarchArm64 = goarch.GoarchArm64 + GoarchArm64be = goarch.GoarchArm64be + GoarchPpc64 = goarch.GoarchPpc64 + GoarchPpc64le = goarch.GoarchPpc64le + GoarchMips = goarch.GoarchMips + GoarchMipsle = goarch.GoarchMipsle + GoarchMips64 = goarch.GoarchMips64 + GoarchMips64le = goarch.GoarchMips64le + GoarchMips64p32 = goarch.GoarchMips64p32 + GoarchMips64p32le = goarch.GoarchMips64p32le + GoarchPpc = goarch.GoarchPpc + GoarchRiscv = goarch.GoarchRiscv + GoarchRiscv64 = goarch.GoarchRiscv64 + GoarchS390 = goarch.GoarchS390 + GoarchS390x = goarch.GoarchS390x + GoarchSparc = goarch.GoarchSparc + GoarchSparc64 = goarch.GoarchSparc64 + GoarchWasm = goarch.GoarchWasm +) + +const GOOS = goos.GOOS + +const ( + GoosAix = goos.GoosAix + GoosAndroid = goos.GoosAndroid + GoosDarwin = goos.GoosDarwin + GoosDragonfly = goos.GoosDragonfly + GoosFreebsd = goos.GoosFreebsd + GoosHurd = goos.GoosHurd + GoosIllumos = goos.GoosIllumos + GoosIos = goos.GoosIos + GoosJs = goos.GoosJs + GoosLinux = goos.GoosLinux + GoosNacl = goos.GoosNacl + GoosNetbsd = goos.GoosNetbsd + GoosOpenbsd = goos.GoosOpenbsd + GoosPlan9 = goos.GoosPlan9 + GoosSolaris = goos.GoosSolaris + GoosWindows = goos.GoosWindows + GoosZos = goos.GoosZos +) diff --git a/src/runtime/internal/sys/sys.go b/src/runtime/internal/sys/sys.go index 9d9ac4507f6..694101d36fd 100644 --- a/src/runtime/internal/sys/sys.go +++ b/src/runtime/internal/sys/sys.go @@ -5,11 +5,3 @@ // package sys contains system- and configuration- and architecture-specific // constants used by the runtime. package sys - -// The next line makes 'go generate' write the zgo*.go files with -// per-OS and per-arch information, including constants -// named Goos$GOOS and Goarch$GOARCH for every -// known GOOS and GOARCH. The constant is 1 on the -// current system, 0 otherwise; multiplying by them is -// useful for defining GOOS- or GOARCH-specific constants. -//go:generate go run gengoos.go From 6d85891b291db01532375a7f69c24cb68b76bf11 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Wed, 16 Jun 2021 23:05:44 +0000 Subject: [PATCH 449/940] [dev.typeparams] runtime: replace uses of runtime/internal/sys.PtrSize with internal/goarch.PtrSize [generated] [git-generate] cd src/runtime/internal/math gofmt -w -r "sys.PtrSize -> goarch.PtrSize" . goimports -w *.go cd ../.. gofmt -w -r "sys.PtrSize -> goarch.PtrSize" . goimports -w *.go Change-Id: I43491cdd54d2e06d4d04152b3d213851b7d6d423 Reviewed-on: https://go-review.googlesource.com/c/go/+/328337 Trust: Michael Knyszek Run-TryBot: Michael Knyszek TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/runtime/alg.go | 9 +- src/runtime/cgocall.go | 5 +- src/runtime/cgocheck.go | 14 +- .../export_debug_regabiargs_off_test.go | 3 +- .../export_debug_regabiargs_on_test.go | 3 +- src/runtime/export_debug_test.go | 8 +- src/runtime/export_test.go | 3 +- src/runtime/heapdump.go | 15 +- src/runtime/iface.go | 11 +- src/runtime/internal/math/math.go | 4 +- src/runtime/malloc.go | 23 +-- src/runtime/map.go | 18 +-- src/runtime/map_fast32.go | 6 +- src/runtime/map_fast64.go | 6 +- src/runtime/map_faststr.go | 56 +++---- src/runtime/map_test.go | 4 +- src/runtime/mbarrier.go | 10 +- src/runtime/mbitmap.go | 139 +++++++++--------- src/runtime/mcheckmark.go | 4 +- src/runtime/mfinal.go | 18 +-- src/runtime/mgcmark.go | 46 +++--- src/runtime/mgcstack.go | 4 +- src/runtime/mgcwork.go | 4 +- src/runtime/mheap.go | 8 +- src/runtime/mranges.go | 8 +- src/runtime/mspanset.go | 14 +- src/runtime/mstats.go | 4 +- src/runtime/mwbbuf.go | 4 +- src/runtime/os3_plan9.go | 4 +- src/runtime/os3_solaris.go | 4 +- src/runtime/os_dragonfly.go | 4 +- src/runtime/os_freebsd.go | 8 +- src/runtime/os_linux.go | 4 +- src/runtime/os_netbsd.go | 4 +- src/runtime/os_openbsd_syscall.go | 4 +- src/runtime/os_windows.go | 4 +- src/runtime/preempt.go | 4 +- src/runtime/print.go | 4 +- src/runtime/proc.go | 15 +- src/runtime/runtime1.go | 8 +- src/runtime/runtime2.go | 6 +- src/runtime/signal_386.go | 4 +- src/runtime/signal_aix_ppc64.go | 4 +- src/runtime/signal_amd64.go | 4 +- src/runtime/signal_linux_386.go | 4 +- src/runtime/signal_linux_amd64.go | 4 +- src/runtime/signal_linux_arm.go | 4 +- src/runtime/signal_linux_arm64.go | 4 +- src/runtime/signal_linux_mips64x.go | 4 +- src/runtime/signal_linux_ppc64x.go | 4 +- src/runtime/signal_linux_riscv64.go | 4 +- src/runtime/signal_linux_s390x.go | 3 +- src/runtime/signal_mips64x.go | 4 +- src/runtime/signal_riscv64.go | 6 +- src/runtime/slice.go | 15 +- src/runtime/stack.go | 23 +-- src/runtime/symtab.go | 11 +- src/runtime/sys_darwin_arm64.go | 4 +- src/runtime/sys_wasm.go | 3 +- src/runtime/sys_x86.go | 4 +- src/runtime/syscall_windows.go | 20 +-- src/runtime/trace.go | 7 +- src/runtime/traceback.go | 21 +-- 63 files changed, 349 insertions(+), 336 deletions(-) diff --git a/src/runtime/alg.go b/src/runtime/alg.go index 39c74268421..493499f2c5a 100644 --- a/src/runtime/alg.go +++ b/src/runtime/alg.go @@ -7,12 +7,13 @@ package runtime import ( "internal/cpu" "runtime/internal/sys" + "internal/goarch" "unsafe" ) const ( - c0 = uintptr((8-sys.PtrSize)/4*2860486313 + (sys.PtrSize-4)/4*33054211828000289) - c1 = uintptr((8-sys.PtrSize)/4*3267000013 + (sys.PtrSize-4)/4*23344194077549503) + c0 = uintptr((8-goarch.PtrSize)/4*2860486313 + (goarch.PtrSize-4)/4*33054211828000289) + c1 = uintptr((8-goarch.PtrSize)/4*3267000013 + (goarch.PtrSize-4)/4*23344194077549503) ) func memhash0(p unsafe.Pointer, h uintptr) uintptr { @@ -300,7 +301,7 @@ func ifaceHash(i interface { return interhash(noescape(unsafe.Pointer(&i)), seed) } -const hashRandomBytes = sys.PtrSize / 4 * 64 +const hashRandomBytes = goarch.PtrSize / 4 * 64 // used in asm_{386,amd64,arm64}.s to seed the hash function var aeskeysched [hashRandomBytes]byte @@ -321,7 +322,7 @@ func alginit() { initAlgAES() return } - getRandomData((*[len(hashkey) * sys.PtrSize]byte)(unsafe.Pointer(&hashkey))[:]) + getRandomData((*[len(hashkey) * goarch.PtrSize]byte)(unsafe.Pointer(&hashkey))[:]) hashkey[0] |= 1 // make sure these numbers are odd hashkey[1] |= 1 hashkey[2] |= 1 diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go index 0e287d0b8ed..2dafda6ca48 100644 --- a/src/runtime/cgocall.go +++ b/src/runtime/cgocall.go @@ -87,6 +87,7 @@ package runtime import ( "runtime/internal/atomic" "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -470,7 +471,7 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) { if inheap(uintptr(unsafe.Pointer(it))) { panic(errorString(msg)) } - p = *(*unsafe.Pointer)(add(p, sys.PtrSize)) + p = *(*unsafe.Pointer)(add(p, goarch.PtrSize)) if !cgoIsGoPointer(p) { return } @@ -550,7 +551,7 @@ func cgoCheckUnknownPointer(p unsafe.Pointer, msg string) (base, i uintptr) { } hbits := heapBitsForAddr(base) n := span.elemsize - for i = uintptr(0); i < n; i += sys.PtrSize { + for i = uintptr(0); i < n; i += goarch.PtrSize { if !hbits.morePointers() { // No more possible pointers. break diff --git a/src/runtime/cgocheck.go b/src/runtime/cgocheck.go index 516045c1633..3acbadf803d 100644 --- a/src/runtime/cgocheck.go +++ b/src/runtime/cgocheck.go @@ -8,7 +8,7 @@ package runtime import ( - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -151,7 +151,7 @@ func cgoCheckTypedBlock(typ *_type, src unsafe.Pointer, off, size uintptr) { // src must be in the regular heap. hbits := heapBitsForAddr(uintptr(src)) - for i := uintptr(0); i < off+size; i += sys.PtrSize { + for i := uintptr(0); i < off+size; i += goarch.PtrSize { bits := hbits.bits() if i >= off && bits&bitPointer != 0 { v := *(*unsafe.Pointer)(add(src, i)) @@ -169,22 +169,22 @@ func cgoCheckTypedBlock(typ *_type, src unsafe.Pointer, off, size uintptr) { //go:nosplit //go:nowritebarrier func cgoCheckBits(src unsafe.Pointer, gcbits *byte, off, size uintptr) { - skipMask := off / sys.PtrSize / 8 - skipBytes := skipMask * sys.PtrSize * 8 + skipMask := off / goarch.PtrSize / 8 + skipBytes := skipMask * goarch.PtrSize * 8 ptrmask := addb(gcbits, skipMask) src = add(src, skipBytes) off -= skipBytes size += off var bits uint32 - for i := uintptr(0); i < size; i += sys.PtrSize { - if i&(sys.PtrSize*8-1) == 0 { + for i := uintptr(0); i < size; i += goarch.PtrSize { + if i&(goarch.PtrSize*8-1) == 0 { bits = uint32(*ptrmask) ptrmask = addb(ptrmask, 1) } else { bits >>= 1 } if off > 0 { - off -= sys.PtrSize + off -= goarch.PtrSize } else { if bits&1 != 0 { v := *(*unsafe.Pointer)(add(src, i)) diff --git a/src/runtime/export_debug_regabiargs_off_test.go b/src/runtime/export_debug_regabiargs_off_test.go index fce37ab4d19..5009003d27d 100644 --- a/src/runtime/export_debug_regabiargs_off_test.go +++ b/src/runtime/export_debug_regabiargs_off_test.go @@ -3,8 +3,7 @@ // license that can be found in the LICENSE file. //go:build amd64 && linux && !goexperiment.regabiargs -// +build amd64,linux -// +build !goexperiment.regabiargs +// +build amd64,linux,!goexperiment.regabiargs package runtime diff --git a/src/runtime/export_debug_regabiargs_on_test.go b/src/runtime/export_debug_regabiargs_on_test.go index 3c65127e560..e1b72efd0f7 100644 --- a/src/runtime/export_debug_regabiargs_on_test.go +++ b/src/runtime/export_debug_regabiargs_on_test.go @@ -3,8 +3,7 @@ // license that can be found in the LICENSE file. //go:build amd64 && linux && goexperiment.regabiargs -// +build amd64,linux -// +build goexperiment.regabiargs +// +build amd64,linux,goexperiment.regabiargs package runtime diff --git a/src/runtime/export_debug_test.go b/src/runtime/export_debug_test.go index 9808fd52991..a2cef02cf86 100644 --- a/src/runtime/export_debug_test.go +++ b/src/runtime/export_debug_test.go @@ -9,7 +9,7 @@ package runtime import ( "internal/abi" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -115,7 +115,7 @@ func (h *debugCallHandler) inject(info *siginfo, ctxt *sigctxt, gp2 *g) bool { return false } // Push current PC on the stack. - rsp := ctxt.rsp() - sys.PtrSize + rsp := ctxt.rsp() - goarch.PtrSize *(*uint64)(unsafe.Pointer(uintptr(rsp))) = ctxt.rip() ctxt.set_rsp(rsp) // Write the argument frame size. @@ -166,7 +166,7 @@ func (h *debugCallHandler) handle(info *siginfo, ctxt *sigctxt, gp2 *g) bool { storeRegArgs(ctxt.regs(), h.regArgs) } // Push return PC. - sp -= sys.PtrSize + sp -= goarch.PtrSize ctxt.set_rsp(sp) *(*uint64)(unsafe.Pointer(uintptr(sp))) = ctxt.rip() // Set PC to call and context register. @@ -182,7 +182,7 @@ func (h *debugCallHandler) handle(info *siginfo, ctxt *sigctxt, gp2 *g) bool { case 2: // Function panicked. Copy panic out. sp := ctxt.rsp() - memmove(unsafe.Pointer(&h.panic), unsafe.Pointer(uintptr(sp)), 2*sys.PtrSize) + memmove(unsafe.Pointer(&h.panic), unsafe.Pointer(uintptr(sp)), 2*goarch.PtrSize) case 8: // Call isn't safe. Get the reason. sp := ctxt.rsp() diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index 60c06c3f10e..ae329746fec 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -9,6 +9,7 @@ package runtime import ( "runtime/internal/atomic" "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -245,7 +246,7 @@ func BenchSetType(n int, x interface{}) { }) } -const PtrSize = sys.PtrSize +const PtrSize = goarch.PtrSize var ForceGCPeriod = &forcegcperiod diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go index 934e55f4952..050628e33e3 100644 --- a/src/runtime/heapdump.go +++ b/src/runtime/heapdump.go @@ -13,6 +13,7 @@ package runtime import ( "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -247,7 +248,7 @@ func dumpbv(cbv *bitvector, offset uintptr) { for i := uintptr(0); i < uintptr(cbv.n); i++ { if cbv.ptrbit(i) == 1 { dumpint(fieldKindPtr) - dumpint(uint64(offset + i*sys.PtrSize)) + dumpint(uint64(offset + i*goarch.PtrSize)) } } } @@ -298,7 +299,7 @@ func dumpframe(s *stkframe, arg unsafe.Pointer) bool { dumpbv(&child.args, child.argoff) } else { // conservative - everything might be a pointer - for off := child.argoff; off < child.argoff+child.arglen; off += sys.PtrSize { + for off := child.argoff; off < child.argoff+child.arglen; off += goarch.PtrSize { dumpint(fieldKindPtr) dumpint(uint64(off)) } @@ -307,21 +308,21 @@ func dumpframe(s *stkframe, arg unsafe.Pointer) bool { // Dump fields in the local vars section if stkmap == nil { // No locals information, dump everything. - for off := child.arglen; off < s.varp-s.sp; off += sys.PtrSize { + for off := child.arglen; off < s.varp-s.sp; off += goarch.PtrSize { dumpint(fieldKindPtr) dumpint(uint64(off)) } } else if stkmap.n < 0 { // Locals size information, dump just the locals. size := uintptr(-stkmap.n) - for off := s.varp - size - s.sp; off < s.varp-s.sp; off += sys.PtrSize { + for off := s.varp - size - s.sp; off < s.varp-s.sp; off += goarch.PtrSize { dumpint(fieldKindPtr) dumpint(uint64(off)) } } else if stkmap.n > 0 { // Locals bitmap information, scan just the pointers in // locals. - dumpbv(&bv, s.varp-uintptr(bv.n)*sys.PtrSize-s.sp) + dumpbv(&bv, s.varp-uintptr(bv.n)*goarch.PtrSize-s.sp) } dumpint(fieldKindEol) @@ -510,7 +511,7 @@ func dumpparams() { } else { dumpbool(true) // big-endian ptrs } - dumpint(sys.PtrSize) + dumpint(goarch.PtrSize) var arenaStart, arenaEnd uintptr for i1 := range mheap_.arenas { if mheap_.arenas[i1] == nil { @@ -725,7 +726,7 @@ func dumpfields(bv bitvector) { func makeheapobjbv(p uintptr, size uintptr) bitvector { // Extend the temp buffer if necessary. - nptr := size / sys.PtrSize + nptr := size / goarch.PtrSize if uintptr(len(tmpbuf)) < nptr/8+1 { if tmpbuf != nil { sysFree(unsafe.Pointer(&tmpbuf[0]), uintptr(len(tmpbuf)), &memstats.other_sys) diff --git a/src/runtime/iface.go b/src/runtime/iface.go index b397d1ff8d4..67c05823638 100644 --- a/src/runtime/iface.go +++ b/src/runtime/iface.go @@ -8,6 +8,7 @@ import ( "internal/abi" "runtime/internal/atomic" "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -64,7 +65,7 @@ func getitab(inter *interfacetype, typ *_type, canfail bool) *itab { } // Entry doesn't exist yet. Make a new entry & add it. - m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*sys.PtrSize, 0, &memstats.other_sys)) + m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*goarch.PtrSize, 0, &memstats.other_sys)) m.inter = inter m._type = typ // The hash is used in type switches. However, compiler statically generates itab's @@ -101,7 +102,7 @@ func (t *itabTableType) find(inter *interfacetype, typ *_type) *itab { mask := t.size - 1 h := itabHashFunc(inter, typ) & mask for i := uintptr(1); ; i++ { - p := (**itab)(add(unsafe.Pointer(&t.entries), h*sys.PtrSize)) + p := (**itab)(add(unsafe.Pointer(&t.entries), h*goarch.PtrSize)) // Use atomic read here so if we see m != nil, we also see // the initializations of the fields of m. // m := *p @@ -134,7 +135,7 @@ func itabAdd(m *itab) { // t2 = new(itabTableType) + some additional entries // We lie and tell malloc we want pointer-free memory because // all the pointed-to values are not in the heap. - t2 := (*itabTableType)(mallocgc((2+2*t.size)*sys.PtrSize, nil, true)) + t2 := (*itabTableType)(mallocgc((2+2*t.size)*goarch.PtrSize, nil, true)) t2.size = t.size * 2 // Copy over entries. @@ -162,7 +163,7 @@ func (t *itabTableType) add(m *itab) { mask := t.size - 1 h := itabHashFunc(m.inter, m._type) & mask for i := uintptr(1); ; i++ { - p := (**itab)(add(unsafe.Pointer(&t.entries), h*sys.PtrSize)) + p := (**itab)(add(unsafe.Pointer(&t.entries), h*goarch.PtrSize)) m2 := *p if m2 == m { // A given itab may be used in more than one module @@ -512,7 +513,7 @@ func iterate_itabs(fn func(*itab)) { // so no other locks/atomics needed. t := itabTable for i := uintptr(0); i < t.size; i++ { - m := *(**itab)(add(unsafe.Pointer(&t.entries), i*sys.PtrSize)) + m := *(**itab)(add(unsafe.Pointer(&t.entries), i*goarch.PtrSize)) if m != nil { fn(m) } diff --git a/src/runtime/internal/math/math.go b/src/runtime/internal/math/math.go index b6bd12d3e8b..c3fac366be0 100644 --- a/src/runtime/internal/math/math.go +++ b/src/runtime/internal/math/math.go @@ -4,14 +4,14 @@ package math -import "runtime/internal/sys" +import "internal/goarch" const MaxUintptr = ^uintptr(0) // MulUintptr returns a * b and whether the multiplication overflowed. // On supported platforms this is an intrinsic lowered by the compiler. func MulUintptr(a, b uintptr) (uintptr, bool) { - if a|b < 1<<(4*sys.PtrSize) || a == 0 { + if a|b < 1<<(4*goarch.PtrSize) || a == 0 { return a * b, false } overflow := b > MaxUintptr/a diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index c5f62483ffc..9f8e04d760b 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -104,6 +104,7 @@ import ( "runtime/internal/atomic" "runtime/internal/math" "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -150,7 +151,7 @@ const ( // windows/32 | 4KB | 3 // windows/64 | 8KB | 2 // plan9 | 4KB | 3 - _NumStackOrders = 4 - sys.PtrSize/4*sys.GoosWindows - 1*sys.GoosPlan9 + _NumStackOrders = 4 - goarch.PtrSize/4*sys.GoosWindows - 1*sys.GoosPlan9 // heapAddrBits is the number of bits in a heap address. On // amd64, addresses are sign-extended beyond heapAddrBits. On @@ -251,7 +252,7 @@ const ( logHeapArenaBytes = (6+20)*(_64bit*(1-sys.GoosWindows)*(1-sys.GoarchWasm)*(1-sys.GoosIos*sys.GoarchArm64)) + (2+20)*(_64bit*sys.GoosWindows) + (2+20)*(1-_64bit) + (2+20)*sys.GoarchWasm + (2+20)*sys.GoosIos*sys.GoarchArm64 // heapArenaBitmapBytes is the size of each heap arena's bitmap. - heapArenaBitmapBytes = heapArenaBytes / (sys.PtrSize * 8 / 2) + heapArenaBitmapBytes = heapArenaBytes / (goarch.PtrSize * 8 / 2) pagesPerArena = heapArenaBytes / pageSize @@ -483,7 +484,7 @@ func mallocinit() { lockInit(&globalAlloc.mutex, lockRankGlobalAlloc) // Create initial arena growth hints. - if sys.PtrSize == 8 { + if goarch.PtrSize == 8 { // On a 64-bit machine, we pick the following hints // because: // @@ -730,7 +731,7 @@ mapped: l2 := h.arenas[ri.l1()] if l2 == nil { // Allocate an L2 arena map. - l2 = (*[1 << arenaL2Bits]*heapArena)(persistentalloc(unsafe.Sizeof(*l2), sys.PtrSize, nil)) + l2 = (*[1 << arenaL2Bits]*heapArena)(persistentalloc(unsafe.Sizeof(*l2), goarch.PtrSize, nil)) if l2 == nil { throw("out of memory allocating heap arena map") } @@ -741,9 +742,9 @@ mapped: throw("arena already initialized") } var r *heapArena - r = (*heapArena)(h.heapArenaAlloc.alloc(unsafe.Sizeof(*r), sys.PtrSize, &memstats.gcMiscSys)) + r = (*heapArena)(h.heapArenaAlloc.alloc(unsafe.Sizeof(*r), goarch.PtrSize, &memstats.gcMiscSys)) if r == nil { - r = (*heapArena)(persistentalloc(unsafe.Sizeof(*r), sys.PtrSize, &memstats.gcMiscSys)) + r = (*heapArena)(persistentalloc(unsafe.Sizeof(*r), goarch.PtrSize, &memstats.gcMiscSys)) if r == nil { throw("out of memory allocating heap arena metadata") } @@ -751,16 +752,16 @@ mapped: // Add the arena to the arenas list. if len(h.allArenas) == cap(h.allArenas) { - size := 2 * uintptr(cap(h.allArenas)) * sys.PtrSize + size := 2 * uintptr(cap(h.allArenas)) * goarch.PtrSize if size == 0 { size = physPageSize } - newArray := (*notInHeap)(persistentalloc(size, sys.PtrSize, &memstats.gcMiscSys)) + newArray := (*notInHeap)(persistentalloc(size, goarch.PtrSize, &memstats.gcMiscSys)) if newArray == nil { throw("out of memory allocating allArenas") } oldSlice := h.allArenas - *(*notInHeapSlice)(unsafe.Pointer(&h.allArenas)) = notInHeapSlice{newArray, len(h.allArenas), int(size / sys.PtrSize)} + *(*notInHeapSlice)(unsafe.Pointer(&h.allArenas)) = notInHeapSlice{newArray, len(h.allArenas), int(size / goarch.PtrSize)} copy(h.allArenas, oldSlice) // Do not free the old backing array because // there may be concurrent readers. Since we @@ -1015,7 +1016,7 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { // Align tiny pointer for required (conservative) alignment. if size&7 == 0 { off = alignUp(off, 8) - } else if sys.PtrSize == 4 && size == 12 { + } else if goarch.PtrSize == 4 && size == 12 { // Conservatively align 12-byte objects to 8 bytes on 32-bit // systems so that objects whose first field is a 64-bit // value is aligned to 8 bytes and does not cause a fault on @@ -1410,7 +1411,7 @@ func persistentalloc1(size, align uintptr, sysStat *sysMemStat) *notInHeap { break } } - persistent.off = alignUp(sys.PtrSize, align) + persistent.off = alignUp(goarch.PtrSize, align) } p := persistent.base.add(persistent.off) persistent.off += size diff --git a/src/runtime/map.go b/src/runtime/map.go index 5575040f2af..ca65d3e77f3 100644 --- a/src/runtime/map.go +++ b/src/runtime/map.go @@ -57,7 +57,7 @@ import ( "internal/abi" "runtime/internal/atomic" "runtime/internal/math" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -104,7 +104,7 @@ const ( sameSizeGrow = 8 // the current map growth is to a new map of the same size // sentinel bucket ID for iterator checks - noCheck = 1<<(8*sys.PtrSize) - 1 + noCheck = 1<<(8*goarch.PtrSize) - 1 ) // isEmpty reports whether the given tophash array entry represents an empty bucket entry. @@ -183,7 +183,7 @@ type hiter struct { // bucketShift returns 1<> (sys.PtrSize*8 - 8)) + top := uint8(hash >> (goarch.PtrSize*8 - 8)) if top < minTopHash { top += minTopHash } @@ -206,11 +206,11 @@ func evacuated(b *bmap) bool { } func (b *bmap) overflow(t *maptype) *bmap { - return *(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-sys.PtrSize)) + return *(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-goarch.PtrSize)) } func (b *bmap) setoverflow(t *maptype, ovf *bmap) { - *(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-sys.PtrSize)) = ovf + *(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-goarch.PtrSize)) = ovf } func (b *bmap) keys() unsafe.Pointer { @@ -810,7 +810,7 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) { return } - if unsafe.Sizeof(hiter{})/sys.PtrSize != 12 { + if unsafe.Sizeof(hiter{})/goarch.PtrSize != 12 { throw("hash_iter size incorrect") // see cmd/compile/internal/reflectdata/reflect.go } it.t = t @@ -1281,11 +1281,11 @@ func reflect_makemap(t *maptype, cap int) *hmap { if t.key.equal == nil { throw("runtime.reflect_makemap: unsupported map key type") } - if t.key.size > maxKeySize && (!t.indirectkey() || t.keysize != uint8(sys.PtrSize)) || + if t.key.size > maxKeySize && (!t.indirectkey() || t.keysize != uint8(goarch.PtrSize)) || t.key.size <= maxKeySize && (t.indirectkey() || t.keysize != uint8(t.key.size)) { throw("key size wrong") } - if t.elem.size > maxElemSize && (!t.indirectelem() || t.elemsize != uint8(sys.PtrSize)) || + if t.elem.size > maxElemSize && (!t.indirectelem() || t.elemsize != uint8(goarch.PtrSize)) || t.elem.size <= maxElemSize && (t.indirectelem() || t.elemsize != uint8(t.elem.size)) { throw("elem size wrong") } diff --git a/src/runtime/map_fast32.go b/src/runtime/map_fast32.go index 420a01daec1..e80caeef552 100644 --- a/src/runtime/map_fast32.go +++ b/src/runtime/map_fast32.go @@ -6,7 +6,7 @@ package runtime import ( "internal/abi" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -302,7 +302,7 @@ search: // Only clear key if there are pointers in it. // This can only happen if pointers are 32 bit // wide as 64 bit pointers do not fit into a 32 bit key. - if sys.PtrSize == 4 && t.key.ptrdata != 0 { + if goarch.PtrSize == 4 && t.key.ptrdata != 0 { // The key must be a pointer as we checked pointers are // 32 bits wide and the key is 32 bits wide also. *(*unsafe.Pointer)(k) = nil @@ -428,7 +428,7 @@ func evacuate_fast32(t *maptype, h *hmap, oldbucket uintptr) { dst.b.tophash[dst.i&(bucketCnt-1)] = top // mask dst.i as an optimization, to avoid a bounds check // Copy key. - if sys.PtrSize == 4 && t.key.ptrdata != 0 && writeBarrier.enabled { + if goarch.PtrSize == 4 && t.key.ptrdata != 0 && writeBarrier.enabled { // Write with a write barrier. *(*unsafe.Pointer)(dst.k) = *(*unsafe.Pointer)(k) } else { diff --git a/src/runtime/map_fast64.go b/src/runtime/map_fast64.go index cb202113ac5..69d8872885a 100644 --- a/src/runtime/map_fast64.go +++ b/src/runtime/map_fast64.go @@ -6,7 +6,7 @@ package runtime import ( "internal/abi" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -301,7 +301,7 @@ search: } // Only clear key if there are pointers in it. if t.key.ptrdata != 0 { - if sys.PtrSize == 8 { + if goarch.PtrSize == 8 { *(*unsafe.Pointer)(k) = nil } else { // There are three ways to squeeze at one ore more 32 bit pointers into 64 bits. @@ -431,7 +431,7 @@ func evacuate_fast64(t *maptype, h *hmap, oldbucket uintptr) { // Copy key. if t.key.ptrdata != 0 && writeBarrier.enabled { - if sys.PtrSize == 8 { + if goarch.PtrSize == 8 { // Write with a write barrier. *(*unsafe.Pointer)(dst.k) = *(*unsafe.Pointer)(k) } else { diff --git a/src/runtime/map_faststr.go b/src/runtime/map_faststr.go index ed7e46b5f68..4dca882c636 100644 --- a/src/runtime/map_faststr.go +++ b/src/runtime/map_faststr.go @@ -6,7 +6,7 @@ package runtime import ( "internal/abi" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -27,7 +27,7 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer { b := (*bmap)(h.buckets) if key.len < 32 { // short key, doing lots of comparisons is ok - for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*sys.PtrSize) { + for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { k := (*stringStruct)(kptr) if k.len != key.len || isEmpty(b.tophash[i]) { if b.tophash[i] == emptyRest { @@ -36,14 +36,14 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer { continue } if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.elemsize)) + return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+i*uintptr(t.elemsize)) } } return unsafe.Pointer(&zeroVal[0]) } // long key, try not to do more comparisons than necessary keymaybe := uintptr(bucketCnt) - for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*sys.PtrSize) { + for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { k := (*stringStruct)(kptr) if k.len != key.len || isEmpty(b.tophash[i]) { if b.tophash[i] == emptyRest { @@ -52,7 +52,7 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer { continue } if k.str == key.str { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.elemsize)) + return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+i*uintptr(t.elemsize)) } // check first 4 bytes if *((*[4]byte)(key.str)) != *((*[4]byte)(k.str)) { @@ -69,9 +69,9 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer { keymaybe = i } if keymaybe != bucketCnt { - k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+keymaybe*2*sys.PtrSize)) + k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+keymaybe*2*goarch.PtrSize)) if memequal(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+keymaybe*uintptr(t.elemsize)) + return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+keymaybe*uintptr(t.elemsize)) } } return unsafe.Pointer(&zeroVal[0]) @@ -92,13 +92,13 @@ dohash: } top := tophash(hash) for ; b != nil; b = b.overflow(t) { - for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*sys.PtrSize) { + for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { k := (*stringStruct)(kptr) if k.len != key.len || b.tophash[i] != top { continue } if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.elemsize)) + return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+i*uintptr(t.elemsize)) } } } @@ -122,7 +122,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { b := (*bmap)(h.buckets) if key.len < 32 { // short key, doing lots of comparisons is ok - for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*sys.PtrSize) { + for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { k := (*stringStruct)(kptr) if k.len != key.len || isEmpty(b.tophash[i]) { if b.tophash[i] == emptyRest { @@ -131,14 +131,14 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { continue } if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.elemsize)), true + return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+i*uintptr(t.elemsize)), true } } return unsafe.Pointer(&zeroVal[0]), false } // long key, try not to do more comparisons than necessary keymaybe := uintptr(bucketCnt) - for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*sys.PtrSize) { + for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { k := (*stringStruct)(kptr) if k.len != key.len || isEmpty(b.tophash[i]) { if b.tophash[i] == emptyRest { @@ -147,7 +147,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { continue } if k.str == key.str { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.elemsize)), true + return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+i*uintptr(t.elemsize)), true } // check first 4 bytes if *((*[4]byte)(key.str)) != *((*[4]byte)(k.str)) { @@ -164,9 +164,9 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { keymaybe = i } if keymaybe != bucketCnt { - k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+keymaybe*2*sys.PtrSize)) + k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+keymaybe*2*goarch.PtrSize)) if memequal(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+keymaybe*uintptr(t.elemsize)), true + return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+keymaybe*uintptr(t.elemsize)), true } } return unsafe.Pointer(&zeroVal[0]), false @@ -187,13 +187,13 @@ dohash: } top := tophash(hash) for ; b != nil; b = b.overflow(t) { - for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*sys.PtrSize) { + for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { k := (*stringStruct)(kptr) if k.len != key.len || b.tophash[i] != top { continue } if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.elemsize)), true + return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+i*uintptr(t.elemsize)), true } } } @@ -246,7 +246,7 @@ bucketloop: } continue } - k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*sys.PtrSize)) + k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*goarch.PtrSize)) if k.len != key.len { continue } @@ -284,13 +284,13 @@ bucketloop: } insertb.tophash[inserti&(bucketCnt-1)] = top // mask inserti to avoid bounds checks - insertk = add(unsafe.Pointer(insertb), dataOffset+inserti*2*sys.PtrSize) + insertk = add(unsafe.Pointer(insertb), dataOffset+inserti*2*goarch.PtrSize) // store new key at insert position *((*stringStruct)(insertk)) = *key h.count++ done: - elem := add(unsafe.Pointer(insertb), dataOffset+bucketCnt*2*sys.PtrSize+inserti*uintptr(t.elemsize)) + elem := add(unsafe.Pointer(insertb), dataOffset+bucketCnt*2*goarch.PtrSize+inserti*uintptr(t.elemsize)) if h.flags&hashWriting == 0 { throw("concurrent map writes") } @@ -325,7 +325,7 @@ func mapdelete_faststr(t *maptype, h *hmap, ky string) { top := tophash(hash) search: for ; b != nil; b = b.overflow(t) { - for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*sys.PtrSize) { + for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { k := (*stringStruct)(kptr) if k.len != key.len || b.tophash[i] != top { continue @@ -335,7 +335,7 @@ search: } // Clear key's pointer. k.str = nil - e := add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.elemsize)) + e := add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+i*uintptr(t.elemsize)) if t.elem.ptrdata != 0 { memclrHasPointers(e, t.elem.size) } else { @@ -411,7 +411,7 @@ func evacuate_faststr(t *maptype, h *hmap, oldbucket uintptr) { x := &xy[0] x.b = (*bmap)(add(h.buckets, oldbucket*uintptr(t.bucketsize))) x.k = add(unsafe.Pointer(x.b), dataOffset) - x.e = add(x.k, bucketCnt*2*sys.PtrSize) + x.e = add(x.k, bucketCnt*2*goarch.PtrSize) if !h.sameSizeGrow() { // Only calculate y pointers if we're growing bigger. @@ -419,13 +419,13 @@ func evacuate_faststr(t *maptype, h *hmap, oldbucket uintptr) { y := &xy[1] y.b = (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.bucketsize))) y.k = add(unsafe.Pointer(y.b), dataOffset) - y.e = add(y.k, bucketCnt*2*sys.PtrSize) + y.e = add(y.k, bucketCnt*2*goarch.PtrSize) } for ; b != nil; b = b.overflow(t) { k := add(unsafe.Pointer(b), dataOffset) - e := add(k, bucketCnt*2*sys.PtrSize) - for i := 0; i < bucketCnt; i, k, e = i+1, add(k, 2*sys.PtrSize), add(e, uintptr(t.elemsize)) { + e := add(k, bucketCnt*2*goarch.PtrSize) + for i := 0; i < bucketCnt; i, k, e = i+1, add(k, 2*goarch.PtrSize), add(e, uintptr(t.elemsize)) { top := b.tophash[i] if isEmpty(top) { b.tophash[i] = evacuatedEmpty @@ -451,7 +451,7 @@ func evacuate_faststr(t *maptype, h *hmap, oldbucket uintptr) { dst.b = h.newoverflow(t, dst.b) dst.i = 0 dst.k = add(unsafe.Pointer(dst.b), dataOffset) - dst.e = add(dst.k, bucketCnt*2*sys.PtrSize) + dst.e = add(dst.k, bucketCnt*2*goarch.PtrSize) } dst.b.tophash[dst.i&(bucketCnt-1)] = top // mask dst.i as an optimization, to avoid a bounds check @@ -464,7 +464,7 @@ func evacuate_faststr(t *maptype, h *hmap, oldbucket uintptr) { // key or elem arrays. That's ok, as we have the overflow pointer // at the end of the bucket to protect against pointing past the // end of the bucket. - dst.k = add(dst.k, 2*sys.PtrSize) + dst.k = add(dst.k, 2*goarch.PtrSize) dst.e = add(dst.e, uintptr(t.elemsize)) } } diff --git a/src/runtime/map_test.go b/src/runtime/map_test.go index 302b3c23c12..583be21eb36 100644 --- a/src/runtime/map_test.go +++ b/src/runtime/map_test.go @@ -9,8 +9,8 @@ import ( "math" "reflect" "runtime" - "runtime/internal/sys" "sort" + "internal/goarch" "strconv" "strings" "sync" @@ -21,7 +21,7 @@ func TestHmapSize(t *testing.T) { // The structure of hmap is defined in runtime/map.go // and in cmd/compile/internal/gc/reflect.go and must be in sync. // The size of hmap should be 48 bytes on 64 bit and 28 bytes on 32 bit platforms. - var hmapSize = uintptr(8 + 5*sys.PtrSize) + var hmapSize = uintptr(8 + 5*goarch.PtrSize) if runtime.RuntimeHmapSize != hmapSize { t.Errorf("sizeof(runtime.hmap{})==%d, want %d", runtime.RuntimeHmapSize, hmapSize) } diff --git a/src/runtime/mbarrier.go b/src/runtime/mbarrier.go index b06ee725ddd..3fd1cca42cc 100644 --- a/src/runtime/mbarrier.go +++ b/src/runtime/mbarrier.go @@ -15,7 +15,7 @@ package runtime import ( "internal/abi" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -197,11 +197,11 @@ func reflectlite_typedmemmove(typ *_type, dst, src unsafe.Pointer) { // off must be a multiple of sys.PtrSize. //go:linkname reflect_typedmemmovepartial reflect.typedmemmovepartial func reflect_typedmemmovepartial(typ *_type, dst, src unsafe.Pointer, off, size uintptr) { - if writeBarrier.needed && typ.ptrdata > off && size >= sys.PtrSize { - if off&(sys.PtrSize-1) != 0 { + if writeBarrier.needed && typ.ptrdata > off && size >= goarch.PtrSize { + if off&(goarch.PtrSize-1) != 0 { panic("reflect: internal error: misaligned offset") } - pwsize := alignDown(size, sys.PtrSize) + pwsize := alignDown(size, goarch.PtrSize) if poff := typ.ptrdata - off; pwsize > poff { pwsize = poff } @@ -225,7 +225,7 @@ func reflect_typedmemmovepartial(typ *_type, dst, src unsafe.Pointer, off, size // //go:nosplit func reflectcallmove(typ *_type, dst, src unsafe.Pointer, size uintptr, regs *abi.RegArgs) { - if writeBarrier.needed && typ != nil && typ.ptrdata != 0 && size >= sys.PtrSize { + if writeBarrier.needed && typ != nil && typ.ptrdata != 0 && size >= goarch.PtrSize { bulkBarrierPreWrite(uintptr(dst), uintptr(src), size) } memmove(dst, src, size) diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go index 819acf40bd6..124ac8f0508 100644 --- a/src/runtime/mbitmap.go +++ b/src/runtime/mbitmap.go @@ -48,6 +48,7 @@ package runtime import ( "runtime/internal/atomic" "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -326,8 +327,8 @@ func heapBitsForAddr(addr uintptr) (h heapBits) { // we expect to crash in the caller. return } - h.bitp = &ha.bitmap[(addr/(sys.PtrSize*4))%heapArenaBitmapBytes] - h.shift = uint32((addr / sys.PtrSize) & 3) + h.bitp = &ha.bitmap[(addr/(goarch.PtrSize*4))%heapArenaBitmapBytes] + h.shift = uint32((addr / goarch.PtrSize) & 3) h.arena = uint32(arena) h.last = &ha.bitmap[len(ha.bitmap)-1] return @@ -557,7 +558,7 @@ func (h heapBits) isPointer() bool { // //go:nosplit func bulkBarrierPreWrite(dst, src, size uintptr) { - if (dst|src|size)&(sys.PtrSize-1) != 0 { + if (dst|src|size)&(goarch.PtrSize-1) != 0 { throw("bulkBarrierPreWrite: unaligned arguments") } if !writeBarrier.needed { @@ -592,7 +593,7 @@ func bulkBarrierPreWrite(dst, src, size uintptr) { buf := &getg().m.p.ptr().wbBuf h := heapBitsForAddr(dst) if src == 0 { - for i := uintptr(0); i < size; i += sys.PtrSize { + for i := uintptr(0); i < size; i += goarch.PtrSize { if h.isPointer() { dstx := (*uintptr)(unsafe.Pointer(dst + i)) if !buf.putFast(*dstx, 0) { @@ -602,7 +603,7 @@ func bulkBarrierPreWrite(dst, src, size uintptr) { h = h.next() } } else { - for i := uintptr(0); i < size; i += sys.PtrSize { + for i := uintptr(0); i < size; i += goarch.PtrSize { if h.isPointer() { dstx := (*uintptr)(unsafe.Pointer(dst + i)) srcx := (*uintptr)(unsafe.Pointer(src + i)) @@ -625,7 +626,7 @@ func bulkBarrierPreWrite(dst, src, size uintptr) { // created and zeroed with malloc. //go:nosplit func bulkBarrierPreWriteSrcOnly(dst, src, size uintptr) { - if (dst|src|size)&(sys.PtrSize-1) != 0 { + if (dst|src|size)&(goarch.PtrSize-1) != 0 { throw("bulkBarrierPreWrite: unaligned arguments") } if !writeBarrier.needed { @@ -633,7 +634,7 @@ func bulkBarrierPreWriteSrcOnly(dst, src, size uintptr) { } buf := &getg().m.p.ptr().wbBuf h := heapBitsForAddr(dst) - for i := uintptr(0); i < size; i += sys.PtrSize { + for i := uintptr(0); i < size; i += goarch.PtrSize { if h.isPointer() { srcx := (*uintptr)(unsafe.Pointer(src + i)) if !buf.putFast(0, *srcx) { @@ -653,17 +654,17 @@ func bulkBarrierPreWriteSrcOnly(dst, src, size uintptr) { // //go:nosplit func bulkBarrierBitmap(dst, src, size, maskOffset uintptr, bits *uint8) { - word := maskOffset / sys.PtrSize + word := maskOffset / goarch.PtrSize bits = addb(bits, word/8) mask := uint8(1) << (word % 8) buf := &getg().m.p.ptr().wbBuf - for i := uintptr(0); i < size; i += sys.PtrSize { + for i := uintptr(0); i < size; i += goarch.PtrSize { if mask == 0 { bits = addb(bits, 1) if *bits == 0 { // Skip 8 words. - i += 7 * sys.PtrSize + i += 7 * goarch.PtrSize continue } mask = 1 @@ -720,8 +721,8 @@ func typeBitsBulkBarrier(typ *_type, dst, src, size uintptr) { ptrmask := typ.gcdata buf := &getg().m.p.ptr().wbBuf var bits uint32 - for i := uintptr(0); i < typ.ptrdata; i += sys.PtrSize { - if i&(sys.PtrSize*8-1) == 0 { + for i := uintptr(0); i < typ.ptrdata; i += goarch.PtrSize { + if i&(goarch.PtrSize*8-1) == 0 { bits = uint32(*ptrmask) ptrmask = addb(ptrmask, 1) } else { @@ -751,14 +752,14 @@ func typeBitsBulkBarrier(typ *_type, dst, src, size uintptr) { // Otherwise, it initializes all words to scalar/dead. func (h heapBits) initSpan(s *mspan) { // Clear bits corresponding to objects. - nw := (s.npages << _PageShift) / sys.PtrSize + nw := (s.npages << _PageShift) / goarch.PtrSize if nw%wordsPerBitmapByte != 0 { throw("initSpan: unaligned length") } if h.shift != 0 { throw("initSpan: unaligned base") } - isPtrs := sys.PtrSize == 8 && s.elemsize == sys.PtrSize + isPtrs := goarch.PtrSize == 8 && s.elemsize == goarch.PtrSize for nw > 0 { hNext, anw := h.forwardOrBoundary(nw) nbyte := anw / wordsPerBitmapByte @@ -836,7 +837,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { // The checks for size == sys.PtrSize and size == 2*sys.PtrSize can therefore // assume that dataSize == size without checking it explicitly. - if sys.PtrSize == 8 && size == sys.PtrSize { + if goarch.PtrSize == 8 && size == goarch.PtrSize { // It's one word and it has pointers, it must be a pointer. // Since all allocated one-word objects are pointers // (non-pointers are aggregated into tinySize allocations), @@ -862,8 +863,8 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { // objects are at least 4 words long and that their bitmaps start either at the beginning // of a bitmap byte, or half-way in (h.shift of 0 and 2 respectively). - if size == 2*sys.PtrSize { - if typ.size == sys.PtrSize { + if size == 2*goarch.PtrSize { + if typ.size == goarch.PtrSize { // We're allocating a block big enough to hold two pointers. // On 64-bit, that means the actual object must be two pointers, // or else we'd have used the one-pointer-sized block. @@ -872,7 +873,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { // just the smallest block available. Distinguish by checking dataSize. // (In general the number of instances of typ being allocated is // dataSize/typ.size.) - if sys.PtrSize == 4 && dataSize == sys.PtrSize { + if goarch.PtrSize == 4 && dataSize == goarch.PtrSize { // 1 pointer object. On 32-bit machines clear the bit for the // unused second word. *h.bitp &^= (bitPointer | bitScan | (bitPointer|bitScan)<> h.shift) & (bitPointer | bitScan) @@ -1446,7 +1447,7 @@ Phase4: print("initial bits h0.bitp=", h0.bitp, " h0.shift=", h0.shift, "\n") print("current bits h.bitp=", h.bitp, " h.shift=", h.shift, " *h.bitp=", hex(*h.bitp), "\n") print("ptrmask=", ptrmask, " p=", p, " endp=", endp, " endnb=", endnb, " pbits=", hex(pbits), " b=", hex(b), " nb=", nb, "\n") - println("at word", i, "offset", i*sys.PtrSize, "have", hex(have), "want", hex(want)) + println("at word", i, "offset", i*goarch.PtrSize, "have", hex(have), "want", hex(want)) if typ.kind&kindGCProg != 0 { println("GC program:") dumpGCProg(addb(typ.gcdata, 4)) @@ -1477,14 +1478,14 @@ var debugPtrmask struct { // so that the relevant bitmap bytes are not shared with surrounding // objects. func heapBitsSetTypeGCProg(h heapBits, progSize, elemSize, dataSize, allocSize uintptr, prog *byte) { - if sys.PtrSize == 8 && allocSize%(4*sys.PtrSize) != 0 { + if goarch.PtrSize == 8 && allocSize%(4*goarch.PtrSize) != 0 { // Alignment will be wrong. throw("heapBitsSetTypeGCProg: small allocation") } var totalBits uintptr if elemSize == dataSize { totalBits = runGCProg(prog, nil, h.bitp, 2) - if totalBits*sys.PtrSize != progSize { + if totalBits*goarch.PtrSize != progSize { println("runtime: heapBitsSetTypeGCProg: total bits", totalBits, "but progSize", progSize) throw("heapBitsSetTypeGCProg: unexpected bit count") } @@ -1499,7 +1500,7 @@ func heapBitsSetTypeGCProg(h heapBits, progSize, elemSize, dataSize, allocSize u // repeats that first element to fill the array. var trailer [40]byte // 3 varints (max 10 each) + some bytes i := 0 - if n := elemSize/sys.PtrSize - progSize/sys.PtrSize; n > 0 { + if n := elemSize/goarch.PtrSize - progSize/goarch.PtrSize; n > 0 { // literal(0) trailer[i] = 0x01 i++ @@ -1521,7 +1522,7 @@ func heapBitsSetTypeGCProg(h heapBits, progSize, elemSize, dataSize, allocSize u // repeat(elemSize/ptrSize, count-1) trailer[i] = 0x80 i++ - n := elemSize / sys.PtrSize + n := elemSize / goarch.PtrSize for ; n >= 0x80; n >>= 7 { trailer[i] = byte(n | 0x80) i++ @@ -1545,10 +1546,10 @@ func heapBitsSetTypeGCProg(h heapBits, progSize, elemSize, dataSize, allocSize u // last element. This will cause the code below to // memclr the dead section of the final array element, // so that scanobject can stop early in the final element. - totalBits = (elemSize*(count-1) + progSize) / sys.PtrSize + totalBits = (elemSize*(count-1) + progSize) / goarch.PtrSize } endProg := unsafe.Pointer(addb(h.bitp, (totalBits+3)/4)) - endAlloc := unsafe.Pointer(addb(h.bitp, allocSize/sys.PtrSize/wordsPerBitmapByte)) + endAlloc := unsafe.Pointer(addb(h.bitp, allocSize/goarch.PtrSize/wordsPerBitmapByte)) memclrNoHeapPointers(endProg, uintptr(endAlloc)-uintptr(endProg)) } @@ -1556,7 +1557,7 @@ func heapBitsSetTypeGCProg(h heapBits, progSize, elemSize, dataSize, allocSize u // size the size of the region described by prog, in bytes. // The resulting bitvector will have no more than size/sys.PtrSize bits. func progToPointerMask(prog *byte, size uintptr) bitvector { - n := (size/sys.PtrSize + 7) / 8 + n := (size/goarch.PtrSize + 7) / 8 x := (*[1 << 30]byte)(persistentalloc(n+1, 1, &memstats.buckhash_sys))[:n+1] x[len(x)-1] = 0xa1 // overflow check sentinel n = runGCProg(prog, nil, &x[0], 1) @@ -1691,7 +1692,7 @@ Run: // the pattern to a bit buffer holding at most 7 bits (a partial byte) // it will not overflow. src := dst - const maxBits = sys.PtrSize*8 - 7 + const maxBits = goarch.PtrSize*8 - 7 if n <= maxBits { // Start with bits in output buffer. pattern := bits @@ -1744,7 +1745,7 @@ Run: nb := npattern if nb+nb <= maxBits { // Double pattern until the whole uintptr is filled. - for nb <= sys.PtrSize*8 { + for nb <= goarch.PtrSize*8 { b |= b << nb nb += nb } @@ -1872,7 +1873,7 @@ Run: // The result must be deallocated with dematerializeGCProg. func materializeGCProg(ptrdata uintptr, prog *byte) *mspan { // Each word of ptrdata needs one bit in the bitmap. - bitmapBytes := divRoundUp(ptrdata, 8*sys.PtrSize) + bitmapBytes := divRoundUp(ptrdata, 8*goarch.PtrSize) // Compute the number of pages needed for bitmapBytes. pages := divRoundUp(bitmapBytes, pageSize) s := mheap_.allocManual(pages, spanAllocPtrScalarBits) @@ -1945,7 +1946,7 @@ func getgcmaskcb(frame *stkframe, ctxt unsafe.Pointer) bool { func reflect_gcbits(x interface{}) []byte { ret := getgcmask(x) typ := (*ptrtype)(unsafe.Pointer(efaceOf(&x)._type)).elem - nptr := typ.ptrdata / sys.PtrSize + nptr := typ.ptrdata / goarch.PtrSize for uintptr(len(ret)) > nptr && ret[len(ret)-1] == 0 { ret = ret[:len(ret)-1] } @@ -1965,10 +1966,10 @@ func getgcmask(ep interface{}) (mask []byte) { if datap.data <= uintptr(p) && uintptr(p) < datap.edata { bitmap := datap.gcdatamask.bytedata n := (*ptrtype)(unsafe.Pointer(t)).elem.size - mask = make([]byte, n/sys.PtrSize) - for i := uintptr(0); i < n; i += sys.PtrSize { - off := (uintptr(p) + i - datap.data) / sys.PtrSize - mask[i/sys.PtrSize] = (*addb(bitmap, off/8) >> (off % 8)) & 1 + mask = make([]byte, n/goarch.PtrSize) + for i := uintptr(0); i < n; i += goarch.PtrSize { + off := (uintptr(p) + i - datap.data) / goarch.PtrSize + mask[i/goarch.PtrSize] = (*addb(bitmap, off/8) >> (off % 8)) & 1 } return } @@ -1977,10 +1978,10 @@ func getgcmask(ep interface{}) (mask []byte) { if datap.bss <= uintptr(p) && uintptr(p) < datap.ebss { bitmap := datap.gcbssmask.bytedata n := (*ptrtype)(unsafe.Pointer(t)).elem.size - mask = make([]byte, n/sys.PtrSize) - for i := uintptr(0); i < n; i += sys.PtrSize { - off := (uintptr(p) + i - datap.bss) / sys.PtrSize - mask[i/sys.PtrSize] = (*addb(bitmap, off/8) >> (off % 8)) & 1 + mask = make([]byte, n/goarch.PtrSize) + for i := uintptr(0); i < n; i += goarch.PtrSize { + off := (uintptr(p) + i - datap.bss) / goarch.PtrSize + mask[i/goarch.PtrSize] = (*addb(bitmap, off/8) >> (off % 8)) & 1 } return } @@ -1990,13 +1991,13 @@ func getgcmask(ep interface{}) (mask []byte) { if base, s, _ := findObject(uintptr(p), 0, 0); base != 0 { hbits := heapBitsForAddr(base) n := s.elemsize - mask = make([]byte, n/sys.PtrSize) - for i := uintptr(0); i < n; i += sys.PtrSize { + mask = make([]byte, n/goarch.PtrSize) + for i := uintptr(0); i < n; i += goarch.PtrSize { if hbits.isPointer() { - mask[i/sys.PtrSize] = 1 + mask[i/goarch.PtrSize] = 1 } if !hbits.morePointers() { - mask = mask[:i/sys.PtrSize] + mask = mask[:i/goarch.PtrSize] break } hbits = hbits.next() @@ -2015,12 +2016,12 @@ func getgcmask(ep interface{}) (mask []byte) { if locals.n == 0 { return } - size := uintptr(locals.n) * sys.PtrSize + size := uintptr(locals.n) * goarch.PtrSize n := (*ptrtype)(unsafe.Pointer(t)).elem.size - mask = make([]byte, n/sys.PtrSize) - for i := uintptr(0); i < n; i += sys.PtrSize { - off := (uintptr(p) + i - frame.varp + size) / sys.PtrSize - mask[i/sys.PtrSize] = locals.ptrbit(off) + mask = make([]byte, n/goarch.PtrSize) + for i := uintptr(0); i < n; i += goarch.PtrSize { + off := (uintptr(p) + i - frame.varp + size) / goarch.PtrSize + mask[i/goarch.PtrSize] = locals.ptrbit(off) } } return diff --git a/src/runtime/mcheckmark.go b/src/runtime/mcheckmark.go index ba80ac1bdf4..6a43142508c 100644 --- a/src/runtime/mcheckmark.go +++ b/src/runtime/mcheckmark.go @@ -14,7 +14,7 @@ package runtime import ( "runtime/internal/atomic" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -24,7 +24,7 @@ import ( // allocation. // //go:notinheap -type checkmarksMap [heapArenaBytes / sys.PtrSize / 8]uint8 +type checkmarksMap [heapArenaBytes / goarch.PtrSize / 8]uint8 // If useCheckmark is true, marking of an object uses the checkmark // bits instead of the standard mark bits. diff --git a/src/runtime/mfinal.go b/src/runtime/mfinal.go index fd318d49a8d..98f7cf793f0 100644 --- a/src/runtime/mfinal.go +++ b/src/runtime/mfinal.go @@ -9,7 +9,7 @@ package runtime import ( "internal/abi" "runtime/internal/atomic" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -26,14 +26,14 @@ type finblock struct { next *finblock cnt uint32 _ int32 - fin [(_FinBlockSize - 2*sys.PtrSize - 2*4) / unsafe.Sizeof(finalizer{})]finalizer + fin [(_FinBlockSize - 2*goarch.PtrSize - 2*4) / unsafe.Sizeof(finalizer{})]finalizer } var finlock mutex // protects the following variables var fing *g // goroutine that runs finalizers var finq *finblock // list of finalizers that are to be executed var finc *finblock // cache of free blocks -var finptrmask [_FinBlockSize / sys.PtrSize / 8]byte +var finptrmask [_FinBlockSize / goarch.PtrSize / 8]byte var fingwait bool var fingwake bool var allfin *finblock // list of all blocks @@ -95,12 +95,12 @@ func queuefinalizer(p unsafe.Pointer, fn *funcval, nret uintptr, fint *_type, ot if finptrmask[0] == 0 { // Build pointer mask for Finalizer array in block. // Check assumptions made in finalizer1 array above. - if (unsafe.Sizeof(finalizer{}) != 5*sys.PtrSize || + if (unsafe.Sizeof(finalizer{}) != 5*goarch.PtrSize || unsafe.Offsetof(finalizer{}.fn) != 0 || - unsafe.Offsetof(finalizer{}.arg) != sys.PtrSize || - unsafe.Offsetof(finalizer{}.nret) != 2*sys.PtrSize || - unsafe.Offsetof(finalizer{}.fint) != 3*sys.PtrSize || - unsafe.Offsetof(finalizer{}.ot) != 4*sys.PtrSize) { + unsafe.Offsetof(finalizer{}.arg) != goarch.PtrSize || + unsafe.Offsetof(finalizer{}.nret) != 2*goarch.PtrSize || + unsafe.Offsetof(finalizer{}.fint) != 3*goarch.PtrSize || + unsafe.Offsetof(finalizer{}.ot) != 4*goarch.PtrSize) { throw("finalizer out of sync") } for i := range finptrmask { @@ -432,7 +432,7 @@ okarg: for _, t := range ft.out() { nret = alignUp(nret, uintptr(t.align)) + uintptr(t.size) } - nret = alignUp(nret, sys.PtrSize) + nret = alignUp(nret, goarch.PtrSize) // make sure we have a finalizer goroutine createfing() diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go index eb70ae9f493..85c78f05a7c 100644 --- a/src/runtime/mgcmark.go +++ b/src/runtime/mgcmark.go @@ -8,7 +8,7 @@ package runtime import ( "runtime/internal/atomic" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -245,7 +245,7 @@ func markroot(gcw *gcWork, i uint32) { // //go:nowritebarrier func markrootBlock(b0, n0 uintptr, ptrmask0 *uint8, gcw *gcWork, shard int) { - if rootBlockBytes%(8*sys.PtrSize) != 0 { + if rootBlockBytes%(8*goarch.PtrSize) != 0 { // This is necessary to pick byte offsets in ptrmask0. throw("rootBlockBytes must be a multiple of 8*ptrSize") } @@ -258,7 +258,7 @@ func markrootBlock(b0, n0 uintptr, ptrmask0 *uint8, gcw *gcWork, shard int) { return } b := b0 + off - ptrmask := (*uint8)(add(unsafe.Pointer(ptrmask0), uintptr(shard)*(rootBlockBytes/(8*sys.PtrSize)))) + ptrmask := (*uint8)(add(unsafe.Pointer(ptrmask0), uintptr(shard)*(rootBlockBytes/(8*goarch.PtrSize)))) n := uintptr(rootBlockBytes) if off+n > n0 { n = n0 - off @@ -372,7 +372,7 @@ func markrootSpans(gcw *gcWork, shard int) { scanobject(p, gcw) // The special itself is a root. - scanblock(uintptr(unsafe.Pointer(&spf.fn)), sys.PtrSize, &oneptrmask[0], gcw, nil) + scanblock(uintptr(unsafe.Pointer(&spf.fn)), goarch.PtrSize, &oneptrmask[0], gcw, nil) } unlock(&s.speciallock) } @@ -737,7 +737,7 @@ func scanstack(gp *g, gcw *gcWork) { // register that gets moved back and forth between the // register and sched.ctxt without a write barrier. if gp.sched.ctxt != nil { - scanblock(uintptr(unsafe.Pointer(&gp.sched.ctxt)), sys.PtrSize, &oneptrmask[0], gcw, &state) + scanblock(uintptr(unsafe.Pointer(&gp.sched.ctxt)), goarch.PtrSize, &oneptrmask[0], gcw, &state) } // Scan the stack. Accumulate a list of stack objects. @@ -755,18 +755,18 @@ func scanstack(gp *g, gcw *gcWork) { if d.fn != nil { // Scan the func value, which could be a stack allocated closure. // See issue 30453. - scanblock(uintptr(unsafe.Pointer(&d.fn)), sys.PtrSize, &oneptrmask[0], gcw, &state) + scanblock(uintptr(unsafe.Pointer(&d.fn)), goarch.PtrSize, &oneptrmask[0], gcw, &state) } if d.link != nil { // The link field of a stack-allocated defer record might point // to a heap-allocated defer record. Keep that heap record live. - scanblock(uintptr(unsafe.Pointer(&d.link)), sys.PtrSize, &oneptrmask[0], gcw, &state) + scanblock(uintptr(unsafe.Pointer(&d.link)), goarch.PtrSize, &oneptrmask[0], gcw, &state) } // Retain defers records themselves. // Defer records might not be reachable from the G through regular heap // tracing because the defer linked list might weave between the stack and the heap. if d.heap { - scanblock(uintptr(unsafe.Pointer(&d)), sys.PtrSize, &oneptrmask[0], gcw, &state) + scanblock(uintptr(unsafe.Pointer(&d)), goarch.PtrSize, &oneptrmask[0], gcw, &state) } } if gp._panic != nil { @@ -910,13 +910,13 @@ func scanframeworker(frame *stkframe, state *stackScanState, gcw *gcWork) { // Scan local variables if stack frame has been allocated. if locals.n > 0 { - size := uintptr(locals.n) * sys.PtrSize + size := uintptr(locals.n) * goarch.PtrSize scanblock(frame.varp-size, size, locals.bytedata, gcw, state) } // Scan arguments. if args.n > 0 { - scanblock(frame.argp, uintptr(args.n)*sys.PtrSize, args.bytedata, gcw, state) + scanblock(frame.argp, uintptr(args.n)*goarch.PtrSize, args.bytedata, gcw, state) } // Add all stack objects to the stack object list. @@ -1169,9 +1169,9 @@ func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork, stk *stackScanState) for i := uintptr(0); i < n; { // Find bits for the next word. - bits := uint32(*addb(ptrmask, i/(sys.PtrSize*8))) + bits := uint32(*addb(ptrmask, i/(goarch.PtrSize*8))) if bits == 0 { - i += sys.PtrSize * 8 + i += goarch.PtrSize * 8 continue } for j := 0; j < 8 && i < n; j++ { @@ -1187,7 +1187,7 @@ func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork, stk *stackScanState) } } bits >>= 1 - i += sys.PtrSize + i += goarch.PtrSize } } } @@ -1248,7 +1248,7 @@ func scanobject(b uintptr, gcw *gcWork) { } var i uintptr - for i = 0; i < n; i, hbits = i+sys.PtrSize, hbits.next() { + for i = 0; i < n; i, hbits = i+goarch.PtrSize, hbits.next() { // Load bits once. See CL 22712 and issue 16973 for discussion. bits := hbits.bits() if bits&bitScan == 0 { @@ -1297,7 +1297,7 @@ func scanConservative(b, n uintptr, ptrmask *uint8, gcw *gcWork, state *stackSca print("conservatively scanning [", hex(b), ",", hex(b+n), ")\n") hexdumpWords(b, b+n, func(p uintptr) byte { if ptrmask != nil { - word := (p - b) / sys.PtrSize + word := (p - b) / goarch.PtrSize bits := *addb(ptrmask, word/8) if (bits>>(word%8))&1 == 0 { return '$' @@ -1322,9 +1322,9 @@ func scanConservative(b, n uintptr, ptrmask *uint8, gcw *gcWork, state *stackSca printunlock() } - for i := uintptr(0); i < n; i += sys.PtrSize { + for i := uintptr(0); i < n; i += goarch.PtrSize { if ptrmask != nil { - word := i / sys.PtrSize + word := i / goarch.PtrSize bits := *addb(ptrmask, word/8) if bits == 0 { // Skip 8 words (the loop increment will do the 8th) @@ -1333,10 +1333,10 @@ func scanConservative(b, n uintptr, ptrmask *uint8, gcw *gcWork, state *stackSca // seen this word of ptrmask, so i // must be 8-word-aligned, but check // our reasoning just in case. - if i%(sys.PtrSize*8) != 0 { + if i%(goarch.PtrSize*8) != 0 { throw("misaligned mask") } - i += sys.PtrSize*8 - sys.PtrSize + i += goarch.PtrSize*8 - goarch.PtrSize continue } if (bits>>(word%8))&1 == 0 { @@ -1398,7 +1398,7 @@ func shade(b uintptr) { //go:nowritebarrierrec func greyobject(obj, base, off uintptr, span *mspan, gcw *gcWork, objIndex uintptr) { // obj should be start of allocation, and so must be at least pointer-aligned. - if obj&(sys.PtrSize-1) != 0 { + if obj&(goarch.PtrSize-1) != 0 { throw("greyobject: obj not pointer-aligned") } mbits := span.markBitsForIndex(objIndex) @@ -1470,13 +1470,13 @@ func gcDumpObject(label string, obj, off uintptr) { // We're printing something from a stack frame. We // don't know how big it is, so just show up to an // including off. - size = off + sys.PtrSize + size = off + goarch.PtrSize } - for i := uintptr(0); i < size; i += sys.PtrSize { + for i := uintptr(0); i < size; i += goarch.PtrSize { // For big objects, just print the beginning (because // that usually hints at the object's type) and the // fields around off. - if !(i < 128*sys.PtrSize || off-16*sys.PtrSize < i && i < off+16*sys.PtrSize) { + if !(i < 128*goarch.PtrSize || off-16*goarch.PtrSize < i && i < off+16*goarch.PtrSize) { skipped = true continue } diff --git a/src/runtime/mgcstack.go b/src/runtime/mgcstack.go index 92d58485f6f..49dc54e1652 100644 --- a/src/runtime/mgcstack.go +++ b/src/runtime/mgcstack.go @@ -95,7 +95,7 @@ package runtime import ( - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -107,7 +107,7 @@ const stackTraceDebug = false //go:notinheap type stackWorkBuf struct { stackWorkBufHdr - obj [(_WorkbufSize - unsafe.Sizeof(stackWorkBufHdr{})) / sys.PtrSize]uintptr + obj [(_WorkbufSize - unsafe.Sizeof(stackWorkBufHdr{})) / goarch.PtrSize]uintptr } // Header declaration must come after the buf declaration above, because of issue #14620. diff --git a/src/runtime/mgcwork.go b/src/runtime/mgcwork.go index 667c7afa971..9454ac46f31 100644 --- a/src/runtime/mgcwork.go +++ b/src/runtime/mgcwork.go @@ -6,7 +6,7 @@ package runtime import ( "runtime/internal/atomic" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -322,7 +322,7 @@ type workbufhdr struct { type workbuf struct { workbufhdr // account for the above fields - obj [(_WorkbufSize - unsafe.Sizeof(workbufhdr{})) / sys.PtrSize]uintptr + obj [(_WorkbufSize - unsafe.Sizeof(workbufhdr{})) / goarch.PtrSize]uintptr } // workbuf factory routines. These funcs are used to manage the diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go index 84c00ce8f85..87716a4b53e 100644 --- a/src/runtime/mheap.go +++ b/src/runtime/mheap.go @@ -11,7 +11,7 @@ package runtime import ( "internal/cpu" "runtime/internal/atomic" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -497,13 +497,13 @@ func recordspan(vh unsafe.Pointer, p unsafe.Pointer) { assertLockHeld(&h.lock) if len(h.allspans) >= cap(h.allspans) { - n := 64 * 1024 / sys.PtrSize + n := 64 * 1024 / goarch.PtrSize if n < cap(h.allspans)*3/2 { n = cap(h.allspans) * 3 / 2 } var new []*mspan sp := (*slice)(unsafe.Pointer(&new)) - sp.array = sysAlloc(uintptr(n)*sys.PtrSize, &memstats.other_sys) + sp.array = sysAlloc(uintptr(n)*goarch.PtrSize, &memstats.other_sys) if sp.array == nil { throw("runtime: cannot allocate memory") } @@ -1822,7 +1822,7 @@ func addfinalizer(p unsafe.Pointer, f *funcval, nret uintptr, fint *_type, ot *p scanobject(base, gcw) // Mark the finalizer itself, since the // special isn't part of the GC'd heap. - scanblock(uintptr(unsafe.Pointer(&s.fn)), sys.PtrSize, &oneptrmask[0], gcw, nil) + scanblock(uintptr(unsafe.Pointer(&s.fn)), goarch.PtrSize, &oneptrmask[0], gcw, nil) releasem(mp) } return true diff --git a/src/runtime/mranges.go b/src/runtime/mranges.go index 84a2c06dbb2..e0be1e134ed 100644 --- a/src/runtime/mranges.go +++ b/src/runtime/mranges.go @@ -10,7 +10,7 @@ package runtime import ( - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -167,7 +167,7 @@ func (a *addrRanges) init(sysStat *sysMemStat) { ranges := (*notInHeapSlice)(unsafe.Pointer(&a.ranges)) ranges.len = 0 ranges.cap = 16 - ranges.array = (*notInHeap)(persistentalloc(unsafe.Sizeof(addrRange{})*uintptr(ranges.cap), sys.PtrSize, sysStat)) + ranges.array = (*notInHeap)(persistentalloc(unsafe.Sizeof(addrRange{})*uintptr(ranges.cap), goarch.PtrSize, sysStat)) a.sysStat = sysStat a.totalBytes = 0 } @@ -294,7 +294,7 @@ func (a *addrRanges) add(r addrRange) { ranges := (*notInHeapSlice)(unsafe.Pointer(&a.ranges)) ranges.len = len(oldRanges) + 1 ranges.cap = cap(oldRanges) * 2 - ranges.array = (*notInHeap)(persistentalloc(unsafe.Sizeof(addrRange{})*uintptr(ranges.cap), sys.PtrSize, a.sysStat)) + ranges.array = (*notInHeap)(persistentalloc(unsafe.Sizeof(addrRange{})*uintptr(ranges.cap), goarch.PtrSize, a.sysStat)) // Copy in the old array, but make space for the new range. copy(a.ranges[:i], oldRanges[:i]) @@ -364,7 +364,7 @@ func (a *addrRanges) cloneInto(b *addrRanges) { ranges := (*notInHeapSlice)(unsafe.Pointer(&b.ranges)) ranges.len = 0 ranges.cap = cap(a.ranges) - ranges.array = (*notInHeap)(persistentalloc(unsafe.Sizeof(addrRange{})*uintptr(ranges.cap), sys.PtrSize, b.sysStat)) + ranges.array = (*notInHeap)(persistentalloc(unsafe.Sizeof(addrRange{})*uintptr(ranges.cap), goarch.PtrSize, b.sysStat)) } b.ranges = b.ranges[:len(a.ranges)] b.totalBytes = a.totalBytes diff --git a/src/runtime/mspanset.go b/src/runtime/mspanset.go index 10d2596c38c..9b0fb99c4cc 100644 --- a/src/runtime/mspanset.go +++ b/src/runtime/mspanset.go @@ -7,7 +7,7 @@ package runtime import ( "internal/cpu" "runtime/internal/atomic" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -82,7 +82,7 @@ func (b *spanSet) push(s *mspan) { retry: if top < spineLen { spine := atomic.Loadp(unsafe.Pointer(&b.spine)) - blockp := add(spine, sys.PtrSize*top) + blockp := add(spine, goarch.PtrSize*top) block = (*spanSetBlock)(atomic.Loadp(blockp)) } else { // Add a new block to the spine, potentially growing @@ -102,11 +102,11 @@ retry: if newCap == 0 { newCap = spanSetInitSpineCap } - newSpine := persistentalloc(newCap*sys.PtrSize, cpu.CacheLineSize, &memstats.gcMiscSys) + newSpine := persistentalloc(newCap*goarch.PtrSize, cpu.CacheLineSize, &memstats.gcMiscSys) if b.spineCap != 0 { // Blocks are allocated off-heap, so // no write barriers. - memmove(newSpine, b.spine, b.spineCap*sys.PtrSize) + memmove(newSpine, b.spine, b.spineCap*goarch.PtrSize) } // Spine is allocated off-heap, so no write barrier. atomic.StorepNoWB(unsafe.Pointer(&b.spine), newSpine) @@ -124,7 +124,7 @@ retry: block = spanSetBlockPool.alloc() // Add it to the spine. - blockp := add(b.spine, sys.PtrSize*top) + blockp := add(b.spine, goarch.PtrSize*top) // Blocks are allocated off-heap, so no write barrier. atomic.StorepNoWB(blockp, unsafe.Pointer(block)) atomic.Storeuintptr(&b.spineLen, spineLen+1) @@ -181,7 +181,7 @@ claimLoop: // grows monotonically and we've already verified it, we'll definitely // be reading from a valid block. spine := atomic.Loadp(unsafe.Pointer(&b.spine)) - blockp := add(spine, sys.PtrSize*uintptr(top)) + blockp := add(spine, goarch.PtrSize*uintptr(top)) // Given that the spine length is correct, we know we will never // see a nil block here, since the length is always updated after @@ -241,7 +241,7 @@ func (b *spanSet) reset() { // since it may be pushed into again. In order to avoid leaking // memory since we're going to reset the head and tail, clean // up such a block now, if it exists. - blockp := (**spanSetBlock)(add(b.spine, sys.PtrSize*uintptr(top))) + blockp := (**spanSetBlock)(add(b.spine, goarch.PtrSize*uintptr(top))) block := *blockp if block != nil { // Sanity check the popped value. diff --git a/src/runtime/mstats.go b/src/runtime/mstats.go index eeb2a7b4bc7..3ac88438bcb 100644 --- a/src/runtime/mstats.go +++ b/src/runtime/mstats.go @@ -8,7 +8,7 @@ package runtime import ( "runtime/internal/atomic" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -713,7 +713,7 @@ type heapStatsDelta struct { // Add a uint32 to ensure this struct is a multiple of 8 bytes in size. // Only necessary on 32-bit platforms. - _ [(sys.PtrSize / 4) % 2]uint32 + _ [(goarch.PtrSize / 4) % 2]uint32 } // merge adds in the deltas from b into a. diff --git a/src/runtime/mwbbuf.go b/src/runtime/mwbbuf.go index 6efc00007d5..7862dfbd9ea 100644 --- a/src/runtime/mwbbuf.go +++ b/src/runtime/mwbbuf.go @@ -24,7 +24,7 @@ package runtime import ( "runtime/internal/atomic" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -145,7 +145,7 @@ func (b *wbBuf) putFast(old, new uintptr) bool { p := (*[2]uintptr)(unsafe.Pointer(b.next)) p[0] = old p[1] = new - b.next += 2 * sys.PtrSize + b.next += 2 * goarch.PtrSize return b.next != b.end } diff --git a/src/runtime/os3_plan9.go b/src/runtime/os3_plan9.go index ce8bc7f1034..a06d74e279f 100644 --- a/src/runtime/os3_plan9.go +++ b/src/runtime/os3_plan9.go @@ -6,7 +6,7 @@ package runtime import ( "internal/abi" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -93,7 +93,7 @@ func sighandler(_ureg *ureg, note *byte, gp *g) int { if usesLR { c.setlr(pc) } else { - sp -= sys.PtrSize + sp -= goarch.PtrSize *(*uintptr)(unsafe.Pointer(sp)) = pc c.setsp(sp) } diff --git a/src/runtime/os3_solaris.go b/src/runtime/os3_solaris.go index bfd7c7eb641..84194a3050d 100644 --- a/src/runtime/os3_solaris.go +++ b/src/runtime/os3_solaris.go @@ -6,7 +6,7 @@ package runtime import ( "internal/abi" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -600,7 +600,7 @@ func sysargs(argc int32, argv **byte) { n++ // now argv+n is auxv - auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*sys.PtrSize)) + auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*goarch.PtrSize)) sysauxv(auxv[:]) } diff --git a/src/runtime/os_dragonfly.go b/src/runtime/os_dragonfly.go index 0c81ed4d7c3..191a560667c 100644 --- a/src/runtime/os_dragonfly.go +++ b/src/runtime/os_dragonfly.go @@ -6,7 +6,7 @@ package runtime import ( "internal/abi" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -279,7 +279,7 @@ func sysargs(argc int32, argv **byte) { // skip NULL separator n++ - auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*sys.PtrSize)) + auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*goarch.PtrSize)) sysauxv(auxv[:]) } diff --git a/src/runtime/os_freebsd.go b/src/runtime/os_freebsd.go index 151a5fd91ab..5a8121a420f 100644 --- a/src/runtime/os_freebsd.go +++ b/src/runtime/os_freebsd.go @@ -6,7 +6,7 @@ package runtime import ( "internal/abi" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -117,8 +117,8 @@ func getncpu() int32 { } maskSize := int(maxcpus+7) / 8 - if maskSize < sys.PtrSize { - maskSize = sys.PtrSize + if maskSize < goarch.PtrSize { + maskSize = goarch.PtrSize } if maskSize > len(mask) { maskSize = len(mask) @@ -392,7 +392,7 @@ func sysargs(argc int32, argv **byte) { n++ // now argv+n is auxv - auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*sys.PtrSize)) + auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*goarch.PtrSize)) sysauxv(auxv[:]) } diff --git a/src/runtime/os_linux.go b/src/runtime/os_linux.go index 1984bf68445..88c16f71639 100644 --- a/src/runtime/os_linux.go +++ b/src/runtime/os_linux.go @@ -6,7 +6,7 @@ package runtime import ( "internal/abi" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -206,7 +206,7 @@ func sysargs(argc int32, argv **byte) { n++ // now argv+n is auxv - auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*sys.PtrSize)) + auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*goarch.PtrSize)) if sysauxv(auxv[:]) != 0 { return } diff --git a/src/runtime/os_netbsd.go b/src/runtime/os_netbsd.go index 151cd17bbe8..bd936d3735f 100644 --- a/src/runtime/os_netbsd.go +++ b/src/runtime/os_netbsd.go @@ -7,7 +7,7 @@ package runtime import ( "internal/abi" "runtime/internal/atomic" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -372,7 +372,7 @@ func sysargs(argc int32, argv **byte) { n++ // now argv+n is auxv - auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*sys.PtrSize)) + auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*goarch.PtrSize)) sysauxv(auxv[:]) } diff --git a/src/runtime/os_openbsd_syscall.go b/src/runtime/os_openbsd_syscall.go index a04eb4fc4dd..1ddee1864e4 100644 --- a/src/runtime/os_openbsd_syscall.go +++ b/src/runtime/os_openbsd_syscall.go @@ -9,7 +9,7 @@ package runtime import ( "internal/abi" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -29,7 +29,7 @@ func newosproc(mp *m) { param := tforkt{ tf_tcb: unsafe.Pointer(&mp.tls[0]), tf_tid: nil, // minit will record tid - tf_stack: uintptr(stk) - sys.PtrSize, + tf_stack: uintptr(stk) - goarch.PtrSize, } var oset sigset diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go index d82173e738a..1cca0876a91 100644 --- a/src/runtime/os_windows.go +++ b/src/runtime/os_windows.go @@ -7,7 +7,7 @@ package runtime import ( "internal/abi" "runtime/internal/atomic" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -1393,7 +1393,7 @@ func preemptM(mp *m) { case "386", "amd64": // Make it look like the thread called targetPC. sp := c.sp() - sp -= sys.PtrSize + sp -= goarch.PtrSize *(*uintptr)(unsafe.Pointer(sp)) = newpc c.set_sp(sp) c.set_ip(targetPC) diff --git a/src/runtime/preempt.go b/src/runtime/preempt.go index d6cdf1b8f83..cfec196a09e 100644 --- a/src/runtime/preempt.go +++ b/src/runtime/preempt.go @@ -55,7 +55,7 @@ package runtime import ( "internal/abi" "runtime/internal/atomic" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -321,7 +321,7 @@ func init() { f = findfunc(abi.FuncPCABIInternal(asyncPreempt2)) total += funcMaxSPDelta(f) // Add some overhead for return PCs, etc. - asyncPreemptStack = uintptr(total) + 8*sys.PtrSize + asyncPreemptStack = uintptr(total) + 8*goarch.PtrSize if asyncPreemptStack > _StackLimit { // We need more than the nosplit limit. This isn't // unsafe, but it may limit asynchronous preemption. diff --git a/src/runtime/print.go b/src/runtime/print.go index f15296cf024..fe32fbb08e6 100644 --- a/src/runtime/print.go +++ b/src/runtime/print.go @@ -6,7 +6,7 @@ package runtime import ( "runtime/internal/atomic" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -271,7 +271,7 @@ func hexdumpWords(p, end uintptr, mark func(uintptr) byte) { var markbuf [1]byte markbuf[0] = ' ' minhexdigits = int(unsafe.Sizeof(uintptr(0)) * 2) - for i := uintptr(0); p+i < end; i += sys.PtrSize { + for i := uintptr(0); p+i < end; i += goarch.PtrSize { if i%16 == 0 { if i != 0 { println() diff --git a/src/runtime/proc.go b/src/runtime/proc.go index e4268b71090..3b1e0673710 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -9,6 +9,7 @@ import ( "internal/cpu" "runtime/internal/atomic" "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -151,7 +152,7 @@ func main() { // Max stack size is 1 GB on 64-bit, 250 MB on 32-bit. // Using decimal instead of binary GB and MB because // they look nicer in the stack overflow failure message. - if sys.PtrSize == 8 { + if goarch.PtrSize == 8 { maxstacksize = 1000000000 } else { maxstacksize = 250000000 @@ -555,7 +556,7 @@ func atomicAllG() (**g, uintptr) { // atomicAllGIndex returns ptr[i] with the allgptr returned from atomicAllG. func atomicAllGIndex(ptr **g, i uintptr) *g { - return *(**g)(add(unsafe.Pointer(ptr), i*sys.PtrSize)) + return *(**g)(add(unsafe.Pointer(ptr), i*goarch.PtrSize)) } // forEachG calls fn on every G from allgs. @@ -2012,7 +2013,7 @@ func oneNewExtraM() { gp := malg(4096) gp.sched.pc = abi.FuncPCABI0(goexit) + sys.PCQuantum gp.sched.sp = gp.stack.hi - gp.sched.sp -= 4 * sys.PtrSize // extra space in case of reads slightly beyond frame + gp.sched.sp -= 4 * goarch.PtrSize // extra space in case of reads slightly beyond frame gp.sched.lr = 0 gp.sched.g = guintptr(unsafe.Pointer(gp)) gp.syscallpc = gp.sched.pc @@ -4262,7 +4263,7 @@ func newproc1(fn *funcval, callergp *g, callerpc uintptr) *g { throw("newproc1: new g is not Gdead") } - totalSize := uintptr(4*sys.PtrSize + sys.MinFrameSize) // extra space in case of reads slightly beyond frame + totalSize := uintptr(4*goarch.PtrSize + sys.MinFrameSize) // extra space in case of reads slightly beyond frame totalSize = alignUp(totalSize, sys.StackAlign) sp := newg.stack.hi - totalSize spArg := sp @@ -6390,7 +6391,7 @@ func doInit(t *initTask) { t.state = 1 // initialization in progress for i := uintptr(0); i < t.ndeps; i++ { - p := add(unsafe.Pointer(t), (3+i)*sys.PtrSize) + p := add(unsafe.Pointer(t), (3+i)*goarch.PtrSize) t2 := *(**initTask)(p) doInit(t2) } @@ -6411,9 +6412,9 @@ func doInit(t *initTask) { before = inittrace } - firstFunc := add(unsafe.Pointer(t), (3+t.ndeps)*sys.PtrSize) + firstFunc := add(unsafe.Pointer(t), (3+t.ndeps)*goarch.PtrSize) for i := uintptr(0); i < t.nfns; i++ { - p := add(firstFunc, i*sys.PtrSize) + p := add(firstFunc, i*goarch.PtrSize) f := *(*func())(unsafe.Pointer(&p)) f() } diff --git a/src/runtime/runtime1.go b/src/runtime/runtime1.go index b238da8f514..eda6aaa401f 100644 --- a/src/runtime/runtime1.go +++ b/src/runtime/runtime1.go @@ -7,7 +7,7 @@ package runtime import ( "internal/bytealg" "runtime/internal/atomic" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -55,7 +55,7 @@ var ( // nosplit for use in linux startup sysargs //go:nosplit func argv_index(argv **byte, i int32) *byte { - return *(**byte)(add(unsafe.Pointer(argv), uintptr(i)*sys.PtrSize)) + return *(**byte)(add(unsafe.Pointer(argv), uintptr(i)*goarch.PtrSize)) } func args(c int32, v **byte) { @@ -190,10 +190,10 @@ func check() { if unsafe.Sizeof(j) != 8 { throw("bad j") } - if unsafe.Sizeof(k) != sys.PtrSize { + if unsafe.Sizeof(k) != goarch.PtrSize { throw("bad k") } - if unsafe.Sizeof(l) != sys.PtrSize { + if unsafe.Sizeof(l) != goarch.PtrSize { throw("bad l") } if unsafe.Sizeof(x1) != 1 { diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index f13c649a090..e2f0d5910f5 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -6,7 +6,7 @@ package runtime import ( "runtime/internal/atomic" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -505,7 +505,7 @@ const ( // tlsSlots is the number of pointer-sized slots reserved for TLS on some platforms, // like Windows. tlsSlots = 6 - tlsSize = tlsSlots * sys.PtrSize + tlsSize = tlsSlots * goarch.PtrSize ) type m struct { @@ -930,7 +930,7 @@ func extendRandom(r []byte, n int) { w = 16 } h := memhash(unsafe.Pointer(&r[n-w]), uintptr(nanotime()), uintptr(w)) - for i := 0; i < sys.PtrSize && n < len(r); i++ { + for i := 0; i < goarch.PtrSize && n < len(r); i++ { r[n] = byte(h) n++ h >>= 8 diff --git a/src/runtime/signal_386.go b/src/runtime/signal_386.go index c77a9cc5224..69a59e6dcff 100644 --- a/src/runtime/signal_386.go +++ b/src/runtime/signal_386.go @@ -9,7 +9,7 @@ package runtime import ( "internal/abi" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -53,7 +53,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { func (c *sigctxt) pushCall(targetPC, resumePC uintptr) { // Make it look like we called target at resumePC. sp := uintptr(c.esp()) - sp -= sys.PtrSize + sp -= goarch.PtrSize *(*uintptr)(unsafe.Pointer(sp)) = resumePC c.set_esp(uint32(sp)) c.set_eip(uint32(targetPC)) diff --git a/src/runtime/signal_aix_ppc64.go b/src/runtime/signal_aix_ppc64.go index a0becd431eb..5999d9dc3d0 100644 --- a/src/runtime/signal_aix_ppc64.go +++ b/src/runtime/signal_aix_ppc64.go @@ -8,7 +8,7 @@ package runtime import ( - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -82,5 +82,5 @@ func (c *sigctxt) set_link(x uint64) { c.regs().lr = x } func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) } func (c *sigctxt) set_sigaddr(x uint64) { - *(*uintptr)(add(unsafe.Pointer(c.info), 2*sys.PtrSize)) = uintptr(x) + *(*uintptr)(add(unsafe.Pointer(c.info), 2*goarch.PtrSize)) = uintptr(x) } diff --git a/src/runtime/signal_amd64.go b/src/runtime/signal_amd64.go index afcf4404fba..20490cffbf5 100644 --- a/src/runtime/signal_amd64.go +++ b/src/runtime/signal_amd64.go @@ -10,7 +10,7 @@ package runtime import ( "internal/abi" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -81,7 +81,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { func (c *sigctxt) pushCall(targetPC, resumePC uintptr) { // Make it look like we called target at resumePC. sp := uintptr(c.rsp()) - sp -= sys.PtrSize + sp -= goarch.PtrSize *(*uintptr)(unsafe.Pointer(sp)) = resumePC c.set_rsp(uint64(sp)) c.set_rip(uint64(targetPC)) diff --git a/src/runtime/signal_linux_386.go b/src/runtime/signal_linux_386.go index 13d9df40710..321518c18e3 100644 --- a/src/runtime/signal_linux_386.go +++ b/src/runtime/signal_linux_386.go @@ -5,7 +5,7 @@ package runtime import ( - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -42,5 +42,5 @@ func (c *sigctxt) set_eip(x uint32) { c.regs().eip = x } func (c *sigctxt) set_esp(x uint32) { c.regs().esp = x } func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) } func (c *sigctxt) set_sigaddr(x uint32) { - *(*uintptr)(add(unsafe.Pointer(c.info), 2*sys.PtrSize)) = uintptr(x) + *(*uintptr)(add(unsafe.Pointer(c.info), 2*goarch.PtrSize)) = uintptr(x) } diff --git a/src/runtime/signal_linux_amd64.go b/src/runtime/signal_linux_amd64.go index 210e8967e5d..573b1183974 100644 --- a/src/runtime/signal_linux_amd64.go +++ b/src/runtime/signal_linux_amd64.go @@ -5,7 +5,7 @@ package runtime import ( - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -52,5 +52,5 @@ func (c *sigctxt) set_rip(x uint64) { c.regs().rip = x } func (c *sigctxt) set_rsp(x uint64) { c.regs().rsp = x } func (c *sigctxt) set_sigcode(x uint64) { c.info.si_code = int32(x) } func (c *sigctxt) set_sigaddr(x uint64) { - *(*uintptr)(add(unsafe.Pointer(c.info), 2*sys.PtrSize)) = uintptr(x) + *(*uintptr)(add(unsafe.Pointer(c.info), 2*goarch.PtrSize)) = uintptr(x) } diff --git a/src/runtime/signal_linux_arm.go b/src/runtime/signal_linux_arm.go index 876b5059173..eb107d68d1b 100644 --- a/src/runtime/signal_linux_arm.go +++ b/src/runtime/signal_linux_arm.go @@ -5,7 +5,7 @@ package runtime import ( - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -54,5 +54,5 @@ func (c *sigctxt) set_r10(x uint32) { c.regs().r10 = x } func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) } func (c *sigctxt) set_sigaddr(x uint32) { - *(*uintptr)(add(unsafe.Pointer(c.info), 2*sys.PtrSize)) = uintptr(x) + *(*uintptr)(add(unsafe.Pointer(c.info), 2*goarch.PtrSize)) = uintptr(x) } diff --git a/src/runtime/signal_linux_arm64.go b/src/runtime/signal_linux_arm64.go index 2075f253d7d..4ccc0307923 100644 --- a/src/runtime/signal_linux_arm64.go +++ b/src/runtime/signal_linux_arm64.go @@ -5,7 +5,7 @@ package runtime import ( - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -67,5 +67,5 @@ func (c *sigctxt) set_lr(x uint64) { c.regs().regs[30] = x } func (c *sigctxt) set_r28(x uint64) { c.regs().regs[28] = x } func (c *sigctxt) set_sigaddr(x uint64) { - *(*uintptr)(add(unsafe.Pointer(c.info), 2*sys.PtrSize)) = uintptr(x) + *(*uintptr)(add(unsafe.Pointer(c.info), 2*goarch.PtrSize)) = uintptr(x) } diff --git a/src/runtime/signal_linux_mips64x.go b/src/runtime/signal_linux_mips64x.go index f0a75ac3ea5..e62d6a93fd2 100644 --- a/src/runtime/signal_linux_mips64x.go +++ b/src/runtime/signal_linux_mips64x.go @@ -9,7 +9,7 @@ package runtime import ( - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -75,5 +75,5 @@ func (c *sigctxt) set_link(x uint64) { c.regs().sc_regs[31] = x } func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) } func (c *sigctxt) set_sigaddr(x uint64) { - *(*uintptr)(add(unsafe.Pointer(c.info), 2*sys.PtrSize)) = uintptr(x) + *(*uintptr)(add(unsafe.Pointer(c.info), 2*goarch.PtrSize)) = uintptr(x) } diff --git a/src/runtime/signal_linux_ppc64x.go b/src/runtime/signal_linux_ppc64x.go index d9d3e55ec20..d2eeb39eadd 100644 --- a/src/runtime/signal_linux_ppc64x.go +++ b/src/runtime/signal_linux_ppc64x.go @@ -9,7 +9,7 @@ package runtime import ( - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -79,5 +79,5 @@ func (c *sigctxt) set_link(x uint64) { c.regs().link = x } func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) } func (c *sigctxt) set_sigaddr(x uint64) { - *(*uintptr)(add(unsafe.Pointer(c.info), 2*sys.PtrSize)) = uintptr(x) + *(*uintptr)(add(unsafe.Pointer(c.info), 2*goarch.PtrSize)) = uintptr(x) } diff --git a/src/runtime/signal_linux_riscv64.go b/src/runtime/signal_linux_riscv64.go index 9f68e5c548f..b26450dbfac 100644 --- a/src/runtime/signal_linux_riscv64.go +++ b/src/runtime/signal_linux_riscv64.go @@ -5,7 +5,7 @@ package runtime import ( - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -64,5 +64,5 @@ func (c *sigctxt) set_gp(x uint64) { c.regs().sc_regs.gp = x } func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) } func (c *sigctxt) set_sigaddr(x uint64) { - *(*uintptr)(add(unsafe.Pointer(c.info), 2*sys.PtrSize)) = uintptr(x) + *(*uintptr)(add(unsafe.Pointer(c.info), 2*goarch.PtrSize)) = uintptr(x) } diff --git a/src/runtime/signal_linux_s390x.go b/src/runtime/signal_linux_s390x.go index 03c58cbbb68..bba8169ded6 100644 --- a/src/runtime/signal_linux_s390x.go +++ b/src/runtime/signal_linux_s390x.go @@ -7,6 +7,7 @@ package runtime import ( "internal/abi" "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -54,7 +55,7 @@ func (c *sigctxt) set_sp(x uint64) { c.regs().gregs[15] = x } func (c *sigctxt) set_pc(x uint64) { c.regs().psw_addr = x } func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) } func (c *sigctxt) set_sigaddr(x uint64) { - *(*uintptr)(add(unsafe.Pointer(c.info), 2*sys.PtrSize)) = uintptr(x) + *(*uintptr)(add(unsafe.Pointer(c.info), 2*goarch.PtrSize)) = uintptr(x) } func dumpregs(c *sigctxt) { diff --git a/src/runtime/signal_mips64x.go b/src/runtime/signal_mips64x.go index eebcc748864..87dfa724c47 100644 --- a/src/runtime/signal_mips64x.go +++ b/src/runtime/signal_mips64x.go @@ -10,7 +10,7 @@ package runtime import ( "internal/abi" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -69,7 +69,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { // functions are correctly handled. This smashes // the stack frame but we're not going back there // anyway. - sp := c.sp() - sys.PtrSize + sp := c.sp() - goarch.PtrSize c.set_sp(sp) *(*uint64)(unsafe.Pointer(uintptr(sp))) = c.link() diff --git a/src/runtime/signal_riscv64.go b/src/runtime/signal_riscv64.go index aaaa217051b..8a24e4e36a9 100644 --- a/src/runtime/signal_riscv64.go +++ b/src/runtime/signal_riscv64.go @@ -9,7 +9,7 @@ package runtime import ( "internal/abi" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -64,7 +64,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { // functions are correctly handled. This smashes // the stack frame but we're not going back there // anyway. - sp := c.sp() - sys.PtrSize + sp := c.sp() - goarch.PtrSize c.set_sp(sp) *(*uint64)(unsafe.Pointer(uintptr(sp))) = c.ra() @@ -85,7 +85,7 @@ func (c *sigctxt) pushCall(targetPC, resumePC uintptr) { // push the call. The function being pushed is responsible // for restoring the LR and setting the SP back. // This extra slot is known to gentraceback. - sp := c.sp() - sys.PtrSize + sp := c.sp() - goarch.PtrSize c.set_sp(sp) *(*uint64)(unsafe.Pointer(uintptr(sp))) = c.ra() // Set up PC and LR to pretend the function being signaled diff --git a/src/runtime/slice.go b/src/runtime/slice.go index 7a470f09b6c..ff59fa6278d 100644 --- a/src/runtime/slice.go +++ b/src/runtime/slice.go @@ -8,6 +8,7 @@ import ( "internal/abi" "runtime/internal/math" "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -195,15 +196,15 @@ func growslice(et *_type, old slice, cap int) slice { capmem = roundupsize(uintptr(newcap)) overflow = uintptr(newcap) > maxAlloc newcap = int(capmem) - case et.size == sys.PtrSize: - lenmem = uintptr(old.len) * sys.PtrSize - newlenmem = uintptr(cap) * sys.PtrSize - capmem = roundupsize(uintptr(newcap) * sys.PtrSize) - overflow = uintptr(newcap) > maxAlloc/sys.PtrSize - newcap = int(capmem / sys.PtrSize) + case et.size == goarch.PtrSize: + lenmem = uintptr(old.len) * goarch.PtrSize + newlenmem = uintptr(cap) * goarch.PtrSize + capmem = roundupsize(uintptr(newcap) * goarch.PtrSize) + overflow = uintptr(newcap) > maxAlloc/goarch.PtrSize + newcap = int(capmem / goarch.PtrSize) case isPowerOfTwo(et.size): var shift uintptr - if sys.PtrSize == 8 { + if goarch.PtrSize == 8 { // Mask shift for better code generation. shift = uintptr(sys.Ctz64(uint64(et.size))) & 63 } else { diff --git a/src/runtime/stack.go b/src/runtime/stack.go index b5545ac796d..c37e8e76eba 100644 --- a/src/runtime/stack.go +++ b/src/runtime/stack.go @@ -9,6 +9,7 @@ import ( "internal/cpu" "runtime/internal/atomic" "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -67,7 +68,7 @@ const ( // to each stack below the usual guard area for OS-specific // purposes like signal handling. Used on Windows, Plan 9, // and iOS because they do not use a separate stack. - _StackSystem = sys.GoosWindows*512*sys.PtrSize + sys.GoosPlan9*512 + sys.GoosIos*sys.GoarchArm64*1024 + _StackSystem = sys.GoosWindows*512*goarch.PtrSize + sys.GoosPlan9*512 + sys.GoosIos*sys.GoarchArm64*1024 // The minimum size of stack used by Go code _StackMin = 2048 @@ -125,7 +126,7 @@ const ( ) const ( - uintptrMask = 1<<(8*sys.PtrSize) - 1 + uintptrMask = 1<<(8*goarch.PtrSize) - 1 // The values below can be stored to g.stackguard0 to force // the next stack check to fail. @@ -599,14 +600,14 @@ func adjustpointers(scanp unsafe.Pointer, bv *bitvector, adjinfo *adjustinfo, f for i := uintptr(0); i < num; i += 8 { if stackDebug >= 4 { for j := uintptr(0); j < 8; j++ { - print(" ", add(scanp, (i+j)*sys.PtrSize), ":", ptrnames[bv.ptrbit(i+j)], ":", hex(*(*uintptr)(add(scanp, (i+j)*sys.PtrSize))), " # ", i, " ", *addb(bv.bytedata, i/8), "\n") + print(" ", add(scanp, (i+j)*goarch.PtrSize), ":", ptrnames[bv.ptrbit(i+j)], ":", hex(*(*uintptr)(add(scanp, (i+j)*goarch.PtrSize))), " # ", i, " ", *addb(bv.bytedata, i/8), "\n") } } b := *(addb(bv.bytedata, i/8)) for b != 0 { j := uintptr(sys.Ctz8(b)) b &= b - 1 - pp := (*uintptr)(add(scanp, (i+j)*sys.PtrSize)) + pp := (*uintptr)(add(scanp, (i+j)*goarch.PtrSize)) retry: p := *pp if f.valid() && 0 < p && p < minLegalPointer && debug.invalidptr != 0 { @@ -655,13 +656,13 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool { // Adjust local variables if stack frame has been allocated. if locals.n > 0 { - size := uintptr(locals.n) * sys.PtrSize + size := uintptr(locals.n) * goarch.PtrSize adjustpointers(unsafe.Pointer(frame.varp-size), &locals, adjinfo, f) } // Adjust saved base pointer if there is one. // TODO what about arm64 frame pointer adjustment? - if sys.ArchFamily == sys.AMD64 && frame.argp-frame.varp == 2*sys.PtrSize { + if sys.ArchFamily == sys.AMD64 && frame.argp-frame.varp == 2*goarch.PtrSize { if stackDebug >= 3 { print(" saved bp\n") } @@ -710,8 +711,8 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool { s = materializeGCProg(ptrdata, gcdata) gcdata = (*byte)(unsafe.Pointer(s.startAddr)) } - for i := uintptr(0); i < ptrdata; i += sys.PtrSize { - if *addb(gcdata, i/(8*sys.PtrSize))>>(i/sys.PtrSize&7)&1 != 0 { + for i := uintptr(0); i < ptrdata; i += goarch.PtrSize { + if *addb(gcdata, i/(8*goarch.PtrSize))>>(i/goarch.PtrSize&7)&1 != 0 { adjustpointer(adjinfo, unsafe.Pointer(p+i)) } } @@ -1014,7 +1015,7 @@ func newstack() { sp := gp.sched.sp if sys.ArchFamily == sys.AMD64 || sys.ArchFamily == sys.I386 || sys.ArchFamily == sys.WASM { // The call to morestack cost a word. - sp -= sys.PtrSize + sp -= goarch.PtrSize } if stackDebug >= 1 || sp < gp.stack.lo { print("runtime: newstack sp=", hex(sp), " stack=[", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n", @@ -1291,7 +1292,7 @@ func getStackMap(frame *stkframe, cache *pcvalueCache, debug bool) (locals, args // In this case, arglen specifies how much of the args section is actually live. // (It could be either all the args + results, or just the args.) args = *frame.argmap - n := int32(frame.arglen / sys.PtrSize) + n := int32(frame.arglen / goarch.PtrSize) if n < args.n { args.n = n // Don't use more of the arguments than arglen. } @@ -1323,7 +1324,7 @@ func getStackMap(frame *stkframe, cache *pcvalueCache, debug bool) (locals, args p := funcdata(f, _FUNCDATA_StackObjects) if p != nil { n := *(*uintptr)(p) - p = add(p, sys.PtrSize) + p = add(p, goarch.PtrSize) *(*slice)(unsafe.Pointer(&objs)) = slice{array: noescape(p), len: int(n), cap: int(n)} // Note: the noescape above is needed to keep // getStackMap from "leaking param content: diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index 6b535dfcbfc..36e0bfa9c43 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -7,6 +7,7 @@ package runtime import ( "runtime/internal/atomic" "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -561,7 +562,7 @@ const debugPcln = false func moduledataverify1(datap *moduledata) { // Check that the pclntab's format is valid. hdr := datap.pcHeader - if hdr.magic != 0xfffffffa || hdr.pad1 != 0 || hdr.pad2 != 0 || hdr.minLC != sys.PCQuantum || hdr.ptrSize != sys.PtrSize { + if hdr.magic != 0xfffffffa || hdr.pad1 != 0 || hdr.pad2 != 0 || hdr.minLC != sys.PCQuantum || hdr.ptrSize != goarch.PtrSize { print("runtime: function symbol table header:", hex(hdr.magic), hex(hdr.pad1), hex(hdr.pad2), hex(hdr.minLC), hex(hdr.ptrSize)) if datap.pluginpath != "" { print(", plugin:", datap.pluginpath) @@ -779,7 +780,7 @@ type pcvalueCacheEnt struct { // For now, align to sys.PtrSize and reduce mod the number of entries. // In practice, this appears to be fairly randomly and evenly distributed. func pcvalueCacheKey(targetpc uintptr) uintptr { - return (targetpc / sys.PtrSize) % uintptr(len(pcvalueCache{}.entries)) + return (targetpc / goarch.PtrSize) % uintptr(len(pcvalueCache{}.entries)) } // Returns the PCData value, and the PC where this value starts. @@ -948,7 +949,7 @@ func funcline(f funcInfo, targetpc uintptr) (file string, line int32) { func funcspdelta(f funcInfo, targetpc uintptr, cache *pcvalueCache) int32 { x, _ := pcvalue(f, f.pcsp, targetpc, cache, true) - if x&(sys.PtrSize-1) != 0 { + if x&(goarch.PtrSize-1) != 0 { print("invalid spdelta ", funcname(f), " ", hex(f.entry), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n") } return x @@ -1007,13 +1008,13 @@ func funcdata(f funcInfo, i uint8) unsafe.Pointer { return nil } p := add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(f.npcdata)*4) - if sys.PtrSize == 8 && uintptr(p)&4 != 0 { + if goarch.PtrSize == 8 && uintptr(p)&4 != 0 { if uintptr(unsafe.Pointer(f._func))&4 != 0 { println("runtime: misaligned func", f._func) } p = add(p, 4) } - return *(*unsafe.Pointer)(add(p, uintptr(i)*sys.PtrSize)) + return *(*unsafe.Pointer)(add(p, uintptr(i)*goarch.PtrSize)) } // step advances to the next pc, value pair in the encoded table. diff --git a/src/runtime/sys_darwin_arm64.go b/src/runtime/sys_darwin_arm64.go index 7dabaca08d2..e6d4c1be484 100644 --- a/src/runtime/sys_darwin_arm64.go +++ b/src/runtime/sys_darwin_arm64.go @@ -6,7 +6,7 @@ package runtime import ( "internal/abi" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -54,7 +54,7 @@ func tlsinit(tlsg *uintptr, tlsbase *[_PTHREAD_KEYS_MAX]uintptr) { for i, x := range tlsbase { if x == magic { - *tlsg = uintptr(i * sys.PtrSize) + *tlsg = uintptr(i * goarch.PtrSize) g0_pthread_setspecific(k, 0) return } diff --git a/src/runtime/sys_wasm.go b/src/runtime/sys_wasm.go index 057ed4ccd90..1bf80289f28 100644 --- a/src/runtime/sys_wasm.go +++ b/src/runtime/sys_wasm.go @@ -6,6 +6,7 @@ package runtime import ( "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -30,7 +31,7 @@ func wasmExit(code int32) // and then stopped before the first instruction in fn. func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) { sp := buf.sp - sp -= sys.PtrSize + sp -= goarch.PtrSize *(*uintptr)(unsafe.Pointer(sp)) = buf.pc buf.sp = sp buf.pc = uintptr(fn) diff --git a/src/runtime/sys_x86.go b/src/runtime/sys_x86.go index 0866e3140e0..856c73a2f6c 100644 --- a/src/runtime/sys_x86.go +++ b/src/runtime/sys_x86.go @@ -8,7 +8,7 @@ package runtime import ( - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -16,7 +16,7 @@ import ( // and then stopped before the first instruction in fn. func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) { sp := buf.sp - sp -= sys.PtrSize + sp -= goarch.PtrSize *(*uintptr)(unsafe.Pointer(sp)) = buf.pc buf.sp = sp buf.pc = uintptr(fn) diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go index 4215d62cc13..e872d74e97f 100644 --- a/src/runtime/syscall_windows.go +++ b/src/runtime/syscall_windows.go @@ -6,7 +6,7 @@ package runtime import ( "internal/abi" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -73,7 +73,7 @@ type abiDesc struct { } func (p *abiDesc) assignArg(t *_type) { - if t.size > sys.PtrSize { + if t.size > goarch.PtrSize { // We don't support this right now. In // stdcall/cdecl, 64-bit ints and doubles are // passed as two words (little endian); and @@ -146,7 +146,7 @@ func (p *abiDesc) assignArg(t *_type) { // cdecl, stdcall, fastcall, and arm pad arguments to word size. // TODO(rsc): On arm and arm64 do we need to skip the caller's saved LR? - p.srcStackSize += sys.PtrSize + p.srcStackSize += goarch.PtrSize } // tryRegAssignArg tries to register-assign a value of type t. @@ -162,7 +162,7 @@ func (p *abiDesc) tryRegAssignArg(t *_type, offset uintptr) bool { return p.assignReg(t.size, offset) case kindInt64, kindUint64: // Only register-assign if the registers are big enough. - if sys.PtrSize == 8 { + if goarch.PtrSize == 8 { return p.assignReg(t.size, offset) } case kindArray: @@ -235,7 +235,7 @@ func callbackasmAddr(i int) uintptr { return abi.FuncPCABI0(callbackasm) + uintptr(i*entrySize) } -const callbackMaxFrame = 64 * sys.PtrSize +const callbackMaxFrame = 64 * goarch.PtrSize // compileCallback converts a Go function fn into a C function pointer // that can be passed to Windows APIs. @@ -263,13 +263,13 @@ func compileCallback(fn eface, cdecl bool) (code uintptr) { } // The Go ABI aligns the result to the word size. src is // already aligned. - abiMap.dstStackSize = alignUp(abiMap.dstStackSize, sys.PtrSize) + abiMap.dstStackSize = alignUp(abiMap.dstStackSize, goarch.PtrSize) abiMap.retOffset = abiMap.dstStackSize if len(ft.out()) != 1 { panic("compileCallback: expected function with one uintptr-sized result") } - if ft.out()[0].size != sys.PtrSize { + if ft.out()[0].size != goarch.PtrSize { panic("compileCallback: expected function with one uintptr-sized result") } if k := ft.out()[0].kind & kindMask; k == kindFloat32 || k == kindFloat64 { @@ -282,12 +282,12 @@ func compileCallback(fn eface, cdecl bool) (code uintptr) { // Make room for the uintptr-sized result. // If there are argument registers, the return value will // be passed in the first register. - abiMap.dstStackSize += sys.PtrSize + abiMap.dstStackSize += goarch.PtrSize } // TODO(mknyszek): Remove dstSpill from this calculation when we no longer have // caller reserved spill space. - frameSize := alignUp(abiMap.dstStackSize, sys.PtrSize) + frameSize := alignUp(abiMap.dstStackSize, goarch.PtrSize) frameSize += abiMap.dstSpill if frameSize > callbackMaxFrame { panic("compileCallback: function argument frame too large") @@ -370,7 +370,7 @@ func callbackWrap(a *callbackArgs) { // TODO(mknyszek): Remove this when we no longer have // caller reserved spill space. - frameSize := alignUp(c.abiMap.dstStackSize, sys.PtrSize) + frameSize := alignUp(c.abiMap.dstStackSize, goarch.PtrSize) frameSize += c.abiMap.dstSpill // Even though this is copying back results, we can pass a nil diff --git a/src/runtime/trace.go b/src/runtime/trace.go index 1530178c853..1864e81a42d 100644 --- a/src/runtime/trace.go +++ b/src/runtime/trace.go @@ -15,6 +15,7 @@ package runtime import ( "runtime/internal/atomic" "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -829,7 +830,7 @@ Search: // newStack allocates a new stack of size n. func (tab *traceStackTable) newStack(n int) *traceStack { - return (*traceStack)(tab.mem.alloc(unsafe.Sizeof(traceStack{}) + uintptr(n)*sys.PtrSize)) + return (*traceStack)(tab.mem.alloc(unsafe.Sizeof(traceStack{}) + uintptr(n)*goarch.PtrSize)) } // allFrames returns all of the Frames corresponding to pcs. @@ -929,7 +930,7 @@ type traceAlloc struct { //go:notinheap type traceAllocBlock struct { next traceAllocBlockPtr - data [64<<10 - sys.PtrSize]byte + data [64<<10 - goarch.PtrSize]byte } // TODO: Since traceAllocBlock is now go:notinheap, this isn't necessary. @@ -940,7 +941,7 @@ func (p *traceAllocBlockPtr) set(x *traceAllocBlock) { *p = traceAllocBlockPtr(u // alloc allocates n-byte block. func (a *traceAlloc) alloc(n uintptr) unsafe.Pointer { - n = alignUp(n, sys.PtrSize) + n = alignUp(n, goarch.PtrSize) if a.head == 0 || a.off+n > uintptr(len(a.head.ptr().data)) { if n > uintptr(len(a.head.ptr().data)) { throw("trace: alloc too large") diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index fa41fdfe2d0..27e187f4ed0 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -8,6 +8,7 @@ import ( "internal/bytealg" "runtime/internal/atomic" "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -91,7 +92,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in frame.lr = 0 } else { frame.pc = uintptr(*(*uintptr)(unsafe.Pointer(frame.sp))) - frame.sp += sys.PtrSize + frame.sp += goarch.PtrSize } } @@ -172,7 +173,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in frame.fp = frame.sp + uintptr(funcspdelta(f, frame.pc, &cache)) if !usesLR { // On x86, call instruction pushes return PC before entering new function. - frame.fp += sys.PtrSize + frame.fp += goarch.PtrSize } } var flr funcInfo @@ -213,7 +214,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in } } else { if frame.lr == 0 { - lrPtr = frame.fp - sys.PtrSize + lrPtr = frame.fp - goarch.PtrSize frame.lr = uintptr(*(*uintptr)(unsafe.Pointer(lrPtr))) } } @@ -244,7 +245,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in frame.varp = frame.fp if !usesLR { // On x86, call instruction pushes return PC before entering new function. - frame.varp -= sys.PtrSize + frame.varp -= goarch.PtrSize } // For architectures with frame pointers, if there's @@ -265,7 +266,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in // And it happens to end up mimicking the x86 layout. // Other architectures may make different decisions. if frame.varp > frame.sp && framepointer_enabled { - frame.varp -= sys.PtrSize + frame.varp -= goarch.PtrSize } // Derive size of arguments. @@ -665,16 +666,16 @@ func getArgInfo(frame *stkframe, f funcInfo, needArgMap bool, ctxt *funcval) (ar // Figure out whether the return values are valid. // Reflect will update this value after it copies // in the return values. - retValid = *(*bool)(unsafe.Pointer(arg0 + 4*sys.PtrSize)) + retValid = *(*bool)(unsafe.Pointer(arg0 + 4*goarch.PtrSize)) } if mv.fn != f.entry { print("runtime: confused by ", funcname(f), "\n") throw("reflect mismatch") } bv := mv.stack - arglen = uintptr(bv.n * sys.PtrSize) + arglen = uintptr(bv.n * goarch.PtrSize) if !retValid { - arglen = uintptr(mv.argLen) &^ (sys.PtrSize - 1) + arglen = uintptr(mv.argLen) &^ (goarch.PtrSize - 1) } argmap = bv } @@ -1010,8 +1011,8 @@ func tracebackothers(me *g) { // for debugging purposes. If the address bad is included in the // hexdumped range, it will mark it as well. func tracebackHexdump(stk stack, frame *stkframe, bad uintptr) { - const expand = 32 * sys.PtrSize - const maxExpand = 256 * sys.PtrSize + const expand = 32 * goarch.PtrSize + const maxExpand = 256 * goarch.PtrSize // Start around frame.sp. lo, hi := frame.sp, frame.sp // Expand to include frame.fp. From 6d89c90fb166bf5c58fff33716ba632b67e9c182 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Wed, 16 Jun 2021 23:16:05 +0000 Subject: [PATCH 450/940] [dev.typeparams] runtime/internal/sys: remove unused PtrSize Change-Id: I01e079b95f71b01edaf049d49a0993a7ed39c7bf Reviewed-on: https://go-review.googlesource.com/c/go/+/328810 Trust: Michael Knyszek Run-TryBot: Michael Knyszek TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/runtime/internal/sys/consts.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/runtime/internal/sys/consts.go b/src/runtime/internal/sys/consts.go index 815f7893808..349d2ed4d65 100644 --- a/src/runtime/internal/sys/consts.go +++ b/src/runtime/internal/sys/consts.go @@ -24,10 +24,6 @@ const ( WASM = goarch.WASM ) -// PtrSize is the size of a pointer in bytes - unsafe.Sizeof(uintptr(0)) but as an ideal constant. -// It is also the size of the machine's native word size (that is, 4 on 32-bit systems, 8 on 64-bit). -const PtrSize = goarch.PtrSize - // ArchFamily is the architecture family (AMD64, ARM, ...) const ArchFamily ArchFamilyType = goarch.ArchFamily From ed834853ad8224611f44a3c467e00a22df341d91 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Thu, 17 Jun 2021 14:12:34 -0400 Subject: [PATCH 451/940] cmd/go: replace a TODO with an explanatory comment I left a TODO to decide whether to add 'go get' arguments as indirect (as we have in the past), or to make them direct. I considered both options, and decided to keep the indirect default because it is easier (and less invasive) for users to fix. Updates #45979 Change-Id: I1f23a88db59a01bdd9e6fe48c2fffc8a3b55145a Reviewed-on: https://go-review.googlesource.com/c/go/+/328971 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Michael Matloob --- src/cmd/go/testdata/script/mod_get_lazy_indirect.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/cmd/go/testdata/script/mod_get_lazy_indirect.txt b/src/cmd/go/testdata/script/mod_get_lazy_indirect.txt index 13640cbc235..1cef9d1c0cf 100644 --- a/src/cmd/go/testdata/script/mod_get_lazy_indirect.txt +++ b/src/cmd/go/testdata/script/mod_get_lazy_indirect.txt @@ -10,10 +10,12 @@ stderr '^m.go:3:8: no required module provides package rsc\.io/quote; to add it: # When we run the suggested 'go get' command, the new dependency can be used -# immediately, even though 'go get' marks it as 'indirect'. +# immediately. # -# TODO(#45979): Should we swap this default state, so that new dependencies -# are added as direct unless otherwise noted? +# 'go get' marks the new dependency as 'indirect', because it doesn't scan +# enough source code to know whether it is direct, and it is easier and less +# invasive to remove an incorrect indirect mark (e.g. using 'go get') than to +# add one that is missing ('go mod tidy' or 'go mod vendor'). go get rsc.io/quote grep 'rsc.io/quote v\d+\.\d+\.\d+ // indirect$' go.mod From 5c028751bde57d069bd0fe4c6769cba11c975d31 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Wed, 16 Jun 2021 21:11:32 +0000 Subject: [PATCH 452/940] [dev.typeparams] runtime/internal/sys: replace uses of GOARCH with goarch.GOARCH Refactoring performed by the rf tool: rf 'ex . { import "internal/goarch" import "runtime/internal/sys" sys.GOARCH -> goarch.GOARCH }' Change-Id: I4b0246bf4e734f08313c6fff7b547db362057714 Reviewed-on: https://go-review.googlesource.com/c/go/+/328338 Trust: Michael Knyszek Run-TryBot: Michael Knyszek TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/runtime/extern.go | 7 +++++-- src/runtime/heapdump.go | 3 +-- src/runtime/internal/sys/consts.go | 2 -- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/runtime/extern.go b/src/runtime/extern.go index 48e1e6603b7..1c70e8a3618 100644 --- a/src/runtime/extern.go +++ b/src/runtime/extern.go @@ -186,7 +186,10 @@ of the run-time system. */ package runtime -import "runtime/internal/sys" +import ( + "internal/goarch" + "runtime/internal/sys" +) // Caller reports file and line number information about function invocations on // the calling goroutine's stack. The argument skip is the number of stack frames @@ -264,4 +267,4 @@ const GOOS string = sys.GOOS // GOARCH is the running program's architecture target: // one of 386, amd64, arm, s390x, and so on. -const GOARCH string = sys.GOARCH +const GOARCH string = goarch.GOARCH diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go index 050628e33e3..18e4666fa40 100644 --- a/src/runtime/heapdump.go +++ b/src/runtime/heapdump.go @@ -12,7 +12,6 @@ package runtime import ( - "runtime/internal/sys" "internal/goarch" "unsafe" ) @@ -532,7 +531,7 @@ func dumpparams() { } dumpint(uint64(arenaStart)) dumpint(uint64(arenaEnd)) - dumpstr(sys.GOARCH) + dumpstr(goarch.GOARCH) dumpstr(buildVersion) dumpint(uint64(ncpu)) } diff --git a/src/runtime/internal/sys/consts.go b/src/runtime/internal/sys/consts.go index 349d2ed4d65..07fbaf4d73c 100644 --- a/src/runtime/internal/sys/consts.go +++ b/src/runtime/internal/sys/consts.go @@ -54,8 +54,6 @@ const MinFrameSize = goarch.MinFrameSize // The stack must be at least word aligned, but some architectures require more. const StackAlign = goarch.StackAlign -const GOARCH = goarch.GOARCH - const ( Goarch386 = goarch.Goarch386 GoarchAmd64 = goarch.GoarchAmd64 From 671954e72e8e3e569e659d29e22c6b2a23cea206 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Wed, 16 Jun 2021 21:15:19 +0000 Subject: [PATCH 453/940] [dev.typeparams] runtime/internal/sys: replace GOOS with goos.GOOS Refactoring done by rf tool: rf 'ex . { import "internal/goos" import "runtime/internal/sys" sys.GOOS -> goos.GOOS }' Change-Id: I4b4aadff8640731ce4cb9bdad9954c267eb484c8 Reviewed-on: https://go-review.googlesource.com/c/go/+/328339 Trust: Michael Knyszek Run-TryBot: Michael Knyszek TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/runtime/extern.go | 4 ++-- src/runtime/internal/sys/consts.go | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/runtime/extern.go b/src/runtime/extern.go index 1c70e8a3618..eca4062e68c 100644 --- a/src/runtime/extern.go +++ b/src/runtime/extern.go @@ -188,7 +188,7 @@ package runtime import ( "internal/goarch" - "runtime/internal/sys" + "internal/goos" ) // Caller reports file and line number information about function invocations on @@ -263,7 +263,7 @@ func Version() string { // GOOS is the running program's operating system target: // one of darwin, freebsd, linux, and so on. // To view possible combinations of GOOS and GOARCH, run "go tool dist list". -const GOOS string = sys.GOOS +const GOOS string = goos.GOOS // GOARCH is the running program's architecture target: // one of 386, amd64, arm, s390x, and so on. diff --git a/src/runtime/internal/sys/consts.go b/src/runtime/internal/sys/consts.go index 07fbaf4d73c..4d45f9d0d03 100644 --- a/src/runtime/internal/sys/consts.go +++ b/src/runtime/internal/sys/consts.go @@ -80,8 +80,6 @@ const ( GoarchWasm = goarch.GoarchWasm ) -const GOOS = goos.GOOS - const ( GoosAix = goos.GoosAix GoosAndroid = goos.GoosAndroid From 9c58e399a40d2cc4102245f072438caaf635d495 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Thu, 17 Jun 2021 19:10:18 +0000 Subject: [PATCH 454/940] [dev.typeparams] runtime: fix import sort order [generated] [git-generate] cd src/runtime goimports -w *.go Change-Id: I1387af0f2fd1a213dc2f4c122e83a8db0fcb15f0 Reviewed-on: https://go-review.googlesource.com/c/go/+/329189 Trust: Michael Knyszek Run-TryBot: Michael Knyszek Reviewed-by: Matthew Dempsky TryBot-Result: Go Bot --- src/runtime/alg.go | 2 +- src/runtime/cgocall.go | 2 +- src/runtime/export_test.go | 2 +- src/runtime/iface.go | 2 +- src/runtime/malloc.go | 2 +- src/runtime/map.go | 2 +- src/runtime/map_test.go | 2 +- src/runtime/mbitmap.go | 2 +- src/runtime/mcheckmark.go | 2 +- src/runtime/mfinal.go | 2 +- src/runtime/mgcmark.go | 2 +- src/runtime/mgcwork.go | 2 +- src/runtime/mheap.go | 2 +- src/runtime/mspanset.go | 2 +- src/runtime/mstats.go | 2 +- src/runtime/mwbbuf.go | 2 +- src/runtime/os_netbsd.go | 2 +- src/runtime/os_windows.go | 2 +- src/runtime/preempt.go | 2 +- src/runtime/print.go | 2 +- src/runtime/proc.go | 2 +- src/runtime/runtime1.go | 2 +- src/runtime/runtime2.go | 2 +- src/runtime/signal_linux_s390x.go | 2 +- src/runtime/slice.go | 2 +- src/runtime/stack.go | 2 +- src/runtime/symtab.go | 2 +- src/runtime/sys_wasm.go | 2 +- src/runtime/trace.go | 2 +- src/runtime/traceback.go | 2 +- 30 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/runtime/alg.go b/src/runtime/alg.go index 493499f2c5a..fe6258caddd 100644 --- a/src/runtime/alg.go +++ b/src/runtime/alg.go @@ -6,8 +6,8 @@ package runtime import ( "internal/cpu" - "runtime/internal/sys" "internal/goarch" + "runtime/internal/sys" "unsafe" ) diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go index 2dafda6ca48..34eec02d07b 100644 --- a/src/runtime/cgocall.go +++ b/src/runtime/cgocall.go @@ -85,9 +85,9 @@ package runtime import ( + "internal/goarch" "runtime/internal/atomic" "runtime/internal/sys" - "internal/goarch" "unsafe" ) diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index ae329746fec..9a471bd9d68 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -7,9 +7,9 @@ package runtime import ( + "internal/goarch" "runtime/internal/atomic" "runtime/internal/sys" - "internal/goarch" "unsafe" ) diff --git a/src/runtime/iface.go b/src/runtime/iface.go index 67c05823638..9d10deee9c5 100644 --- a/src/runtime/iface.go +++ b/src/runtime/iface.go @@ -6,9 +6,9 @@ package runtime import ( "internal/abi" + "internal/goarch" "runtime/internal/atomic" "runtime/internal/sys" - "internal/goarch" "unsafe" ) diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 9f8e04d760b..205e25ed881 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -101,10 +101,10 @@ package runtime import ( + "internal/goarch" "runtime/internal/atomic" "runtime/internal/math" "runtime/internal/sys" - "internal/goarch" "unsafe" ) diff --git a/src/runtime/map.go b/src/runtime/map.go index ca65d3e77f3..0cad1a354de 100644 --- a/src/runtime/map.go +++ b/src/runtime/map.go @@ -55,9 +55,9 @@ package runtime import ( "internal/abi" + "internal/goarch" "runtime/internal/atomic" "runtime/internal/math" - "internal/goarch" "unsafe" ) diff --git a/src/runtime/map_test.go b/src/runtime/map_test.go index 583be21eb36..24556b4093c 100644 --- a/src/runtime/map_test.go +++ b/src/runtime/map_test.go @@ -6,11 +6,11 @@ package runtime_test import ( "fmt" + "internal/goarch" "math" "reflect" "runtime" "sort" - "internal/goarch" "strconv" "strings" "sync" diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go index 124ac8f0508..9363409e361 100644 --- a/src/runtime/mbitmap.go +++ b/src/runtime/mbitmap.go @@ -46,9 +46,9 @@ package runtime import ( + "internal/goarch" "runtime/internal/atomic" "runtime/internal/sys" - "internal/goarch" "unsafe" ) diff --git a/src/runtime/mcheckmark.go b/src/runtime/mcheckmark.go index 6a43142508c..1dd28585f1c 100644 --- a/src/runtime/mcheckmark.go +++ b/src/runtime/mcheckmark.go @@ -13,8 +13,8 @@ package runtime import ( - "runtime/internal/atomic" "internal/goarch" + "runtime/internal/atomic" "unsafe" ) diff --git a/src/runtime/mfinal.go b/src/runtime/mfinal.go index 98f7cf793f0..c07ea5e3752 100644 --- a/src/runtime/mfinal.go +++ b/src/runtime/mfinal.go @@ -8,8 +8,8 @@ package runtime import ( "internal/abi" - "runtime/internal/atomic" "internal/goarch" + "runtime/internal/atomic" "unsafe" ) diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go index 85c78f05a7c..874d9107209 100644 --- a/src/runtime/mgcmark.go +++ b/src/runtime/mgcmark.go @@ -7,8 +7,8 @@ package runtime import ( - "runtime/internal/atomic" "internal/goarch" + "runtime/internal/atomic" "unsafe" ) diff --git a/src/runtime/mgcwork.go b/src/runtime/mgcwork.go index 9454ac46f31..8787d93d873 100644 --- a/src/runtime/mgcwork.go +++ b/src/runtime/mgcwork.go @@ -5,8 +5,8 @@ package runtime import ( - "runtime/internal/atomic" "internal/goarch" + "runtime/internal/atomic" "unsafe" ) diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go index 87716a4b53e..b78f752ded6 100644 --- a/src/runtime/mheap.go +++ b/src/runtime/mheap.go @@ -10,8 +10,8 @@ package runtime import ( "internal/cpu" - "runtime/internal/atomic" "internal/goarch" + "runtime/internal/atomic" "unsafe" ) diff --git a/src/runtime/mspanset.go b/src/runtime/mspanset.go index 9b0fb99c4cc..29f14910ccd 100644 --- a/src/runtime/mspanset.go +++ b/src/runtime/mspanset.go @@ -6,8 +6,8 @@ package runtime import ( "internal/cpu" - "runtime/internal/atomic" "internal/goarch" + "runtime/internal/atomic" "unsafe" ) diff --git a/src/runtime/mstats.go b/src/runtime/mstats.go index 3ac88438bcb..341ba9a9365 100644 --- a/src/runtime/mstats.go +++ b/src/runtime/mstats.go @@ -7,8 +7,8 @@ package runtime import ( - "runtime/internal/atomic" "internal/goarch" + "runtime/internal/atomic" "unsafe" ) diff --git a/src/runtime/mwbbuf.go b/src/runtime/mwbbuf.go index 7862dfbd9ea..78d9382620b 100644 --- a/src/runtime/mwbbuf.go +++ b/src/runtime/mwbbuf.go @@ -23,8 +23,8 @@ package runtime import ( - "runtime/internal/atomic" "internal/goarch" + "runtime/internal/atomic" "unsafe" ) diff --git a/src/runtime/os_netbsd.go b/src/runtime/os_netbsd.go index bd936d3735f..2c20ee21734 100644 --- a/src/runtime/os_netbsd.go +++ b/src/runtime/os_netbsd.go @@ -6,8 +6,8 @@ package runtime import ( "internal/abi" - "runtime/internal/atomic" "internal/goarch" + "runtime/internal/atomic" "unsafe" ) diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go index 1cca0876a91..648239fb366 100644 --- a/src/runtime/os_windows.go +++ b/src/runtime/os_windows.go @@ -6,8 +6,8 @@ package runtime import ( "internal/abi" - "runtime/internal/atomic" "internal/goarch" + "runtime/internal/atomic" "unsafe" ) diff --git a/src/runtime/preempt.go b/src/runtime/preempt.go index cfec196a09e..a38ab793986 100644 --- a/src/runtime/preempt.go +++ b/src/runtime/preempt.go @@ -54,8 +54,8 @@ package runtime import ( "internal/abi" - "runtime/internal/atomic" "internal/goarch" + "runtime/internal/atomic" "unsafe" ) diff --git a/src/runtime/print.go b/src/runtime/print.go index fe32fbb08e6..59a91203b9f 100644 --- a/src/runtime/print.go +++ b/src/runtime/print.go @@ -5,8 +5,8 @@ package runtime import ( - "runtime/internal/atomic" "internal/goarch" + "runtime/internal/atomic" "unsafe" ) diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 3b1e0673710..f13f7d20a35 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -7,9 +7,9 @@ package runtime import ( "internal/abi" "internal/cpu" + "internal/goarch" "runtime/internal/atomic" "runtime/internal/sys" - "internal/goarch" "unsafe" ) diff --git a/src/runtime/runtime1.go b/src/runtime/runtime1.go index eda6aaa401f..b6c3cbfff48 100644 --- a/src/runtime/runtime1.go +++ b/src/runtime/runtime1.go @@ -6,8 +6,8 @@ package runtime import ( "internal/bytealg" - "runtime/internal/atomic" "internal/goarch" + "runtime/internal/atomic" "unsafe" ) diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index e2f0d5910f5..57959293014 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -5,8 +5,8 @@ package runtime import ( - "runtime/internal/atomic" "internal/goarch" + "runtime/internal/atomic" "unsafe" ) diff --git a/src/runtime/signal_linux_s390x.go b/src/runtime/signal_linux_s390x.go index bba8169ded6..18c3b115efc 100644 --- a/src/runtime/signal_linux_s390x.go +++ b/src/runtime/signal_linux_s390x.go @@ -6,8 +6,8 @@ package runtime import ( "internal/abi" - "runtime/internal/sys" "internal/goarch" + "runtime/internal/sys" "unsafe" ) diff --git a/src/runtime/slice.go b/src/runtime/slice.go index ff59fa6278d..66e3aff1a4b 100644 --- a/src/runtime/slice.go +++ b/src/runtime/slice.go @@ -6,9 +6,9 @@ package runtime import ( "internal/abi" + "internal/goarch" "runtime/internal/math" "runtime/internal/sys" - "internal/goarch" "unsafe" ) diff --git a/src/runtime/stack.go b/src/runtime/stack.go index c37e8e76eba..0c862e5d08f 100644 --- a/src/runtime/stack.go +++ b/src/runtime/stack.go @@ -7,9 +7,9 @@ package runtime import ( "internal/abi" "internal/cpu" + "internal/goarch" "runtime/internal/atomic" "runtime/internal/sys" - "internal/goarch" "unsafe" ) diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index 36e0bfa9c43..0167d51d603 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -5,9 +5,9 @@ package runtime import ( + "internal/goarch" "runtime/internal/atomic" "runtime/internal/sys" - "internal/goarch" "unsafe" ) diff --git a/src/runtime/sys_wasm.go b/src/runtime/sys_wasm.go index 1bf80289f28..e6e7f471eea 100644 --- a/src/runtime/sys_wasm.go +++ b/src/runtime/sys_wasm.go @@ -5,8 +5,8 @@ package runtime import ( - "runtime/internal/sys" "internal/goarch" + "runtime/internal/sys" "unsafe" ) diff --git a/src/runtime/trace.go b/src/runtime/trace.go index 1864e81a42d..72e95947db9 100644 --- a/src/runtime/trace.go +++ b/src/runtime/trace.go @@ -13,9 +13,9 @@ package runtime import ( + "internal/goarch" "runtime/internal/atomic" "runtime/internal/sys" - "internal/goarch" "unsafe" ) diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index 27e187f4ed0..0bea20bf4d3 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -6,9 +6,9 @@ package runtime import ( "internal/bytealg" + "internal/goarch" "runtime/internal/atomic" "runtime/internal/sys" - "internal/goarch" "unsafe" ) From 9a93072a0709c7940f765774dbde0989425ac499 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Thu, 17 Jun 2021 19:01:08 +0000 Subject: [PATCH 455/940] [dev.typeparams] runtime/internal/sys: replace BigEndian with goarch.BigEndian [generated] [git-generate] cd src/runtime/internal/atomic gofmt -w -r "sys.BigEndian -> goarch.BigEndian" . goimports -w *.go cd ../.. gofmt -w -r "sys.BigEndian -> goarch.BigEndian" . goimports -w *.go Change-Id: Iad35d2b367d8defb081a77ca837e7a7c805c2b7b Reviewed-on: https://go-review.googlesource.com/c/go/+/329190 Trust: Michael Knyszek Run-TryBot: Michael Knyszek Reviewed-by: Matthew Dempsky TryBot-Result: Go Bot --- src/runtime/alg.go | 5 ++--- src/runtime/export_test.go | 2 +- src/runtime/iface.go | 5 ++--- src/runtime/internal/atomic/atomic_test.go | 4 ++-- src/runtime/string.go | 4 ++-- src/runtime/traceback.go | 2 +- 6 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/runtime/alg.go b/src/runtime/alg.go index fe6258caddd..978a3b85dcb 100644 --- a/src/runtime/alg.go +++ b/src/runtime/alg.go @@ -7,7 +7,6 @@ package runtime import ( "internal/cpu" "internal/goarch" - "runtime/internal/sys" "unsafe" ) @@ -338,7 +337,7 @@ func initAlgAES() { // Note: These routines perform the read with a native endianness. func readUnaligned32(p unsafe.Pointer) uint32 { q := (*[4]byte)(p) - if sys.BigEndian { + if goarch.BigEndian { return uint32(q[3]) | uint32(q[2])<<8 | uint32(q[1])<<16 | uint32(q[0])<<24 } return uint32(q[0]) | uint32(q[1])<<8 | uint32(q[2])<<16 | uint32(q[3])<<24 @@ -346,7 +345,7 @@ func readUnaligned32(p unsafe.Pointer) uint32 { func readUnaligned64(p unsafe.Pointer) uint64 { q := (*[8]byte)(p) - if sys.BigEndian { + if goarch.BigEndian { return uint64(q[7]) | uint64(q[6])<<8 | uint64(q[5])<<16 | uint64(q[4])<<24 | uint64(q[3])<<32 | uint64(q[2])<<40 | uint64(q[1])<<48 | uint64(q[0])<<56 } diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index 9a471bd9d68..de3d5b709d0 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -215,7 +215,7 @@ var Write = write func Envs() []string { return envs } func SetEnvs(e []string) { envs = e } -var BigEndian = sys.BigEndian +var BigEndian = goarch.BigEndian // For benchmarking. diff --git a/src/runtime/iface.go b/src/runtime/iface.go index 9d10deee9c5..79a49c0dffb 100644 --- a/src/runtime/iface.go +++ b/src/runtime/iface.go @@ -8,7 +8,6 @@ import ( "internal/abi" "internal/goarch" "runtime/internal/atomic" - "runtime/internal/sys" "unsafe" ) @@ -336,7 +335,7 @@ func convT2E(t *_type, elem unsafe.Pointer) (e eface) { func convT16(val uint16) (x unsafe.Pointer) { if val < uint16(len(staticuint64s)) { x = unsafe.Pointer(&staticuint64s[val]) - if sys.BigEndian { + if goarch.BigEndian { x = add(x, 6) } } else { @@ -349,7 +348,7 @@ func convT16(val uint16) (x unsafe.Pointer) { func convT32(val uint32) (x unsafe.Pointer) { if val < uint32(len(staticuint64s)) { x = unsafe.Pointer(&staticuint64s[val]) - if sys.BigEndian { + if goarch.BigEndian { x = add(x, 4) } } else { diff --git a/src/runtime/internal/atomic/atomic_test.go b/src/runtime/internal/atomic/atomic_test.go index c9c2eba248c..2ae60b8507e 100644 --- a/src/runtime/internal/atomic/atomic_test.go +++ b/src/runtime/internal/atomic/atomic_test.go @@ -5,9 +5,9 @@ package atomic_test import ( + "internal/goarch" "runtime" "runtime/internal/atomic" - "runtime/internal/sys" "testing" "unsafe" ) @@ -56,7 +56,7 @@ func TestXadduintptr(t *testing.T) { // Tests that xadduintptr correctly updates 64-bit values. The place where // we actually do so is mstats.go, functions mSysStat{Inc,Dec}. func TestXadduintptrOnUint64(t *testing.T) { - if sys.BigEndian { + if goarch.BigEndian { // On big endian architectures, we never use xadduintptr to update // 64-bit values and hence we skip the test. (Note that functions // mSysStat{Inc,Dec} in mstats.go have explicit checks for diff --git a/src/runtime/string.go b/src/runtime/string.go index 3c215d37540..d6990dab9aa 100644 --- a/src/runtime/string.go +++ b/src/runtime/string.go @@ -7,7 +7,7 @@ package runtime import ( "internal/abi" "internal/bytealg" - "runtime/internal/sys" + "internal/goarch" "unsafe" ) @@ -96,7 +96,7 @@ func slicebytetostring(buf *tmpBuf, ptr *byte, n int) (str string) { } if n == 1 { p := unsafe.Pointer(&staticuint64s[*ptr]) - if sys.BigEndian { + if goarch.BigEndian { p = add(p, 7) } stringStructOf(&str).str = p diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index 0bea20bf4d3..addfa6faac8 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -569,7 +569,7 @@ func printArgs(f funcInfo, argp unsafe.Pointer) { // mask out irrelavant bits if sz < 8 { shift := 64 - sz*8 - if sys.BigEndian { + if goarch.BigEndian { x = x >> shift } else { x = x << shift >> shift From 85b12a856313f4410376df8d02a11cc902acefa3 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Thu, 17 Jun 2021 19:13:55 +0000 Subject: [PATCH 456/940] [dev.typeparams] runtime,runtime/internal/sys: remove unused BigEndian Change-Id: I1209904326b1563e12d9c7d19a12a10c72d1dbcb Reviewed-on: https://go-review.googlesource.com/c/go/+/329191 Trust: Michael Knyszek Run-TryBot: Michael Knyszek Reviewed-by: Matthew Dempsky TryBot-Result: Go Bot --- src/runtime/export_test.go | 2 -- src/runtime/internal/sys/consts.go | 3 --- 2 files changed, 5 deletions(-) diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index de3d5b709d0..f3118472fdb 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -215,8 +215,6 @@ var Write = write func Envs() []string { return envs } func SetEnvs(e []string) { envs = e } -var BigEndian = goarch.BigEndian - // For benchmarking. func BenchSetType(n int, x interface{}) { diff --git a/src/runtime/internal/sys/consts.go b/src/runtime/internal/sys/consts.go index 4d45f9d0d03..dcba7a6e0d1 100644 --- a/src/runtime/internal/sys/consts.go +++ b/src/runtime/internal/sys/consts.go @@ -30,9 +30,6 @@ const ArchFamily ArchFamilyType = goarch.ArchFamily // AIX requires a larger stack for syscalls. const StackGuardMultiplier = StackGuardMultiplierDefault*(1-goos.GoosAix) + 2*goos.GoosAix -// BigEndian reports whether the architecture is big-endian. -const BigEndian = goarch.BigEndian - // DefaultPhysPageSize is the default physical page size. const DefaultPhysPageSize = goarch.DefaultPhysPageSize From 33d1b82d16a199b1f8c61cba40b4d883088ca278 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Wed, 16 Jun 2021 21:25:19 +0000 Subject: [PATCH 457/940] [dev.typeparams] runtime/internal/sys: replace ArchFamily and constants with goarch Refactoring with rf rf 'ex . { import "internal/goarch" import "runtime/internal/sys" sys.ArchFamily -> goarch.ArchFamily sys.AMD64 -> goarch.AMD64 sys.ARM -> goarch.ARM sys.ARM64 -> goarch.ARM64 sys.I386 -> goarch.I386 sys.MIPS -> goarch.MIPS sys.MIPS64 -> goarch.MIPS64 sys.PPC64 -> goarch.PPC64 sys.RISCV64 -> goarch.RISCV64 sys.S390X -> goarch.S390X sys.WASM -> goarch.WASM }' Change-Id: I0cc29ed3fdcf9ff39aa901d8bc92270996f0821c Reviewed-on: https://go-review.googlesource.com/c/go/+/328341 Trust: Michael Knyszek Run-TryBot: Michael Knyszek TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/runtime/internal/sys/consts.go | 18 ------------------ src/runtime/stack.go | 8 ++++---- 2 files changed, 4 insertions(+), 22 deletions(-) diff --git a/src/runtime/internal/sys/consts.go b/src/runtime/internal/sys/consts.go index dcba7a6e0d1..6400c107483 100644 --- a/src/runtime/internal/sys/consts.go +++ b/src/runtime/internal/sys/consts.go @@ -9,24 +9,6 @@ import ( "internal/goos" ) -type ArchFamilyType = goarch.ArchFamilyType - -const ( - AMD64 = goarch.AMD64 - ARM = goarch.ARM - ARM64 = goarch.ARM64 - I386 = goarch.I386 - MIPS = goarch.MIPS - MIPS64 = goarch.MIPS64 - PPC64 = goarch.PPC64 - RISCV64 = goarch.RISCV64 - S390X = goarch.S390X - WASM = goarch.WASM -) - -// ArchFamily is the architecture family (AMD64, ARM, ...) -const ArchFamily ArchFamilyType = goarch.ArchFamily - // AIX requires a larger stack for syscalls. const StackGuardMultiplier = StackGuardMultiplierDefault*(1-goos.GoosAix) + 2*goos.GoosAix diff --git a/src/runtime/stack.go b/src/runtime/stack.go index 0c862e5d08f..d63b86ddc17 100644 --- a/src/runtime/stack.go +++ b/src/runtime/stack.go @@ -662,7 +662,7 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool { // Adjust saved base pointer if there is one. // TODO what about arm64 frame pointer adjustment? - if sys.ArchFamily == sys.AMD64 && frame.argp-frame.varp == 2*goarch.PtrSize { + if goarch.ArchFamily == goarch.AMD64 && frame.argp-frame.varp == 2*goarch.PtrSize { if stackDebug >= 3 { print(" saved bp\n") } @@ -1013,7 +1013,7 @@ func newstack() { throw("missing stack in newstack") } sp := gp.sched.sp - if sys.ArchFamily == sys.AMD64 || sys.ArchFamily == sys.I386 || sys.ArchFamily == sys.WASM { + if goarch.ArchFamily == goarch.AMD64 || goarch.ArchFamily == goarch.I386 || goarch.ArchFamily == goarch.WASM { // The call to morestack cost a word. sp -= goarch.PtrSize } @@ -1256,8 +1256,8 @@ func getStackMap(frame *stkframe, cache *pcvalueCache, debug bool) (locals, args // Local variables. size := frame.varp - frame.sp var minsize uintptr - switch sys.ArchFamily { - case sys.ARM64: + switch goarch.ArchFamily { + case goarch.ARM64: minsize = sys.StackAlign default: minsize = sys.MinFrameSize From 81a6a4354b8f64b9f3a3d870e366cd8af48afbdd Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Wed, 16 Jun 2021 21:47:33 +0000 Subject: [PATCH 458/940] [dev.typeparams] internal/goarch,internal/goos: rename Goos and Goarch constants Lots of constants in these packages start with Goarch and Goos, which is redundant. Instead, add the "Is" prefix to make the constant clearer, and to differentiate from the arch family constants. Change-Id: Id92c1d3e911296a72949f8c9d649f142e7dc9d17 Reviewed-on: https://go-review.googlesource.com/c/go/+/328343 Trust: Michael Knyszek Run-TryBot: Michael Knyszek TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/internal/goarch/gengoarch.go | 2 +- src/internal/goarch/goarch.go | 4 +- src/internal/goarch/zgoarch_386.go | 46 ++++++------ src/internal/goarch/zgoarch_amd64.go | 46 ++++++------ src/internal/goarch/zgoarch_arm.go | 46 ++++++------ src/internal/goarch/zgoarch_arm64.go | 46 ++++++------ src/internal/goarch/zgoarch_arm64be.go | 46 ++++++------ src/internal/goarch/zgoarch_armbe.go | 46 ++++++------ src/internal/goarch/zgoarch_mips.go | 46 ++++++------ src/internal/goarch/zgoarch_mips64.go | 46 ++++++------ src/internal/goarch/zgoarch_mips64le.go | 46 ++++++------ src/internal/goarch/zgoarch_mips64p32.go | 46 ++++++------ src/internal/goarch/zgoarch_mips64p32le.go | 46 ++++++------ src/internal/goarch/zgoarch_mipsle.go | 46 ++++++------ src/internal/goarch/zgoarch_ppc.go | 46 ++++++------ src/internal/goarch/zgoarch_ppc64.go | 46 ++++++------ src/internal/goarch/zgoarch_ppc64le.go | 46 ++++++------ src/internal/goarch/zgoarch_riscv.go | 46 ++++++------ src/internal/goarch/zgoarch_riscv64.go | 46 ++++++------ src/internal/goarch/zgoarch_s390.go | 46 ++++++------ src/internal/goarch/zgoarch_s390x.go | 46 ++++++------ src/internal/goarch/zgoarch_sparc.go | 46 ++++++------ src/internal/goarch/zgoarch_sparc64.go | 46 ++++++------ src/internal/goarch/zgoarch_wasm.go | 46 ++++++------ src/internal/goos/gengoos.go | 2 +- src/internal/goos/goos.go | 2 +- src/internal/goos/zgoos_aix.go | 34 ++++----- src/internal/goos/zgoos_android.go | 34 ++++----- src/internal/goos/zgoos_darwin.go | 34 ++++----- src/internal/goos/zgoos_dragonfly.go | 34 ++++----- src/internal/goos/zgoos_freebsd.go | 34 ++++----- src/internal/goos/zgoos_hurd.go | 34 ++++----- src/internal/goos/zgoos_illumos.go | 34 ++++----- src/internal/goos/zgoos_ios.go | 34 ++++----- src/internal/goos/zgoos_js.go | 34 ++++----- src/internal/goos/zgoos_linux.go | 34 ++++----- src/internal/goos/zgoos_netbsd.go | 34 ++++----- src/internal/goos/zgoos_openbsd.go | 34 ++++----- src/internal/goos/zgoos_plan9.go | 34 ++++----- src/internal/goos/zgoos_solaris.go | 34 ++++----- src/internal/goos/zgoos_windows.go | 34 ++++----- src/internal/goos/zgoos_zos.go | 34 ++++----- src/runtime/internal/sys/consts.go | 82 +++++++++++----------- 43 files changed, 824 insertions(+), 824 deletions(-) diff --git a/src/internal/goarch/gengoarch.go b/src/internal/goarch/gengoarch.go index 58c3b1104c9..af15518ad8b 100644 --- a/src/internal/goarch/gengoarch.go +++ b/src/internal/goarch/gengoarch.go @@ -49,7 +49,7 @@ func main() { if goarch == target { value = 1 } - fmt.Fprintf(&buf, "const Goarch%s = %d\n", strings.Title(goarch), value) + fmt.Fprintf(&buf, "const Is%s = %d\n", strings.Title(goarch), value) } err := os.WriteFile("zgoarch_"+target+".go", buf.Bytes(), 0666) if err != nil { diff --git a/src/internal/goarch/goarch.go b/src/internal/goarch/goarch.go index 8e240295b33..921f5a208fc 100644 --- a/src/internal/goarch/goarch.go +++ b/src/internal/goarch/goarch.go @@ -6,7 +6,7 @@ package goarch // The next line makes 'go generate' write the zgoarch*.go files with -// per-arch information, including constants named Goarch$GOARCH for every +// per-arch information, including constants named $GOARCH for every // GOARCH. The constant is 1 on the current system, 0 otherwise; multiplying // by them is useful for defining GOARCH-specific constants. //go:generate go run gengoarch.go @@ -34,7 +34,7 @@ const PtrSize = 4 << (^uintptr(0) >> 63) const ArchFamily ArchFamilyType = _ArchFamily // BigEndian reports whether the architecture is big-endian. -const BigEndian = GoarchArmbe|GoarchArm64be|GoarchMips|GoarchMips64|GoarchPpc|GoarchPpc64|GoarchS390|GoarchS390x|GoarchSparc|GoarchSparc64 == 1 +const BigEndian = IsArmbe|IsArm64be|IsMips|IsMips64|IsPpc|IsPpc64|IsS390|IsS390x|IsSparc|IsSparc64 == 1 // DefaultPhysPageSize is the default physical page size. const DefaultPhysPageSize = _DefaultPhysPageSize diff --git a/src/internal/goarch/zgoarch_386.go b/src/internal/goarch/zgoarch_386.go index f424b5a6b97..7fa23b07efb 100644 --- a/src/internal/goarch/zgoarch_386.go +++ b/src/internal/goarch/zgoarch_386.go @@ -7,26 +7,26 @@ package goarch const GOARCH = `386` -const Goarch386 = 1 -const GoarchAmd64 = 0 -const GoarchAmd64p32 = 0 -const GoarchArm = 0 -const GoarchArmbe = 0 -const GoarchArm64 = 0 -const GoarchArm64be = 0 -const GoarchPpc64 = 0 -const GoarchPpc64le = 0 -const GoarchMips = 0 -const GoarchMipsle = 0 -const GoarchMips64 = 0 -const GoarchMips64le = 0 -const GoarchMips64p32 = 0 -const GoarchMips64p32le = 0 -const GoarchPpc = 0 -const GoarchRiscv = 0 -const GoarchRiscv64 = 0 -const GoarchS390 = 0 -const GoarchS390x = 0 -const GoarchSparc = 0 -const GoarchSparc64 = 0 -const GoarchWasm = 0 +const Is386 = 1 +const IsAmd64 = 0 +const IsAmd64p32 = 0 +const IsArm = 0 +const IsArmbe = 0 +const IsArm64 = 0 +const IsArm64be = 0 +const IsPpc64 = 0 +const IsPpc64le = 0 +const IsMips = 0 +const IsMipsle = 0 +const IsMips64 = 0 +const IsMips64le = 0 +const IsMips64p32 = 0 +const IsMips64p32le = 0 +const IsPpc = 0 +const IsRiscv = 0 +const IsRiscv64 = 0 +const IsS390 = 0 +const IsS390x = 0 +const IsSparc = 0 +const IsSparc64 = 0 +const IsWasm = 0 diff --git a/src/internal/goarch/zgoarch_amd64.go b/src/internal/goarch/zgoarch_amd64.go index 728896c367e..a6bf1cc6f4a 100644 --- a/src/internal/goarch/zgoarch_amd64.go +++ b/src/internal/goarch/zgoarch_amd64.go @@ -7,26 +7,26 @@ package goarch const GOARCH = `amd64` -const Goarch386 = 0 -const GoarchAmd64 = 1 -const GoarchAmd64p32 = 0 -const GoarchArm = 0 -const GoarchArmbe = 0 -const GoarchArm64 = 0 -const GoarchArm64be = 0 -const GoarchPpc64 = 0 -const GoarchPpc64le = 0 -const GoarchMips = 0 -const GoarchMipsle = 0 -const GoarchMips64 = 0 -const GoarchMips64le = 0 -const GoarchMips64p32 = 0 -const GoarchMips64p32le = 0 -const GoarchPpc = 0 -const GoarchRiscv = 0 -const GoarchRiscv64 = 0 -const GoarchS390 = 0 -const GoarchS390x = 0 -const GoarchSparc = 0 -const GoarchSparc64 = 0 -const GoarchWasm = 0 +const Is386 = 0 +const IsAmd64 = 1 +const IsAmd64p32 = 0 +const IsArm = 0 +const IsArmbe = 0 +const IsArm64 = 0 +const IsArm64be = 0 +const IsPpc64 = 0 +const IsPpc64le = 0 +const IsMips = 0 +const IsMipsle = 0 +const IsMips64 = 0 +const IsMips64le = 0 +const IsMips64p32 = 0 +const IsMips64p32le = 0 +const IsPpc = 0 +const IsRiscv = 0 +const IsRiscv64 = 0 +const IsS390 = 0 +const IsS390x = 0 +const IsSparc = 0 +const IsSparc64 = 0 +const IsWasm = 0 diff --git a/src/internal/goarch/zgoarch_arm.go b/src/internal/goarch/zgoarch_arm.go index 9d388b0554d..dcdaa1f44dc 100644 --- a/src/internal/goarch/zgoarch_arm.go +++ b/src/internal/goarch/zgoarch_arm.go @@ -7,26 +7,26 @@ package goarch const GOARCH = `arm` -const Goarch386 = 0 -const GoarchAmd64 = 0 -const GoarchAmd64p32 = 0 -const GoarchArm = 1 -const GoarchArmbe = 0 -const GoarchArm64 = 0 -const GoarchArm64be = 0 -const GoarchPpc64 = 0 -const GoarchPpc64le = 0 -const GoarchMips = 0 -const GoarchMipsle = 0 -const GoarchMips64 = 0 -const GoarchMips64le = 0 -const GoarchMips64p32 = 0 -const GoarchMips64p32le = 0 -const GoarchPpc = 0 -const GoarchRiscv = 0 -const GoarchRiscv64 = 0 -const GoarchS390 = 0 -const GoarchS390x = 0 -const GoarchSparc = 0 -const GoarchSparc64 = 0 -const GoarchWasm = 0 +const Is386 = 0 +const IsAmd64 = 0 +const IsAmd64p32 = 0 +const IsArm = 1 +const IsArmbe = 0 +const IsArm64 = 0 +const IsArm64be = 0 +const IsPpc64 = 0 +const IsPpc64le = 0 +const IsMips = 0 +const IsMipsle = 0 +const IsMips64 = 0 +const IsMips64le = 0 +const IsMips64p32 = 0 +const IsMips64p32le = 0 +const IsPpc = 0 +const IsRiscv = 0 +const IsRiscv64 = 0 +const IsS390 = 0 +const IsS390x = 0 +const IsSparc = 0 +const IsSparc64 = 0 +const IsWasm = 0 diff --git a/src/internal/goarch/zgoarch_arm64.go b/src/internal/goarch/zgoarch_arm64.go index a375ac80762..dd8d9806ab7 100644 --- a/src/internal/goarch/zgoarch_arm64.go +++ b/src/internal/goarch/zgoarch_arm64.go @@ -7,26 +7,26 @@ package goarch const GOARCH = `arm64` -const Goarch386 = 0 -const GoarchAmd64 = 0 -const GoarchAmd64p32 = 0 -const GoarchArm = 0 -const GoarchArmbe = 0 -const GoarchArm64 = 1 -const GoarchArm64be = 0 -const GoarchPpc64 = 0 -const GoarchPpc64le = 0 -const GoarchMips = 0 -const GoarchMipsle = 0 -const GoarchMips64 = 0 -const GoarchMips64le = 0 -const GoarchMips64p32 = 0 -const GoarchMips64p32le = 0 -const GoarchPpc = 0 -const GoarchRiscv = 0 -const GoarchRiscv64 = 0 -const GoarchS390 = 0 -const GoarchS390x = 0 -const GoarchSparc = 0 -const GoarchSparc64 = 0 -const GoarchWasm = 0 +const Is386 = 0 +const IsAmd64 = 0 +const IsAmd64p32 = 0 +const IsArm = 0 +const IsArmbe = 0 +const IsArm64 = 1 +const IsArm64be = 0 +const IsPpc64 = 0 +const IsPpc64le = 0 +const IsMips = 0 +const IsMipsle = 0 +const IsMips64 = 0 +const IsMips64le = 0 +const IsMips64p32 = 0 +const IsMips64p32le = 0 +const IsPpc = 0 +const IsRiscv = 0 +const IsRiscv64 = 0 +const IsS390 = 0 +const IsS390x = 0 +const IsSparc = 0 +const IsSparc64 = 0 +const IsWasm = 0 diff --git a/src/internal/goarch/zgoarch_arm64be.go b/src/internal/goarch/zgoarch_arm64be.go index 6fcc4f6bfa7..a37df97031d 100644 --- a/src/internal/goarch/zgoarch_arm64be.go +++ b/src/internal/goarch/zgoarch_arm64be.go @@ -7,26 +7,26 @@ package goarch const GOARCH = `arm64be` -const Goarch386 = 0 -const GoarchAmd64 = 0 -const GoarchAmd64p32 = 0 -const GoarchArm = 0 -const GoarchArmbe = 0 -const GoarchArm64 = 0 -const GoarchArm64be = 1 -const GoarchPpc64 = 0 -const GoarchPpc64le = 0 -const GoarchMips = 0 -const GoarchMipsle = 0 -const GoarchMips64 = 0 -const GoarchMips64le = 0 -const GoarchMips64p32 = 0 -const GoarchMips64p32le = 0 -const GoarchPpc = 0 -const GoarchRiscv = 0 -const GoarchRiscv64 = 0 -const GoarchS390 = 0 -const GoarchS390x = 0 -const GoarchSparc = 0 -const GoarchSparc64 = 0 -const GoarchWasm = 0 +const Is386 = 0 +const IsAmd64 = 0 +const IsAmd64p32 = 0 +const IsArm = 0 +const IsArmbe = 0 +const IsArm64 = 0 +const IsArm64be = 1 +const IsPpc64 = 0 +const IsPpc64le = 0 +const IsMips = 0 +const IsMipsle = 0 +const IsMips64 = 0 +const IsMips64le = 0 +const IsMips64p32 = 0 +const IsMips64p32le = 0 +const IsPpc = 0 +const IsRiscv = 0 +const IsRiscv64 = 0 +const IsS390 = 0 +const IsS390x = 0 +const IsSparc = 0 +const IsSparc64 = 0 +const IsWasm = 0 diff --git a/src/internal/goarch/zgoarch_armbe.go b/src/internal/goarch/zgoarch_armbe.go index a3ac487d80c..909b1143305 100644 --- a/src/internal/goarch/zgoarch_armbe.go +++ b/src/internal/goarch/zgoarch_armbe.go @@ -7,26 +7,26 @@ package goarch const GOARCH = `armbe` -const Goarch386 = 0 -const GoarchAmd64 = 0 -const GoarchAmd64p32 = 0 -const GoarchArm = 0 -const GoarchArmbe = 1 -const GoarchArm64 = 0 -const GoarchArm64be = 0 -const GoarchPpc64 = 0 -const GoarchPpc64le = 0 -const GoarchMips = 0 -const GoarchMipsle = 0 -const GoarchMips64 = 0 -const GoarchMips64le = 0 -const GoarchMips64p32 = 0 -const GoarchMips64p32le = 0 -const GoarchPpc = 0 -const GoarchRiscv = 0 -const GoarchRiscv64 = 0 -const GoarchS390 = 0 -const GoarchS390x = 0 -const GoarchSparc = 0 -const GoarchSparc64 = 0 -const GoarchWasm = 0 +const Is386 = 0 +const IsAmd64 = 0 +const IsAmd64p32 = 0 +const IsArm = 0 +const IsArmbe = 1 +const IsArm64 = 0 +const IsArm64be = 0 +const IsPpc64 = 0 +const IsPpc64le = 0 +const IsMips = 0 +const IsMipsle = 0 +const IsMips64 = 0 +const IsMips64le = 0 +const IsMips64p32 = 0 +const IsMips64p32le = 0 +const IsPpc = 0 +const IsRiscv = 0 +const IsRiscv64 = 0 +const IsS390 = 0 +const IsS390x = 0 +const IsSparc = 0 +const IsSparc64 = 0 +const IsWasm = 0 diff --git a/src/internal/goarch/zgoarch_mips.go b/src/internal/goarch/zgoarch_mips.go index 00cfd90c3b7..0ff91f201a1 100644 --- a/src/internal/goarch/zgoarch_mips.go +++ b/src/internal/goarch/zgoarch_mips.go @@ -7,26 +7,26 @@ package goarch const GOARCH = `mips` -const Goarch386 = 0 -const GoarchAmd64 = 0 -const GoarchAmd64p32 = 0 -const GoarchArm = 0 -const GoarchArmbe = 0 -const GoarchArm64 = 0 -const GoarchArm64be = 0 -const GoarchPpc64 = 0 -const GoarchPpc64le = 0 -const GoarchMips = 1 -const GoarchMipsle = 0 -const GoarchMips64 = 0 -const GoarchMips64le = 0 -const GoarchMips64p32 = 0 -const GoarchMips64p32le = 0 -const GoarchPpc = 0 -const GoarchRiscv = 0 -const GoarchRiscv64 = 0 -const GoarchS390 = 0 -const GoarchS390x = 0 -const GoarchSparc = 0 -const GoarchSparc64 = 0 -const GoarchWasm = 0 +const Is386 = 0 +const IsAmd64 = 0 +const IsAmd64p32 = 0 +const IsArm = 0 +const IsArmbe = 0 +const IsArm64 = 0 +const IsArm64be = 0 +const IsPpc64 = 0 +const IsPpc64le = 0 +const IsMips = 1 +const IsMipsle = 0 +const IsMips64 = 0 +const IsMips64le = 0 +const IsMips64p32 = 0 +const IsMips64p32le = 0 +const IsPpc = 0 +const IsRiscv = 0 +const IsRiscv64 = 0 +const IsS390 = 0 +const IsS390x = 0 +const IsSparc = 0 +const IsSparc64 = 0 +const IsWasm = 0 diff --git a/src/internal/goarch/zgoarch_mips64.go b/src/internal/goarch/zgoarch_mips64.go index 947db612eb0..3b61356b182 100644 --- a/src/internal/goarch/zgoarch_mips64.go +++ b/src/internal/goarch/zgoarch_mips64.go @@ -7,26 +7,26 @@ package goarch const GOARCH = `mips64` -const Goarch386 = 0 -const GoarchAmd64 = 0 -const GoarchAmd64p32 = 0 -const GoarchArm = 0 -const GoarchArmbe = 0 -const GoarchArm64 = 0 -const GoarchArm64be = 0 -const GoarchPpc64 = 0 -const GoarchPpc64le = 0 -const GoarchMips = 0 -const GoarchMipsle = 0 -const GoarchMips64 = 1 -const GoarchMips64le = 0 -const GoarchMips64p32 = 0 -const GoarchMips64p32le = 0 -const GoarchPpc = 0 -const GoarchRiscv = 0 -const GoarchRiscv64 = 0 -const GoarchS390 = 0 -const GoarchS390x = 0 -const GoarchSparc = 0 -const GoarchSparc64 = 0 -const GoarchWasm = 0 +const Is386 = 0 +const IsAmd64 = 0 +const IsAmd64p32 = 0 +const IsArm = 0 +const IsArmbe = 0 +const IsArm64 = 0 +const IsArm64be = 0 +const IsPpc64 = 0 +const IsPpc64le = 0 +const IsMips = 0 +const IsMipsle = 0 +const IsMips64 = 1 +const IsMips64le = 0 +const IsMips64p32 = 0 +const IsMips64p32le = 0 +const IsPpc = 0 +const IsRiscv = 0 +const IsRiscv64 = 0 +const IsS390 = 0 +const IsS390x = 0 +const IsSparc = 0 +const IsSparc64 = 0 +const IsWasm = 0 diff --git a/src/internal/goarch/zgoarch_mips64le.go b/src/internal/goarch/zgoarch_mips64le.go index 35ffbe2d3f3..14c9330cad6 100644 --- a/src/internal/goarch/zgoarch_mips64le.go +++ b/src/internal/goarch/zgoarch_mips64le.go @@ -7,26 +7,26 @@ package goarch const GOARCH = `mips64le` -const Goarch386 = 0 -const GoarchAmd64 = 0 -const GoarchAmd64p32 = 0 -const GoarchArm = 0 -const GoarchArmbe = 0 -const GoarchArm64 = 0 -const GoarchArm64be = 0 -const GoarchPpc64 = 0 -const GoarchPpc64le = 0 -const GoarchMips = 0 -const GoarchMipsle = 0 -const GoarchMips64 = 0 -const GoarchMips64le = 1 -const GoarchMips64p32 = 0 -const GoarchMips64p32le = 0 -const GoarchPpc = 0 -const GoarchRiscv = 0 -const GoarchRiscv64 = 0 -const GoarchS390 = 0 -const GoarchS390x = 0 -const GoarchSparc = 0 -const GoarchSparc64 = 0 -const GoarchWasm = 0 +const Is386 = 0 +const IsAmd64 = 0 +const IsAmd64p32 = 0 +const IsArm = 0 +const IsArmbe = 0 +const IsArm64 = 0 +const IsArm64be = 0 +const IsPpc64 = 0 +const IsPpc64le = 0 +const IsMips = 0 +const IsMipsle = 0 +const IsMips64 = 0 +const IsMips64le = 1 +const IsMips64p32 = 0 +const IsMips64p32le = 0 +const IsPpc = 0 +const IsRiscv = 0 +const IsRiscv64 = 0 +const IsS390 = 0 +const IsS390x = 0 +const IsSparc = 0 +const IsSparc64 = 0 +const IsWasm = 0 diff --git a/src/internal/goarch/zgoarch_mips64p32.go b/src/internal/goarch/zgoarch_mips64p32.go index c7c712032be..b7429f2bf36 100644 --- a/src/internal/goarch/zgoarch_mips64p32.go +++ b/src/internal/goarch/zgoarch_mips64p32.go @@ -7,26 +7,26 @@ package goarch const GOARCH = `mips64p32` -const Goarch386 = 0 -const GoarchAmd64 = 0 -const GoarchAmd64p32 = 0 -const GoarchArm = 0 -const GoarchArmbe = 0 -const GoarchArm64 = 0 -const GoarchArm64be = 0 -const GoarchPpc64 = 0 -const GoarchPpc64le = 0 -const GoarchMips = 0 -const GoarchMipsle = 0 -const GoarchMips64 = 0 -const GoarchMips64le = 0 -const GoarchMips64p32 = 1 -const GoarchMips64p32le = 0 -const GoarchPpc = 0 -const GoarchRiscv = 0 -const GoarchRiscv64 = 0 -const GoarchS390 = 0 -const GoarchS390x = 0 -const GoarchSparc = 0 -const GoarchSparc64 = 0 -const GoarchWasm = 0 +const Is386 = 0 +const IsAmd64 = 0 +const IsAmd64p32 = 0 +const IsArm = 0 +const IsArmbe = 0 +const IsArm64 = 0 +const IsArm64be = 0 +const IsPpc64 = 0 +const IsPpc64le = 0 +const IsMips = 0 +const IsMipsle = 0 +const IsMips64 = 0 +const IsMips64le = 0 +const IsMips64p32 = 1 +const IsMips64p32le = 0 +const IsPpc = 0 +const IsRiscv = 0 +const IsRiscv64 = 0 +const IsS390 = 0 +const IsS390x = 0 +const IsSparc = 0 +const IsSparc64 = 0 +const IsWasm = 0 diff --git a/src/internal/goarch/zgoarch_mips64p32le.go b/src/internal/goarch/zgoarch_mips64p32le.go index f605a6ff783..35c21c1675c 100644 --- a/src/internal/goarch/zgoarch_mips64p32le.go +++ b/src/internal/goarch/zgoarch_mips64p32le.go @@ -7,26 +7,26 @@ package goarch const GOARCH = `mips64p32le` -const Goarch386 = 0 -const GoarchAmd64 = 0 -const GoarchAmd64p32 = 0 -const GoarchArm = 0 -const GoarchArmbe = 0 -const GoarchArm64 = 0 -const GoarchArm64be = 0 -const GoarchPpc64 = 0 -const GoarchPpc64le = 0 -const GoarchMips = 0 -const GoarchMipsle = 0 -const GoarchMips64 = 0 -const GoarchMips64le = 0 -const GoarchMips64p32 = 0 -const GoarchMips64p32le = 1 -const GoarchPpc = 0 -const GoarchRiscv = 0 -const GoarchRiscv64 = 0 -const GoarchS390 = 0 -const GoarchS390x = 0 -const GoarchSparc = 0 -const GoarchSparc64 = 0 -const GoarchWasm = 0 +const Is386 = 0 +const IsAmd64 = 0 +const IsAmd64p32 = 0 +const IsArm = 0 +const IsArmbe = 0 +const IsArm64 = 0 +const IsArm64be = 0 +const IsPpc64 = 0 +const IsPpc64le = 0 +const IsMips = 0 +const IsMipsle = 0 +const IsMips64 = 0 +const IsMips64le = 0 +const IsMips64p32 = 0 +const IsMips64p32le = 1 +const IsPpc = 0 +const IsRiscv = 0 +const IsRiscv64 = 0 +const IsS390 = 0 +const IsS390x = 0 +const IsSparc = 0 +const IsSparc64 = 0 +const IsWasm = 0 diff --git a/src/internal/goarch/zgoarch_mipsle.go b/src/internal/goarch/zgoarch_mipsle.go index 56e24dc7b3d..ba7be189bc6 100644 --- a/src/internal/goarch/zgoarch_mipsle.go +++ b/src/internal/goarch/zgoarch_mipsle.go @@ -7,26 +7,26 @@ package goarch const GOARCH = `mipsle` -const Goarch386 = 0 -const GoarchAmd64 = 0 -const GoarchAmd64p32 = 0 -const GoarchArm = 0 -const GoarchArmbe = 0 -const GoarchArm64 = 0 -const GoarchArm64be = 0 -const GoarchPpc64 = 0 -const GoarchPpc64le = 0 -const GoarchMips = 0 -const GoarchMipsle = 1 -const GoarchMips64 = 0 -const GoarchMips64le = 0 -const GoarchMips64p32 = 0 -const GoarchMips64p32le = 0 -const GoarchPpc = 0 -const GoarchRiscv = 0 -const GoarchRiscv64 = 0 -const GoarchS390 = 0 -const GoarchS390x = 0 -const GoarchSparc = 0 -const GoarchSparc64 = 0 -const GoarchWasm = 0 +const Is386 = 0 +const IsAmd64 = 0 +const IsAmd64p32 = 0 +const IsArm = 0 +const IsArmbe = 0 +const IsArm64 = 0 +const IsArm64be = 0 +const IsPpc64 = 0 +const IsPpc64le = 0 +const IsMips = 0 +const IsMipsle = 1 +const IsMips64 = 0 +const IsMips64le = 0 +const IsMips64p32 = 0 +const IsMips64p32le = 0 +const IsPpc = 0 +const IsRiscv = 0 +const IsRiscv64 = 0 +const IsS390 = 0 +const IsS390x = 0 +const IsSparc = 0 +const IsSparc64 = 0 +const IsWasm = 0 diff --git a/src/internal/goarch/zgoarch_ppc.go b/src/internal/goarch/zgoarch_ppc.go index 4617d127927..ab19982a120 100644 --- a/src/internal/goarch/zgoarch_ppc.go +++ b/src/internal/goarch/zgoarch_ppc.go @@ -7,26 +7,26 @@ package goarch const GOARCH = `ppc` -const Goarch386 = 0 -const GoarchAmd64 = 0 -const GoarchAmd64p32 = 0 -const GoarchArm = 0 -const GoarchArmbe = 0 -const GoarchArm64 = 0 -const GoarchArm64be = 0 -const GoarchPpc64 = 0 -const GoarchPpc64le = 0 -const GoarchMips = 0 -const GoarchMipsle = 0 -const GoarchMips64 = 0 -const GoarchMips64le = 0 -const GoarchMips64p32 = 0 -const GoarchMips64p32le = 0 -const GoarchPpc = 1 -const GoarchRiscv = 0 -const GoarchRiscv64 = 0 -const GoarchS390 = 0 -const GoarchS390x = 0 -const GoarchSparc = 0 -const GoarchSparc64 = 0 -const GoarchWasm = 0 +const Is386 = 0 +const IsAmd64 = 0 +const IsAmd64p32 = 0 +const IsArm = 0 +const IsArmbe = 0 +const IsArm64 = 0 +const IsArm64be = 0 +const IsPpc64 = 0 +const IsPpc64le = 0 +const IsMips = 0 +const IsMipsle = 0 +const IsMips64 = 0 +const IsMips64le = 0 +const IsMips64p32 = 0 +const IsMips64p32le = 0 +const IsPpc = 1 +const IsRiscv = 0 +const IsRiscv64 = 0 +const IsS390 = 0 +const IsS390x = 0 +const IsSparc = 0 +const IsSparc64 = 0 +const IsWasm = 0 diff --git a/src/internal/goarch/zgoarch_ppc64.go b/src/internal/goarch/zgoarch_ppc64.go index f3cb16e9b64..d3e35ca877c 100644 --- a/src/internal/goarch/zgoarch_ppc64.go +++ b/src/internal/goarch/zgoarch_ppc64.go @@ -7,26 +7,26 @@ package goarch const GOARCH = `ppc64` -const Goarch386 = 0 -const GoarchAmd64 = 0 -const GoarchAmd64p32 = 0 -const GoarchArm = 0 -const GoarchArmbe = 0 -const GoarchArm64 = 0 -const GoarchArm64be = 0 -const GoarchPpc64 = 1 -const GoarchPpc64le = 0 -const GoarchMips = 0 -const GoarchMipsle = 0 -const GoarchMips64 = 0 -const GoarchMips64le = 0 -const GoarchMips64p32 = 0 -const GoarchMips64p32le = 0 -const GoarchPpc = 0 -const GoarchRiscv = 0 -const GoarchRiscv64 = 0 -const GoarchS390 = 0 -const GoarchS390x = 0 -const GoarchSparc = 0 -const GoarchSparc64 = 0 -const GoarchWasm = 0 +const Is386 = 0 +const IsAmd64 = 0 +const IsAmd64p32 = 0 +const IsArm = 0 +const IsArmbe = 0 +const IsArm64 = 0 +const IsArm64be = 0 +const IsPpc64 = 1 +const IsPpc64le = 0 +const IsMips = 0 +const IsMipsle = 0 +const IsMips64 = 0 +const IsMips64le = 0 +const IsMips64p32 = 0 +const IsMips64p32le = 0 +const IsPpc = 0 +const IsRiscv = 0 +const IsRiscv64 = 0 +const IsS390 = 0 +const IsS390x = 0 +const IsSparc = 0 +const IsSparc64 = 0 +const IsWasm = 0 diff --git a/src/internal/goarch/zgoarch_ppc64le.go b/src/internal/goarch/zgoarch_ppc64le.go index b70abfb953e..ef24e95c4d9 100644 --- a/src/internal/goarch/zgoarch_ppc64le.go +++ b/src/internal/goarch/zgoarch_ppc64le.go @@ -7,26 +7,26 @@ package goarch const GOARCH = `ppc64le` -const Goarch386 = 0 -const GoarchAmd64 = 0 -const GoarchAmd64p32 = 0 -const GoarchArm = 0 -const GoarchArmbe = 0 -const GoarchArm64 = 0 -const GoarchArm64be = 0 -const GoarchPpc64 = 0 -const GoarchPpc64le = 1 -const GoarchMips = 0 -const GoarchMipsle = 0 -const GoarchMips64 = 0 -const GoarchMips64le = 0 -const GoarchMips64p32 = 0 -const GoarchMips64p32le = 0 -const GoarchPpc = 0 -const GoarchRiscv = 0 -const GoarchRiscv64 = 0 -const GoarchS390 = 0 -const GoarchS390x = 0 -const GoarchSparc = 0 -const GoarchSparc64 = 0 -const GoarchWasm = 0 +const Is386 = 0 +const IsAmd64 = 0 +const IsAmd64p32 = 0 +const IsArm = 0 +const IsArmbe = 0 +const IsArm64 = 0 +const IsArm64be = 0 +const IsPpc64 = 0 +const IsPpc64le = 1 +const IsMips = 0 +const IsMipsle = 0 +const IsMips64 = 0 +const IsMips64le = 0 +const IsMips64p32 = 0 +const IsMips64p32le = 0 +const IsPpc = 0 +const IsRiscv = 0 +const IsRiscv64 = 0 +const IsS390 = 0 +const IsS390x = 0 +const IsSparc = 0 +const IsSparc64 = 0 +const IsWasm = 0 diff --git a/src/internal/goarch/zgoarch_riscv.go b/src/internal/goarch/zgoarch_riscv.go index f72973fbc59..fe6b385c504 100644 --- a/src/internal/goarch/zgoarch_riscv.go +++ b/src/internal/goarch/zgoarch_riscv.go @@ -7,26 +7,26 @@ package goarch const GOARCH = `riscv` -const Goarch386 = 0 -const GoarchAmd64 = 0 -const GoarchAmd64p32 = 0 -const GoarchArm = 0 -const GoarchArmbe = 0 -const GoarchArm64 = 0 -const GoarchArm64be = 0 -const GoarchPpc64 = 0 -const GoarchPpc64le = 0 -const GoarchMips = 0 -const GoarchMipsle = 0 -const GoarchMips64 = 0 -const GoarchMips64le = 0 -const GoarchMips64p32 = 0 -const GoarchMips64p32le = 0 -const GoarchPpc = 0 -const GoarchRiscv = 1 -const GoarchRiscv64 = 0 -const GoarchS390 = 0 -const GoarchS390x = 0 -const GoarchSparc = 0 -const GoarchSparc64 = 0 -const GoarchWasm = 0 +const Is386 = 0 +const IsAmd64 = 0 +const IsAmd64p32 = 0 +const IsArm = 0 +const IsArmbe = 0 +const IsArm64 = 0 +const IsArm64be = 0 +const IsPpc64 = 0 +const IsPpc64le = 0 +const IsMips = 0 +const IsMipsle = 0 +const IsMips64 = 0 +const IsMips64le = 0 +const IsMips64p32 = 0 +const IsMips64p32le = 0 +const IsPpc = 0 +const IsRiscv = 1 +const IsRiscv64 = 0 +const IsS390 = 0 +const IsS390x = 0 +const IsSparc = 0 +const IsSparc64 = 0 +const IsWasm = 0 diff --git a/src/internal/goarch/zgoarch_riscv64.go b/src/internal/goarch/zgoarch_riscv64.go index 5d09b63a031..85299a6b4be 100644 --- a/src/internal/goarch/zgoarch_riscv64.go +++ b/src/internal/goarch/zgoarch_riscv64.go @@ -7,26 +7,26 @@ package goarch const GOARCH = `riscv64` -const Goarch386 = 0 -const GoarchAmd64 = 0 -const GoarchAmd64p32 = 0 -const GoarchArm = 0 -const GoarchArmbe = 0 -const GoarchArm64 = 0 -const GoarchArm64be = 0 -const GoarchPpc64 = 0 -const GoarchPpc64le = 0 -const GoarchMips = 0 -const GoarchMipsle = 0 -const GoarchMips64 = 0 -const GoarchMips64le = 0 -const GoarchMips64p32 = 0 -const GoarchMips64p32le = 0 -const GoarchPpc = 0 -const GoarchRiscv = 0 -const GoarchRiscv64 = 1 -const GoarchS390 = 0 -const GoarchS390x = 0 -const GoarchSparc = 0 -const GoarchSparc64 = 0 -const GoarchWasm = 0 +const Is386 = 0 +const IsAmd64 = 0 +const IsAmd64p32 = 0 +const IsArm = 0 +const IsArmbe = 0 +const IsArm64 = 0 +const IsArm64be = 0 +const IsPpc64 = 0 +const IsPpc64le = 0 +const IsMips = 0 +const IsMipsle = 0 +const IsMips64 = 0 +const IsMips64le = 0 +const IsMips64p32 = 0 +const IsMips64p32le = 0 +const IsPpc = 0 +const IsRiscv = 0 +const IsRiscv64 = 1 +const IsS390 = 0 +const IsS390x = 0 +const IsSparc = 0 +const IsSparc64 = 0 +const IsWasm = 0 diff --git a/src/internal/goarch/zgoarch_s390.go b/src/internal/goarch/zgoarch_s390.go index 0ceffe6c2ec..39325c473ef 100644 --- a/src/internal/goarch/zgoarch_s390.go +++ b/src/internal/goarch/zgoarch_s390.go @@ -7,26 +7,26 @@ package goarch const GOARCH = `s390` -const Goarch386 = 0 -const GoarchAmd64 = 0 -const GoarchAmd64p32 = 0 -const GoarchArm = 0 -const GoarchArmbe = 0 -const GoarchArm64 = 0 -const GoarchArm64be = 0 -const GoarchPpc64 = 0 -const GoarchPpc64le = 0 -const GoarchMips = 0 -const GoarchMipsle = 0 -const GoarchMips64 = 0 -const GoarchMips64le = 0 -const GoarchMips64p32 = 0 -const GoarchMips64p32le = 0 -const GoarchPpc = 0 -const GoarchRiscv = 0 -const GoarchRiscv64 = 0 -const GoarchS390 = 1 -const GoarchS390x = 0 -const GoarchSparc = 0 -const GoarchSparc64 = 0 -const GoarchWasm = 0 +const Is386 = 0 +const IsAmd64 = 0 +const IsAmd64p32 = 0 +const IsArm = 0 +const IsArmbe = 0 +const IsArm64 = 0 +const IsArm64be = 0 +const IsPpc64 = 0 +const IsPpc64le = 0 +const IsMips = 0 +const IsMipsle = 0 +const IsMips64 = 0 +const IsMips64le = 0 +const IsMips64p32 = 0 +const IsMips64p32le = 0 +const IsPpc = 0 +const IsRiscv = 0 +const IsRiscv64 = 0 +const IsS390 = 1 +const IsS390x = 0 +const IsSparc = 0 +const IsSparc64 = 0 +const IsWasm = 0 diff --git a/src/internal/goarch/zgoarch_s390x.go b/src/internal/goarch/zgoarch_s390x.go index 142bc0f1e38..64d714ace21 100644 --- a/src/internal/goarch/zgoarch_s390x.go +++ b/src/internal/goarch/zgoarch_s390x.go @@ -7,26 +7,26 @@ package goarch const GOARCH = `s390x` -const Goarch386 = 0 -const GoarchAmd64 = 0 -const GoarchAmd64p32 = 0 -const GoarchArm = 0 -const GoarchArmbe = 0 -const GoarchArm64 = 0 -const GoarchArm64be = 0 -const GoarchPpc64 = 0 -const GoarchPpc64le = 0 -const GoarchMips = 0 -const GoarchMipsle = 0 -const GoarchMips64 = 0 -const GoarchMips64le = 0 -const GoarchMips64p32 = 0 -const GoarchMips64p32le = 0 -const GoarchPpc = 0 -const GoarchRiscv = 0 -const GoarchRiscv64 = 0 -const GoarchS390 = 0 -const GoarchS390x = 1 -const GoarchSparc = 0 -const GoarchSparc64 = 0 -const GoarchWasm = 0 +const Is386 = 0 +const IsAmd64 = 0 +const IsAmd64p32 = 0 +const IsArm = 0 +const IsArmbe = 0 +const IsArm64 = 0 +const IsArm64be = 0 +const IsPpc64 = 0 +const IsPpc64le = 0 +const IsMips = 0 +const IsMipsle = 0 +const IsMips64 = 0 +const IsMips64le = 0 +const IsMips64p32 = 0 +const IsMips64p32le = 0 +const IsPpc = 0 +const IsRiscv = 0 +const IsRiscv64 = 0 +const IsS390 = 0 +const IsS390x = 1 +const IsSparc = 0 +const IsSparc64 = 0 +const IsWasm = 0 diff --git a/src/internal/goarch/zgoarch_sparc.go b/src/internal/goarch/zgoarch_sparc.go index 62452b9d38d..9ccd3624149 100644 --- a/src/internal/goarch/zgoarch_sparc.go +++ b/src/internal/goarch/zgoarch_sparc.go @@ -7,26 +7,26 @@ package goarch const GOARCH = `sparc` -const Goarch386 = 0 -const GoarchAmd64 = 0 -const GoarchAmd64p32 = 0 -const GoarchArm = 0 -const GoarchArmbe = 0 -const GoarchArm64 = 0 -const GoarchArm64be = 0 -const GoarchPpc64 = 0 -const GoarchPpc64le = 0 -const GoarchMips = 0 -const GoarchMipsle = 0 -const GoarchMips64 = 0 -const GoarchMips64le = 0 -const GoarchMips64p32 = 0 -const GoarchMips64p32le = 0 -const GoarchPpc = 0 -const GoarchRiscv = 0 -const GoarchRiscv64 = 0 -const GoarchS390 = 0 -const GoarchS390x = 0 -const GoarchSparc = 1 -const GoarchSparc64 = 0 -const GoarchWasm = 0 +const Is386 = 0 +const IsAmd64 = 0 +const IsAmd64p32 = 0 +const IsArm = 0 +const IsArmbe = 0 +const IsArm64 = 0 +const IsArm64be = 0 +const IsPpc64 = 0 +const IsPpc64le = 0 +const IsMips = 0 +const IsMipsle = 0 +const IsMips64 = 0 +const IsMips64le = 0 +const IsMips64p32 = 0 +const IsMips64p32le = 0 +const IsPpc = 0 +const IsRiscv = 0 +const IsRiscv64 = 0 +const IsS390 = 0 +const IsS390x = 0 +const IsSparc = 1 +const IsSparc64 = 0 +const IsWasm = 0 diff --git a/src/internal/goarch/zgoarch_sparc64.go b/src/internal/goarch/zgoarch_sparc64.go index 5149507917d..490a714eb6c 100644 --- a/src/internal/goarch/zgoarch_sparc64.go +++ b/src/internal/goarch/zgoarch_sparc64.go @@ -7,26 +7,26 @@ package goarch const GOARCH = `sparc64` -const Goarch386 = 0 -const GoarchAmd64 = 0 -const GoarchAmd64p32 = 0 -const GoarchArm = 0 -const GoarchArmbe = 0 -const GoarchArm64 = 0 -const GoarchArm64be = 0 -const GoarchPpc64 = 0 -const GoarchPpc64le = 0 -const GoarchMips = 0 -const GoarchMipsle = 0 -const GoarchMips64 = 0 -const GoarchMips64le = 0 -const GoarchMips64p32 = 0 -const GoarchMips64p32le = 0 -const GoarchPpc = 0 -const GoarchRiscv = 0 -const GoarchRiscv64 = 0 -const GoarchS390 = 0 -const GoarchS390x = 0 -const GoarchSparc = 0 -const GoarchSparc64 = 1 -const GoarchWasm = 0 +const Is386 = 0 +const IsAmd64 = 0 +const IsAmd64p32 = 0 +const IsArm = 0 +const IsArmbe = 0 +const IsArm64 = 0 +const IsArm64be = 0 +const IsPpc64 = 0 +const IsPpc64le = 0 +const IsMips = 0 +const IsMipsle = 0 +const IsMips64 = 0 +const IsMips64le = 0 +const IsMips64p32 = 0 +const IsMips64p32le = 0 +const IsPpc = 0 +const IsRiscv = 0 +const IsRiscv64 = 0 +const IsS390 = 0 +const IsS390x = 0 +const IsSparc = 0 +const IsSparc64 = 1 +const IsWasm = 0 diff --git a/src/internal/goarch/zgoarch_wasm.go b/src/internal/goarch/zgoarch_wasm.go index fd25e93e747..a4b4a38401a 100644 --- a/src/internal/goarch/zgoarch_wasm.go +++ b/src/internal/goarch/zgoarch_wasm.go @@ -7,26 +7,26 @@ package goarch const GOARCH = `wasm` -const Goarch386 = 0 -const GoarchAmd64 = 0 -const GoarchAmd64p32 = 0 -const GoarchArm = 0 -const GoarchArmbe = 0 -const GoarchArm64 = 0 -const GoarchArm64be = 0 -const GoarchPpc64 = 0 -const GoarchPpc64le = 0 -const GoarchMips = 0 -const GoarchMipsle = 0 -const GoarchMips64 = 0 -const GoarchMips64le = 0 -const GoarchMips64p32 = 0 -const GoarchMips64p32le = 0 -const GoarchPpc = 0 -const GoarchRiscv = 0 -const GoarchRiscv64 = 0 -const GoarchS390 = 0 -const GoarchS390x = 0 -const GoarchSparc = 0 -const GoarchSparc64 = 0 -const GoarchWasm = 1 +const Is386 = 0 +const IsAmd64 = 0 +const IsAmd64p32 = 0 +const IsArm = 0 +const IsArmbe = 0 +const IsArm64 = 0 +const IsArm64be = 0 +const IsPpc64 = 0 +const IsPpc64le = 0 +const IsMips = 0 +const IsMipsle = 0 +const IsMips64 = 0 +const IsMips64le = 0 +const IsMips64p32 = 0 +const IsMips64p32le = 0 +const IsPpc = 0 +const IsRiscv = 0 +const IsRiscv64 = 0 +const IsS390 = 0 +const IsS390x = 0 +const IsSparc = 0 +const IsSparc64 = 0 +const IsWasm = 1 diff --git a/src/internal/goos/gengoos.go b/src/internal/goos/gengoos.go index ebcdfec3ba9..1860cd700df 100644 --- a/src/internal/goos/gengoos.go +++ b/src/internal/goos/gengoos.go @@ -60,7 +60,7 @@ func main() { if goos == target { value = 1 } - fmt.Fprintf(&buf, "const Goos%s = %d\n", strings.Title(goos), value) + fmt.Fprintf(&buf, "const Is%s = %d\n", strings.Title(goos), value) } err := os.WriteFile("zgoos_"+target+".go", buf.Bytes(), 0666) if err != nil { diff --git a/src/internal/goos/goos.go b/src/internal/goos/goos.go index 332cf51e5dc..ebb521fec68 100644 --- a/src/internal/goos/goos.go +++ b/src/internal/goos/goos.go @@ -6,7 +6,7 @@ package goos // The next line makes 'go generate' write the zgoos*.go files with -// per-OS information, including constants named Goos$GOOS for every +// per-OS information, including constants named Is$GOOS for every // known GOOS. The constant is 1 on the current system, 0 otherwise; // multiplying by them is useful for defining GOOS-specific constants. //go:generate go run gengoos.go diff --git a/src/internal/goos/zgoos_aix.go b/src/internal/goos/zgoos_aix.go index f453a8a0a8f..063e698b82c 100644 --- a/src/internal/goos/zgoos_aix.go +++ b/src/internal/goos/zgoos_aix.go @@ -7,20 +7,20 @@ package goos const GOOS = `aix` -const GoosAix = 1 -const GoosAndroid = 0 -const GoosDarwin = 0 -const GoosDragonfly = 0 -const GoosFreebsd = 0 -const GoosHurd = 0 -const GoosIllumos = 0 -const GoosIos = 0 -const GoosJs = 0 -const GoosLinux = 0 -const GoosNacl = 0 -const GoosNetbsd = 0 -const GoosOpenbsd = 0 -const GoosPlan9 = 0 -const GoosSolaris = 0 -const GoosWindows = 0 -const GoosZos = 0 +const IsAix = 1 +const IsAndroid = 0 +const IsDarwin = 0 +const IsDragonfly = 0 +const IsFreebsd = 0 +const IsHurd = 0 +const IsIllumos = 0 +const IsIos = 0 +const IsJs = 0 +const IsLinux = 0 +const IsNacl = 0 +const IsNetbsd = 0 +const IsOpenbsd = 0 +const IsPlan9 = 0 +const IsSolaris = 0 +const IsWindows = 0 +const IsZos = 0 diff --git a/src/internal/goos/zgoos_android.go b/src/internal/goos/zgoos_android.go index d90c04f7589..e9e48649782 100644 --- a/src/internal/goos/zgoos_android.go +++ b/src/internal/goos/zgoos_android.go @@ -7,20 +7,20 @@ package goos const GOOS = `android` -const GoosAix = 0 -const GoosAndroid = 1 -const GoosDarwin = 0 -const GoosDragonfly = 0 -const GoosFreebsd = 0 -const GoosHurd = 0 -const GoosIllumos = 0 -const GoosIos = 0 -const GoosJs = 0 -const GoosLinux = 0 -const GoosNacl = 0 -const GoosNetbsd = 0 -const GoosOpenbsd = 0 -const GoosPlan9 = 0 -const GoosSolaris = 0 -const GoosWindows = 0 -const GoosZos = 0 +const IsAix = 0 +const IsAndroid = 1 +const IsDarwin = 0 +const IsDragonfly = 0 +const IsFreebsd = 0 +const IsHurd = 0 +const IsIllumos = 0 +const IsIos = 0 +const IsJs = 0 +const IsLinux = 0 +const IsNacl = 0 +const IsNetbsd = 0 +const IsOpenbsd = 0 +const IsPlan9 = 0 +const IsSolaris = 0 +const IsWindows = 0 +const IsZos = 0 diff --git a/src/internal/goos/zgoos_darwin.go b/src/internal/goos/zgoos_darwin.go index 18f6c28b128..309d6a27172 100644 --- a/src/internal/goos/zgoos_darwin.go +++ b/src/internal/goos/zgoos_darwin.go @@ -7,20 +7,20 @@ package goos const GOOS = `darwin` -const GoosAix = 0 -const GoosAndroid = 0 -const GoosDarwin = 1 -const GoosDragonfly = 0 -const GoosFreebsd = 0 -const GoosHurd = 0 -const GoosIllumos = 0 -const GoosIos = 0 -const GoosJs = 0 -const GoosLinux = 0 -const GoosNacl = 0 -const GoosNetbsd = 0 -const GoosOpenbsd = 0 -const GoosPlan9 = 0 -const GoosSolaris = 0 -const GoosWindows = 0 -const GoosZos = 0 +const IsAix = 0 +const IsAndroid = 0 +const IsDarwin = 1 +const IsDragonfly = 0 +const IsFreebsd = 0 +const IsHurd = 0 +const IsIllumos = 0 +const IsIos = 0 +const IsJs = 0 +const IsLinux = 0 +const IsNacl = 0 +const IsNetbsd = 0 +const IsOpenbsd = 0 +const IsPlan9 = 0 +const IsSolaris = 0 +const IsWindows = 0 +const IsZos = 0 diff --git a/src/internal/goos/zgoos_dragonfly.go b/src/internal/goos/zgoos_dragonfly.go index a658d1d07f2..4e8711b94c5 100644 --- a/src/internal/goos/zgoos_dragonfly.go +++ b/src/internal/goos/zgoos_dragonfly.go @@ -7,20 +7,20 @@ package goos const GOOS = `dragonfly` -const GoosAix = 0 -const GoosAndroid = 0 -const GoosDarwin = 0 -const GoosDragonfly = 1 -const GoosFreebsd = 0 -const GoosHurd = 0 -const GoosIllumos = 0 -const GoosIos = 0 -const GoosJs = 0 -const GoosLinux = 0 -const GoosNacl = 0 -const GoosNetbsd = 0 -const GoosOpenbsd = 0 -const GoosPlan9 = 0 -const GoosSolaris = 0 -const GoosWindows = 0 -const GoosZos = 0 +const IsAix = 0 +const IsAndroid = 0 +const IsDarwin = 0 +const IsDragonfly = 1 +const IsFreebsd = 0 +const IsHurd = 0 +const IsIllumos = 0 +const IsIos = 0 +const IsJs = 0 +const IsLinux = 0 +const IsNacl = 0 +const IsNetbsd = 0 +const IsOpenbsd = 0 +const IsPlan9 = 0 +const IsSolaris = 0 +const IsWindows = 0 +const IsZos = 0 diff --git a/src/internal/goos/zgoos_freebsd.go b/src/internal/goos/zgoos_freebsd.go index 2534eb8c6f8..f312bd16081 100644 --- a/src/internal/goos/zgoos_freebsd.go +++ b/src/internal/goos/zgoos_freebsd.go @@ -7,20 +7,20 @@ package goos const GOOS = `freebsd` -const GoosAix = 0 -const GoosAndroid = 0 -const GoosDarwin = 0 -const GoosDragonfly = 0 -const GoosFreebsd = 1 -const GoosHurd = 0 -const GoosIllumos = 0 -const GoosIos = 0 -const GoosJs = 0 -const GoosLinux = 0 -const GoosNacl = 0 -const GoosNetbsd = 0 -const GoosOpenbsd = 0 -const GoosPlan9 = 0 -const GoosSolaris = 0 -const GoosWindows = 0 -const GoosZos = 0 +const IsAix = 0 +const IsAndroid = 0 +const IsDarwin = 0 +const IsDragonfly = 0 +const IsFreebsd = 1 +const IsHurd = 0 +const IsIllumos = 0 +const IsIos = 0 +const IsJs = 0 +const IsLinux = 0 +const IsNacl = 0 +const IsNetbsd = 0 +const IsOpenbsd = 0 +const IsPlan9 = 0 +const IsSolaris = 0 +const IsWindows = 0 +const IsZos = 0 diff --git a/src/internal/goos/zgoos_hurd.go b/src/internal/goos/zgoos_hurd.go index 3fefb1fbb18..0f0dd28b81b 100644 --- a/src/internal/goos/zgoos_hurd.go +++ b/src/internal/goos/zgoos_hurd.go @@ -7,20 +7,20 @@ package goos const GOOS = `hurd` -const GoosAix = 0 -const GoosAndroid = 0 -const GoosDarwin = 0 -const GoosDragonfly = 0 -const GoosFreebsd = 0 -const GoosHurd = 1 -const GoosIllumos = 0 -const GoosIos = 0 -const GoosJs = 0 -const GoosLinux = 0 -const GoosNacl = 0 -const GoosNetbsd = 0 -const GoosOpenbsd = 0 -const GoosPlan9 = 0 -const GoosSolaris = 0 -const GoosWindows = 0 -const GoosZos = 0 +const IsAix = 0 +const IsAndroid = 0 +const IsDarwin = 0 +const IsDragonfly = 0 +const IsFreebsd = 0 +const IsHurd = 1 +const IsIllumos = 0 +const IsIos = 0 +const IsJs = 0 +const IsLinux = 0 +const IsNacl = 0 +const IsNetbsd = 0 +const IsOpenbsd = 0 +const IsPlan9 = 0 +const IsSolaris = 0 +const IsWindows = 0 +const IsZos = 0 diff --git a/src/internal/goos/zgoos_illumos.go b/src/internal/goos/zgoos_illumos.go index 77495a3369b..17e7c53a403 100644 --- a/src/internal/goos/zgoos_illumos.go +++ b/src/internal/goos/zgoos_illumos.go @@ -7,20 +7,20 @@ package goos const GOOS = `illumos` -const GoosAix = 0 -const GoosAndroid = 0 -const GoosDarwin = 0 -const GoosDragonfly = 0 -const GoosFreebsd = 0 -const GoosHurd = 0 -const GoosIllumos = 1 -const GoosIos = 0 -const GoosJs = 0 -const GoosLinux = 0 -const GoosNacl = 0 -const GoosNetbsd = 0 -const GoosOpenbsd = 0 -const GoosPlan9 = 0 -const GoosSolaris = 0 -const GoosWindows = 0 -const GoosZos = 0 +const IsAix = 0 +const IsAndroid = 0 +const IsDarwin = 0 +const IsDragonfly = 0 +const IsFreebsd = 0 +const IsHurd = 0 +const IsIllumos = 1 +const IsIos = 0 +const IsJs = 0 +const IsLinux = 0 +const IsNacl = 0 +const IsNetbsd = 0 +const IsOpenbsd = 0 +const IsPlan9 = 0 +const IsSolaris = 0 +const IsWindows = 0 +const IsZos = 0 diff --git a/src/internal/goos/zgoos_ios.go b/src/internal/goos/zgoos_ios.go index 92820fe77e8..e4745ca4134 100644 --- a/src/internal/goos/zgoos_ios.go +++ b/src/internal/goos/zgoos_ios.go @@ -7,20 +7,20 @@ package goos const GOOS = `ios` -const GoosAix = 0 -const GoosAndroid = 0 -const GoosDarwin = 0 -const GoosDragonfly = 0 -const GoosFreebsd = 0 -const GoosHurd = 0 -const GoosIllumos = 0 -const GoosIos = 1 -const GoosJs = 0 -const GoosLinux = 0 -const GoosNacl = 0 -const GoosNetbsd = 0 -const GoosOpenbsd = 0 -const GoosPlan9 = 0 -const GoosSolaris = 0 -const GoosWindows = 0 -const GoosZos = 0 +const IsAix = 0 +const IsAndroid = 0 +const IsDarwin = 0 +const IsDragonfly = 0 +const IsFreebsd = 0 +const IsHurd = 0 +const IsIllumos = 0 +const IsIos = 1 +const IsJs = 0 +const IsLinux = 0 +const IsNacl = 0 +const IsNetbsd = 0 +const IsOpenbsd = 0 +const IsPlan9 = 0 +const IsSolaris = 0 +const IsWindows = 0 +const IsZos = 0 diff --git a/src/internal/goos/zgoos_js.go b/src/internal/goos/zgoos_js.go index 6331a5c3f19..bd2417e9cea 100644 --- a/src/internal/goos/zgoos_js.go +++ b/src/internal/goos/zgoos_js.go @@ -7,20 +7,20 @@ package goos const GOOS = `js` -const GoosAix = 0 -const GoosAndroid = 0 -const GoosDarwin = 0 -const GoosDragonfly = 0 -const GoosFreebsd = 0 -const GoosHurd = 0 -const GoosIllumos = 0 -const GoosIos = 0 -const GoosJs = 1 -const GoosLinux = 0 -const GoosNacl = 0 -const GoosNetbsd = 0 -const GoosOpenbsd = 0 -const GoosPlan9 = 0 -const GoosSolaris = 0 -const GoosWindows = 0 -const GoosZos = 0 +const IsAix = 0 +const IsAndroid = 0 +const IsDarwin = 0 +const IsDragonfly = 0 +const IsFreebsd = 0 +const IsHurd = 0 +const IsIllumos = 0 +const IsIos = 0 +const IsJs = 1 +const IsLinux = 0 +const IsNacl = 0 +const IsNetbsd = 0 +const IsOpenbsd = 0 +const IsPlan9 = 0 +const IsSolaris = 0 +const IsWindows = 0 +const IsZos = 0 diff --git a/src/internal/goos/zgoos_linux.go b/src/internal/goos/zgoos_linux.go index aa4e2d31451..476702f442a 100644 --- a/src/internal/goos/zgoos_linux.go +++ b/src/internal/goos/zgoos_linux.go @@ -7,20 +7,20 @@ package goos const GOOS = `linux` -const GoosAix = 0 -const GoosAndroid = 0 -const GoosDarwin = 0 -const GoosDragonfly = 0 -const GoosFreebsd = 0 -const GoosHurd = 0 -const GoosIllumos = 0 -const GoosIos = 0 -const GoosJs = 0 -const GoosLinux = 1 -const GoosNacl = 0 -const GoosNetbsd = 0 -const GoosOpenbsd = 0 -const GoosPlan9 = 0 -const GoosSolaris = 0 -const GoosWindows = 0 -const GoosZos = 0 +const IsAix = 0 +const IsAndroid = 0 +const IsDarwin = 0 +const IsDragonfly = 0 +const IsFreebsd = 0 +const IsHurd = 0 +const IsIllumos = 0 +const IsIos = 0 +const IsJs = 0 +const IsLinux = 1 +const IsNacl = 0 +const IsNetbsd = 0 +const IsOpenbsd = 0 +const IsPlan9 = 0 +const IsSolaris = 0 +const IsWindows = 0 +const IsZos = 0 diff --git a/src/internal/goos/zgoos_netbsd.go b/src/internal/goos/zgoos_netbsd.go index 39635104c03..97b7564babd 100644 --- a/src/internal/goos/zgoos_netbsd.go +++ b/src/internal/goos/zgoos_netbsd.go @@ -7,20 +7,20 @@ package goos const GOOS = `netbsd` -const GoosAix = 0 -const GoosAndroid = 0 -const GoosDarwin = 0 -const GoosDragonfly = 0 -const GoosFreebsd = 0 -const GoosHurd = 0 -const GoosIllumos = 0 -const GoosIos = 0 -const GoosJs = 0 -const GoosLinux = 0 -const GoosNacl = 0 -const GoosNetbsd = 1 -const GoosOpenbsd = 0 -const GoosPlan9 = 0 -const GoosSolaris = 0 -const GoosWindows = 0 -const GoosZos = 0 +const IsAix = 0 +const IsAndroid = 0 +const IsDarwin = 0 +const IsDragonfly = 0 +const IsFreebsd = 0 +const IsHurd = 0 +const IsIllumos = 0 +const IsIos = 0 +const IsJs = 0 +const IsLinux = 0 +const IsNacl = 0 +const IsNetbsd = 1 +const IsOpenbsd = 0 +const IsPlan9 = 0 +const IsSolaris = 0 +const IsWindows = 0 +const IsZos = 0 diff --git a/src/internal/goos/zgoos_openbsd.go b/src/internal/goos/zgoos_openbsd.go index 61d4ac8bb02..384a96480d6 100644 --- a/src/internal/goos/zgoos_openbsd.go +++ b/src/internal/goos/zgoos_openbsd.go @@ -7,20 +7,20 @@ package goos const GOOS = `openbsd` -const GoosAix = 0 -const GoosAndroid = 0 -const GoosDarwin = 0 -const GoosDragonfly = 0 -const GoosFreebsd = 0 -const GoosHurd = 0 -const GoosIllumos = 0 -const GoosIos = 0 -const GoosJs = 0 -const GoosLinux = 0 -const GoosNacl = 0 -const GoosNetbsd = 0 -const GoosOpenbsd = 1 -const GoosPlan9 = 0 -const GoosSolaris = 0 -const GoosWindows = 0 -const GoosZos = 0 +const IsAix = 0 +const IsAndroid = 0 +const IsDarwin = 0 +const IsDragonfly = 0 +const IsFreebsd = 0 +const IsHurd = 0 +const IsIllumos = 0 +const IsIos = 0 +const IsJs = 0 +const IsLinux = 0 +const IsNacl = 0 +const IsNetbsd = 0 +const IsOpenbsd = 1 +const IsPlan9 = 0 +const IsSolaris = 0 +const IsWindows = 0 +const IsZos = 0 diff --git a/src/internal/goos/zgoos_plan9.go b/src/internal/goos/zgoos_plan9.go index 7f0dc2fa041..fcc279a79ec 100644 --- a/src/internal/goos/zgoos_plan9.go +++ b/src/internal/goos/zgoos_plan9.go @@ -7,20 +7,20 @@ package goos const GOOS = `plan9` -const GoosAix = 0 -const GoosAndroid = 0 -const GoosDarwin = 0 -const GoosDragonfly = 0 -const GoosFreebsd = 0 -const GoosHurd = 0 -const GoosIllumos = 0 -const GoosIos = 0 -const GoosJs = 0 -const GoosLinux = 0 -const GoosNacl = 0 -const GoosNetbsd = 0 -const GoosOpenbsd = 0 -const GoosPlan9 = 1 -const GoosSolaris = 0 -const GoosWindows = 0 -const GoosZos = 0 +const IsAix = 0 +const IsAndroid = 0 +const IsDarwin = 0 +const IsDragonfly = 0 +const IsFreebsd = 0 +const IsHurd = 0 +const IsIllumos = 0 +const IsIos = 0 +const IsJs = 0 +const IsLinux = 0 +const IsNacl = 0 +const IsNetbsd = 0 +const IsOpenbsd = 0 +const IsPlan9 = 1 +const IsSolaris = 0 +const IsWindows = 0 +const IsZos = 0 diff --git a/src/internal/goos/zgoos_solaris.go b/src/internal/goos/zgoos_solaris.go index 7497324a4f6..3f366cf7101 100644 --- a/src/internal/goos/zgoos_solaris.go +++ b/src/internal/goos/zgoos_solaris.go @@ -7,20 +7,20 @@ package goos const GOOS = `solaris` -const GoosAix = 0 -const GoosAndroid = 0 -const GoosDarwin = 0 -const GoosDragonfly = 0 -const GoosFreebsd = 0 -const GoosHurd = 0 -const GoosIllumos = 0 -const GoosIos = 0 -const GoosJs = 0 -const GoosLinux = 0 -const GoosNacl = 0 -const GoosNetbsd = 0 -const GoosOpenbsd = 0 -const GoosPlan9 = 0 -const GoosSolaris = 1 -const GoosWindows = 0 -const GoosZos = 0 +const IsAix = 0 +const IsAndroid = 0 +const IsDarwin = 0 +const IsDragonfly = 0 +const IsFreebsd = 0 +const IsHurd = 0 +const IsIllumos = 0 +const IsIos = 0 +const IsJs = 0 +const IsLinux = 0 +const IsNacl = 0 +const IsNetbsd = 0 +const IsOpenbsd = 0 +const IsPlan9 = 0 +const IsSolaris = 1 +const IsWindows = 0 +const IsZos = 0 diff --git a/src/internal/goos/zgoos_windows.go b/src/internal/goos/zgoos_windows.go index e316b80c82f..dfa55339d34 100644 --- a/src/internal/goos/zgoos_windows.go +++ b/src/internal/goos/zgoos_windows.go @@ -7,20 +7,20 @@ package goos const GOOS = `windows` -const GoosAix = 0 -const GoosAndroid = 0 -const GoosDarwin = 0 -const GoosDragonfly = 0 -const GoosFreebsd = 0 -const GoosHurd = 0 -const GoosIllumos = 0 -const GoosIos = 0 -const GoosJs = 0 -const GoosLinux = 0 -const GoosNacl = 0 -const GoosNetbsd = 0 -const GoosOpenbsd = 0 -const GoosPlan9 = 0 -const GoosSolaris = 0 -const GoosWindows = 1 -const GoosZos = 0 +const IsAix = 0 +const IsAndroid = 0 +const IsDarwin = 0 +const IsDragonfly = 0 +const IsFreebsd = 0 +const IsHurd = 0 +const IsIllumos = 0 +const IsIos = 0 +const IsJs = 0 +const IsLinux = 0 +const IsNacl = 0 +const IsNetbsd = 0 +const IsOpenbsd = 0 +const IsPlan9 = 0 +const IsSolaris = 0 +const IsWindows = 1 +const IsZos = 0 diff --git a/src/internal/goos/zgoos_zos.go b/src/internal/goos/zgoos_zos.go index 26471f4f36e..714f24963a2 100644 --- a/src/internal/goos/zgoos_zos.go +++ b/src/internal/goos/zgoos_zos.go @@ -7,20 +7,20 @@ package goos const GOOS = `zos` -const GoosAix = 0 -const GoosAndroid = 0 -const GoosDarwin = 0 -const GoosDragonfly = 0 -const GoosFreebsd = 0 -const GoosHurd = 0 -const GoosIllumos = 0 -const GoosIos = 0 -const GoosJs = 0 -const GoosLinux = 0 -const GoosNacl = 0 -const GoosNetbsd = 0 -const GoosOpenbsd = 0 -const GoosPlan9 = 0 -const GoosSolaris = 0 -const GoosWindows = 0 -const GoosZos = 1 +const IsAix = 0 +const IsAndroid = 0 +const IsDarwin = 0 +const IsDragonfly = 0 +const IsFreebsd = 0 +const IsHurd = 0 +const IsIllumos = 0 +const IsIos = 0 +const IsJs = 0 +const IsLinux = 0 +const IsNacl = 0 +const IsNetbsd = 0 +const IsOpenbsd = 0 +const IsPlan9 = 0 +const IsSolaris = 0 +const IsWindows = 0 +const IsZos = 1 diff --git a/src/runtime/internal/sys/consts.go b/src/runtime/internal/sys/consts.go index 6400c107483..ab0a02671a0 100644 --- a/src/runtime/internal/sys/consts.go +++ b/src/runtime/internal/sys/consts.go @@ -10,7 +10,7 @@ import ( ) // AIX requires a larger stack for syscalls. -const StackGuardMultiplier = StackGuardMultiplierDefault*(1-goos.GoosAix) + 2*goos.GoosAix +const StackGuardMultiplier = StackGuardMultiplierDefault*(1-goos.IsAix) + 2*goos.IsAix // DefaultPhysPageSize is the default physical page size. const DefaultPhysPageSize = goarch.DefaultPhysPageSize @@ -34,47 +34,47 @@ const MinFrameSize = goarch.MinFrameSize const StackAlign = goarch.StackAlign const ( - Goarch386 = goarch.Goarch386 - GoarchAmd64 = goarch.GoarchAmd64 - GoarchAmd64p32 = goarch.GoarchAmd64p32 - GoarchArm = goarch.GoarchArm - GoarchArmbe = goarch.GoarchArmbe - GoarchArm64 = goarch.GoarchArm64 - GoarchArm64be = goarch.GoarchArm64be - GoarchPpc64 = goarch.GoarchPpc64 - GoarchPpc64le = goarch.GoarchPpc64le - GoarchMips = goarch.GoarchMips - GoarchMipsle = goarch.GoarchMipsle - GoarchMips64 = goarch.GoarchMips64 - GoarchMips64le = goarch.GoarchMips64le - GoarchMips64p32 = goarch.GoarchMips64p32 - GoarchMips64p32le = goarch.GoarchMips64p32le - GoarchPpc = goarch.GoarchPpc - GoarchRiscv = goarch.GoarchRiscv - GoarchRiscv64 = goarch.GoarchRiscv64 - GoarchS390 = goarch.GoarchS390 - GoarchS390x = goarch.GoarchS390x - GoarchSparc = goarch.GoarchSparc - GoarchSparc64 = goarch.GoarchSparc64 - GoarchWasm = goarch.GoarchWasm + Goarch386 = goarch.Is386 + GoarchAmd64 = goarch.IsAmd64 + GoarchAmd64p32 = goarch.IsAmd64p32 + GoarchArm = goarch.IsArm + GoarchArmbe = goarch.IsArmbe + GoarchArm64 = goarch.IsArm64 + GoarchArm64be = goarch.IsArm64be + GoarchPpc64 = goarch.IsPpc64 + GoarchPpc64le = goarch.IsPpc64le + GoarchMips = goarch.IsMips + GoarchMipsle = goarch.IsMipsle + GoarchMips64 = goarch.IsMips64 + GoarchMips64le = goarch.IsMips64le + GoarchMips64p32 = goarch.IsMips64p32 + GoarchMips64p32le = goarch.IsMips64p32le + GoarchPpc = goarch.IsPpc + GoarchRiscv = goarch.IsRiscv + GoarchRiscv64 = goarch.IsRiscv64 + GoarchS390 = goarch.IsS390 + GoarchS390x = goarch.IsS390x + GoarchSparc = goarch.IsSparc + GoarchSparc64 = goarch.IsSparc64 + GoarchWasm = goarch.IsWasm ) const ( - GoosAix = goos.GoosAix - GoosAndroid = goos.GoosAndroid - GoosDarwin = goos.GoosDarwin - GoosDragonfly = goos.GoosDragonfly - GoosFreebsd = goos.GoosFreebsd - GoosHurd = goos.GoosHurd - GoosIllumos = goos.GoosIllumos - GoosIos = goos.GoosIos - GoosJs = goos.GoosJs - GoosLinux = goos.GoosLinux - GoosNacl = goos.GoosNacl - GoosNetbsd = goos.GoosNetbsd - GoosOpenbsd = goos.GoosOpenbsd - GoosPlan9 = goos.GoosPlan9 - GoosSolaris = goos.GoosSolaris - GoosWindows = goos.GoosWindows - GoosZos = goos.GoosZos + GoosAix = goos.IsAix + GoosAndroid = goos.IsAndroid + GoosDarwin = goos.IsDarwin + GoosDragonfly = goos.IsDragonfly + GoosFreebsd = goos.IsFreebsd + GoosHurd = goos.IsHurd + GoosIllumos = goos.IsIllumos + GoosIos = goos.IsIos + GoosJs = goos.IsJs + GoosLinux = goos.IsLinux + GoosNacl = goos.IsNacl + GoosNetbsd = goos.IsNetbsd + GoosOpenbsd = goos.IsOpenbsd + GoosPlan9 = goos.IsPlan9 + GoosSolaris = goos.IsSolaris + GoosWindows = goos.IsWindows + GoosZos = goos.IsZos ) From 7b0e9cae66fc706bb390ba08fb4801015359f17b Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Wed, 16 Jun 2021 21:52:24 +0000 Subject: [PATCH 459/940] [dev.typeparams] runtime: replace Goos* constants with internal/goos versions [generated] [git-generate] cd src/runtime gofmt -w -r "sys.GoosAix -> goos.IsAix" . gofmt -w -r "sys.GoosAndroid -> goos.IsAndroid" . gofmt -w -r "sys.GoosDarwin -> goos.IsDarwin" . gofmt -w -r "sys.GoosDragonfly -> goos.IsDragonfly" . gofmt -w -r "sys.GoosFreebsd -> goos.IsFreebsd" . gofmt -w -r "sys.GoosHurd -> goos.IsHurd" . gofmt -w -r "sys.GoosIllumos -> goos.IsIllumos" . gofmt -w -r "sys.GoosIos -> goos.IsIos" . gofmt -w -r "sys.GoosJs -> goos.IsJs" . gofmt -w -r "sys.GoosLinux -> goos.IsLinux" . gofmt -w -r "sys.GoosNacl -> goos.IsNacl" . gofmt -w -r "sys.GoosNetbsd -> goos.IsNetbsd" . gofmt -w -r "sys.GoosOpenbsd -> goos.IsOpenbsd" . gofmt -w -r "sys.GoosPlan9 -> goos.IsPlan9" . gofmt -w -r "sys.GoosSolaris -> goos.IsSolaris" . gofmt -w -r "sys.GoosWindows -> goos.IsWindows" . gofmt -w -r "sys.GoosZos -> goos.IsZos" . goimports -w *.go Change-Id: I42bed2907317ed409812e5a3e2897c88a5d36f24 Reviewed-on: https://go-review.googlesource.com/c/go/+/328344 Trust: Michael Knyszek Run-TryBot: Michael Knyszek TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/runtime/export_test.go | 3 ++- src/runtime/malloc.go | 11 ++++++----- src/runtime/mgcscavenge.go | 3 ++- src/runtime/stack.go | 3 ++- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index f3118472fdb..e7279564e3f 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -8,6 +8,7 @@ package runtime import ( "internal/goarch" + "internal/goos" "runtime/internal/atomic" "runtime/internal/sys" "unsafe" @@ -1051,7 +1052,7 @@ func FreePageAlloc(pp *PageAlloc) { // // This should not be higher than 0x100*pallocChunkBytes to support // mips and mipsle, which only have 31-bit address spaces. -var BaseChunkIdx = ChunkIdx(chunkIndex(((0xc000*pageAlloc64Bit + 0x100*pageAlloc32Bit) * pallocChunkBytes) + arenaBaseOffset*sys.GoosAix)) +var BaseChunkIdx = ChunkIdx(chunkIndex(((0xc000*pageAlloc64Bit + 0x100*pageAlloc32Bit) * pallocChunkBytes) + arenaBaseOffset*goos.IsAix)) // PageBase returns an address given a chunk index and a page index // relative to that chunk. diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 205e25ed881..715019671d9 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -102,6 +102,7 @@ package runtime import ( "internal/goarch" + "internal/goos" "runtime/internal/atomic" "runtime/internal/math" "runtime/internal/sys" @@ -151,7 +152,7 @@ const ( // windows/32 | 4KB | 3 // windows/64 | 8KB | 2 // plan9 | 4KB | 3 - _NumStackOrders = 4 - goarch.PtrSize/4*sys.GoosWindows - 1*sys.GoosPlan9 + _NumStackOrders = 4 - goarch.PtrSize/4*goos.IsWindows - 1*goos.IsPlan9 // heapAddrBits is the number of bits in a heap address. On // amd64, addresses are sign-extended beyond heapAddrBits. On @@ -208,7 +209,7 @@ const ( // arenaBaseOffset to offset into the top 4 GiB. // // WebAssembly currently has a limit of 4GB linear memory. - heapAddrBits = (_64bit*(1-sys.GoarchWasm)*(1-sys.GoosIos*sys.GoarchArm64))*48 + (1-_64bit+sys.GoarchWasm)*(32-(sys.GoarchMips+sys.GoarchMipsle)) + 33*sys.GoosIos*sys.GoarchArm64 + heapAddrBits = (_64bit*(1-sys.GoarchWasm)*(1-goos.IsIos*sys.GoarchArm64))*48 + (1-_64bit+sys.GoarchWasm)*(32-(sys.GoarchMips+sys.GoarchMipsle)) + 33*goos.IsIos*sys.GoarchArm64 // maxAlloc is the maximum size of an allocation. On 64-bit, // it's theoretically possible to allocate 1< Date: Wed, 16 Jun 2021 21:57:58 +0000 Subject: [PATCH 460/940] [dev.typeparams] runtime: replace Goarch* constants with internal/goarch versions [generated] [git-generate] cd src/runtime gofmt -w -r "sys.Goarch386 -> goarch.Is386" . gofmt -w -r "sys.GoarchAmd64 -> goarch.IsAmd64" . gofmt -w -r "sys.GoarchAmd64p32 -> goarch.IsAmd64p32" . gofmt -w -r "sys.GoarchArm -> goarch.IsArm" . gofmt -w -r "sys.GoarchArmbe -> goarch.IsArmbe" . gofmt -w -r "sys.GoarchArm64 -> goarch.IsArm64" . gofmt -w -r "sys.GoarchArm64be -> goarch.IsArm64be" . gofmt -w -r "sys.GoarchPpc64 -> goarch.IsPpc64" . gofmt -w -r "sys.GoarchPpc64le -> goarch.IsPpc64le" . gofmt -w -r "sys.GoarchMips -> goarch.IsMips" . gofmt -w -r "sys.GoarchMipsle -> goarch.IsMipsle" . gofmt -w -r "sys.GoarchMips64 -> goarch.IsMips64" . gofmt -w -r "sys.GoarchMips64le -> goarch.IsMips64le" . gofmt -w -r "sys.GoarchMips64p32 -> goarch.IsMips64p32" . gofmt -w -r "sys.GoarchMips64p32le -> goarch.IsMips64p32le" . gofmt -w -r "sys.GoarchPpc -> goarch.IsPpc" . gofmt -w -r "sys.GoarchRiscv -> goarch.IsRiscv" . gofmt -w -r "sys.GoarchRiscv64 -> goarch.IsRiscv64" . gofmt -w -r "sys.GoarchS390 -> goarch.IsS390" . gofmt -w -r "sys.GoarchS390x -> goarch.IsS390x" . gofmt -w -r "sys.GoarchSparc -> goarch.IsSparc" . gofmt -w -r "sys.GoarchSparc64 -> goarch.IsSparc64" . gofmt -w -r "sys.GoarchWasm -> goarch.IsWasm" . goimports -w *.go Change-Id: I9d88e1284efabaeb0ee3733cba6286247d078c85 Reviewed-on: https://go-review.googlesource.com/c/go/+/328345 Trust: Michael Knyszek Run-TryBot: Michael Knyszek TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/runtime/malloc.go | 6 +++--- src/runtime/panic.go | 3 ++- src/runtime/stack.go | 2 +- src/runtime/trace.go | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 715019671d9..8483ec99d88 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -209,7 +209,7 @@ const ( // arenaBaseOffset to offset into the top 4 GiB. // // WebAssembly currently has a limit of 4GB linear memory. - heapAddrBits = (_64bit*(1-sys.GoarchWasm)*(1-goos.IsIos*sys.GoarchArm64))*48 + (1-_64bit+sys.GoarchWasm)*(32-(sys.GoarchMips+sys.GoarchMipsle)) + 33*goos.IsIos*sys.GoarchArm64 + heapAddrBits = (_64bit*(1-goarch.IsWasm)*(1-goos.IsIos*goarch.IsArm64))*48 + (1-_64bit+goarch.IsWasm)*(32-(goarch.IsMips+goarch.IsMipsle)) + 33*goos.IsIos*goarch.IsArm64 // maxAlloc is the maximum size of an allocation. On 64-bit, // it's theoretically possible to allocate 1< Date: Thu, 17 Jun 2021 19:49:42 +0000 Subject: [PATCH 461/940] [dev.typeparams] runtime/internal/sys: remove unused Goarch* and Goos* constants Change-Id: Ibc8381662242c6754f34edce9c0ad81681f55940 Reviewed-on: https://go-review.googlesource.com/c/go/+/329192 Trust: Michael Knyszek Run-TryBot: Michael Knyszek Reviewed-by: Matthew Dempsky TryBot-Result: Go Bot --- src/runtime/internal/sys/consts.go | 46 ------------------------------ 1 file changed, 46 deletions(-) diff --git a/src/runtime/internal/sys/consts.go b/src/runtime/internal/sys/consts.go index ab0a02671a0..fffcf81d1f3 100644 --- a/src/runtime/internal/sys/consts.go +++ b/src/runtime/internal/sys/consts.go @@ -32,49 +32,3 @@ const MinFrameSize = goarch.MinFrameSize // StackAlign is the required alignment of the SP register. // The stack must be at least word aligned, but some architectures require more. const StackAlign = goarch.StackAlign - -const ( - Goarch386 = goarch.Is386 - GoarchAmd64 = goarch.IsAmd64 - GoarchAmd64p32 = goarch.IsAmd64p32 - GoarchArm = goarch.IsArm - GoarchArmbe = goarch.IsArmbe - GoarchArm64 = goarch.IsArm64 - GoarchArm64be = goarch.IsArm64be - GoarchPpc64 = goarch.IsPpc64 - GoarchPpc64le = goarch.IsPpc64le - GoarchMips = goarch.IsMips - GoarchMipsle = goarch.IsMipsle - GoarchMips64 = goarch.IsMips64 - GoarchMips64le = goarch.IsMips64le - GoarchMips64p32 = goarch.IsMips64p32 - GoarchMips64p32le = goarch.IsMips64p32le - GoarchPpc = goarch.IsPpc - GoarchRiscv = goarch.IsRiscv - GoarchRiscv64 = goarch.IsRiscv64 - GoarchS390 = goarch.IsS390 - GoarchS390x = goarch.IsS390x - GoarchSparc = goarch.IsSparc - GoarchSparc64 = goarch.IsSparc64 - GoarchWasm = goarch.IsWasm -) - -const ( - GoosAix = goos.IsAix - GoosAndroid = goos.IsAndroid - GoosDarwin = goos.IsDarwin - GoosDragonfly = goos.IsDragonfly - GoosFreebsd = goos.IsFreebsd - GoosHurd = goos.IsHurd - GoosIllumos = goos.IsIllumos - GoosIos = goos.IsIos - GoosJs = goos.IsJs - GoosLinux = goos.IsLinux - GoosNacl = goos.IsNacl - GoosNetbsd = goos.IsNetbsd - GoosOpenbsd = goos.IsOpenbsd - GoosPlan9 = goos.IsPlan9 - GoosSolaris = goos.IsSolaris - GoosWindows = goos.IsWindows - GoosZos = goos.IsZos -) From 95c104ee61c88f77f43131b02a9ff3926e128669 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Wed, 16 Jun 2021 22:05:36 +0000 Subject: [PATCH 462/940] [dev.typeparams] reflect: use goarch.PtrSize instead of the duplicated ptrSize [generated] [git-generate] cd src/reflect gofmt -w -r "PtrSize -> goarch.PtrSize" . gofmt -w -r "ptrSize -> goarch.PtrSize" . goimports -w *.go Change-Id: Ib534bb0ecde10d93f45365ab4f8efd620d6d2ef3 Reviewed-on: https://go-review.googlesource.com/c/go/+/328346 Trust: Michael Knyszek Run-TryBot: Michael Knyszek TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/reflect/abi.go | 23 ++++++------ src/reflect/all_test.go | 75 +++++++++++++++++++------------------- src/reflect/export_test.go | 5 ++- src/reflect/swapper.go | 3 +- src/reflect/type.go | 47 ++++++++++++------------ src/reflect/value.go | 7 ++-- 6 files changed, 83 insertions(+), 77 deletions(-) diff --git a/src/reflect/abi.go b/src/reflect/abi.go index 17b79a8394f..9ddde3ae57c 100644 --- a/src/reflect/abi.go +++ b/src/reflect/abi.go @@ -6,6 +6,7 @@ package reflect import ( "internal/abi" + "internal/goarch" "internal/goexperiment" "unsafe" ) @@ -167,7 +168,7 @@ func (a *abiSeq) addRcvr(rcvr *rtype) (*abiStep, bool) { a.valueStart = append(a.valueStart, len(a.steps)) var ok, ptr bool if ifaceIndir(rcvr) || rcvr.pointers() { - ok = a.assignIntN(0, ptrSize, 1, 0b1) + ok = a.assignIntN(0, goarch.PtrSize, 1, 0b1) ptr = true } else { // TODO(mknyszek): Is this case even possible? @@ -176,11 +177,11 @@ func (a *abiSeq) addRcvr(rcvr *rtype) (*abiStep, bool) { // in the reflect package which only conditionally added // a pointer bit to the reflect.(Value).Call stack frame's // GC bitmap. - ok = a.assignIntN(0, ptrSize, 1, 0b0) + ok = a.assignIntN(0, goarch.PtrSize, 1, 0b0) ptr = false } if !ok { - a.stackAssign(ptrSize, ptrSize) + a.stackAssign(goarch.PtrSize, goarch.PtrSize) return &a.steps[len(a.steps)-1], ptr } return nil, ptr @@ -202,7 +203,7 @@ func (a *abiSeq) regAssign(t *rtype, offset uintptr) bool { case Bool, Int, Uint, Int8, Uint8, Int16, Uint16, Int32, Uint32, Uintptr: return a.assignIntN(offset, t.size, 1, 0b0) case Int64, Uint64: - switch ptrSize { + switch goarch.PtrSize { case 4: return a.assignIntN(offset, 4, 2, 0b0) case 8: @@ -215,11 +216,11 @@ func (a *abiSeq) regAssign(t *rtype, offset uintptr) bool { case Complex128: return a.assignFloatN(offset, 8, 2) case String: - return a.assignIntN(offset, ptrSize, 2, 0b01) + return a.assignIntN(offset, goarch.PtrSize, 2, 0b01) case Interface: - return a.assignIntN(offset, ptrSize, 2, 0b10) + return a.assignIntN(offset, goarch.PtrSize, 2, 0b10) case Slice: - return a.assignIntN(offset, ptrSize, 3, 0b001) + return a.assignIntN(offset, goarch.PtrSize, 3, 0b001) case Array: tt := (*arrayType)(unsafe.Pointer(t)) switch tt.len { @@ -262,7 +263,7 @@ func (a *abiSeq) assignIntN(offset, size uintptr, n int, ptrMap uint8) bool { if n > 8 || n < 0 { panic("invalid n") } - if ptrMap != 0 && size != ptrSize { + if ptrMap != 0 && size != goarch.PtrSize { panic("non-empty pointer map passed for non-pointer-size values") } if a.iregs+n > intArgRegs { @@ -413,7 +414,7 @@ func newAbiDesc(t *funcType, rcvr *rtype) abiDesc { stackPtrs.append(0) } } else { - spill += ptrSize + spill += goarch.PtrSize } } for i, arg := range t.in() { @@ -430,12 +431,12 @@ func newAbiDesc(t *funcType, rcvr *rtype) abiDesc { } } } - spill = align(spill, ptrSize) + spill = align(spill, goarch.PtrSize) // From the input parameters alone, we now know // the stackCallArgsSize and retOffset. stackCallArgsSize := in.stackBytes - retOffset := align(in.stackBytes, ptrSize) + retOffset := align(in.stackBytes, goarch.PtrSize) // Compute the stack frame pointer bitmap and register // pointer bitmap for return values. diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 0db5e132172..e3faa31c1f7 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -10,6 +10,7 @@ import ( "flag" "fmt" "go/token" + "internal/goarch" "io" "math" "math/rand" @@ -6457,10 +6458,10 @@ func clobber() { func TestFuncLayout(t *testing.T) { align := func(x uintptr) uintptr { - return (x + PtrSize - 1) &^ (PtrSize - 1) + return (x + goarch.PtrSize - 1) &^ (goarch.PtrSize - 1) } var r []byte - if PtrSize == 4 { + if goarch.PtrSize == 4 { r = []byte{0, 0, 0, 1} } else { r = []byte{0, 0, 1} @@ -6481,56 +6482,56 @@ func TestFuncLayout(t *testing.T) { tests := []test{ { typ: ValueOf(func(a, b string) string { return "" }).Type(), - size: 6 * PtrSize, - argsize: 4 * PtrSize, - retOffset: 4 * PtrSize, + size: 6 * goarch.PtrSize, + argsize: 4 * goarch.PtrSize, + retOffset: 4 * goarch.PtrSize, stack: []byte{1, 0, 1, 0, 1}, gc: []byte{1, 0, 1, 0, 1}, }, { typ: ValueOf(func(a, b, c uint32, p *byte, d uint16) {}).Type(), - size: align(align(3*4) + PtrSize + 2), - argsize: align(3*4) + PtrSize + 2, - retOffset: align(align(3*4) + PtrSize + 2), + size: align(align(3*4) + goarch.PtrSize + 2), + argsize: align(3*4) + goarch.PtrSize + 2, + retOffset: align(align(3*4) + goarch.PtrSize + 2), stack: r, gc: r, }, { typ: ValueOf(func(a map[int]int, b uintptr, c interface{}) {}).Type(), - size: 4 * PtrSize, - argsize: 4 * PtrSize, - retOffset: 4 * PtrSize, + size: 4 * goarch.PtrSize, + argsize: 4 * goarch.PtrSize, + retOffset: 4 * goarch.PtrSize, stack: []byte{1, 0, 1, 1}, gc: []byte{1, 0, 1, 1}, }, { typ: ValueOf(func(a S) {}).Type(), - size: 4 * PtrSize, - argsize: 4 * PtrSize, - retOffset: 4 * PtrSize, + size: 4 * goarch.PtrSize, + argsize: 4 * goarch.PtrSize, + retOffset: 4 * goarch.PtrSize, stack: []byte{0, 0, 1, 1}, gc: []byte{0, 0, 1, 1}, }, { rcvr: ValueOf((*byte)(nil)).Type(), typ: ValueOf(func(a uintptr, b *int) {}).Type(), - size: 3 * PtrSize, - argsize: 3 * PtrSize, - retOffset: 3 * PtrSize, + size: 3 * goarch.PtrSize, + argsize: 3 * goarch.PtrSize, + retOffset: 3 * goarch.PtrSize, stack: []byte{1, 0, 1}, gc: []byte{1, 0, 1}, }, { typ: ValueOf(func(a uintptr) {}).Type(), - size: PtrSize, - argsize: PtrSize, - retOffset: PtrSize, + size: goarch.PtrSize, + argsize: goarch.PtrSize, + retOffset: goarch.PtrSize, stack: []byte{}, gc: []byte{}, }, { typ: ValueOf(func() uintptr { return 0 }).Type(), - size: PtrSize, + size: goarch.PtrSize, argsize: 0, retOffset: 0, stack: []byte{}, @@ -6539,9 +6540,9 @@ func TestFuncLayout(t *testing.T) { { rcvr: ValueOf(uintptr(0)).Type(), typ: ValueOf(func(a uintptr) {}).Type(), - size: 2 * PtrSize, - argsize: 2 * PtrSize, - retOffset: 2 * PtrSize, + size: 2 * goarch.PtrSize, + argsize: 2 * goarch.PtrSize, + retOffset: 2 * goarch.PtrSize, stack: []byte{1}, gc: []byte{1}, // Note: this one is tricky, as the receiver is not a pointer. But we @@ -6747,7 +6748,7 @@ func TestGCBits(t *testing.T) { verifyGCBits(t, TypeOf(([][10000]Xscalar)(nil)), lit(1)) verifyGCBits(t, SliceOf(ArrayOf(10000, Tscalar)), lit(1)) - hdr := make([]byte, 8/PtrSize) + hdr := make([]byte, 8/goarch.PtrSize) verifyMapBucket := func(t *testing.T, k, e Type, m interface{}, want []byte) { verifyGCBits(t, MapBucketOf(k, e), want) @@ -6763,7 +6764,7 @@ func TestGCBits(t *testing.T) { join(hdr, rep(8, lit(0, 1)), rep(8, lit(1)), lit(1))) verifyMapBucket(t, Tint64, Tptr, map[int64]Xptr(nil), - join(hdr, rep(8, rep(8/PtrSize, lit(0))), rep(8, lit(1)), lit(1))) + join(hdr, rep(8, rep(8/goarch.PtrSize, lit(0))), rep(8, lit(1)), lit(1))) verifyMapBucket(t, Tscalar, Tscalar, map[Xscalar]Xscalar(nil), @@ -6773,20 +6774,20 @@ func TestGCBits(t *testing.T) { map[[2]Xscalarptr][3]Xptrscalar(nil), join(hdr, rep(8*2, lit(0, 1)), rep(8*3, lit(1, 0)), lit(1))) verifyMapBucket(t, - ArrayOf(64/PtrSize, Tscalarptr), ArrayOf(64/PtrSize, Tptrscalar), - map[[64 / PtrSize]Xscalarptr][64 / PtrSize]Xptrscalar(nil), - join(hdr, rep(8*64/PtrSize, lit(0, 1)), rep(8*64/PtrSize, lit(1, 0)), lit(1))) + ArrayOf(64/goarch.PtrSize, Tscalarptr), ArrayOf(64/goarch.PtrSize, Tptrscalar), + map[[64 / goarch.PtrSize]Xscalarptr][64 / goarch.PtrSize]Xptrscalar(nil), + join(hdr, rep(8*64/goarch.PtrSize, lit(0, 1)), rep(8*64/goarch.PtrSize, lit(1, 0)), lit(1))) verifyMapBucket(t, - ArrayOf(64/PtrSize+1, Tscalarptr), ArrayOf(64/PtrSize, Tptrscalar), - map[[64/PtrSize + 1]Xscalarptr][64 / PtrSize]Xptrscalar(nil), - join(hdr, rep(8, lit(1)), rep(8*64/PtrSize, lit(1, 0)), lit(1))) + ArrayOf(64/goarch.PtrSize+1, Tscalarptr), ArrayOf(64/goarch.PtrSize, Tptrscalar), + map[[64/goarch.PtrSize + 1]Xscalarptr][64 / goarch.PtrSize]Xptrscalar(nil), + join(hdr, rep(8, lit(1)), rep(8*64/goarch.PtrSize, lit(1, 0)), lit(1))) verifyMapBucket(t, - ArrayOf(64/PtrSize, Tscalarptr), ArrayOf(64/PtrSize+1, Tptrscalar), - map[[64 / PtrSize]Xscalarptr][64/PtrSize + 1]Xptrscalar(nil), - join(hdr, rep(8*64/PtrSize, lit(0, 1)), rep(8, lit(1)), lit(1))) + ArrayOf(64/goarch.PtrSize, Tscalarptr), ArrayOf(64/goarch.PtrSize+1, Tptrscalar), + map[[64 / goarch.PtrSize]Xscalarptr][64/goarch.PtrSize + 1]Xptrscalar(nil), + join(hdr, rep(8*64/goarch.PtrSize, lit(0, 1)), rep(8, lit(1)), lit(1))) verifyMapBucket(t, - ArrayOf(64/PtrSize+1, Tscalarptr), ArrayOf(64/PtrSize+1, Tptrscalar), - map[[64/PtrSize + 1]Xscalarptr][64/PtrSize + 1]Xptrscalar(nil), + ArrayOf(64/goarch.PtrSize+1, Tscalarptr), ArrayOf(64/goarch.PtrSize+1, Tptrscalar), + map[[64/goarch.PtrSize + 1]Xscalarptr][64/goarch.PtrSize + 1]Xptrscalar(nil), join(hdr, rep(8, lit(1)), rep(8, lit(1)), lit(1))) } diff --git a/src/reflect/export_test.go b/src/reflect/export_test.go index b6830a98020..e775eaf1350 100644 --- a/src/reflect/export_test.go +++ b/src/reflect/export_test.go @@ -5,6 +5,7 @@ package reflect import ( + "internal/goarch" "sync" "unsafe" ) @@ -22,7 +23,7 @@ func IsRO(v Value) bool { var CallGC = &callGC -const PtrSize = ptrSize +const PtrSize = goarch.PtrSize // FuncLayout calls funcLayout and returns a subset of the results for testing. // @@ -65,7 +66,7 @@ func FuncLayout(t Type, rcvr Type) (frametype Type, argSize, retOffset uintptr, // Expand frame type's GC bitmap into byte-map. ptrs = ft.ptrdata != 0 if ptrs { - nptrs := ft.ptrdata / ptrSize + nptrs := ft.ptrdata / goarch.PtrSize gcdata := ft.gcSlice(0, (nptrs+7)/8) for i := uintptr(0); i < nptrs; i++ { gc = append(gc, gcdata[i/8]>>(i%8)&1) diff --git a/src/reflect/swapper.go b/src/reflect/swapper.go index 0cf40666b1e..67b7fbe59be 100644 --- a/src/reflect/swapper.go +++ b/src/reflect/swapper.go @@ -5,6 +5,7 @@ package reflect import ( + "internal/goarch" "internal/unsafeheader" "unsafe" ) @@ -36,7 +37,7 @@ func Swapper(slice interface{}) func(i, j int) { // Some common & small cases, without using memmove: if hasPtr { - if size == ptrSize { + if size == goarch.PtrSize { ps := *(*[]unsafe.Pointer)(v.ptr) return func(i, j int) { ps[i], ps[j] = ps[j], ps[i] } } diff --git a/src/reflect/type.go b/src/reflect/type.go index df863ae106f..e119354af42 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -16,6 +16,7 @@ package reflect import ( + "internal/goarch" "internal/unsafeheader" "strconv" "sync" @@ -1924,13 +1925,13 @@ func MapOf(key, elem Type) Type { } mt.flags = 0 if ktyp.size > maxKeySize { - mt.keysize = uint8(ptrSize) + mt.keysize = uint8(goarch.PtrSize) mt.flags |= 1 // indirect key } else { mt.keysize = uint8(ktyp.size) } if etyp.size > maxValSize { - mt.valuesize = uint8(ptrSize) + mt.valuesize = uint8(goarch.PtrSize) mt.flags |= 2 // indirect value } else { mt.valuesize = uint8(etyp.size) @@ -2231,31 +2232,31 @@ func bucketOf(ktyp, etyp *rtype) *rtype { var ptrdata uintptr var overflowPad uintptr - size := bucketSize*(1+ktyp.size+etyp.size) + overflowPad + ptrSize + size := bucketSize*(1+ktyp.size+etyp.size) + overflowPad + goarch.PtrSize if size&uintptr(ktyp.align-1) != 0 || size&uintptr(etyp.align-1) != 0 { panic("reflect: bad size computation in MapOf") } if ktyp.ptrdata != 0 || etyp.ptrdata != 0 { - nptr := (bucketSize*(1+ktyp.size+etyp.size) + ptrSize) / ptrSize + nptr := (bucketSize*(1+ktyp.size+etyp.size) + goarch.PtrSize) / goarch.PtrSize mask := make([]byte, (nptr+7)/8) - base := bucketSize / ptrSize + base := bucketSize / goarch.PtrSize if ktyp.ptrdata != 0 { emitGCMask(mask, base, ktyp, bucketSize) } - base += bucketSize * ktyp.size / ptrSize + base += bucketSize * ktyp.size / goarch.PtrSize if etyp.ptrdata != 0 { emitGCMask(mask, base, etyp, bucketSize) } - base += bucketSize * etyp.size / ptrSize - base += overflowPad / ptrSize + base += bucketSize * etyp.size / goarch.PtrSize + base += overflowPad / goarch.PtrSize word := base mask[word/8] |= 1 << (word % 8) gcdata = &mask[0] - ptrdata = (word + 1) * ptrSize + ptrdata = (word + 1) * goarch.PtrSize // overflow word must be last if ptrdata != size { @@ -2264,7 +2265,7 @@ func bucketOf(ktyp, etyp *rtype) *rtype { } b := &rtype{ - align: ptrSize, + align: goarch.PtrSize, size: size, kind: uint8(Struct), ptrdata: ptrdata, @@ -2288,8 +2289,8 @@ func emitGCMask(out []byte, base uintptr, typ *rtype, n uintptr) { if typ.kind&kindGCProg != 0 { panic("reflect: unexpected GC program") } - ptrs := typ.ptrdata / ptrSize - words := typ.size / ptrSize + ptrs := typ.ptrdata / goarch.PtrSize + words := typ.size / goarch.PtrSize mask := typ.gcSlice(0, (ptrs+7)/8) for j := uintptr(0); j < ptrs; j++ { if (mask[j/8]>>(j%8))&1 != 0 { @@ -2312,7 +2313,7 @@ func appendGCProg(dst []byte, typ *rtype) []byte { } // Element is small with pointer mask; use as literal bits. - ptrs := typ.ptrdata / ptrSize + ptrs := typ.ptrdata / goarch.PtrSize mask := typ.gcSlice(0, (ptrs+7)/8) // Emit 120-bit chunks of full bytes (max is 127 but we avoid using partial bytes). @@ -2759,7 +2760,7 @@ func StructOf(fields []StructField) Type { } // Pad to start of this field with zeros. if ft.offset() > off { - n := (ft.offset() - off) / ptrSize + n := (ft.offset() - off) / goarch.PtrSize prog = append(prog, 0x01, 0x00) // emit a 0 bit if n > 1 { prog = append(prog, 0x81) // repeat previous bit @@ -2936,11 +2937,11 @@ func ArrayOf(length int, elem Type) Type { array.gcdata = typ.gcdata array.ptrdata = typ.ptrdata - case typ.kind&kindGCProg == 0 && array.size <= maxPtrmaskBytes*8*ptrSize: + case typ.kind&kindGCProg == 0 && array.size <= maxPtrmaskBytes*8*goarch.PtrSize: // Element is small with pointer mask; array is still small. // Create direct pointer mask by turning each 1 bit in elem // into length 1 bits in larger mask. - mask := make([]byte, (array.ptrdata/ptrSize+7)/8) + mask := make([]byte, (array.ptrdata/goarch.PtrSize+7)/8) emitGCMask(mask, 0, typ, array.len) array.gcdata = &mask[0] @@ -2950,8 +2951,8 @@ func ArrayOf(length int, elem Type) Type { prog := []byte{0, 0, 0, 0} // will be length of prog prog = appendGCProg(prog, typ) // Pad from ptrdata to size. - elemPtrs := typ.ptrdata / ptrSize - elemWords := typ.size / ptrSize + elemPtrs := typ.ptrdata / goarch.PtrSize + elemWords := typ.size / goarch.PtrSize if elemPtrs < elemWords { // Emit literal 0 bit, then repeat as needed. prog = append(prog, 0x01, 0x00) @@ -3063,13 +3064,13 @@ func funcLayout(t *funcType, rcvr *rtype) (frametype *rtype, framePool *sync.Poo // build dummy rtype holding gc program x := &rtype{ - align: ptrSize, + align: goarch.PtrSize, // Don't add spill space here; it's only necessary in // reflectcall's frame, not in the allocated frame. // TODO(mknyszek): Remove this comment when register // spill space in the frame is no longer required. - size: align(abi.retOffset+abi.ret.stackBytes, ptrSize), - ptrdata: uintptr(abi.stackPtrs.n) * ptrSize, + size: align(abi.retOffset+abi.ret.stackBytes, goarch.PtrSize), + ptrdata: uintptr(abi.stackPtrs.n) * goarch.PtrSize, } if abi.stackPtrs.n > 0 { x.gcdata = &abi.stackPtrs.data[0] @@ -3124,14 +3125,14 @@ func addTypeBits(bv *bitVector, offset uintptr, t *rtype) { switch Kind(t.kind & kindMask) { case Chan, Func, Map, Ptr, Slice, String, UnsafePointer: // 1 pointer at start of representation - for bv.n < uint32(offset/uintptr(ptrSize)) { + for bv.n < uint32(offset/uintptr(goarch.PtrSize)) { bv.append(0) } bv.append(1) case Interface: // 2 pointers - for bv.n < uint32(offset/uintptr(ptrSize)) { + for bv.n < uint32(offset/uintptr(goarch.PtrSize)) { bv.append(0) } bv.append(1) diff --git a/src/reflect/value.go b/src/reflect/value.go index 6ba6202a1a1..e5ad4d5cd53 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -6,6 +6,7 @@ package reflect import ( "internal/abi" + "internal/goarch" "internal/itoa" "internal/unsafeheader" "math" @@ -94,7 +95,7 @@ func (f flag) ro() flag { // v.Kind() must be Ptr, Map, Chan, Func, or UnsafePointer // if v.Kind() == Ptr, the base type must not be go:notinheap. func (v Value) pointer() unsafe.Pointer { - if v.typ.size != ptrSize || !v.typ.pointers() { + if v.typ.size != goarch.PtrSize || !v.typ.pointers() { panic("can't call pointer on a non-pointer Value") } if v.flag&flagIndir != 0 { @@ -533,7 +534,7 @@ func (v Value) call(op string, in []Value) []Value { } // TODO(mknyszek): Remove this when we no longer have // caller reserved spill space. - frameSize = align(frameSize, ptrSize) + frameSize = align(frameSize, goarch.PtrSize) frameSize += abi.spill // Mark pointers in registers for the return path. @@ -1043,7 +1044,7 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer, retValid *bool, regs *a methodFrameSize := methodFrameType.size // TODO(mknyszek): Remove this when we no longer have // caller reserved spill space. - methodFrameSize = align(methodFrameSize, ptrSize) + methodFrameSize = align(methodFrameSize, goarch.PtrSize) methodFrameSize += methodABI.spill // Mark pointers in registers for the return path. From bfd9b63f125aebfbe2de3b6fa0b329cae2120b20 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Wed, 16 Jun 2021 23:26:39 +0000 Subject: [PATCH 463/940] [dev.typeparams] reflect: delete unused ptrSize and PtrSize Change-Id: I522263eb5112b78639340b83d92e80a13f738bd4 Reviewed-on: https://go-review.googlesource.com/c/go/+/328811 Trust: Michael Knyszek Run-TryBot: Michael Knyszek TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/reflect/export_test.go | 2 -- src/reflect/value.go | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/reflect/export_test.go b/src/reflect/export_test.go index e775eaf1350..01749e30d85 100644 --- a/src/reflect/export_test.go +++ b/src/reflect/export_test.go @@ -23,8 +23,6 @@ func IsRO(v Value) bool { var CallGC = &callGC -const PtrSize = goarch.PtrSize - // FuncLayout calls funcLayout and returns a subset of the results for testing. // // Bitmaps like stack, gc, inReg, and outReg are expanded such that each bit diff --git a/src/reflect/value.go b/src/reflect/value.go index e5ad4d5cd53..d8a0b5245ed 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -14,8 +14,6 @@ import ( "unsafe" ) -const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const - // Value is the reflection interface to a Go value. // // Not all methods apply to all kinds of values. Restrictions, From 890a8407a9c30c0a1d08ff80100e4f53da7df17a Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Wed, 16 Jun 2021 22:07:16 +0000 Subject: [PATCH 464/940] [dev.typeparams] internal/reflectlite: use goarch.PtrSize instead of the duplicated ptrSize [generated] [git-generate] cd src/internal/reflectlite gofmt -w -r "ptrSize -> goarch.PtrSize" . goimports -w *.go Change-Id: I6a55f2aa035ed863785856ddd4fcc519dec15ac9 Reviewed-on: https://go-review.googlesource.com/c/go/+/328347 Trust: Michael Knyszek Run-TryBot: Michael Knyszek TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/internal/reflectlite/swapper.go | 3 ++- src/internal/reflectlite/value.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/internal/reflectlite/swapper.go b/src/internal/reflectlite/swapper.go index 6330ab2d346..ac081d49bbb 100644 --- a/src/internal/reflectlite/swapper.go +++ b/src/internal/reflectlite/swapper.go @@ -5,6 +5,7 @@ package reflectlite import ( + "internal/goarch" "internal/unsafeheader" "unsafe" ) @@ -36,7 +37,7 @@ func Swapper(slice interface{}) func(i, j int) { // Some common & small cases, without using memmove: if hasPtr { - if size == ptrSize { + if size == goarch.PtrSize { ps := *(*[]unsafe.Pointer)(v.ptr) return func(i, j int) { ps[i], ps[j] = ps[j], ps[i] } } diff --git a/src/internal/reflectlite/value.go b/src/internal/reflectlite/value.go index 0365eeeabf6..86dfcb5c362 100644 --- a/src/internal/reflectlite/value.go +++ b/src/internal/reflectlite/value.go @@ -5,6 +5,7 @@ package reflectlite import ( + "internal/goarch" "internal/unsafeheader" "runtime" "unsafe" @@ -90,7 +91,7 @@ func (f flag) ro() flag { // pointer returns the underlying pointer represented by v. // v.Kind() must be Ptr, Map, Chan, Func, or UnsafePointer func (v Value) pointer() unsafe.Pointer { - if v.typ.size != ptrSize || !v.typ.pointers() { + if v.typ.size != goarch.PtrSize || !v.typ.pointers() { panic("can't call pointer on a non-pointer Value") } if v.flag&flagIndir != 0 { From 9f50d9a0b41bc0618272535f84c3e518e74f2fea Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Wed, 16 Jun 2021 23:29:40 +0000 Subject: [PATCH 465/940] [dev.typeparams] internal/reflectlite: remove unused ptrSize Change-Id: Ia0da5e5d1e8d20327690cb53c9df067401f3428c Reviewed-on: https://go-review.googlesource.com/c/go/+/328812 Trust: Michael Knyszek Run-TryBot: Michael Knyszek TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/internal/reflectlite/value.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/internal/reflectlite/value.go b/src/internal/reflectlite/value.go index 86dfcb5c362..136273842ce 100644 --- a/src/internal/reflectlite/value.go +++ b/src/internal/reflectlite/value.go @@ -11,8 +11,6 @@ import ( "unsafe" ) -const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const - // Value is the reflection interface to a Go value. // // Not all methods apply to all kinds of values. Restrictions, From fb84d213a8551526913647b7dea6103233f550db Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Wed, 16 Jun 2021 19:08:52 +0000 Subject: [PATCH 466/940] [dev.typeparams] reflect: support big endian architectures in callMethod Currently, callMethod has some ABI translation code that is not agnostic of endianness. This change rectifies that by adding a method to internal/abi.RegArgs for safely returning an offset into a register slot that's endianness-dependent. No tests for this because it's just best-effort. There's no actual way to test this because we don't support a register ABI on any big endian architectures yet. Change-Id: Ic68d9ee1bfdea0fc2992d467d749e2b083e92de3 Reviewed-on: https://go-review.googlesource.com/c/go/+/328348 Trust: Michael Knyszek Run-TryBot: Michael Knyszek TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/go/build/deps_test.go | 4 ++-- src/internal/abi/abi.go | 45 ++++++++++++++++++++++++++++++++++++++- src/reflect/value.go | 11 ++++------ 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index b440f7d2351..80f8e1a00d7 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -77,8 +77,8 @@ var depsRules = ` unicode/utf8, unicode/utf16, unicode, unsafe; - # These packages depend only on unsafe. - unsafe + # These packages depend only on internal/goarch and unsafe. + internal/goarch, unsafe < internal/abi; # RUNTIME is the core runtime group of packages, all of them very light-weight. diff --git a/src/internal/abi/abi.go b/src/internal/abi/abi.go index aaff9cece35..eadff248d99 100644 --- a/src/internal/abi/abi.go +++ b/src/internal/abi/abi.go @@ -4,7 +4,10 @@ package abi -import "unsafe" +import ( + "internal/goarch" + "unsafe" +) // RegArgs is a struct that has space for each argument // and return value register on the current architecture. @@ -33,6 +36,46 @@ type RegArgs struct { ReturnIsPtr IntArgRegBitmap } +// IntRegArgAddr returns a pointer inside of r.Ints[reg] that is appropriately +// offset for an argument of size argSize. +// +// argSize must be non-zero, fit in a register, and a power-of-two. +// +// This method is a helper for dealing with the endianness of different CPU +// architectures, since sub-word-sized arguments in big endian architectures +// need to be "aligned" to the upper edge of the register to be interpreted +// by the CPU correctly. +func (r *RegArgs) IntRegArgAddr(reg int, argSize uintptr) unsafe.Pointer { + if argSize > goarch.PtrSize || argSize == 0 || argSize&(argSize-1) != 0 { + panic("invalid argSize") + } + offset := uintptr(0) + if goarch.BigEndian { + offset = goarch.PtrSize - argSize + } + return unsafe.Pointer(uintptr(unsafe.Pointer(&r.Ints[reg])) + offset) +} + +// FloatRegArgAddr returns a pointer inside of r.Floats[reg] that is appropriately +// offset for an argument of size argSize. +// +// argSize must be non-zero, fit in a register, and a power-of-two. +// +// This method is a helper for dealing with the endianness of different CPU +// architectures, since sub-word-sized arguments in big endian architectures +// need to be "aligned" to the upper edge of the register to be interpreted +// by the CPU correctly. +func (r *RegArgs) FloatRegArgAddr(reg int, argSize uintptr) unsafe.Pointer { + if argSize > EffectiveFloatRegSize || argSize == 0 || argSize&(argSize-1) != 0 { + panic("invalid argSize") + } + offset := uintptr(0) + if goarch.BigEndian { + offset = EffectiveFloatRegSize - argSize + } + return unsafe.Pointer(uintptr(unsafe.Pointer(&r.Floats[reg])) + offset) +} + // IntArgRegBitmap is a bitmap large enough to hold one bit per // integer argument/return register. type IntArgRegBitmap [(IntArgRegs + 7) / 8]uint8 diff --git a/src/reflect/value.go b/src/reflect/value.go index d8a0b5245ed..4341fd3f901 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -957,9 +957,6 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer, retValid *bool, regs *a // 2. Stack -> registers translation. // 3. Registers -> stack translation. // 4. Registers -> registers translation. - // TODO(mknyszek): Cases 2 and 3 below only work on little endian - // architectures. This is OK for now, but this needs to be fixed - // before supporting the register ABI on big endian architectures. // If the value ABI passes the value on the stack, // then the method ABI does too, because it has strictly @@ -985,9 +982,9 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer, retValid *bool, regs *a methodRegs.Ptrs[mStep.ireg] = *(*unsafe.Pointer)(from) fallthrough // We need to make sure this ends up in Ints, too. case abiStepIntReg: - memmove(unsafe.Pointer(&methodRegs.Ints[mStep.ireg]), from, mStep.size) + memmove(methodRegs.IntRegArgAddr(mStep.ireg, mStep.size), from, mStep.size) case abiStepFloatReg: - memmove(unsafe.Pointer(&methodRegs.Floats[mStep.freg]), from, mStep.size) + memmove(methodRegs.FloatRegArgAddr(mStep.freg, mStep.size), from, mStep.size) default: panic("unexpected method step") } @@ -1003,9 +1000,9 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer, retValid *bool, regs *a // Do the pointer copy directly so we get a write barrier. *(*unsafe.Pointer)(to) = valueRegs.Ptrs[vStep.ireg] case abiStepIntReg: - memmove(to, unsafe.Pointer(&valueRegs.Ints[vStep.ireg]), vStep.size) + memmove(to, valueRegs.IntRegArgAddr(vStep.ireg, vStep.size), vStep.size) case abiStepFloatReg: - memmove(to, unsafe.Pointer(&valueRegs.Floats[vStep.freg]), vStep.size) + memmove(to, valueRegs.FloatRegArgAddr(vStep.freg, vStep.size), vStep.size) default: panic("unexpected value step") } From 45f251ad6cfe0a8fa1aeac0c2c8e42bfe3549c29 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Thu, 17 Jun 2021 15:23:53 -0400 Subject: [PATCH 467/940] cmd/pprof,runtime/pprof: disable test on more broken platforms runtime/pprof has a more complete list of platforms with broken profiling than I used in cmd/pprof in https://golang.org/cl/325809. Duplicate that list in cmd/pprof and clean it up a bit in runtime/pprof for easier reference. Change-Id: I8f2580aac223de9b73cfff4355f49916f7b76493 Reviewed-on: https://go-review.googlesource.com/c/go/+/329149 Trust: Michael Pratt Run-TryBot: Michael Pratt Reviewed-by: Bryan C. Mills Reviewed-by: Cherry Mui TryBot-Result: Go Bot --- src/cmd/pprof/pprof_test.go | 17 +++++++++++++++++ src/runtime/pprof/pprof_test.go | 32 ++++++++++++++++++++++---------- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/cmd/pprof/pprof_test.go b/src/cmd/pprof/pprof_test.go index 170cdf3bb81..11e251bfde2 100644 --- a/src/cmd/pprof/pprof_test.go +++ b/src/cmd/pprof/pprof_test.go @@ -54,6 +54,22 @@ func buildPprof() error { return nil } +// See also runtime/pprof.cpuProfilingBroken. +func mustHaveCPUProfiling(t *testing.T) { + switch runtime.GOOS { + case "plan9": + t.Skipf("skipping on %s, unimplemented", runtime.GOOS) + case "aix": + t.Skipf("skipping on %s, issue 45170", runtime.GOOS) + case "ios", "dragonfly", "netbsd", "illumos", "solaris": + t.Skipf("skipping on %s, issue 13841", runtime.GOOS) + case "openbsd": + if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" { + t.Skipf("skipping on %s/%s, issue 13841", runtime.GOOS, runtime.GOARCH) + } + } +} + func mustHaveDisasm(t *testing.T) { switch runtime.GOARCH { case "mips", "mipsle", "mips64", "mips64le": @@ -77,6 +93,7 @@ func mustHaveDisasm(t *testing.T) { // // This is a regression test for issue 46636. func TestDisasm(t *testing.T) { + mustHaveCPUProfiling(t) mustHaveDisasm(t) testenv.MustHaveGoBuild(t) diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go index 7cbb4fc7ae4..f6ae15daabf 100644 --- a/src/runtime/pprof/pprof_test.go +++ b/src/runtime/pprof/pprof_test.go @@ -260,6 +260,27 @@ func parseProfile(t *testing.T, valBytes []byte, f func(uintptr, []*profile.Loca return p } +func cpuProfilingBroken() bool { + switch runtime.GOOS { + case "plan9": + // Profiling unimplemented. + return true + case "aix": + // See https://golang.org/issue/45170. + return true + case "ios", "dragonfly", "netbsd", "illumos", "solaris": + // See https://golang.org/issue/13841. + return true + case "openbsd": + if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" { + // See https://golang.org/issue/13841. + return true + } + } + + return false +} + // testCPUProfile runs f under the CPU profiler, checking for some conditions specified by need, // as interpreted by matches, and returns the parsed profile. func testCPUProfile(t *testing.T, matches matchFunc, need []string, avoid []string, f func(dur time.Duration)) *profile.Profile { @@ -275,16 +296,7 @@ func testCPUProfile(t *testing.T, matches matchFunc, need []string, avoid []stri t.Skip("skipping on plan9") } - broken := false - switch runtime.GOOS { - // See https://golang.org/issue/45170 for AIX. - case "ios", "dragonfly", "netbsd", "illumos", "solaris", "aix": - broken = true - case "openbsd": - if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" { - broken = true - } - } + broken := cpuProfilingBroken() maxDuration := 5 * time.Second if testing.Short() && broken { From feec53c4e5641f6a9f89ba9dcd8d89d84ea2717c Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 17 Jun 2021 15:36:23 -0700 Subject: [PATCH 468/940] [dev.typeparams] cmd/compile: skip types2 GC test during bootstrapping Unified includes a check to make sure that types2 memory has been garbage collected, but it relies on precise finalization, which we provide (for dynamically allocated objects, at least) but isn't guaranteed by the Go spec. In particular, Go 1.4 doesn't provide this. The check is strictly unnecessary and only exists to make sure we don't regress and start holding onto types2 memory accidentally. So just disable the check during bootstrap builds. Change-Id: Ie54fe53b2edba02c0b0b1e5ae39d81be8a0ace8d Reviewed-on: https://go-review.googlesource.com/c/go/+/329269 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/base/bootstrap_false.go | 11 +++++++++++ src/cmd/compile/internal/base/bootstrap_true.go | 11 +++++++++++ src/cmd/compile/internal/noder/unified.go | 10 ++++++++++ 3 files changed, 32 insertions(+) create mode 100644 src/cmd/compile/internal/base/bootstrap_false.go create mode 100644 src/cmd/compile/internal/base/bootstrap_true.go diff --git a/src/cmd/compile/internal/base/bootstrap_false.go b/src/cmd/compile/internal/base/bootstrap_false.go new file mode 100644 index 00000000000..de86644527d --- /dev/null +++ b/src/cmd/compile/internal/base/bootstrap_false.go @@ -0,0 +1,11 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !compiler_bootstrap + +package base + +// CompilerBootstrap reports whether the current compiler binary was +// built with -tags=compiler_bootstrap. +const CompilerBootstrap = false diff --git a/src/cmd/compile/internal/base/bootstrap_true.go b/src/cmd/compile/internal/base/bootstrap_true.go new file mode 100644 index 00000000000..81a17e1f6e5 --- /dev/null +++ b/src/cmd/compile/internal/base/bootstrap_true.go @@ -0,0 +1,11 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build compiler_bootstrap + +package base + +// CompilerBootstrap reports whether the current compiler binary was +// built with -tags=compiler_bootstrap. +const CompilerBootstrap = true diff --git a/src/cmd/compile/internal/noder/unified.go b/src/cmd/compile/internal/noder/unified.go index 9a41ea9dfe4..96c09164935 100644 --- a/src/cmd/compile/internal/noder/unified.go +++ b/src/cmd/compile/internal/noder/unified.go @@ -161,6 +161,16 @@ func writePkgStub(noders []*noder) string { // freePackage ensures the given package is garbage collected. func freePackage(pkg *types2.Package) { + // The GC test below relies on a precise GC that runs finalizers as + // soon as objects are unreachable. Our implementation provides + // this, but other/older implementations may not (e.g., Go 1.4 does + // not because of #22350). To avoid imposing unnecessary + // restrictions on the GOROOT_BOOTSTRAP toolchain, we skip the test + // during bootstrapping. + if base.CompilerBootstrap { + return + } + // Set a finalizer on pkg so we can detect if/when it's collected. done := make(chan struct{}) runtime.SetFinalizer(pkg, func(*types2.Package) { close(done) }) From 90096f445eaf78b954b9d37c47d137d4fcbd272c Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 15 Jun 2021 17:48:31 -0700 Subject: [PATCH 469/940] [dev.typeparams] cmd/compile/internal/syntax: convert (most) parser tests to new type set syntax Left a couple of tests with old notation so that we keep testing it while the notation is still supported. Change-Id: Ia6a3e7911af87eaccc7b06189c10f79789575a98 Reviewed-on: https://go-review.googlesource.com/c/go/+/328256 Trust: Robert Griesemer Run-TryBot: Robert Griesemer Reviewed-by: Robert Findley --- .../internal/syntax/testdata/go2/linalg.go2 | 16 ++--- .../syntax/testdata/go2/smoketest.go2 | 6 +- .../syntax/testdata/go2/typeinst2.go2 | 10 +-- .../syntax/testdata/go2/typeparams.go2 | 68 +++++++++---------- 4 files changed, 50 insertions(+), 50 deletions(-) diff --git a/src/cmd/compile/internal/syntax/testdata/go2/linalg.go2 b/src/cmd/compile/internal/syntax/testdata/go2/linalg.go2 index 0d27603a583..822d0287e74 100644 --- a/src/cmd/compile/internal/syntax/testdata/go2/linalg.go2 +++ b/src/cmd/compile/internal/syntax/testdata/go2/linalg.go2 @@ -9,10 +9,10 @@ import "math" // Numeric is type bound that matches any numeric type. // It would likely be in a constraints package in the standard library. type Numeric interface { - type int, int8, int16, int32, int64, - uint, uint8, uint16, uint32, uint64, uintptr, - float32, float64, - complex64, complex128 + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + float32 | ~float64 | + complex64 | ~complex128 } func DotProduct[T Numeric](s1, s2 []T) T { @@ -42,14 +42,14 @@ func AbsDifference[T NumericAbs[T]](a, b T) T { // OrderedNumeric is a type bound that matches numeric types that support the < operator. type OrderedNumeric interface { - type int, int8, int16, int32, int64, - uint, uint8, uint16, uint32, uint64, uintptr, - float32, float64 + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + float32 | ~float64 } // Complex is a type bound that matches the two complex types, which do not have a < operator. type Complex interface { - type complex64, complex128 + ~complex64 | ~complex128 } // OrderedAbs is a helper type that defines an Abs method for diff --git a/src/cmd/compile/internal/syntax/testdata/go2/smoketest.go2 b/src/cmd/compile/internal/syntax/testdata/go2/smoketest.go2 index e5cfba06125..42efb425275 100644 --- a/src/cmd/compile/internal/syntax/testdata/go2/smoketest.go2 +++ b/src/cmd/compile/internal/syntax/testdata/go2/smoketest.go2 @@ -46,12 +46,12 @@ type _ struct{ T[int] } // interfaces type _ interface{ m() - type int + ~int } type _ interface{ - type int, float, string - type complex128 + ~int | ~float | ~string + ~complex128 underlying(underlying underlying) underlying } diff --git a/src/cmd/compile/internal/syntax/testdata/go2/typeinst2.go2 b/src/cmd/compile/internal/syntax/testdata/go2/typeinst2.go2 index 6e2104a5150..f3deb703b67 100644 --- a/src/cmd/compile/internal/syntax/testdata/go2/typeinst2.go2 +++ b/src/cmd/compile/internal/syntax/testdata/go2/typeinst2.go2 @@ -175,12 +175,12 @@ type _ interface { // Interface type lists can contain any type, incl. *Named types. // Verify that we use the underlying type to compute the operational type. type MyInt int -func add1[T interface{type MyInt}](x T) T { +func add1[T interface{ ~MyInt }](x T) T { return x + 1 } type MyString string -func double[T interface{type MyInt, MyString}](x T) T { +func double[T interface{ ~MyInt | ~MyString }](x T) T { return x + x } @@ -189,15 +189,15 @@ func double[T interface{type MyInt, MyString}](x T) T { // type lists. type E0 interface { - type int, bool, string + ~int | ~bool | ~string } type E1 interface { - type int, float64, string + ~int | ~float64 | ~string } type E2 interface { - type float64 + ~float64 } type I0 interface { diff --git a/src/cmd/compile/internal/syntax/testdata/go2/typeparams.go2 b/src/cmd/compile/internal/syntax/testdata/go2/typeparams.go2 index f78037f0f5d..111f7c10042 100644 --- a/src/cmd/compile/internal/syntax/testdata/go2/typeparams.go2 +++ b/src/cmd/compile/internal/syntax/testdata/go2/typeparams.go2 @@ -48,22 +48,22 @@ func swapswap[A, B any](a A, b B) (A, B) { type F[A, B any] func(A, B) (B, A) -func min[T interface{ type int }](x, y T) T { +func min[T interface{ ~int }](x, y T) T { if x < y { return x } return y } -func _[T interface{type int, float32}](x, y T) bool { return x < y } +func _[T interface{ ~int | ~float32 }](x, y T) bool { return x < y } func _[T any](x, y T) bool { return x /* ERROR cannot compare */ < y } -func _[T interface{type int, float32, bool}](x, y T) bool { return x /* ERROR cannot compare */ < y } +func _[T interface{ ~int | ~float32 | ~bool }](x, y T) bool { return x /* ERROR cannot compare */ < y } func _[T C1[T]](x, y T) bool { return x /* ERROR cannot compare */ < y } func _[T C2[T]](x, y T) bool { return x < y } type C1[T any] interface{} -type C2[T any] interface{ type int, float32 } +type C2[T any] interface{ ~int | ~float32 } func new[T any]() *T { var x T @@ -91,40 +91,40 @@ var _ = f3[int, rune, bool](1, struct{x rune}{}, nil) // indexing func _[T any] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } -func _[T interface{ type int }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } -func _[T interface{ type string }] (x T, i int) { _ = x[i] } -func _[T interface{ type []int }] (x T, i int) { _ = x[i] } -func _[T interface{ type [10]int, *[20]int, map[string]int }] (x T, i int) { _ = x[i] } -func _[T interface{ type string, []byte }] (x T, i int) { _ = x[i] } -func _[T interface{ type []int, [1]rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } -func _[T interface{ type string, []rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } +func _[T interface{ ~int }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } +func _[T interface{ ~string }] (x T, i int) { _ = x[i] } +func _[T interface{ ~[]int }] (x T, i int) { _ = x[i] } +func _[T interface{ ~[10]int | ~*[20]int | ~map[string]int }] (x T, i int) { _ = x[i] } +func _[T interface{ ~string | ~[]byte }] (x T, i int) { _ = x[i] } +func _[T interface{ ~[]int | ~[1]rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } +func _[T interface{ ~string | ~[]rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } // slicing // TODO(gri) implement this -func _[T interface{ type string }] (x T, i, j, k int) { _ = x /* ERROR invalid operation */ [i:j:k] } +func _[T interface{ ~string }] (x T, i, j, k int) { _ = x /* ERROR invalid operation */ [i:j:k] } // len/cap built-ins func _[T any](x T) { _ = len(x /* ERROR invalid argument */ ) } -func _[T interface{ type int }](x T) { _ = len(x /* ERROR invalid argument */ ) } -func _[T interface{ type string, []byte, int }](x T) { _ = len(x /* ERROR invalid argument */ ) } -func _[T interface{ type string }](x T) { _ = len(x) } -func _[T interface{ type [10]int }](x T) { _ = len(x) } -func _[T interface{ type []byte }](x T) { _ = len(x) } -func _[T interface{ type map[int]int }](x T) { _ = len(x) } -func _[T interface{ type chan int }](x T) { _ = len(x) } -func _[T interface{ type string, []byte, chan int }](x T) { _ = len(x) } +func _[T interface{ ~int }](x T) { _ = len(x /* ERROR invalid argument */ ) } +func _[T interface{ ~string | ~[]byte | ~int }](x T) { _ = len(x /* ERROR invalid argument */ ) } +func _[T interface{ ~string }](x T) { _ = len(x) } +func _[T interface{ ~[10]int }](x T) { _ = len(x) } +func _[T interface{ ~[]byte }](x T) { _ = len(x) } +func _[T interface{ ~map[int]int }](x T) { _ = len(x) } +func _[T interface{ ~chan int }](x T) { _ = len(x) } +func _[T interface{ ~string | ~[]byte | ~chan int }](x T) { _ = len(x) } func _[T any](x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _[T interface{ type int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _[T interface{ type string, []byte, int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _[T interface{ type string }](x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _[T interface{ type [10]int }](x T) { _ = cap(x) } -func _[T interface{ type []byte }](x T) { _ = cap(x) } -func _[T interface{ type map[int]int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _[T interface{ type chan int }](x T) { _ = cap(x) } -func _[T interface{ type []byte, chan int }](x T) { _ = cap(x) } +func _[T interface{ ~int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } +func _[T interface{ ~string | ~[]byte | ~int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } +func _[T interface{ ~string }](x T) { _ = cap(x /* ERROR invalid argument */ ) } +func _[T interface{ ~[10]int }](x T) { _ = cap(x) } +func _[T interface{ ~[]byte }](x T) { _ = cap(x) } +func _[T interface{ ~map[int]int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } +func _[T interface{ ~chan int }](x T) { _ = cap(x) } +func _[T interface{ ~[]byte | ~chan int }](x T) { _ = cap(x) } // range iteration @@ -132,7 +132,7 @@ func _[T interface{}](x T) { for range x /* ERROR cannot range */ {} } -func _[T interface{ type string, []string }](x T) { +func _[T interface{ ~string | ~[]string }](x T) { for range x {} for i := range x { _ = i } for i, _ := range x { _ = i } @@ -144,23 +144,23 @@ func _[T interface{ type string, []string }](x T) { } -func _[T interface{ type string, []rune, map[int]rune }](x T) { +func _[T interface{ ~string | ~[]rune | ~map[int]rune }](x T) { for _, e := range x { _ = e } for i, e := range x { _ = i; _ = e } } -func _[T interface{ type string, []rune, map[string]rune }](x T) { +func _[T interface{ ~string | ~[]rune | ~map[string]rune }](x T) { for _, e := range x { _ = e } for i, e := range x /* ERROR must have the same key type */ { _ = e } } -func _[T interface{ type string, chan int }](x T) { +func _[T interface{ ~string | ~chan int }](x T) { for range x {} for i := range x { _ = i } for i, _ := range x { _ = i } // TODO(gri) should get an error here: channels only return one value } -func _[T interface{ type string, chan<-int }](x T) { +func _[T interface{ ~string | ~chan<-int }](x T) { for i := range x /* ERROR send-only channel */ { _ = i } } @@ -388,7 +388,7 @@ func _[T any](x T) { } } -func _[T interface{type int}](x T) { +func _[T interface{ ~int }](x T) { _ = x /* ERROR not an interface */ .(int) switch x /* ERROR not an interface */ .(type) { } From 2a7900762c24a4b04d0d51c833e22bc319d0234e Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Thu, 17 Jun 2021 10:14:07 +0700 Subject: [PATCH 470/940] [dev.typeparams] go/types: report better error for invalid untyped operation This is port of CL 328053 for types2 to go/type. The change is identical, but for some tweaks to the error positions in tests. Updates #46749 Change-Id: I8d34c5b1669e59e4ec7d91f81dcf655b2bfd89a5 Reviewed-on: https://go-review.googlesource.com/c/go/+/328869 Trust: Cuong Manh Le Trust: Robert Griesemer Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Robert Findley Reviewed-by: Robert Griesemer --- src/go/types/errorcodes.go | 2 +- src/go/types/expr.go | 28 +++++++++++++++++++------- src/go/types/testdata/check/const0.src | 2 +- src/go/types/testdata/check/decls1.src | 2 +- src/go/types/testdata/check/expr1.src | 4 ++-- src/go/types/testdata/check/expr2.src | 2 +- src/go/types/testdata/check/expr3.src | 2 +- src/go/types/testdata/check/stmt0.src | 12 +++++------ 8 files changed, 34 insertions(+), 20 deletions(-) diff --git a/src/go/types/errorcodes.go b/src/go/types/errorcodes.go index 2afb6a383c9..bcc850f7538 100644 --- a/src/go/types/errorcodes.go +++ b/src/go/types/errorcodes.go @@ -875,7 +875,7 @@ const ( // context in which it is used. // // Example: - // var _ = 1 + "" + // var _ = 1 + nil _InvalidUntypedConversion // _BadOffsetofSyntax occurs when unsafe.Offsetof is called with an argument diff --git a/src/go/types/expr.go b/src/go/types/expr.go index b7cc6e8ae7b..402d96f66a4 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -927,14 +927,28 @@ func (check *Checker) binary(x *operand, e ast.Expr, lhs, rhs ast.Expr, op token return } - check.convertUntyped(x, y.typ) - if x.mode == invalid { - return + canMix := func(x, y *operand) bool { + if IsInterface(x.typ) || IsInterface(y.typ) { + return true + } + if isBoolean(x.typ) != isBoolean(y.typ) { + return false + } + if isString(x.typ) != isString(y.typ) { + return false + } + return true } - check.convertUntyped(&y, x.typ) - if y.mode == invalid { - x.mode = invalid - return + if canMix(x, &y) { + check.convertUntyped(x, y.typ) + if x.mode == invalid { + return + } + check.convertUntyped(&y, x.typ) + if y.mode == invalid { + x.mode = invalid + return + } } if isComparison(op) { diff --git a/src/go/types/testdata/check/const0.src b/src/go/types/testdata/check/const0.src index 5608b1549ba..3cffdf904c8 100644 --- a/src/go/types/testdata/check/const0.src +++ b/src/go/types/testdata/check/const0.src @@ -27,7 +27,7 @@ const ( ub1 = true ub2 = 2 < 1 ub3 = ui1 == uf1 - ub4 = true /* ERROR "cannot convert" */ == 0 + ub4 = true /* ERROR "mismatched types untyped bool and untyped int" */ == 0 // integer values ui0 = 0 diff --git a/src/go/types/testdata/check/decls1.src b/src/go/types/testdata/check/decls1.src index f4d2eaba911..6fe349b0b2f 100644 --- a/src/go/types/testdata/check/decls1.src +++ b/src/go/types/testdata/check/decls1.src @@ -83,7 +83,7 @@ var ( // Constant expression initializations var ( - v1 = 1 /* ERROR "cannot convert" */ + "foo" + v1 = 1 /* ERROR "mismatched types untyped int and untyped string" */ + "foo" v2 = c + 255 v3 = c + 256 /* ERROR "overflows" */ v4 = r + 2147483647 diff --git a/src/go/types/testdata/check/expr1.src b/src/go/types/testdata/check/expr1.src index 4ead815158f..42b95fbb37b 100644 --- a/src/go/types/testdata/check/expr1.src +++ b/src/go/types/testdata/check/expr1.src @@ -111,10 +111,10 @@ type mystring string func _(x, y string, z mystring) { x = x + "foo" x = x /* ERROR not defined */ - "foo" - x = x + 1 // ERROR cannot convert + x = x /* ERROR mismatched types string and untyped int */ + 1 x = x + y x = x /* ERROR not defined */ - y - x = x * 10 // ERROR cannot convert + x = x /* ERROR mismatched types string and untyped int */* 10 } func f() (a, b int) { return } diff --git a/src/go/types/testdata/check/expr2.src b/src/go/types/testdata/check/expr2.src index 0c959e80119..f9726b5de53 100644 --- a/src/go/types/testdata/check/expr2.src +++ b/src/go/types/testdata/check/expr2.src @@ -10,7 +10,7 @@ func _bool() { const t = true == true const f = true == false _ = t /* ERROR "cannot compare" */ < f - _ = 0 /* ERROR "cannot convert" */ == t + _ = 0 /* ERROR "mismatched types untyped int and untyped bool" */ == t var b bool var x, y float32 b = x < y diff --git a/src/go/types/testdata/check/expr3.src b/src/go/types/testdata/check/expr3.src index 0525a5a33ae..3ab367810f5 100644 --- a/src/go/types/testdata/check/expr3.src +++ b/src/go/types/testdata/check/expr3.src @@ -103,7 +103,7 @@ func indexes() { var ok mybool _, ok = m["bar"] _ = ok - _ = m[0 /* ERROR "cannot use 0" */ ] + "foo" // ERROR "cannot convert" + _ = m/* ERROR "mismatched types int and untyped string" */[0 /* ERROR "cannot use 0" */ ] + "foo" var t string _ = t[- /* ERROR "negative" */ 1] diff --git a/src/go/types/testdata/check/stmt0.src b/src/go/types/testdata/check/stmt0.src index 76b6e70d63b..15df37703c1 100644 --- a/src/go/types/testdata/check/stmt0.src +++ b/src/go/types/testdata/check/stmt0.src @@ -49,18 +49,18 @@ func assignments1() { b = true i += 1 - i += "foo" /* ERROR "cannot convert.*int" */ + i /* ERROR "mismatched types int and untyped string" */+= "foo" f -= 1 f /= 0 f = float32(0)/0 /* ERROR "division by zero" */ - f -= "foo" /* ERROR "cannot convert.*float64" */ + f /* ERROR "mismatched types float64 and untyped string" */-= "foo" c *= 1 c /= 0 s += "bar" - s += 1 /* ERROR "cannot convert.*string" */ + s /* ERROR "mismatched types string and untyped int" */+= 1 var u64 uint64 u64 += 1< Date: Fri, 18 Jun 2021 03:14:09 +0000 Subject: [PATCH 471/940] [dev.typeparams] cmd/go: include new internal packages in TestNewReleaseRebuildsStalePackagesInGOPATH CL 328336 introduced two new packages that the runtime and other low-level packages depend on. Include them as targets to copy in this test with other such packages. Fixes the dev.typeparams longtest builders. Change-Id: Ia886f0264962a68acd06ebca002eef8515f06487 Reviewed-on: https://go-review.googlesource.com/c/go/+/329251 Trust: Michael Knyszek Run-TryBot: Michael Knyszek TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/go/go_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index c0c86ab9f58..eaafe792352 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -806,7 +806,9 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) { "src/internal/abi", "src/internal/bytealg", "src/internal/cpu", + "src/internal/goarch", "src/internal/goexperiment", + "src/internal/goos", "src/math/bits", "src/unsafe", filepath.Join("pkg", runtime.GOOS+"_"+runtime.GOARCH), From 54fe57bc22f7890810bbddae2499eda8d4acfaef Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 17 Jun 2021 01:12:23 -0700 Subject: [PATCH 472/940] [dev.typeparams] cmd/compile: record writer's stack at export data sync points This CL extends the unified export data format's existing sync mechanism to save writer stacks, controlled by the -d=syncframes debug flag. This allows readers to provide more details when reporting desync errors, which should simplify development of the data format and the various reader/writer implementations. For example, CL 328051 updated reader and writer, but missed making a similar change to the linker (fix in CL 328054). Re-reviewing the CL in isolation after the failure, it was not immediately obvious what was going wrong. But the pair of stack traces below identifies exactly what happened: it should have updated linker.relocFuncExt to write out the new sync marker too. ``` data sync error: package "internal/abi", section 6, index 4, offset 536 found UseReloc, written at: /home/mdempsky/wd/go/src/cmd/compile/internal/noder/encoder.go:221: (*encoder).reloc +0x44 /home/mdempsky/wd/go/src/cmd/compile/internal/noder/linker.go:214: (*linker).relocFuncExt +0x580 /home/mdempsky/wd/go/src/cmd/compile/internal/noder/linker.go:233: (*linker).relocTypeExt +0x234 /home/mdempsky/wd/go/src/cmd/compile/internal/noder/linker.go:161: (*linker).relocObj +0x2198 /home/mdempsky/wd/go/src/cmd/compile/internal/noder/linker.go:64: (*linker).relocIdx +0x196 expected ImplicitTypes, reading at: /home/mdempsky/wd/go/src/cmd/compile/internal/noder/reader.go:796: (*reader).implicitTypes +0x36 /home/mdempsky/wd/go/src/cmd/compile/internal/noder/reader.go:810: (*reader).addBody +0x81 /home/mdempsky/wd/go/src/cmd/compile/internal/noder/reader.go:727: (*reader).funcExt +0x542 /home/mdempsky/wd/go/src/cmd/compile/internal/noder/reader.go:651: (*reader).method +0x324 /home/mdempsky/wd/go/src/cmd/compile/internal/noder/reader.go:557: (*pkgReader).objIdx +0x2704 ``` Change-Id: I911193edd2a965f81b7459f15fb613a773584685 Reviewed-on: https://go-review.googlesource.com/c/go/+/328909 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Trust: Matthew Dempsky Reviewed-by: Cuong Manh Le Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/base/debug.go | 1 + src/cmd/compile/internal/noder/decoder.go | 100 ++++++++++++++---- src/cmd/compile/internal/noder/encoder.go | 83 +++++++++++---- src/cmd/compile/internal/noder/frames_go1.go | 20 ++++ src/cmd/compile/internal/noder/frames_go17.go | 24 +++++ src/cmd/compile/internal/noder/reader.go | 2 +- src/cmd/compile/internal/noder/sync.go | 33 +++++- src/cmd/compile/internal/noder/writer.go | 2 +- 8 files changed, 219 insertions(+), 46 deletions(-) create mode 100644 src/cmd/compile/internal/noder/frames_go1.go create mode 100644 src/cmd/compile/internal/noder/frames_go17.go diff --git a/src/cmd/compile/internal/base/debug.go b/src/cmd/compile/internal/base/debug.go index 824a8baa832..fd420219466 100644 --- a/src/cmd/compile/internal/base/debug.go +++ b/src/cmd/compile/internal/base/debug.go @@ -44,6 +44,7 @@ type DebugFlags struct { Panic int `help:"show all compiler panics"` Slice int `help:"print information about slice compilation"` SoftFloat int `help:"force compiler to emit soft-float code"` + SyncFrames int `help:"how many writer stack frames to include at sync points in unified export data"` TypeAssert int `help:"print information about type assertion inlining"` TypecheckInl int `help:"eager typechecking of inline function bodies"` Unified int `help:"enable unified IR construction"` diff --git a/src/cmd/compile/internal/noder/decoder.go b/src/cmd/compile/internal/noder/decoder.go index 023388875c4..3dc61c6a692 100644 --- a/src/cmd/compile/internal/noder/decoder.go +++ b/src/cmd/compile/internal/noder/decoder.go @@ -13,6 +13,7 @@ import ( "go/token" "math/big" "os" + "runtime" "strings" "cmd/compile/internal/base" @@ -131,17 +132,82 @@ func (r *decoder) checkErr(err error) { } } -func (r *decoder) sync(m syncMarker) { - if debug { - pos, err0 := r.data.Seek(0, os.SEEK_CUR) - x, err := r.data.ReadByte() - r.checkErr(err) - if x != byte(m) { - // TODO(mdempsky): Revisit this error message, and make it more - // useful (e.g., include r.p.pkgPath). - base.Fatalf("data sync error: found %v at %v (%v) in (%v:%v), but expected %v", syncMarker(x), pos, err0, r.k, r.idx, m) - } +func (r *decoder) rawUvarint() uint64 { + x, err := binary.ReadUvarint(&r.data) + r.checkErr(err) + return x +} + +func (r *decoder) rawVarint() int64 { + ux := r.rawUvarint() + + // Zig-zag decode. + x := int64(ux >> 1) + if ux&1 != 0 { + x = ^x } + return x +} + +func (r *decoder) rawReloc(k reloc, idx int) int { + e := r.relocs[idx] + assert(e.kind == k) + return e.idx +} + +func (r *decoder) sync(mWant syncMarker) { + if !enableSync { + return + } + + pos, _ := r.data.Seek(0, os.SEEK_CUR) // TODO(mdempsky): io.SeekCurrent after #44505 is resolved + mHave := syncMarker(r.rawUvarint()) + writerPCs := make([]int, r.rawUvarint()) + for i := range writerPCs { + writerPCs[i] = int(r.rawUvarint()) + } + + if mHave == mWant { + return + } + + // There's some tension here between printing: + // + // (1) full file paths that tools can recognize (e.g., so emacs + // hyperlinks the "file:line" text for easy navigation), or + // + // (2) short file paths that are easier for humans to read (e.g., by + // omitting redundant or irrelevant details, so it's easier to + // focus on the useful bits that remain). + // + // The current formatting favors the former, as it seems more + // helpful in practice. But perhaps the formatting could be improved + // to better address both concerns. For example, use relative file + // paths if they would be shorter, or rewrite file paths to contain + // "$GOROOT" (like objabi.AbsFile does) if tools can be taught how + // to reliably expand that again. + + fmt.Printf("export data desync: package %q, section %v, index %v, offset %v\n", r.common.pkgPath, r.k, r.idx, pos) + + fmt.Printf("\nfound %v, written at:\n", mHave) + if len(writerPCs) == 0 { + fmt.Printf("\t[stack trace unavailable; recompile package %q with -d=syncframes]\n", r.common.pkgPath) + } + for _, pc := range writerPCs { + fmt.Printf("\t%s\n", r.common.stringIdx(r.rawReloc(relocString, pc))) + } + + fmt.Printf("\nexpected %v, reading at:\n", mWant) + var readerPCs [32]uintptr // TODO(mdempsky): Dynamically size? + n := runtime.Callers(2, readerPCs[:]) + for _, pc := range fmtFrames(readerPCs[:n]...) { + fmt.Printf("\t%s\n", pc) + } + + // We already printed a stack trace for the reader, so now we can + // simply exit. Printing a second one with panic or base.Fatalf + // would just be noise. + os.Exit(1) } func (r *decoder) bool() bool { @@ -154,16 +220,12 @@ func (r *decoder) bool() bool { func (r *decoder) int64() int64 { r.sync(syncInt64) - x, err := binary.ReadVarint(&r.data) - r.checkErr(err) - return x + return r.rawVarint() } func (r *decoder) uint64() uint64 { r.sync(syncUint64) - x, err := binary.ReadUvarint(&r.data) - r.checkErr(err) - return x + return r.rawUvarint() } func (r *decoder) len() int { x := r.uint64(); v := int(x); assert(uint64(v) == x); return v } @@ -177,11 +239,7 @@ func (r *decoder) code(mark syncMarker) int { func (r *decoder) reloc(k reloc) int { r.sync(syncUseReloc) - idx := r.len() - - e := r.relocs[idx] - assert(e.kind == k) - return e.idx + return r.rawReloc(k, r.len()) } func (r *decoder) string() string { diff --git a/src/cmd/compile/internal/noder/encoder.go b/src/cmd/compile/internal/noder/encoder.go index dc288dc29fe..d8ab0f6255d 100644 --- a/src/cmd/compile/internal/noder/encoder.go +++ b/src/cmd/compile/internal/noder/encoder.go @@ -13,6 +13,7 @@ import ( "go/constant" "io" "math/big" + "runtime" "cmd/compile/internal/base" ) @@ -93,6 +94,8 @@ type encoder struct { relocs []relocEnt data bytes.Buffer + encodingRelocHeader bool + k reloc idx int } @@ -107,6 +110,10 @@ func (w *encoder) flush() int { // TODO(mdempsky): Consider writing these out separately so they're // easier to strip, along with function bodies, so that we can prune // down to just the data that's relevant to go/types. + if w.encodingRelocHeader { + base.Fatalf("encodingRelocHeader already true; recursive flush?") + } + w.encodingRelocHeader = true w.sync(syncRelocs) w.len(len(w.relocs)) for _, rent := range w.relocs { @@ -128,10 +135,58 @@ func (w *encoder) checkErr(err error) { } } +func (w *encoder) rawUvarint(x uint64) { + var buf [binary.MaxVarintLen64]byte + n := binary.PutUvarint(buf[:], x) + _, err := w.data.Write(buf[:n]) + w.checkErr(err) +} + +func (w *encoder) rawVarint(x int64) { + // Zig-zag encode. + ux := uint64(x) << 1 + if x < 0 { + ux = ^ux + } + + w.rawUvarint(ux) +} + +func (w *encoder) rawReloc(r reloc, idx int) int { + // TODO(mdempsky): Use map for lookup. + for i, rent := range w.relocs { + if rent.kind == r && rent.idx == idx { + return i + } + } + + i := len(w.relocs) + w.relocs = append(w.relocs, relocEnt{r, idx}) + return i +} + func (w *encoder) sync(m syncMarker) { - if debug { - err := w.data.WriteByte(byte(m)) - w.checkErr(err) + if !enableSync { + return + } + + // Writing out stack frame string references requires working + // relocations, but writing out the relocations themselves involves + // sync markers. To prevent infinite recursion, we simply trim the + // stack frame for sync markers within the relocation header. + var frames []string + if !w.encodingRelocHeader && base.Debug.SyncFrames > 0 { + pcs := make([]uintptr, base.Debug.SyncFrames) + n := runtime.Callers(2, pcs) + frames = fmtFrames(pcs[:n]...) + } + + // TODO(mdempsky): Save space by writing out stack frames as a + // linked list so we can share common stack frames. + w.rawUvarint(uint64(m)) + w.rawUvarint(uint64(len(frames))) + for _, frame := range frames { + w.rawUvarint(uint64(w.rawReloc(relocString, w.p.stringIdx(frame)))) } } @@ -148,18 +203,12 @@ func (w *encoder) bool(b bool) bool { func (w *encoder) int64(x int64) { w.sync(syncInt64) - var buf [binary.MaxVarintLen64]byte - n := binary.PutVarint(buf[:], x) - _, err := w.data.Write(buf[:n]) - w.checkErr(err) + w.rawVarint(x) } func (w *encoder) uint64(x uint64) { w.sync(syncUint64) - var buf [binary.MaxVarintLen64]byte - n := binary.PutUvarint(buf[:], x) - _, err := w.data.Write(buf[:n]) - w.checkErr(err) + w.rawUvarint(x) } func (w *encoder) len(x int) { assert(x >= 0); w.uint64(uint64(x)) } @@ -168,17 +217,7 @@ func (w *encoder) uint(x uint) { w.uint64(uint64(x)) } func (w *encoder) reloc(r reloc, idx int) { w.sync(syncUseReloc) - - // TODO(mdempsky): Use map for lookup. - for i, rent := range w.relocs { - if rent.kind == r && rent.idx == idx { - w.len(i) - return - } - } - - w.len(len(w.relocs)) - w.relocs = append(w.relocs, relocEnt{r, idx}) + w.len(w.rawReloc(r, idx)) } func (w *encoder) code(c code) { diff --git a/src/cmd/compile/internal/noder/frames_go1.go b/src/cmd/compile/internal/noder/frames_go1.go new file mode 100644 index 00000000000..2958efd6222 --- /dev/null +++ b/src/cmd/compile/internal/noder/frames_go1.go @@ -0,0 +1,20 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !go1.7 + +// TODO(mdempsky): Remove after #44505 is resolved + +package noder + +import "runtime" + +func walkFrames(pcs []uintptr, visit frameVisitor) { + for _, pc := range pcs { + fn := runtime.FuncForPC(pc) + file, line := fn.FileLine(pc) + + visit(file, line, fn.Name(), pc-fn.Entry()) + } +} diff --git a/src/cmd/compile/internal/noder/frames_go17.go b/src/cmd/compile/internal/noder/frames_go17.go new file mode 100644 index 00000000000..273217e39a1 --- /dev/null +++ b/src/cmd/compile/internal/noder/frames_go17.go @@ -0,0 +1,24 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.7 + +package noder + +import "runtime" + +func walkFrames(pcs []uintptr, visit frameVisitor) { + if len(pcs) == 0 { + return + } + + frames := runtime.CallersFrames(pcs) + for { + frame, more := frames.Next() + visit(frame.File, frame.Line, frame.Function, frame.PC-frame.Entry) + if !more { + return + } + } +} diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 803acaa88dc..efa607e13ba 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -910,7 +910,7 @@ func (r *reader) addLocal(name *ir.Name, ctxt ir.Class) { assert(ctxt == ir.PAUTO || ctxt == ir.PPARAM || ctxt == ir.PPARAMOUT) r.sync(syncAddLocal) - if debug { + if enableSync { want := r.int() if have := len(r.locals); have != want { base.FatalfAt(name.Pos(), "locals table has desynced") diff --git a/src/cmd/compile/internal/noder/sync.go b/src/cmd/compile/internal/noder/sync.go index 7326a6edbef..aef98dbd788 100644 --- a/src/cmd/compile/internal/noder/sync.go +++ b/src/cmd/compile/internal/noder/sync.go @@ -6,8 +6,39 @@ package noder -const debug = true +import ( + "fmt" + "strings" +) +// enableSync controls whether sync markers are written into unified +// IR's export data format and also whether they're expected when +// reading them back in. They're inessential to the correct +// functioning of unified IR, but are helpful during development to +// detect mistakes. +// +// When sync is enabled, writer stack frames will also be included in +// the export data. Currently, a fixed number of frames are included, +// controlled by -d=syncframes (default 0). +const enableSync = true + +// fmtFrames formats a backtrace for reporting reader/writer desyncs. +func fmtFrames(pcs ...uintptr) []string { + res := make([]string, 0, len(pcs)) + walkFrames(pcs, func(file string, line int, name string, offset uintptr) { + // Trim package from function name. It's just redundant noise. + name = strings.TrimPrefix(name, "cmd/compile/internal/noder.") + + res = append(res, fmt.Sprintf("%s:%v: %s +0x%v", file, line, name, offset)) + }) + return res +} + +type frameVisitor func(file string, line int, name string, offset uintptr) + +// syncMarker is an enum type that represents markers that may be +// written to export data to ensure the reader and writer stay +// synchronized. type syncMarker int //go:generate stringer -type=syncMarker -trimprefix=sync diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go index 1475540d84c..cc749b0d1e5 100644 --- a/src/cmd/compile/internal/noder/writer.go +++ b/src/cmd/compile/internal/noder/writer.go @@ -733,7 +733,7 @@ func (w *writer) funcarg(param *types2.Var, result bool) { func (w *writer) addLocal(obj types2.Object) { w.sync(syncAddLocal) idx := len(w.localsIdx) - if debug { + if enableSync { w.int(idx) } w.localsIdx[obj] = idx From 6fa043795870305d96a1e4c0f276ac431f688524 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Thu, 17 Jun 2021 22:51:45 +0700 Subject: [PATCH 473/940] [dev.typeparams] cmd/compile: add documentation for unified IR pipeline While at it, also rename "useUnifiedIR" to "unified", to be consistent with "-d=unified" and "GOEXPERIMENT=unified". Change-Id: I48ffdb4b36368343893b74f174608f5f59278249 Reviewed-on: https://go-review.googlesource.com/c/go/+/328989 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/noder/noder.go | 2 +- src/cmd/compile/internal/noder/quirks.go | 2 +- src/cmd/compile/internal/noder/unified.go | 50 ++++++++++++++++++++--- 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go index c7970396f8d..3d83129aea6 100644 --- a/src/cmd/compile/internal/noder/noder.go +++ b/src/cmd/compile/internal/noder/noder.go @@ -77,7 +77,7 @@ func LoadPackage(filenames []string) { base.Timer.AddEvent(int64(lines), "lines") if base.Debug.Unified != 0 { - useUnifiedIR(noders) + unified(noders) return } diff --git a/src/cmd/compile/internal/noder/quirks.go b/src/cmd/compile/internal/noder/quirks.go index 9f33fc576d9..28a729f2763 100644 --- a/src/cmd/compile/internal/noder/quirks.go +++ b/src/cmd/compile/internal/noder/quirks.go @@ -20,7 +20,7 @@ import ( // -cmp when compared against the legacy frontend behavior, but can be // removed after that's no longer a concern. -// quirksMode controls whether behavior specific to satsifying +// quirksMode controls whether behavior specific to satisfying // toolstash -cmp is used. func quirksMode() bool { // Currently, unified IR doesn't try to be compatible with diff --git a/src/cmd/compile/internal/noder/unified.go b/src/cmd/compile/internal/noder/unified.go index 96c09164935..7a1bb88537a 100644 --- a/src/cmd/compile/internal/noder/unified.go +++ b/src/cmd/compile/internal/noder/unified.go @@ -28,9 +28,48 @@ import ( // later. var localPkgReader *pkgReader -// useUnifiedIR reports whether the unified IR frontend should be -// used; and if so, uses it to construct the local package's IR. -func useUnifiedIR(noders []*noder) { +// unified construct the local package's IR from syntax's AST. +// +// The pipeline contains 2 steps: +// +// (1) Generate package export data "stub". +// +// (2) Generate package IR from package export data. +// +// The package data "stub" at step (1) contains everything from the local package, +// but nothing that have been imported. When we're actually writing out export data +// to the output files (see writeNewExport function), we run the "linker", which does +// a few things: +// +// + Updates compiler extensions data (e.g., inlining cost, escape analysis results). +// +// + Handles re-exporting any transitive dependencies. +// +// + Prunes out any unnecessary details (e.g., non-inlineable functions, because any +// downstream importers only care about inlinable functions). +// +// The source files are typechecked twice, once before writing export data +// using types2 checker, once after read export data using gc/typecheck. +// This duplication of work will go away once we always use types2 checker, +// we can remove the gc/typecheck pass. The reason it is still here: +// +// + It reduces engineering costs in maintaining a fork of typecheck +// (e.g., no need to backport fixes like CL 327651). +// +// + It makes it easier to pass toolstash -cmp. +// +// + Historically, we would always re-run the typechecker after import, even though +// we know the imported data is valid. It's not ideal, but also not causing any +// problem either. +// +// + There's still transformation that being done during gc/typecheck, like rewriting +// multi-valued function call, or transform ir.OINDEX -> ir.OINDEXMAP. +// +// Using syntax+types2 tree, which already has a complete representation of generics, +// the unified IR has the full typed AST for doing introspection during step (1). +// In other words, we have all necessary information to build the generic IR form +// (see writer.captureVars for an example). +func unified(noders []*noder) { inline.NewInline = InlineCall if !quirksMode() { @@ -111,8 +150,9 @@ func useUnifiedIR(noders []*noder) { base.ExitIfErrors() // just in case } -// writePkgStub type checks the given parsed source files and then -// returns +// writePkgStub type checks the given parsed source files, +// writes an export data package stub representing them, +// and returns the result. func writePkgStub(noders []*noder) string { m, pkg, info := checkFiles(noders) From 6f22d2c682d5fb7e8c4e9d2ab3e6a762756c1e30 Mon Sep 17 00:00:00 2001 From: Nick Miyake Date: Fri, 18 Jun 2021 00:19:10 +0000 Subject: [PATCH 474/940] doc/go1.17: fix typo Change-Id: Ie8629e0f710d3eb95b4bbcc9c680ffc5004c2f15 GitHub-Last-Rev: 52f48f429cdd65692b88f724f757efed1fa39cd2 GitHub-Pull-Request: golang/go#46812 Reviewed-on: https://go-review.googlesource.com/c/go/+/329289 Reviewed-by: Ian Lance Taylor Trust: Tobias Klauser --- doc/go1.17.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index f8d7aad0348..64247094539 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -162,7 +162,7 @@ Do not send CLs removing the interior tags from such phrases. By default, go mod tidy verifies that the selected versions of dependencies relevant to the main module are the same versions that would be used by the prior Go release (Go 1.16 for a module that - spsecifies go 1.17), and preserves + specifies go 1.17), and preserves the go.sum entries needed by that release even for dependencies that are not normally needed by other commands.

From e9c01f980403ef88340ded62d78b4cd3a4b592f8 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Sun, 13 Jun 2021 11:05:45 -0700 Subject: [PATCH 475/940] [dev.typeparams] cmd/compile: add missing copy of Field.Embedded in type substituter. Change-Id: I876933370a6bcb6586eda9d8fc28a081bf31b1cf Reviewed-on: https://go-review.googlesource.com/c/go/+/328511 Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Robert Griesemer Trust: Dan Scales --- src/cmd/compile/internal/typecheck/subr.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index 79b2402fe70..fb6d660db52 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -1220,6 +1220,7 @@ func (ts *Tsubster) tstruct(t *types.Type, force bool) *types.Type { // names of embedded types (which should keep the name of // the type param, not the instantiated type). newfields[i] = types.NewField(f.Pos, f.Sym, t2) + newfields[i].Embedded = f.Embedded if f.Nname != nil && ts.Vars != nil { v := ts.Vars[f.Nname.(*ir.Name)] if v != nil { From 57aaa19aae32a6c75a07ea8e3006fdcda7583385 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 17 Jun 2021 17:34:18 -0700 Subject: [PATCH 476/940] runtime: disable CPU profiling before removing the SIGPROF handler Otherwise, in c-archive or c-shared mode, there is the chance of getting a SIGPROF just after the signal handler is removed but before profiling is disabled, in which case the program will die. Fixes #46498 Change-Id: I5492beef45fec9fb9a7f58724356d6aedaf799ac Reviewed-on: https://go-review.googlesource.com/c/go/+/329290 Trust: Ian Lance Taylor Reviewed-by: Bryan C. Mills --- src/runtime/signal_unix.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go index f2e526973df..03e2a40ce65 100644 --- a/src/runtime/signal_unix.go +++ b/src/runtime/signal_unix.go @@ -280,6 +280,8 @@ func setProcessCPUProfiler(hz int32) { it.it_value = it.it_interval setitimer(_ITIMER_PROF, &it, nil) } else { + setitimer(_ITIMER_PROF, &itimerval{}, nil) + // If the Go signal handler should be disabled by default, // switch back to the signal handler that was installed // when we enabled profiling. We don't try to handle the case @@ -303,8 +305,6 @@ func setProcessCPUProfiler(hz int32) { setsig(_SIGPROF, h) } } - - setitimer(_ITIMER_PROF, &itimerval{}, nil) } } From 9401172166ee6ac64a5a74b4a8f2aa6d3f936ea1 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 17 Jun 2021 22:12:24 -0700 Subject: [PATCH 477/940] runtime: clarify Frames.Next documentation I wrote code that relied on this API, but I misunderstood the original description of the "more" result. As a consequence, my code always stopped one frame early. This CL expands the documentation to be more explicit and specifically call out my confusion (i.e., that the "more" result indicates whether the *next* Next call will return a valid Frame, and not whether this call did). Change-Id: If135f8f8c05425073d45377c4179e4f79e6bd6ca Reviewed-on: https://go-review.googlesource.com/c/go/+/329389 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor Trust: Matthew Dempsky --- src/runtime/example_test.go | 16 ++++++++++++---- src/runtime/symtab.go | 11 +++++++++-- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/runtime/example_test.go b/src/runtime/example_test.go index e4912a51588..dcb8f7798e2 100644 --- a/src/runtime/example_test.go +++ b/src/runtime/example_test.go @@ -12,12 +12,15 @@ import ( func ExampleFrames() { c := func() { - // Ask runtime.Callers for up to 10 pcs, including runtime.Callers itself. + // Ask runtime.Callers for up to 10 PCs, including runtime.Callers itself. pc := make([]uintptr, 10) n := runtime.Callers(0, pc) if n == 0 { - // No pcs available. Stop now. - // This can happen if the first argument to runtime.Callers is large. + // No PCs available. This can happen if the first argument to + // runtime.Callers is large. + // + // Return now to avoid processing the zero Frame that would + // otherwise be returned by frames.Next below. return } @@ -25,9 +28,12 @@ func ExampleFrames() { frames := runtime.CallersFrames(pc) // Loop to get frames. - // A fixed number of pcs can expand to an indefinite number of Frames. + // A fixed number of PCs can expand to an indefinite number of Frames. for { frame, more := frames.Next() + + // Process this frame. + // // To keep this example's output stable // even if there are changes in the testing package, // stop unwinding when we leave package runtime. @@ -35,6 +41,8 @@ func ExampleFrames() { break } fmt.Printf("- more:%v | %s\n", more, frame.Function) + + // Check whether there are more frames to process after this one. if !more { break } diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index 6b535dfcbfc..999300a58ec 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -68,8 +68,15 @@ func CallersFrames(callers []uintptr) *Frames { return f } -// Next returns frame information for the next caller. -// If more is false, there are no more callers (the Frame value is valid). +// Next returns a Frame representing the next call frame in the slice +// of PC values. If it has already returned all call frames, Next +// returns a zero Frame. +// +// The more result indicates whether the next call to Next will return +// a valid Frame. It does not necessarily indicate whether this call +// returned one. +// +// See the Frames example for idiomatic usage. func (ci *Frames) Next() (frame Frame, more bool) { for len(ci.frames) < 2 { // Find the next frame. From 3f7a3133da4e13635c9012b451963cca76914270 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 18 Jun 2021 03:21:43 -0700 Subject: [PATCH 478/940] [dev.typeparams] cmd/compile: add "toolstash -cmp"-like test of -d=unified This CL adds a longtest test to make sure -d=unified=1 produces output identical to -d=unified=0. Change-Id: I2c5d38f67dbc8fecd8332a91ba7cae22225b090c Reviewed-on: https://go-review.googlesource.com/c/go/+/329429 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- .../compile/internal/noder/unified_test.go | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 src/cmd/compile/internal/noder/unified_test.go diff --git a/src/cmd/compile/internal/noder/unified_test.go b/src/cmd/compile/internal/noder/unified_test.go new file mode 100644 index 00000000000..242fa1282f4 --- /dev/null +++ b/src/cmd/compile/internal/noder/unified_test.go @@ -0,0 +1,151 @@ +// Copyright 2021 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 noder_test + +import ( + "encoding/json" + "flag" + exec "internal/execabs" + "os" + "reflect" + "runtime" + "strings" + "testing" +) + +var ( + flagPkgs = flag.String("pkgs", "std", "list of packages to compare") + flagAll = flag.Bool("all", false, "enable testing of all GOOS/GOARCH targets") + flagParallel = flag.Bool("parallel", false, "test GOOS/GOARCH targets in parallel") +) + +// TestUnifiedCompare implements a test similar to running: +// +// $ go build -toolexec="toolstash -cmp" std +// +// The -pkgs flag controls the list of packages tested. +// +// By default, only the native GOOS/GOARCH target is enabled. The -all +// flag enables testing of non-native targets. The -parallel flag +// additionally enables testing of targets in parallel. +// +// Caution: Testing all targets is very resource intensive! On an IBM +// P920 (dual Intel Xeon Gold 6154 CPUs; 36 cores, 192GB RAM), testing +// all targets in parallel takes about 5 minutes. Using the 'go test' +// command's -run flag for subtest matching is recommended for less +// powerful machines. +func TestUnifiedCompare(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode") + } + + targets, err := exec.Command("go", "tool", "dist", "list").Output() + if err != nil { + t.Fatal(err) + } + + for _, target := range strings.Fields(string(targets)) { + t.Run(target, func(t *testing.T) { + parts := strings.Split(target, "/") + goos, goarch := parts[0], parts[1] + + if !(*flagAll || goos == runtime.GOOS && goarch == runtime.GOARCH) { + t.Skip("skipping non-native target (use -all to enable)") + } + if *flagParallel { + t.Parallel() + } + + pkgs1 := loadPackages(t, goos, goarch, "-d=unified=0 -d=inlfuncswithclosures=0") + pkgs2 := loadPackages(t, goos, goarch, "-d=unified=1 -d=inlfuncswithclosures=0") + + if len(pkgs1) != len(pkgs2) { + t.Fatalf("length mismatch: %v != %v", len(pkgs1), len(pkgs2)) + } + + for i := range pkgs1 { + pkg1 := pkgs1[i] + pkg2 := pkgs2[i] + + path := pkg1.ImportPath + if path != pkg2.ImportPath { + t.Fatalf("mismatched paths: %q != %q", path, pkg2.ImportPath) + } + + // Packages that don't have any source files (e.g., packages + // unsafe, embed/internal/embedtest, and cmd/internal/moddeps). + if pkg1.Export == "" && pkg2.Export == "" { + continue + } + + if pkg1.BuildID == pkg2.BuildID { + t.Errorf("package %q: build IDs unexpectedly matched", path) + } + + // Unlike toolstash -cmp, we're comparing the same compiler + // binary against itself, just with different flags. So we + // don't need to worry about skipping over mismatched version + // strings, but we do need to account for differing build IDs. + // + // Fortunately, build IDs are cryptographic 256-bit hashes, + // and cmd/go provides us with them up front. So we can just + // use them as delimeters to split the files, and then check + // that the substrings are all equal. + file1 := strings.Split(readFile(t, pkg1.Export), pkg1.BuildID) + file2 := strings.Split(readFile(t, pkg2.Export), pkg2.BuildID) + if !reflect.DeepEqual(file1, file2) { + t.Errorf("package %q: compile output differs", path) + } + } + }) + } +} + +type pkg struct { + ImportPath string + Export string + BuildID string + Incomplete bool +} + +func loadPackages(t *testing.T, goos, goarch, gcflags string) []pkg { + args := []string{"list", "-e", "-export", "-json", "-gcflags=all=" + gcflags, "--"} + args = append(args, strings.Fields(*flagPkgs)...) + + cmd := exec.Command("go", args...) + cmd.Env = append(os.Environ(), "GOOS="+goos, "GOARCH="+goarch) + cmd.Stderr = os.Stderr + stdout, err := cmd.StdoutPipe() + if err != nil { + t.Fatal(err) + } + if err := cmd.Start(); err != nil { + t.Fatal(err) + } + + var res []pkg + for dec := json.NewDecoder(stdout); dec.More(); { + var pkg pkg + if err := dec.Decode(&pkg); err != nil { + t.Fatal(err) + } + if pkg.Incomplete { + t.Fatalf("incomplete package: %q", pkg.ImportPath) + } + res = append(res, pkg) + } + if err := cmd.Wait(); err != nil { + t.Fatal(err) + } + return res +} + +func readFile(t *testing.T, name string) string { + buf, err := os.ReadFile(name) + if err != nil { + t.Fatal(err) + } + return string(buf) +} From 86743e7d8652c316b5f77a84ffc83244ee10a41b Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Sun, 18 Apr 2021 13:38:34 +1000 Subject: [PATCH 479/940] image: add RGBA64Image interface The new RGBA64At method is equivalent to the existing At method (and the new SetRGBA64 method is equivalent to the existing Set method in the image/draw package), but they can avoid allocations from converting concrete color types to the color.Color interface type. Also update api/go1.17.txt and doc/go1.17.html Fixes #44808 Change-Id: I8671f3144512b1200fa373840ed6729a5d61bc35 Reviewed-on: https://go-review.googlesource.com/c/go/+/311129 Trust: Nigel Tao Reviewed-by: Dmitri Shuralyov Reviewed-by: Rob Pike --- api/go1.17.txt | 34 ++++++- doc/go1.17.html | 13 +++ src/image/draw/draw.go | 10 ++ src/image/image.go | 197 ++++++++++++++++++++++++++++++++++++++++ src/image/image_test.go | 75 +++++++++++++++ src/image/ycbcr.go | 10 ++ 6 files changed, 338 insertions(+), 1 deletion(-) diff --git a/api/go1.17.txt b/api/go1.17.txt index 257ca271d3d..c5eb381708c 100644 --- a/api/go1.17.txt +++ b/api/go1.17.txt @@ -28,6 +28,38 @@ pkg encoding/csv, method (*Reader) FieldPos(int) (int, int) pkg go/build, type Context struct, ToolTags []string pkg go/parser, const SkipObjectResolution = 64 pkg go/parser, const SkipObjectResolution Mode +pkg image, method (*Alpha) RGBA64At(int, int) color.RGBA64 +pkg image, method (*Alpha) SetRGBA64(int, int, color.RGBA64) +pkg image, method (*Alpha16) RGBA64At(int, int) color.RGBA64 +pkg image, method (*Alpha16) SetRGBA64(int, int, color.RGBA64) +pkg image, method (*CMYK) RGBA64At(int, int) color.RGBA64 +pkg image, method (*CMYK) SetRGBA64(int, int, color.RGBA64) +pkg image, method (*Gray) RGBA64At(int, int) color.RGBA64 +pkg image, method (*Gray) SetRGBA64(int, int, color.RGBA64) +pkg image, method (*Gray16) RGBA64At(int, int) color.RGBA64 +pkg image, method (*Gray16) SetRGBA64(int, int, color.RGBA64) +pkg image, method (*NRGBA) RGBA64At(int, int) color.RGBA64 +pkg image, method (*NRGBA) SetRGBA64(int, int, color.RGBA64) +pkg image, method (*NRGBA64) RGBA64At(int, int) color.RGBA64 +pkg image, method (*NRGBA64) SetRGBA64(int, int, color.RGBA64) +pkg image, method (*NYCbCrA) RGBA64At(int, int) color.RGBA64 +pkg image, method (*Paletted) RGBA64At(int, int) color.RGBA64 +pkg image, method (*Paletted) SetRGBA64(int, int, color.RGBA64) +pkg image, method (*RGBA) RGBA64At(int, int) color.RGBA64 +pkg image, method (*RGBA) SetRGBA64(int, int, color.RGBA64) +pkg image, method (*YCbCr) RGBA64At(int, int) color.RGBA64 +pkg image, type RGBA64Image interface { At, Bounds, ColorModel, RGBA64At } +pkg image, type RGBA64Image interface, At(int, int) color.Color +pkg image, type RGBA64Image interface, Bounds() Rectangle +pkg image, type RGBA64Image interface, ColorModel() color.Model +pkg image, type RGBA64Image interface, RGBA64At(int, int) color.RGBA64 +pkg image/draw, type RGBA64Image interface { At, Bounds, ColorModel, RGBA64At, Set, SetRGBA64 } +pkg image/draw, type RGBA64Image interface, At(int, int) color.Color +pkg image/draw, type RGBA64Image interface, Bounds() image.Rectangle +pkg image/draw, type RGBA64Image interface, ColorModel() color.Model +pkg image/draw, type RGBA64Image interface, RGBA64At(int, int) color.RGBA64 +pkg image/draw, type RGBA64Image interface, Set(int, int, color.Color) +pkg image/draw, type RGBA64Image interface, SetRGBA64(int, int, color.RGBA64) pkg io/fs, func FileInfoToDirEntry(FileInfo) DirEntry pkg math, const MaxFloat64 = 1.79769e+308 // 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368 pkg math, const MaxInt = 9223372036854775807 @@ -153,7 +185,7 @@ pkg time, const Layout = "01/02 03:04:05PM '06 -0700" pkg time, const Layout ideal-string pkg time, func UnixMicro(int64) Time pkg time, func UnixMilli(int64) Time -pkg time, method (Time) IsDST() bool pkg time, method (Time) GoString() string +pkg time, method (Time) IsDST() bool pkg time, method (Time) UnixMicro() int64 pkg time, method (Time) UnixMilli() int64 diff --git a/doc/go1.17.html b/doc/go1.17.html index 64247094539..94526512957 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -693,6 +693,19 @@ func Foo() bool {
+
image
+
+

+ The concrete image types (RGBA, Gray16 and so on) + now implement a new RGBA64Image + interface. Those concrete types, other than the chroma-subsampling + related YCbCr and NYCbCrA, also now implement + draw.RGBA64Image, a + new interface in the image/draw package. +

+
+
+
io/fs

diff --git a/src/image/draw/draw.go b/src/image/draw/draw.go index 8f96aa2d180..13f66682938 100644 --- a/src/image/draw/draw.go +++ b/src/image/draw/draw.go @@ -23,6 +23,16 @@ type Image interface { Set(x, y int, c color.Color) } +// RGBA64Image extends both the Image and image.RGBA64Image interfaces with a +// SetRGBA64 method to change a single pixel. SetRGBA64 is equivalent to +// calling Set, but it can avoid allocations from converting concrete color +// types to the color.Color interface type. +type RGBA64Image interface { + image.RGBA64Image + Set(x, y int, c color.Color) + SetRGBA64(x, y int, c color.RGBA64) +} + // Quantizer produces a palette for an image. type Quantizer interface { // Quantize appends up to cap(p) - len(p) colors to p and returns the diff --git a/src/image/image.go b/src/image/image.go index 8adba96ab6e..930d9ac6c7b 100644 --- a/src/image/image.go +++ b/src/image/image.go @@ -45,6 +45,17 @@ type Image interface { At(x, y int) color.Color } +// RGBA64Image is an Image whose pixels can be converted directly to a +// color.RGBA64. +type RGBA64Image interface { + // RGBA64At returns the RGBA64 color of the pixel at (x, y). It is + // equivalent to calling At(x, y).RGBA() and converting the resulting + // 32-bit return values to a color.RGBA64, but it can avoid allocations + // from converting concrete color types to the color.Color interface type. + RGBA64At(x, y int) color.RGBA64 + Image +} + // PalettedImage is an image whose colors may come from a limited palette. // If m is a PalettedImage and m.ColorModel() returns a color.Palette p, // then m.At(x, y) should be equivalent to p[m.ColorIndexAt(x, y)]. If m's @@ -90,6 +101,24 @@ func (p *RGBA) At(x, y int) color.Color { return p.RGBAAt(x, y) } +func (p *RGBA) RGBA64At(x, y int) color.RGBA64 { + if !(Point{x, y}.In(p.Rect)) { + return color.RGBA64{} + } + i := p.PixOffset(x, y) + s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 + r := uint16(s[0]) + g := uint16(s[1]) + b := uint16(s[2]) + a := uint16(s[3]) + return color.RGBA64{ + (r << 8) | r, + (g << 8) | g, + (b << 8) | b, + (a << 8) | a, + } +} + func (p *RGBA) RGBAAt(x, y int) color.RGBA { if !(Point{x, y}.In(p.Rect)) { return color.RGBA{} @@ -118,6 +147,18 @@ func (p *RGBA) Set(x, y int, c color.Color) { s[3] = c1.A } +func (p *RGBA) SetRGBA64(x, y int, c color.RGBA64) { + if !(Point{x, y}.In(p.Rect)) { + return + } + i := p.PixOffset(x, y) + s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 + s[0] = uint8(c.R >> 8) + s[1] = uint8(c.G >> 8) + s[2] = uint8(c.B >> 8) + s[3] = uint8(c.A >> 8) +} + func (p *RGBA) SetRGBA(x, y int, c color.RGBA) { if !(Point{x, y}.In(p.Rect)) { return @@ -311,6 +352,11 @@ func (p *NRGBA) At(x, y int) color.Color { return p.NRGBAAt(x, y) } +func (p *NRGBA) RGBA64At(x, y int) color.RGBA64 { + r, g, b, a := p.NRGBAAt(x, y).RGBA() + return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)} +} + func (p *NRGBA) NRGBAAt(x, y int) color.NRGBA { if !(Point{x, y}.In(p.Rect)) { return color.NRGBA{} @@ -339,6 +385,24 @@ func (p *NRGBA) Set(x, y int, c color.Color) { s[3] = c1.A } +func (p *NRGBA) SetRGBA64(x, y int, c color.RGBA64) { + if !(Point{x, y}.In(p.Rect)) { + return + } + r, g, b, a := uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A) + if (a != 0) && (a != 0xffff) { + r = (r * 0xffff) / a + g = (g * 0xffff) / a + b = (b * 0xffff) / a + } + i := p.PixOffset(x, y) + s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 + s[0] = uint8(r >> 8) + s[1] = uint8(g >> 8) + s[2] = uint8(b >> 8) + s[3] = uint8(a >> 8) +} + func (p *NRGBA) SetNRGBA(x, y int, c color.NRGBA) { if !(Point{x, y}.In(p.Rect)) { return @@ -415,6 +479,11 @@ func (p *NRGBA64) At(x, y int) color.Color { return p.NRGBA64At(x, y) } +func (p *NRGBA64) RGBA64At(x, y int) color.RGBA64 { + r, g, b, a := p.NRGBA64At(x, y).RGBA() + return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)} +} + func (p *NRGBA64) NRGBA64At(x, y int) color.NRGBA64 { if !(Point{x, y}.In(p.Rect)) { return color.NRGBA64{} @@ -452,6 +521,28 @@ func (p *NRGBA64) Set(x, y int, c color.Color) { s[7] = uint8(c1.A) } +func (p *NRGBA64) SetRGBA64(x, y int, c color.RGBA64) { + if !(Point{x, y}.In(p.Rect)) { + return + } + r, g, b, a := uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A) + if (a != 0) && (a != 0xffff) { + r = (r * 0xffff) / a + g = (g * 0xffff) / a + b = (b * 0xffff) / a + } + i := p.PixOffset(x, y) + s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857 + s[0] = uint8(r >> 8) + s[1] = uint8(r) + s[2] = uint8(g >> 8) + s[3] = uint8(g) + s[4] = uint8(b >> 8) + s[5] = uint8(b) + s[6] = uint8(a >> 8) + s[7] = uint8(a) +} + func (p *NRGBA64) SetNRGBA64(x, y int, c color.NRGBA64) { if !(Point{x, y}.In(p.Rect)) { return @@ -532,6 +623,12 @@ func (p *Alpha) At(x, y int) color.Color { return p.AlphaAt(x, y) } +func (p *Alpha) RGBA64At(x, y int) color.RGBA64 { + a := uint16(p.AlphaAt(x, y).A) + a |= a << 8 + return color.RGBA64{a, a, a, a} +} + func (p *Alpha) AlphaAt(x, y int) color.Alpha { if !(Point{x, y}.In(p.Rect)) { return color.Alpha{} @@ -554,6 +651,14 @@ func (p *Alpha) Set(x, y int, c color.Color) { p.Pix[i] = color.AlphaModel.Convert(c).(color.Alpha).A } +func (p *Alpha) SetRGBA64(x, y int, c color.RGBA64) { + if !(Point{x, y}.In(p.Rect)) { + return + } + i := p.PixOffset(x, y) + p.Pix[i] = uint8(c.A >> 8) +} + func (p *Alpha) SetAlpha(x, y int, c color.Alpha) { if !(Point{x, y}.In(p.Rect)) { return @@ -626,6 +731,11 @@ func (p *Alpha16) At(x, y int) color.Color { return p.Alpha16At(x, y) } +func (p *Alpha16) RGBA64At(x, y int) color.RGBA64 { + a := p.Alpha16At(x, y).A + return color.RGBA64{a, a, a, a} +} + func (p *Alpha16) Alpha16At(x, y int) color.Alpha16 { if !(Point{x, y}.In(p.Rect)) { return color.Alpha16{} @@ -650,6 +760,15 @@ func (p *Alpha16) Set(x, y int, c color.Color) { p.Pix[i+1] = uint8(c1.A) } +func (p *Alpha16) SetRGBA64(x, y int, c color.RGBA64) { + if !(Point{x, y}.In(p.Rect)) { + return + } + i := p.PixOffset(x, y) + p.Pix[i+0] = uint8(c.A >> 8) + p.Pix[i+1] = uint8(c.A) +} + func (p *Alpha16) SetAlpha16(x, y int, c color.Alpha16) { if !(Point{x, y}.In(p.Rect)) { return @@ -723,6 +842,12 @@ func (p *Gray) At(x, y int) color.Color { return p.GrayAt(x, y) } +func (p *Gray) RGBA64At(x, y int) color.RGBA64 { + gray := uint16(p.GrayAt(x, y).Y) + gray |= gray << 8 + return color.RGBA64{gray, gray, gray, 0xffff} +} + func (p *Gray) GrayAt(x, y int) color.Gray { if !(Point{x, y}.In(p.Rect)) { return color.Gray{} @@ -745,6 +870,16 @@ func (p *Gray) Set(x, y int, c color.Color) { p.Pix[i] = color.GrayModel.Convert(c).(color.Gray).Y } +func (p *Gray) SetRGBA64(x, y int, c color.RGBA64) { + if !(Point{x, y}.In(p.Rect)) { + return + } + // This formula is the same as in color.grayModel. + gray := (19595*uint32(c.R) + 38470*uint32(c.G) + 7471*uint32(c.B) + 1<<15) >> 24 + i := p.PixOffset(x, y) + p.Pix[i] = uint8(gray) +} + func (p *Gray) SetGray(x, y int, c color.Gray) { if !(Point{x, y}.In(p.Rect)) { return @@ -804,6 +939,11 @@ func (p *Gray16) At(x, y int) color.Color { return p.Gray16At(x, y) } +func (p *Gray16) RGBA64At(x, y int) color.RGBA64 { + gray := p.Gray16At(x, y).Y + return color.RGBA64{gray, gray, gray, 0xffff} +} + func (p *Gray16) Gray16At(x, y int) color.Gray16 { if !(Point{x, y}.In(p.Rect)) { return color.Gray16{} @@ -828,6 +968,17 @@ func (p *Gray16) Set(x, y int, c color.Color) { p.Pix[i+1] = uint8(c1.Y) } +func (p *Gray16) SetRGBA64(x, y int, c color.RGBA64) { + if !(Point{x, y}.In(p.Rect)) { + return + } + // This formula is the same as in color.gray16Model. + gray := (19595*uint32(c.R) + 38470*uint32(c.G) + 7471*uint32(c.B) + 1<<15) >> 16 + i := p.PixOffset(x, y) + p.Pix[i+0] = uint8(gray >> 8) + p.Pix[i+1] = uint8(gray) +} + func (p *Gray16) SetGray16(x, y int, c color.Gray16) { if !(Point{x, y}.In(p.Rect)) { return @@ -888,6 +1039,11 @@ func (p *CMYK) At(x, y int) color.Color { return p.CMYKAt(x, y) } +func (p *CMYK) RGBA64At(x, y int) color.RGBA64 { + r, g, b, a := p.CMYKAt(x, y).RGBA() + return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)} +} + func (p *CMYK) CMYKAt(x, y int) color.CMYK { if !(Point{x, y}.In(p.Rect)) { return color.CMYK{} @@ -916,6 +1072,19 @@ func (p *CMYK) Set(x, y int, c color.Color) { s[3] = c1.K } +func (p *CMYK) SetRGBA64(x, y int, c color.RGBA64) { + if !(Point{x, y}.In(p.Rect)) { + return + } + cc, mm, yy, kk := color.RGBToCMYK(uint8(c.R>>8), uint8(c.G>>8), uint8(c.B>>8)) + i := p.PixOffset(x, y) + s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 + s[0] = cc + s[1] = mm + s[2] = yy + s[3] = kk +} + func (p *CMYK) SetCMYK(x, y int, c color.CMYK) { if !(Point{x, y}.In(p.Rect)) { return @@ -988,6 +1157,26 @@ func (p *Paletted) At(x, y int) color.Color { return p.Palette[p.Pix[i]] } +func (p *Paletted) RGBA64At(x, y int) color.RGBA64 { + if len(p.Palette) == 0 { + return color.RGBA64{} + } + c := color.Color(nil) + if !(Point{x, y}.In(p.Rect)) { + c = p.Palette[0] + } else { + i := p.PixOffset(x, y) + c = p.Palette[p.Pix[i]] + } + r, g, b, a := c.RGBA() + return color.RGBA64{ + uint16(r), + uint16(g), + uint16(b), + uint16(a), + } +} + // PixOffset returns the index of the first element of Pix that corresponds to // the pixel at (x, y). func (p *Paletted) PixOffset(x, y int) int { @@ -1002,6 +1191,14 @@ func (p *Paletted) Set(x, y int, c color.Color) { p.Pix[i] = uint8(p.Palette.Index(c)) } +func (p *Paletted) SetRGBA64(x, y int, c color.RGBA64) { + if !(Point{x, y}.In(p.Rect)) { + return + } + i := p.PixOffset(x, y) + p.Pix[i] = uint8(p.Palette.Index(c)) +} + func (p *Paletted) ColorIndexAt(x, y int) uint8 { if !(Point{x, y}.In(p.Rect)) { return 0 diff --git a/src/image/image_test.go b/src/image/image_test.go index b9b9bfaa28c..c64b6107b74 100644 --- a/src/image/image_test.go +++ b/src/image/image_test.go @@ -6,6 +6,7 @@ package image import ( "image/color" + "image/color/palette" "testing" ) @@ -191,6 +192,80 @@ func Test16BitsPerColorChannel(t *testing.T) { } } +func TestRGBA64Image(t *testing.T) { + // memset sets every element of s to v. + memset := func(s []byte, v byte) { + for i := range s { + s[i] = v + } + } + + r := Rect(0, 0, 3, 2) + testCases := []Image{ + NewAlpha(r), + NewAlpha16(r), + NewCMYK(r), + NewGray(r), + NewGray16(r), + NewNRGBA(r), + NewNRGBA64(r), + NewNYCbCrA(r, YCbCrSubsampleRatio444), + NewPaletted(r, palette.Plan9), + NewRGBA(r), + NewRGBA64(r), + NewYCbCr(r, YCbCrSubsampleRatio444), + } + for _, tc := range testCases { + switch tc := tc.(type) { + // Most of the concrete image types in the testCases implement the + // draw.RGBA64Image interface: they have a SetRGBA64 method. We use an + // interface literal here, instead of importing "image/draw", to avoid + // an import cycle. + // + // The YCbCr and NYCbCrA types are special-cased. Chroma subsampling + // means that setting one pixel can modify neighboring pixels. They + // don't have Set or SetRGBA64 methods because that side effect could + // be surprising. Here, we just memset the channel buffers instead. + case interface { + SetRGBA64(x, y int, c color.RGBA64) + }: + tc.SetRGBA64(1, 1, color.RGBA64{0x7FFF, 0x3FFF, 0x0000, 0x7FFF}) + + case *NYCbCrA: + memset(tc.YCbCr.Y, 0x77) + memset(tc.YCbCr.Cb, 0x88) + memset(tc.YCbCr.Cr, 0x99) + memset(tc.A, 0xAA) + + case *YCbCr: + memset(tc.Y, 0x77) + memset(tc.Cb, 0x88) + memset(tc.Cr, 0x99) + + default: + t.Errorf("could not initialize pixels for %T", tc) + continue + } + + // Check that RGBA64At(x, y) is equivalent to At(x, y).RGBA(). + rgba64Image, ok := tc.(RGBA64Image) + if !ok { + t.Errorf("%T is not an RGBA64Image", tc) + continue + } + got := rgba64Image.RGBA64At(1, 1) + wantR, wantG, wantB, wantA := tc.At(1, 1).RGBA() + if (uint32(got.R) != wantR) || (uint32(got.G) != wantG) || + (uint32(got.B) != wantB) || (uint32(got.A) != wantA) { + t.Errorf("%T:\ngot (0x%04X, 0x%04X, 0x%04X, 0x%04X)\n"+ + "want (0x%04X, 0x%04X, 0x%04X, 0x%04X)", tc, + got.R, got.G, got.B, got.A, + wantR, wantG, wantB, wantA) + continue + } + } +} + func BenchmarkAt(b *testing.B) { for _, tc := range testImages { b.Run(tc.name, func(b *testing.B) { diff --git a/src/image/ycbcr.go b/src/image/ycbcr.go index fbdffe1bd1b..328b90d1525 100644 --- a/src/image/ycbcr.go +++ b/src/image/ycbcr.go @@ -71,6 +71,11 @@ func (p *YCbCr) At(x, y int) color.Color { return p.YCbCrAt(x, y) } +func (p *YCbCr) RGBA64At(x, y int) color.RGBA64 { + r, g, b, a := p.YCbCrAt(x, y).RGBA() + return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)} +} + func (p *YCbCr) YCbCrAt(x, y int) color.YCbCr { if !(Point{x, y}.In(p.Rect)) { return color.YCbCr{} @@ -210,6 +215,11 @@ func (p *NYCbCrA) At(x, y int) color.Color { return p.NYCbCrAAt(x, y) } +func (p *NYCbCrA) RGBA64At(x, y int) color.RGBA64 { + r, g, b, a := p.NYCbCrAAt(x, y).RGBA() + return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)} +} + func (p *NYCbCrA) NYCbCrAAt(x, y int) color.NYCbCrA { if !(Point{X: x, Y: y}.In(p.Rect)) { return color.NYCbCrA{} From b73cc4b02b3801603b3ce0bcc57cf01d6aa9a4dd Mon Sep 17 00:00:00 2001 From: Daniel Theophanes Date: Wed, 16 Jun 2021 11:46:00 -0500 Subject: [PATCH 480/940] database/sql: do not rely on timeout for deadlock test Fixes #46783 Change-Id: I8a8d1716279a041a7411c0c47a440a7997b39c80 Reviewed-on: https://go-review.googlesource.com/c/go/+/328649 Run-TryBot: Daniel Theophanes TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills Trust: Carlos Amedee --- src/database/sql/sql_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go index 80f63e877d0..7d1cb9b85a5 100644 --- a/src/database/sql/sql_test.go +++ b/src/database/sql/sql_test.go @@ -2838,9 +2838,10 @@ func TestTxStmtDeadlock(t *testing.T) { db := newTestDB(t, "people") defer closeDB(t, db) - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Millisecond) + ctx, cancel := context.WithCancel(context.Background()) defer cancel() tx, err := db.BeginTx(ctx, nil) + cancel() if err != nil { t.Fatal(err) } From d24c90a1534a1399cc667696e05a0dcf2d15aa6d Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Sun, 20 Jun 2021 02:06:45 +0700 Subject: [PATCH 481/940] [dev.typeparams] cmd/compile: explain how pkgReader.typIdx handles alias cyclic Change-Id: Ib9357c21bb010abf0d5fd17c3bee3197854c3a8a Reviewed-on: https://go-review.googlesource.com/c/go/+/329570 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/noder/reader.go | 41 ++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index efa607e13ba..004f9cc271d 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -295,9 +295,46 @@ func (pr *pkgReader) typIdx(idx int, implicits, explicits []*types.Type) *types. typ := r.doTyp() assert(typ != nil) + // For recursive type declarations involving interfaces and aliases, + // above r.doTyp() call may have already set pr.typs[idx], so just + // double check and return the type. + // + // Example: + // + // type F = func(I) + // + // type I interface { + // m(F) + // } + // + // The writer writes data types in following index order: + // + // 0: func(I) + // 1: I + // 2: interface{m(func(I))} + // + // The reader resolves it in following index order: + // + // 0 -> 1 -> 2 -> 0 -> 1 + // + // and can divide in logically 2 steps: + // + // - 0 -> 1 : first time the reader reach type I, + // it creates new named type with symbol I. + // + // - 2 -> 0 -> 1: the reader ends up reaching symbol I again, + // now the symbol I was setup in above step, so + // the reader just return the named type. + // + // Now, the functions called return, the pr.typs looks like below: + // + // - 0 -> 1 -> 2 -> 0 : [ I ] + // - 0 -> 1 -> 2 : [func(I) I ] + // - 0 -> 1 : [func(I) I interface { "".m(func("".I)) }] + // + // The idx 1, corresponding with type I was resolved successfully + // after r.doTyp() call. if typ := pr.typs[idx]; typ != nil { - // This happens in fixedbugs/issue27232.go. - // TODO(mdempsky): Explain why/how this happens. return typ } From 460900a7b51f917888cb17608367979243178fe1 Mon Sep 17 00:00:00 2001 From: "Andrew G. Morgan" Date: Sat, 19 Jun 2021 09:46:52 -0700 Subject: [PATCH 482/940] os/signal: test with a significantly longer fatal timeout We've observed some occasional os-arch specific timeouts in signal.TestSignalTrace(). While the main purpose of a short timeout is to ensure the passing tests complete quickly, the unexpected failure path can tolerate waiting longer (the test is not intended to test how slow or overloaded the OS is at the time it is run). Fixes #46736 Change-Id: Ib392fc6ce485a919612784ca88ed76c30f4898e2 Reviewed-on: https://go-review.googlesource.com/c/go/+/329502 Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor Reviewed-by: Emmanuel Odeke Trust: Emmanuel Odeke --- src/os/signal/signal_test.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/os/signal/signal_test.go b/src/os/signal/signal_test.go index cea68742d26..649854b746c 100644 --- a/src/os/signal/signal_test.go +++ b/src/os/signal/signal_test.go @@ -32,6 +32,11 @@ import ( // The current value is set based on flakes observed in the Go builders. var settleTime = 100 * time.Millisecond +// fatalWaitingTime is an absurdly long time to wait for signals to be +// delivered but, using it, we (hopefully) eliminate test flakes on the +// build servers. See #46736 for discussion. +var fatalWaitingTime = 30 * time.Second + func init() { if testenv.Builder() == "solaris-amd64-oraclerel" { // The solaris-amd64-oraclerel builder has been observed to time out in @@ -84,7 +89,7 @@ func waitSig1(t *testing.T, c <-chan os.Signal, sig os.Signal, all bool) { // General user code should filter out all unexpected signals instead of just // SIGURG, but since os/signal is tightly coupled to the runtime it seems // appropriate to be stricter here. - for time.Since(start) < settleTime { + for time.Since(start) < fatalWaitingTime { select { case s := <-c: if s == sig { @@ -97,7 +102,7 @@ func waitSig1(t *testing.T, c <-chan os.Signal, sig os.Signal, all bool) { timer.Reset(settleTime / 10) } } - t.Fatalf("timeout after %v waiting for %v", settleTime, sig) + t.Fatalf("timeout after %v waiting for %v", fatalWaitingTime, sig) } // quiesce waits until we can be reasonably confident that all pending signals From 3f7f72a258394e19610c14772b07ba6f13e8bae6 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Sun, 20 Jun 2021 14:33:51 +0700 Subject: [PATCH 483/940] [dev.typeparams] cmd/compile: fold reader checking type params logic to separate method So making it less verbose and clearer to the reader what that check means. Change-Id: I41587aab399e63600356c5cecec64978048bed36 Reviewed-on: https://go-review.googlesource.com/c/go/+/329571 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/noder/reader.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 004f9cc271d..ad3cc25fd0b 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -543,7 +543,7 @@ func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node return pri.pr.objIdx(pri.idx, pri.implicits, r.explicits) } if haveLegacyImports { - assert(len(r.implicits)+len(r.explicits) == 0) + assert(!r.hasTypeParams()) return typecheck.Resolve(ir.NewIdent(src.NoXPos, origSym)) } base.Fatalf("unresolved stub: %v", origSym) @@ -608,7 +608,7 @@ func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node } func (r *reader) mangle(sym *types.Sym) *types.Sym { - if len(r.implicits)+len(r.explicits) == 0 { + if !r.hasTypeParams() { return sym } @@ -722,6 +722,10 @@ func (r *reader) selector() (origPkg *types.Pkg, sym *types.Sym) { return } +func (r *reader) hasTypeParams() bool { + return len(r.implicits)+len(r.explicits) != 0 +} + // @@@ Compiler extensions func (r *reader) funcExt(name *ir.Name) { @@ -739,7 +743,7 @@ func (r *reader) funcExt(name *ir.Name) { // TODO(mdempsky): Remember why I wrote this code. I think it has to // do with how ir.VisitFuncsBottomUp works? - if name.Sym().Pkg == types.LocalPkg || len(r.implicits)+len(r.explicits) != 0 { + if name.Sym().Pkg == types.LocalPkg || r.hasTypeParams() { name.Defn = fn } @@ -774,7 +778,7 @@ func (r *reader) typeExt(name *ir.Name) { typ := name.Type() - if len(r.implicits)+len(r.explicits) != 0 { + if r.hasTypeParams() { // Set "RParams" (really type arguments here, not parameters) so // this type is treated as "fully instantiated". This ensures the // type descriptor is written out as DUPOK and method wrappers are From e57da8e53cadd2f456c6a9457beabd1b4659fc1f Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Sun, 20 Jun 2021 22:17:19 +0700 Subject: [PATCH 484/940] [dev.typeparams] cmd/compile: explain why reader.funcExt need to set n.Defn Change-Id: I1a7d669879af57a1c1f48ce63ff0d214b694e680 Reviewed-on: https://go-review.googlesource.com/c/go/+/329572 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/noder/reader.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index ad3cc25fd0b..4fc9e7a777a 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -741,8 +741,13 @@ func (r *reader) funcExt(name *ir.Name) { fn.SetPos(name.Pos()) } - // TODO(mdempsky): Remember why I wrote this code. I think it has to - // do with how ir.VisitFuncsBottomUp works? + // Normally, we only compile local functions, which saves redundant compilation work. + // n.Defn is not nil for local functions, and is nil for imported function. But for + // generic functions, we might have an instantiation that no other package has seen before. + // So we need to be conservative and compile it again. + // + // That's why name.Defn is set here, so ir.VisitFuncsBottomUp can analyze function. + // TODO(mdempsky,cuonglm): find a cleaner way to handle this. if name.Sym().Pkg == types.LocalPkg || r.hasTypeParams() { name.Defn = fn } From 844c0763591e6c01ae2a30a743150be71b6d356f Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Sun, 20 Jun 2021 21:33:54 +0700 Subject: [PATCH 485/940] [dev.typeparams] cmd/compile: simplify import* functions CL 280634 remove Sym.Importdef, so ipkg in importsym is not used anymore. So we can remove it from importsym and all other import* functions, which just call importsym internally. Change-Id: I15b9d11c4445dbe40982f7ff2a33a2116705e790 Reviewed-on: https://go-review.googlesource.com/c/go/+/329573 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/typecheck/export.go | 26 +++++++++---------- src/cmd/compile/internal/typecheck/iimport.go | 10 +++---- src/cmd/compile/internal/typecheck/syms.go | 4 +-- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/cmd/compile/internal/typecheck/export.go b/src/cmd/compile/internal/typecheck/export.go index 63d0a1ec6c6..30726d4327f 100644 --- a/src/cmd/compile/internal/typecheck/export.go +++ b/src/cmd/compile/internal/typecheck/export.go @@ -15,22 +15,22 @@ import ( // importalias declares symbol s as an imported type alias with type t. // ipkg is the package being imported -func importalias(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) *ir.Name { - return importobj(ipkg, pos, s, ir.OTYPE, ir.PEXTERN, t) +func importalias(pos src.XPos, s *types.Sym, t *types.Type) *ir.Name { + return importobj(pos, s, ir.OTYPE, ir.PEXTERN, t) } // importconst declares symbol s as an imported constant with type t and value val. // ipkg is the package being imported -func importconst(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type, val constant.Value) *ir.Name { - n := importobj(ipkg, pos, s, ir.OLITERAL, ir.PEXTERN, t) +func importconst(pos src.XPos, s *types.Sym, t *types.Type, val constant.Value) *ir.Name { + n := importobj(pos, s, ir.OLITERAL, ir.PEXTERN, t) n.SetVal(val) return n } // importfunc declares symbol s as an imported function with type t. // ipkg is the package being imported -func importfunc(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) *ir.Name { - n := importobj(ipkg, pos, s, ir.ONAME, ir.PFUNC, t) +func importfunc(pos src.XPos, s *types.Sym, t *types.Type) *ir.Name { + n := importobj(pos, s, ir.ONAME, ir.PFUNC, t) n.Func = ir.NewFunc(pos) n.Func.Nname = n return n @@ -38,8 +38,8 @@ func importfunc(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) *ir. // importobj declares symbol s as an imported object representable by op. // ipkg is the package being imported -func importobj(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op ir.Op, ctxt ir.Class, t *types.Type) *ir.Name { - n := importsym(ipkg, pos, s, op, ctxt) +func importobj(pos src.XPos, s *types.Sym, op ir.Op, ctxt ir.Class, t *types.Type) *ir.Name { + n := importsym(pos, s, op, ctxt) n.SetType(t) if ctxt == ir.PFUNC { n.Sym().SetFunc(true) @@ -47,7 +47,7 @@ func importobj(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op ir.Op, ctxt ir.Cl return n } -func importsym(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op ir.Op, ctxt ir.Class) *ir.Name { +func importsym(pos src.XPos, s *types.Sym, op ir.Op, ctxt ir.Class) *ir.Name { if n := s.PkgDef(); n != nil { base.Fatalf("importsym of symbol that already exists: %v", n) } @@ -61,14 +61,14 @@ func importsym(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op ir.Op, ctxt ir.Cl // importtype returns the named type declared by symbol s. // If no such type has been declared yet, a forward declaration is returned. // ipkg is the package being imported -func importtype(ipkg *types.Pkg, pos src.XPos, s *types.Sym) *ir.Name { - n := importsym(ipkg, pos, s, ir.OTYPE, ir.PEXTERN) +func importtype(pos src.XPos, s *types.Sym) *ir.Name { + n := importsym(pos, s, ir.OTYPE, ir.PEXTERN) n.SetType(types.NewNamed(n)) return n } // importvar declares symbol s as an imported variable with type t. // ipkg is the package being imported -func importvar(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) *ir.Name { - return importobj(ipkg, pos, s, ir.ONAME, ir.PEXTERN, t) +func importvar(pos src.XPos, s *types.Sym, t *types.Type) *ir.Name { + return importobj(pos, s, ir.ONAME, ir.PEXTERN, t) } diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 81f8ea05d9c..d94f649a452 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -294,13 +294,13 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name { case 'A': typ := r.typ() - return importalias(r.p.ipkg, pos, sym, typ) + return importalias(pos, sym, typ) case 'C': typ := r.typ() val := r.value(typ) - n := importconst(r.p.ipkg, pos, sym, typ, val) + n := importconst(pos, sym, typ, val) r.constExt(n) return n @@ -311,7 +311,7 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name { } typ := r.signature(nil, tparams) - n := importfunc(r.p.ipkg, pos, sym, typ) + n := importfunc(pos, sym, typ) r.funcExt(n) return n @@ -323,7 +323,7 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name { // Types can be recursive. We need to setup a stub // declaration before recursing. - n := importtype(r.p.ipkg, pos, sym) + n := importtype(pos, sym) t := n.Type() if rparams != nil { t.SetRParams(rparams) @@ -401,7 +401,7 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name { case 'V': typ := r.typ() - n := importvar(r.p.ipkg, pos, sym, typ) + n := importvar(pos, sym, typ) r.varExt(n) return n diff --git a/src/cmd/compile/internal/typecheck/syms.go b/src/cmd/compile/internal/typecheck/syms.go index f29af82db2c..ed3aaecc5a2 100644 --- a/src/cmd/compile/internal/typecheck/syms.go +++ b/src/cmd/compile/internal/typecheck/syms.go @@ -75,9 +75,9 @@ func InitRuntime() { typ := typs[d.typ] switch d.tag { case funcTag: - importfunc(ir.Pkgs.Runtime, src.NoXPos, sym, typ) + importfunc(src.NoXPos, sym, typ) case varTag: - importvar(ir.Pkgs.Runtime, src.NoXPos, sym, typ) + importvar(src.NoXPos, sym, typ) default: base.Fatalf("unhandled declaration tag %v", d.tag) } From 117ebe0f52efc5128a9c86722e07fe22cb65450d Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Wed, 16 Jun 2021 14:48:45 -0400 Subject: [PATCH 486/940] cmd/go: do not require the module cache to exist for 'go mod edit' Updates #46695 Change-Id: I4afbc1401ef4183d94c1ac6271394fac1fff95ae Reviewed-on: https://go-review.googlesource.com/c/go/+/328769 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Jay Conrod --- src/cmd/go/internal/modfetch/cache.go | 2 +- .../go/testdata/script/mod_edit_no_modcache.txt | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 src/cmd/go/testdata/script/mod_edit_no_modcache.txt diff --git a/src/cmd/go/internal/modfetch/cache.go b/src/cmd/go/internal/modfetch/cache.go index f3b58a172a6..b01b4674131 100644 --- a/src/cmd/go/internal/modfetch/cache.go +++ b/src/cmd/go/internal/modfetch/cache.go @@ -152,7 +152,7 @@ func lockVersion(mod module.Version) (unlock func(), err error) { // If err is nil, the caller MUST eventually call the unlock function. func SideLock() (unlock func(), err error) { if err := checkCacheDir(); err != nil { - base.Fatalf("go: %v", err) + return nil, err } path := filepath.Join(cfg.GOMODCACHE, "cache", "lock") diff --git a/src/cmd/go/testdata/script/mod_edit_no_modcache.txt b/src/cmd/go/testdata/script/mod_edit_no_modcache.txt new file mode 100644 index 00000000000..ced15bb3018 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_edit_no_modcache.txt @@ -0,0 +1,15 @@ +# 'go mod edit' opportunistically locks the side-lock file in the module cache, +# for compatibility with older versions of the 'go' command. +# It does not otherwise depend on the module cache, so it should not +# fail if the module cache directory cannot be created. + +[root] skip + +mkdir $WORK/readonly +chmod 0555 $WORK/readonly +env GOPATH=$WORK/readonly/nonexist + +go mod edit -go=1.17 + +-- go.mod -- +module example.com/m From 1de332996c25bf99bb31c82393dc018e6cec18ae Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 17 Jun 2021 12:28:53 -0400 Subject: [PATCH 487/940] doc/go1.17: document go/parser.SkipObjectResolution Documents the mode added in CL 306149 to skip object resolution. Fixes #46298 Change-Id: I6a14aaa00790f9f7e4e4ba17033355f5e878d74b Reviewed-on: https://go-review.googlesource.com/c/go/+/329009 Trust: Robert Findley Trust: Robert Griesemer Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- doc/go1.17.html | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/go1.17.html b/doc/go1.17.html index 94526512957..50559c89339 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -693,6 +693,16 @@ func Foo() bool {

+
go/parser
+
+

+ The new SkipObjectResolution + Mode value instructs the parser not to resolve identifiers to + their declaration. This may improve parsing speed. +

+
+
+
image

From 85a2e24afd87d94c62f78672dc28c1991b2a271c Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Tue, 15 Jun 2021 07:13:08 -0400 Subject: [PATCH 488/940] doc/go1.17: add security-related release notes Change-Id: I573def0f48fe66a1bc60fff321ab007c76b47ef0 Reviewed-on: https://go-review.googlesource.com/c/go/+/327810 Reviewed-by: Katie Hockman Trust: Katie Hockman Trust: Filippo Valsorda --- doc/go1.17.html | 124 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 115 insertions(+), 9 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 50559c89339..f1b3e3fdc70 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -441,6 +441,67 @@ func Foo() bool { runtime/cgo.Handle for more information.

+

URL query parsing

+ + +

+ The net/url and net/http packages used to accept + ";" (semicolon) as a setting separator in URL queries, in + addition to "&" (ampersand). Now, settings with non-percent-encoded + semicolons are rejected and net/http servers will log a warning to + Server.ErrorLog + when encountering one in a request URL. +

+ +

+ For example, before Go 1.17 the Query + method of the URL example?a=1;b=2&c=3 would have returned + map[a:[1] b:[2] c:[3]], while now it returns map[c:[3]]. +

+ +

+ When encountering such a query string, + URL.Query + and + Request.FormValue + ignore any settings that contain a semicolon, + ParseQuery + returns the remaining settings and an error, and + Request.ParseForm + and + Request.ParseMultipartForm + return an error but still set Request fields based on the + remaining settings. +

+ +

+ net/http users can restore the original behavior by using the new + AllowQuerySemicolons + handler wrapper. This will also suppress the ErrorLog warning. + Note that accepting semicolons as query separators can lead to security issues + if different systems interpret cache keys differently. + See issue 25192 for more information. +

+ +

TLS strict ALPN

+ + +

+ When Config.NextProtos + is set, servers now enforce that there is an overlap between the configured + protocols and the ALPN protocols advertised by the client, if any. If there is + no mutually supported protocol, the connection is closed with the + no_application_protocol alert, as required by RFC 7301. This + helps mitigate the ALPACA cross-protocol attack. +

+ +

+ As an exception, when the value "h2" is included in the server's + Config.NextProtos, HTTP/1.1 clients will be allowed to connect as + if they didn't support ALPN. + See issue 46310 for more information. +

+

Minor changes to the library

@@ -549,14 +610,6 @@ func Foo() bool { methods. Canceling the context after the handshake has finished has no effect.

-

- When Config.NextProtos - is set, servers now enforce that there is an overlap between the - configured protocols and the protocols advertised by the client, if any. - If there is no overlap the connection is closed with the - no_application_protocol alert, as required by RFC 7301. -

-

Cipher suite ordering is now handled entirely by the crypto/tls package. Currently, cipher suites are sorted based @@ -658,6 +711,22 @@ func Foo() bool {

+
encoding/xml
+
+

+ When a comment appears within a + Directive, it is now replaced + with a single space instead of being completely elided. +

+ +

+ Invalid element or attribute names with leading, trailing, or multiple + colons are now stored unmodified into the + Name.Local field. +

+
+
+
flag

@@ -744,6 +813,20 @@ func Foo() bool {

+
mime/multipart
+
+

+ Part.FileName + now applies + filepath.Base to the + return value. This mitigates potential path traversal vulnerabilities in + applications that accept multipart messages, such as net/http + servers that call + Request.FormFile. +

+
+
+
net

@@ -763,7 +846,7 @@ func Foo() bool { the net.Error interface.

-

+

The ParseIP and ParseCIDR functions now reject IPv4 addresses which contain decimal components with leading zeros. @@ -794,6 +877,29 @@ func Foo() bool { The ReadRequest function now returns an error when the request has multiple Host headers.

+ +

+ When producing a redirect to the cleaned version of a URL, + ServeMux now always + uses relative URLs in the Location header. Previously it + would echo the full URL of the request, which could lead to unintended + redirects if the client could be made to send an absolute request URL. +

+ +

+ When interpreting certain HTTP headers handled by net/http, + non-ASCII characters are now ignored or rejected. +

+ +

+ If + Request.ParseForm + returns an error when called by + Request.ParseMultipartForm, + the latter now continues populating + Request.MultipartForm + before returning it. +

From 7a5e7047a4606e1deab7d4adcf9f057c7f8ce88c Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Tue, 15 Jun 2021 10:59:58 -0400 Subject: [PATCH 489/940] doc/go1.17: add Go 1.18 pre-announcements Updates #41682 Updates #45428 Change-Id: Ia31d454284f0e114bd29ba398a2858fc90454032 Reviewed-on: https://go-review.googlesource.com/c/go/+/327811 Trust: Filippo Valsorda Trust: Katie Hockman Reviewed-by: Katie Hockman --- doc/go1.17.html | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/doc/go1.17.html b/doc/go1.17.html index f1b3e3fdc70..c9b64da2442 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -629,6 +629,15 @@ func Foo() bool { weakness. They are still enabled by default but only as a last resort, thanks to the cipher suite ordering change above.

+ +

+ Beginning in the next release, Go 1.18, the + Config.MinVersion + for crypto/tls clients will default to TLS 1.2, disabling TLS 1.0 + and TLS 1.1 by default. Applications will be able to override the change by + explicitly setting Config.MinVersion. + This will not affect crypto/tls servers. +

@@ -656,6 +665,14 @@ func Foo() bool { roots. This adds support for the new system trusted certificate store in FreeBSD 12.2+.

+ +

+ Beginning in the next release, Go 1.18, crypto/x509 will + reject certificates signed with the SHA-1 hash function. This doesn't + apply to self-signed root certificates. Practical attacks against SHA-1 + have been demonstrated in 2017 and publicly + trusted Certificate Authorities have not issued SHA-1 certificates since 2015. +

From ced0fdbad0655d63d535390b1a7126fd1fef8348 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Fri, 18 Jun 2021 15:07:00 -0700 Subject: [PATCH 490/940] doc/go1.17: note deprecation of 'go get' for installing commands Fixes #43684 Change-Id: I8982f6816c002c71e62f37a926c8543e34b8b785 Reviewed-on: https://go-review.googlesource.com/c/go/+/329549 Trust: Jay Conrod Reviewed-by: Bryan C. Mills --- doc/go1.17.html | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/go1.17.html b/doc/go1.17.html index c9b64da2442..02cd18d0375 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -214,6 +214,16 @@ Do not send CLs removing the interior tags from such phrases. environment for details.

+

+ go get prints a deprecation warning when installing + commands outside the main module (without the -d flag). + go install cmd@version should be used + instead to install a command at a specific version, using a suffix like + @latest or @v1.2.3. In Go 1.18, the -d + flag will always be enabled, and go get will only + be used to change dependencies in go.mod. +

+

go.mod files missing go directives

From 2e542c3c061950dbaf202645fb00bcf4aa5861a0 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Mon, 21 Jun 2021 12:09:43 -0400 Subject: [PATCH 491/940] runtime/pprof: deflake TestMorestack more Apparently, TestMorestack is still flaky on darwin/arm64 builder after CL 307730. Let it spend more time in copying the stack. With this CL, on my Apple M1 machine it passes reliably in short mode for 1000 runs, and reliably gets 250+ samples in the 5-second interval in long mode. May fix #46755. Change-Id: I07b36c1cf63ad35f7820e1f8e837e29376a37b2a Reviewed-on: https://go-review.googlesource.com/c/go/+/329869 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Pratt --- src/runtime/pprof/pprof_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go index f6ae15daabf..7c71d8263be 100644 --- a/src/runtime/pprof/pprof_test.go +++ b/src/runtime/pprof/pprof_test.go @@ -623,7 +623,7 @@ func growstack1() { //go:noinline func growstack(n int) { - var buf [8 << 16]byte + var buf [8 << 18]byte use(buf) if n > 0 { growstack(n - 1) @@ -631,7 +631,7 @@ func growstack(n int) { } //go:noinline -func use(x [8 << 16]byte) {} +func use(x [8 << 18]byte) {} func TestBlockProfile(t *testing.T) { type TestCase struct { From 16e82be454cbf41299e6a055d54d489ca4612ee0 Mon Sep 17 00:00:00 2001 From: Derek Parker Date: Thu, 17 Jun 2021 20:22:40 +0000 Subject: [PATCH 492/940] runtime: fix crash during VDSO calls on PowerPC This patch reinstates a fix for PowerPC with regard to making VDSO calls while receiving a signal, and subsequently crashing. The crash happens because certain VDSO calls can modify the r30 register, which is where g is stored. This change was reverted for PowerPC because r30 is supposed to be a non-volatile register. This is true, but that only makes a guarantee across function calls, but not "within" a function call. This patch was seemingly fine before because the Linux kernel still had hand rolled assembly VDSO function calls, however with a recent change to C function calls it seems the compiler used can generate instructions which temporarily clobber r30. This means that when we receive a signal during one of these calls the value of r30 will not be the g as the runtime expects, causing a segfault. You can see from this assembly dump how the register is clobbered during the call: (the following is from a 5.13rc2 kernel) ``` Dump of assembler code for function __cvdso_clock_gettime_data: 0x00007ffff7ff0700 <+0>: cmplwi r4,15 0x00007ffff7ff0704 <+4>: bgt 0x7ffff7ff07f0 <__cvdso_clock_gettime_data+240> 0x00007ffff7ff0708 <+8>: li r9,1 0x00007ffff7ff070c <+12>: slw r9,r9,r4 0x00007ffff7ff0710 <+16>: andi. r10,r9,2179 0x00007ffff7ff0714 <+20>: beq 0x7ffff7ff0810 <__cvdso_clock_gettime_data+272> 0x00007ffff7ff0718 <+24>: rldicr r10,r4,4,59 0x00007ffff7ff071c <+28>: lis r9,32767 0x00007ffff7ff0720 <+32>: std r30,-16(r1) 0x00007ffff7ff0724 <+36>: std r31,-8(r1) 0x00007ffff7ff0728 <+40>: add r6,r3,r10 0x00007ffff7ff072c <+44>: ori r4,r9,65535 0x00007ffff7ff0730 <+48>: lwz r8,0(r3) 0x00007ffff7ff0734 <+52>: andi. r9,r8,1 0x00007ffff7ff0738 <+56>: bne 0x7ffff7ff07d0 <__cvdso_clock_gettime_data+208> 0x00007ffff7ff073c <+60>: lwsync 0x00007ffff7ff0740 <+64>: mftb r30 <---- RIGHT HERE => 0x00007ffff7ff0744 <+68>: ld r12,40(r6) ``` What I believe is happening is that the kernel changed the PowerPC VDSO calls to use standard C calls instead of using hand rolled assembly. The hand rolled assembly calls never touched r30, so this change was safe to roll back. That does not seem to be the case anymore as on the 5.13rc2 kernel the compiler *is* generating assembly which modifies r30, making this change again unsafe and causing a crash when the program receives a signal during these calls (which will happen often due to async preempt). This change happened here: https://lwn.net/ml/linux-kernel/235e5571959cfa89ced081d7e838ed5ff38447d2.1601365870.git.christophe.leroy@csgroup.eu/. I realize this was reverted due to unexplained hangs in PowerPC builders, but I think we should reinstate this change and investigate those issues separately: https://github.com/golang/go/commit/f4ca3c1e0a2066ca4f7bd6203866d282ed34acf2 Fixes #46803 Change-Id: Ib18d7bbfc80a1a9cb558f0098878d41081324b52 GitHub-Last-Rev: c3002bcfca3ef58b27485e31328e6297b7a9dfe7 GitHub-Pull-Request: golang/go#46767 Reviewed-on: https://go-review.googlesource.com/c/go/+/328110 Run-TryBot: Lynn Boger TryBot-Result: Go Bot Reviewed-by: Cherry Mui Trust: Lynn Boger --- src/runtime/signal_unix.go | 2 +- src/runtime/sys_linux_ppc64x.s | 86 +++++++++++++++++++++++++++++----- 2 files changed, 74 insertions(+), 14 deletions(-) diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go index 03e2a40ce65..6096760b50c 100644 --- a/src/runtime/signal_unix.go +++ b/src/runtime/signal_unix.go @@ -382,7 +382,7 @@ func preemptM(mp *m) { //go:nosplit func sigFetchG(c *sigctxt) *g { switch GOARCH { - case "arm", "arm64": + case "arm", "arm64", "ppc64", "ppc64le": if !iscgo && inVDSOPage(c.sigpc()) { // When using cgo, we save the g on TLS and load it from there // in sigtramp. Just use that. diff --git a/src/runtime/sys_linux_ppc64x.s b/src/runtime/sys_linux_ppc64x.s index 05b5916db41..005fa4d2b4d 100644 --- a/src/runtime/sys_linux_ppc64x.s +++ b/src/runtime/sys_linux_ppc64x.s @@ -216,15 +216,45 @@ TEXT runtime·walltime(SB),NOSPLIT,$16-12 MOVD (g_sched+gobuf_sp)(R7), R1 // Set SP to g0 stack noswitch: - SUB $16, R1 // Space for results - RLDICR $0, R1, $59, R1 // Align for C code + SUB $16, R1 // Space for results + RLDICR $0, R1, $59, R1 // Align for C code MOVD R12, CTR MOVD R1, R4 - BL (CTR) // Call from VDSO - MOVD $0, R0 // Restore R0 - MOVD 0(R1), R3 // sec - MOVD 8(R1), R5 // nsec - MOVD R15, R1 // Restore SP + + // Store g on gsignal's stack, so if we receive a signal + // during VDSO code we can find the g. + // If we don't have a signal stack, we won't receive signal, + // so don't bother saving g. + // When using cgo, we already saved g on TLS, also don't save + // g here. + // Also don't save g if we are already on the signal stack. + // We won't get a nested signal. + MOVBZ runtime·iscgo(SB), R22 + CMP R22, $0 + BNE nosaveg + MOVD m_gsignal(R21), R22 // g.m.gsignal + CMP R22, $0 + BEQ nosaveg + + CMP g, R22 + BEQ nosaveg + MOVD (g_stack+stack_lo)(R22), R22 // g.m.gsignal.stack.lo + MOVD g, (R22) + + BL (CTR) // Call from VDSO + + MOVD $0, (R22) // clear g slot, R22 is unchanged by C code + + JMP finish + +nosaveg: + BL (CTR) // Call from VDSO + +finish: + MOVD $0, R0 // Restore R0 + MOVD 0(R1), R3 // sec + MOVD 8(R1), R5 // nsec + MOVD R15, R1 // Restore SP // Restore vdsoPC, vdsoSP // We don't worry about being signaled between the two stores. @@ -236,7 +266,7 @@ noswitch: MOVD 32(R1), R6 MOVD R6, m_vdsoPC(R21) -finish: +return: MOVD R3, sec+0(FP) MOVW R5, nsec+8(FP) RET @@ -247,7 +277,7 @@ fallback: SYSCALL $SYS_clock_gettime MOVD 32(R1), R3 MOVD 40(R1), R5 - JMP finish + JMP return TEXT runtime·nanotime1(SB),NOSPLIT,$16-8 MOVD $1, R3 // CLOCK_MONOTONIC @@ -283,7 +313,37 @@ noswitch: RLDICR $0, R1, $59, R1 // Align for C code MOVD R12, CTR MOVD R1, R4 - BL (CTR) // Call from VDSO + + // Store g on gsignal's stack, so if we receive a signal + // during VDSO code we can find the g. + // If we don't have a signal stack, we won't receive signal, + // so don't bother saving g. + // When using cgo, we already saved g on TLS, also don't save + // g here. + // Also don't save g if we are already on the signal stack. + // We won't get a nested signal. + MOVBZ runtime·iscgo(SB), R22 + CMP R22, $0 + BNE nosaveg + MOVD m_gsignal(R21), R22 // g.m.gsignal + CMP R22, $0 + BEQ nosaveg + + CMP g, R22 + BEQ nosaveg + MOVD (g_stack+stack_lo)(R22), R22 // g.m.gsignal.stack.lo + MOVD g, (R22) + + BL (CTR) // Call from VDSO + + MOVD $0, (R22) // clear g slot, R22 is unchanged by C code + + JMP finish + +nosaveg: + BL (CTR) // Call from VDSO + +finish: MOVD $0, R0 // Restore R0 MOVD 0(R1), R3 // sec MOVD 8(R1), R5 // nsec @@ -299,7 +359,7 @@ noswitch: MOVD 32(R1), R6 MOVD R6, m_vdsoPC(R21) -finish: +return: // sec is in R3, nsec in R5 // return nsec in R3 MOVD $1000000000, R4 @@ -314,7 +374,7 @@ fallback: SYSCALL $SYS_clock_gettime MOVD 32(R1), R3 MOVD 40(R1), R5 - JMP finish + JMP return TEXT runtime·rtsigprocmask(SB),NOSPLIT|NOFRAME,$0-28 MOVW how+0(FP), R3 @@ -469,7 +529,7 @@ TEXT sigtramp<>(SB),NOSPLIT|NOFRAME,$0 // this might be called in external code context, // where g is not set. MOVBZ runtime·iscgo(SB), R6 - CMP R6, $0 + CMP R6, $0 BEQ 2(PC) BL runtime·load_g(SB) From 44f9a3566ce564f9a21b1b92940a520ea241e065 Mon Sep 17 00:00:00 2001 From: Daniel Theophanes Date: Mon, 21 Jun 2021 11:11:20 -0500 Subject: [PATCH 493/940] database/sql: fix deadlock test in prepare statement The issue go#46783 correctly diagnosed the context timeout caused an intermittent failure when the context was canceled prior to the BeginTx call. However due to the asynchronous nature of canceling a Tx through a context on fast systems, the tx.Prepare also succeeded. On slower systems or if a time.Sleep was inserted between the BeginTx and Prepare, the Prepare would fail. Resolve this by moving the context cancel after the Prepare. This will still trigger the deadlock which I tested locally. In addition, I interspersed multiple time.Sleep calls and the test still functioned. Fixes #46852 Change-Id: I9cbf90d3c12b2555493a37799738772b615ae39d Reviewed-on: https://go-review.googlesource.com/c/go/+/329830 Run-TryBot: Daniel Theophanes Reviewed-by: Ian Lance Taylor Trust: Bryan C. Mills --- src/database/sql/sql_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go index 7d1cb9b85a5..f771dee4a97 100644 --- a/src/database/sql/sql_test.go +++ b/src/database/sql/sql_test.go @@ -2841,7 +2841,6 @@ func TestTxStmtDeadlock(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() tx, err := db.BeginTx(ctx, nil) - cancel() if err != nil { t.Fatal(err) } @@ -2850,6 +2849,7 @@ func TestTxStmtDeadlock(t *testing.T) { if err != nil { t.Fatal(err) } + cancel() // Run number of stmt queries to reproduce deadlock from context cancel for i := 0; i < 1e3; i++ { // Encounter any close related errors (e.g. ErrTxDone, stmt is closed) From 20bdfba32590c3dcce8885df875dc56a84b2d269 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Mon, 21 Jun 2021 12:52:17 -0400 Subject: [PATCH 494/940] go/scanner: fall back to next() when encountering 0 bytes in parseIdentifier CL 308611 optimized parseIdentifier for ASCII, but inadvertently skipped error handling for 0 bytes. Don't take the optimized path when encountering 0. Fixes #46855 Change-Id: Ic584e077eb74c012611fefa20eb71ca09c81b3c7 Reviewed-on: https://go-review.googlesource.com/c/go/+/329790 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/scanner/scanner.go | 2 +- src/go/scanner/scanner_test.go | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/go/scanner/scanner.go b/src/go/scanner/scanner.go index 29cbf39721f..f08e28cdd6b 100644 --- a/src/go/scanner/scanner.go +++ b/src/go/scanner/scanner.go @@ -373,7 +373,7 @@ func (s *Scanner) scanIdentifier() string { continue } s.rdOffset += rdOffset - if b < utf8.RuneSelf { + if 0 < b && b < utf8.RuneSelf { // Optimization: we've encountered an ASCII character that's not a letter // or number. Avoid the call into s.next() and corresponding set up. // diff --git a/src/go/scanner/scanner_test.go b/src/go/scanner/scanner_test.go index ac8d2577169..db123c32e01 100644 --- a/src/go/scanner/scanner_test.go +++ b/src/go/scanner/scanner_test.go @@ -812,6 +812,8 @@ var errors = []struct { {"//\ufeff", token.COMMENT, 2, "//\ufeff", "illegal byte order mark"}, // only first BOM is ignored {"'\ufeff" + `'`, token.CHAR, 1, "'\ufeff" + `'`, "illegal byte order mark"}, // only first BOM is ignored {`"` + "abc\ufeffdef" + `"`, token.STRING, 4, `"` + "abc\ufeffdef" + `"`, "illegal byte order mark"}, // only first BOM is ignored + {"abc\x00def", token.IDENT, 3, "abc", "illegal character NUL"}, + {"abc\x00", token.IDENT, 3, "abc", "illegal character NUL"}, } func TestScanErrors(t *testing.T) { From 3f9ec83b10c6de2a992b7458eb3be279f48eb6f8 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 20 Jun 2021 12:22:16 -0700 Subject: [PATCH 495/940] cmd/go: document GOPPC64 environment variable Change-Id: I2d2c02eec4ac6eca218fa5334d32650c1620692c Reviewed-on: https://go-review.googlesource.com/c/go/+/329689 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Carlos Eduardo Seo --- src/cmd/go/alldocs.go | 3 +++ src/cmd/go/internal/help/helpdoc.go | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index 3febe880cdd..27f993aeb35 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -1887,6 +1887,9 @@ // GOMIPS64 // For GOARCH=mips64{,le}, whether to use floating point instructions. // Valid values are hardfloat (default), softfloat. +// GOPPC64 +// For GOARCH=ppc64{,le}, the target ISA (Instruction Set Architecture). +// Valid values are power8 (default), power9. // GOWASM // For GOARCH=wasm, comma-separated list of experimental WebAssembly features to use. // Valid values are satconv, signext. diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go index 9ec65018926..b552777e3e0 100644 --- a/src/cmd/go/internal/help/helpdoc.go +++ b/src/cmd/go/internal/help/helpdoc.go @@ -598,6 +598,9 @@ Architecture-specific environment variables: GOMIPS64 For GOARCH=mips64{,le}, whether to use floating point instructions. Valid values are hardfloat (default), softfloat. + GOPPC64 + For GOARCH=ppc64{,le}, the target ISA (Instruction Set Architecture). + Valid values are power8 (default), power9. GOWASM For GOARCH=wasm, comma-separated list of experimental WebAssembly features to use. Valid values are satconv, signext. From a0400420ade001265f656c5dd9be1b48d7c8e6fe Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Wed, 16 Jun 2021 14:34:54 -0400 Subject: [PATCH 496/940] cmd/internal/moddeps: use -mod=readonly instead of -mod=mod MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TestAllDependencies is attempting to check that the modules in GOROOT satisfy certain properties; it should not modify those modules itself. The “quick” part of the test checks that vendored packages are present and complete, without constructing a parallel GOROOT. It shouldn't resolve new dependencies or change formatting in any way. The longer version of the test already constructs a parallel GOROOT and tidies the modules within it. That part of the test will flag any modifications needed to the go.mod and go.sum files, without modifying the original GOROOT. From what I can tell, the failure mode in #46695 is caused by running the test on a module rooted in $GOROOT proper. There is no such module in the mainline Go repo, but it may have been introduced in the fork and could also be introduced by stray edits in contributor CLs. It should be diagnosed clearly. For #46695 Change-Id: I62b90ccbd54cb3e3b413017021c952a7b1d455e7 Reviewed-on: https://go-review.googlesource.com/c/go/+/328770 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Dmitri Shuralyov --- src/cmd/internal/moddeps/moddeps_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/internal/moddeps/moddeps_test.go b/src/cmd/internal/moddeps/moddeps_test.go index 7723250468e..8d01b913c37 100644 --- a/src/cmd/internal/moddeps/moddeps_test.go +++ b/src/cmd/internal/moddeps/moddeps_test.go @@ -68,7 +68,7 @@ func TestAllDependencies(t *testing.T) { // There is no vendor directory, so the module must have no dependencies. // Check that the list of active modules contains only the main module. - cmd := exec.Command(goBin, "list", "-mod=mod", "-m", "all") + cmd := exec.Command(goBin, "list", "-mod=readonly", "-m", "all") cmd.Env = append(os.Environ(), "GO111MODULE=on") cmd.Dir = m.Dir cmd.Stderr = new(strings.Builder) From 761edf71f64bb2ef949ceb588822c47d2e1cc6ac Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Wed, 16 Jun 2021 16:33:29 -0400 Subject: [PATCH 497/940] cmd/internal/moddeps: use a temporary directory for GOMODCACHE if needed CL 328770 should be sufficient to fix the specific failure in the report, but when attempting to reproduce it I noticed a related failure mode, triggered by the environment variables set in src/run.bash. The failure mode is currently masked on the Go project builders due to the lack of any 'longtest' builder running as a non-root user (#10719). It is also masked from Go contributors running 'run.bash' locally because 'run.bash' does not actually run all of the tests unless GO_TEST_SHORT=0 is set in the environment (#29266, #46054). Fixes #46695 Change-Id: I272c09dae462734590dce59b3d3c5b6d3f733c92 Reviewed-on: https://go-review.googlesource.com/c/go/+/328771 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Dmitri Shuralyov --- src/cmd/internal/moddeps/moddeps_test.go | 33 ++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/cmd/internal/moddeps/moddeps_test.go b/src/cmd/internal/moddeps/moddeps_test.go index 8d01b913c37..56c3b2585c7 100644 --- a/src/cmd/internal/moddeps/moddeps_test.go +++ b/src/cmd/internal/moddeps/moddeps_test.go @@ -5,6 +5,7 @@ package moddeps_test import ( + "bytes" "encoding/json" "fmt" "internal/testenv" @@ -123,10 +124,38 @@ func TestAllDependencies(t *testing.T) { t.Skip("skipping because a diff command with support for --recursive and --unified flags is unavailable") } + // We're going to check the standard modules for tidiness, so we need a usable + // GOMODCACHE. If the default directory doesn't exist, use a temporary + // directory instead. (That can occur, for example, when running under + // run.bash with GO_TEST_SHORT=0: run.bash sets GOPATH=/nonexist-gopath, and + // GO_TEST_SHORT=0 causes it to run this portion of the test.) + var modcacheEnv []string + { + out, err := exec.Command(goBin, "env", "GOMODCACHE").Output() + if err != nil { + t.Fatalf("%s env GOMODCACHE: %v", goBin, err) + } + modcacheOk := false + if gomodcache := string(bytes.TrimSpace(out)); gomodcache != "" { + if _, err := os.Stat(gomodcache); err == nil { + modcacheOk = true + } + } + if !modcacheOk { + modcacheEnv = []string{ + "GOMODCACHE=" + t.TempDir(), + "GOFLAGS=" + os.Getenv("GOFLAGS") + " -modcacherw", // Allow t.TempDir() to clean up subdirectories. + } + } + } + // Build the bundle binary at the golang.org/x/tools // module version specified in GOROOT/src/cmd/go.mod. bundleDir := t.TempDir() - r := runner{Dir: filepath.Join(runtime.GOROOT(), "src/cmd")} + r := runner{ + Dir: filepath.Join(runtime.GOROOT(), "src/cmd"), + Env: append(os.Environ(), modcacheEnv...), + } r.run(t, goBin, "build", "-mod=readonly", "-o", bundleDir, "golang.org/x/tools/cmd/bundle") var gorootCopyDir string @@ -160,7 +189,7 @@ func TestAllDependencies(t *testing.T) { } r := runner{ Dir: filepath.Join(gorootCopyDir, rel), - Env: append(os.Environ(), + Env: append(append(os.Environ(), modcacheEnv...), // Set GOROOT. "GOROOT="+gorootCopyDir, // Explicitly override PWD and clear GOROOT_FINAL so that GOROOT=gorootCopyDir is definitely used. From 1bd5a20e3c8a3a82e87487c381b76c97b720cd52 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Fri, 18 Jun 2021 17:28:29 -0400 Subject: [PATCH 498/940] cmd/go: add a -go flag to 'go mod graph' For #46366 Change-Id: I8417e6e4dbb8cb56ff7afc16893a01b7bb938217 Reviewed-on: https://go-review.googlesource.com/c/go/+/329529 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Jay Conrod --- doc/go1.17.html | 7 ++ src/cmd/go/alldocs.go | 6 +- src/cmd/go/internal/modcmd/graph.go | 13 ++- src/cmd/go/internal/modcmd/verify.go | 3 +- src/cmd/go/internal/modget/get.go | 6 +- src/cmd/go/internal/modload/buildlist.go | 26 ++++- .../go/testdata/script/mod_graph_version.txt | 101 ++++++++++++++++++ 7 files changed, 154 insertions(+), 8 deletions(-) create mode 100644 src/cmd/go/testdata/script/mod_graph_version.txt diff --git a/doc/go1.17.html b/doc/go1.17.html index 02cd18d0375..22896c8c273 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -187,6 +187,13 @@ Do not send CLs removing the interior tags from such phrases. features.

+

+ The go mod graph subcommand also + supports the -go flag, which causes it to report the graph as + seen by the indicated Go version, showing dependencies that may otherwise be + pruned out by lazy loading. +

+

Module deprecation comments

diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index 27f993aeb35..fd95da23eb0 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -1186,13 +1186,17 @@ // // Usage: // -// go mod graph +// go mod graph [-go=version] // // Graph prints the module requirement graph (with replacements applied) // in text form. Each line in the output has two space-separated fields: a module // and one of its requirements. Each module is identified as a string of the form // path@version, except for the main module, which has no @version suffix. // +// The -go flag causes graph to report the module graph as loaded by by the +// given Go version, instead of the version indicated by the 'go' directive +// in the go.mod file. +// // See https://golang.org/ref/mod#go-mod-graph for more about 'go mod graph'. // // diff --git a/src/cmd/go/internal/modcmd/graph.go b/src/cmd/go/internal/modcmd/graph.go index 77853304e9d..903bd9970f1 100644 --- a/src/cmd/go/internal/modcmd/graph.go +++ b/src/cmd/go/internal/modcmd/graph.go @@ -18,7 +18,7 @@ import ( ) var cmdGraph = &base.Command{ - UsageLine: "go mod graph", + UsageLine: "go mod graph [-go=version]", Short: "print module requirement graph", Long: ` Graph prints the module requirement graph (with replacements applied) @@ -26,12 +26,21 @@ in text form. Each line in the output has two space-separated fields: a module and one of its requirements. Each module is identified as a string of the form path@version, except for the main module, which has no @version suffix. +The -go flag causes graph to report the module graph as loaded by by the +given Go version, instead of the version indicated by the 'go' directive +in the go.mod file. + See https://golang.org/ref/mod#go-mod-graph for more about 'go mod graph'. `, Run: runGraph, } +var ( + graphGo goVersionFlag +) + func init() { + cmdGraph.Flag.Var(&graphGo, "go", "") base.AddModCommonFlags(&cmdGraph.Flag) } @@ -41,7 +50,7 @@ func runGraph(ctx context.Context, cmd *base.Command, args []string) { } modload.ForceUseModules = true modload.RootMode = modload.NeedRoot - mg := modload.LoadModGraph(ctx) + mg := modload.LoadModGraph(ctx, graphGo.String()) w := bufio.NewWriter(os.Stdout) defer w.Flush() diff --git a/src/cmd/go/internal/modcmd/verify.go b/src/cmd/go/internal/modcmd/verify.go index 5c321c783ae..5a6eca32cfb 100644 --- a/src/cmd/go/internal/modcmd/verify.go +++ b/src/cmd/go/internal/modcmd/verify.go @@ -54,7 +54,8 @@ func runVerify(ctx context.Context, cmd *base.Command, args []string) { sem := make(chan token, runtime.GOMAXPROCS(0)) // Use a slice of result channels, so that the output is deterministic. - mods := modload.LoadModGraph(ctx).BuildList()[1:] + const defaultGoVersion = "" + mods := modload.LoadModGraph(ctx, defaultGoVersion).BuildList()[1:] errsChans := make([]<-chan []error, len(mods)) for i, mod := range mods { diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go index ea5c4e229a5..9672e5598e0 100644 --- a/src/cmd/go/internal/modget/get.go +++ b/src/cmd/go/internal/modget/get.go @@ -506,7 +506,8 @@ type versionReason struct { func newResolver(ctx context.Context, queries []*query) *resolver { // LoadModGraph also sets modload.Target, which is needed by various resolver // methods. - mg := modload.LoadModGraph(ctx) + const defaultGoVersion = "" + mg := modload.LoadModGraph(ctx, defaultGoVersion) buildList := mg.BuildList() initialVersion := make(map[string]string, len(buildList)) @@ -1803,7 +1804,8 @@ func (r *resolver) updateBuildList(ctx context.Context, additions []module.Versi return false } - r.buildList = modload.LoadModGraph(ctx).BuildList() + const defaultGoVersion = "" + r.buildList = modload.LoadModGraph(ctx, defaultGoVersion).BuildList() r.buildListVersion = make(map[string]string, len(r.buildList)) for _, m := range r.buildList { r.buildListVersion[m.Path] = m.Version diff --git a/src/cmd/go/internal/modload/buildlist.go b/src/cmd/go/internal/modload/buildlist.go index 64eaa16e8b1..604a57b4373 100644 --- a/src/cmd/go/internal/modload/buildlist.go +++ b/src/cmd/go/internal/modload/buildlist.go @@ -403,11 +403,33 @@ func (mg *ModuleGraph) allRootsSelected() bool { // LoadModGraph loads and returns the graph of module dependencies of the main module, // without loading any packages. // +// If the goVersion string is non-empty, the returned graph is the graph +// as interpreted by the given Go version (instead of the version indicated +// in the go.mod file). +// // Modules are loaded automatically (and lazily) in LoadPackages: // LoadModGraph need only be called if LoadPackages is not, // typically in commands that care about modules but no particular package. -func LoadModGraph(ctx context.Context) *ModuleGraph { - rs, mg, err := expandGraph(ctx, LoadModFile(ctx)) +func LoadModGraph(ctx context.Context, goVersion string) *ModuleGraph { + rs := LoadModFile(ctx) + + if goVersion != "" { + depth := modDepthFromGoVersion(goVersion) + if depth == eager && rs.depth != eager { + // Use newRequirements instead of convertDepth because convertDepth + // also updates roots; here, we want to report the unmodified roots + // even though they may seem inconsistent. + rs = newRequirements(eager, rs.rootModules, rs.direct) + } + + mg, err := rs.Graph(ctx) + if err != nil { + base.Fatalf("go: %v", err) + } + return mg + } + + rs, mg, err := expandGraph(ctx, rs) if err != nil { base.Fatalf("go: %v", err) } diff --git a/src/cmd/go/testdata/script/mod_graph_version.txt b/src/cmd/go/testdata/script/mod_graph_version.txt new file mode 100644 index 00000000000..f9a73f4617b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_graph_version.txt @@ -0,0 +1,101 @@ +# For this module, Go 1.17 prunes out a (transitive and otherwise-irrelevant) +# requirement on a retracted higher version of a dependency. +# However, when Go 1.16 reads the same requirements from the go.mod file, +# it does not prune out that requirement, and selects the retracted version. +# +# The Go 1.16 module graph looks like: +# +# m ---- lazy v0.1.0 ---- requireincompatible v0.1.0 ---- incompatible v2.0.0+incompatible +# | | +# + -------+------------- incompatible v1.0.0 +# +# The Go 1.17 module graph is the same except that the dependencies of +# requireincompatible are pruned out (because the module that requires +# it — lazy v0.1.0 — specifies 'go 1.17', and it is not otherwise relevant to +# the main module). + +cp go.mod go.mod.orig + +go mod graph +cp stdout graph-1.17.txt +stdout '^example\.com/m example\.com/retract/incompatible@v1\.0\.0$' +stdout '^example\.net/lazy@v0\.1\.0 example\.com/retract/incompatible@v1\.0\.0$' +! stdout 'example\.com/retract/incompatible@v2\.0\.0\+incompatible' + +go mod graph -go=1.17 +cmp stdout graph-1.17.txt + +cmp go.mod go.mod.orig + + +# Setting -go=1.16 should report the graph as viewed by Go 1.16, +# but should not edit the go.mod file. + +go mod graph -go=1.16 +cp stdout graph-1.16.txt +stdout '^example\.com/m example\.com/retract/incompatible@v1\.0\.0$' +stdout '^example\.net/lazy@v0\.1\.0 example.com/retract/incompatible@v1\.0\.0$' +stdout '^example.net/requireincompatible@v0.1.0 example.com/retract/incompatible@v2\.0\.0\+incompatible$' + +cmp go.mod go.mod.orig + + +# If we actually update the go.mod file to the requested go version, +# we should get the same selected versions, but the roots of the graph +# may be updated. +# +# TODO(#45551): The roots should not be updated. + +go mod edit -go=1.16 +go mod graph +! stdout '^example\.com/m example\.com/retract/incompatible@v1\.0\.0$' +stdout '^example\.net/lazy@v0.1.0 example.com/retract/incompatible@v1\.0\.0$' +stdout '^example.net/requireincompatible@v0.1.0 example.com/retract/incompatible@v2\.0\.0\+incompatible$' + # TODO(#45551): cmp stdout graph-1.16.txt + + +# Unsupported go versions should be rejected, since we don't know +# what versions they would report. +! go mod graph -go=1.99999999999 +stderr '^invalid value "1\.99999999999" for flag -go: maximum supported Go version is '$goversion'\nusage: go mod graph \[-go=version\]\nRun ''go help mod graph'' for details.$' + + +-- go.mod -- +// Module m indirectly imports a package from +// example.com/retract/incompatible. Its selected version of +// that module is lower under Go 1.17 semantics than under Go 1.16. +module example.com/m + +go 1.17 + +replace ( + example.net/lazy v0.1.0 => ./lazy + example.net/requireincompatible v0.1.0 => ./requireincompatible +) + +require ( + example.com/retract/incompatible v1.0.0 // indirect + example.net/lazy v0.1.0 +) +-- lazy/go.mod -- +// Module lazy requires example.com/retract/incompatible v1.0.0. +// +// When viewed from the outside it also has a transitive dependency +// on v2.0.0+incompatible, but in lazy mode that transitive dependency +// is pruned out. +module example.net/lazy + +go 1.17 + +exclude example.com/retract/incompatible v2.0.0+incompatible + +require ( + example.com/retract/incompatible v1.0.0 + example.net/requireincompatible v0.1.0 +) +-- requireincompatible/go.mod -- +module example.net/requireincompatible + +go 1.15 + +require example.com/retract/incompatible v2.0.0+incompatible From 9afd158eb228fbe191ffa27b1a334a8837c45ef7 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Mon, 21 Jun 2021 16:10:14 -0400 Subject: [PATCH 499/940] go/parser: parse an ast.IndexExpr for a[] To be consistent with Go 1.16, and to preserve as much information in the AST as possible, parse an ast.IndexExpr with BadExpr Index for the invalid expression a[]. A go/types test had to be adjusted to account for an additional error resulting from this change. We don't have a lot of test coverage for parser error recovery, so rather than write an ad-hoc test for this issue, add a new go/types test that checks that the indexed operand is used. Updates #46403 Change-Id: I21e6ff4179746aaa50e530d4091fded450e69824 Reviewed-on: https://go-review.googlesource.com/c/go/+/329791 Trust: Robert Findley Trust: Robert Griesemer Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/parser/parser.go | 7 ++++++- src/go/types/testdata/examples/functions.go2 | 2 +- src/go/types/testdata/fixedbugs/issue46403.src | 11 +++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 src/go/types/testdata/fixedbugs/issue46403.src diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go index 3965641713a..f10c8650afd 100644 --- a/src/go/parser/parser.go +++ b/src/go/parser/parser.go @@ -1302,7 +1302,12 @@ func (p *parser) parseIndexOrSliceOrInstance(x ast.Expr) ast.Expr { p.errorExpected(p.pos, "operand") rbrack := p.pos p.next() - return &ast.BadExpr{From: x.Pos(), To: rbrack} + return &ast.IndexExpr{ + X: x, + Lbrack: lbrack, + Index: &ast.BadExpr{From: rbrack, To: rbrack}, + Rbrack: rbrack, + } } p.exprLev++ diff --git a/src/go/types/testdata/examples/functions.go2 b/src/go/types/testdata/examples/functions.go2 index fb74ae7ae25..a0534712025 100644 --- a/src/go/types/testdata/examples/functions.go2 +++ b/src/go/types/testdata/examples/functions.go2 @@ -210,5 +210,5 @@ func _() { func h[] /* ERROR empty type parameter list */ () func _() { - h[] /* ERROR operand */ () + h /* ERROR cannot index */ [] /* ERROR operand */ () } diff --git a/src/go/types/testdata/fixedbugs/issue46403.src b/src/go/types/testdata/fixedbugs/issue46403.src new file mode 100644 index 00000000000..9d475222adb --- /dev/null +++ b/src/go/types/testdata/fixedbugs/issue46403.src @@ -0,0 +1,11 @@ +// Copyright 2021 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 issue46403 + +func _() { + // a should be used, despite the parser error below. + var a []int + var _ = a[] // ERROR expected operand +} From 197a5ee2ab8b64c687c74b986bf92139057366b6 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Mon, 21 Jun 2021 20:14:21 -0400 Subject: [PATCH 500/940] cmd/gofmt: remove stale documentation for the -G flag This documentation remained from the original dev.typeparams merge. This flag no longer exists. Change-Id: Ic9a82071c512614dc1382780d69ef13253fca21d Reviewed-on: https://go-review.googlesource.com/c/go/+/329792 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/gofmt/doc.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/cmd/gofmt/doc.go b/src/cmd/gofmt/doc.go index 68476e7d443..e3406655941 100644 --- a/src/cmd/gofmt/doc.go +++ b/src/cmd/gofmt/doc.go @@ -26,9 +26,6 @@ The flags are: Do not print reformatted sources to standard output. If a file's formatting is different from gofmt's, print its name to standard output. - -G - Allow generic code, using type parameters. - See golang.org/issues/43651 for more information. -r rule Apply the rewrite rule to the source before reformatting. -s From 859d903b06af669edbbc74be371186f732b60bfa Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 21 Jun 2021 20:03:58 -0700 Subject: [PATCH 501/940] [dev.typeparams] cmd/compile: add -d=unifiedquirks for quirks mode Originally, overloading -d=inlfuncswithclosures=0 to enable quirks mode was convenient because toolstash -cmp doesn't provide a way to pass different gcflags to the installed vs stashed toolchains. Prior to unified IR being merged, the stashed toolchain wouldn't know about or accept any unified-specific flags. However, this concern is no longer applicable since unified IR has been merged, and the TestUnifiedCompare test can easily specify different flag sets for the baseline and experiment build configs. This CL adds a new -d=unifiedquirks flag to enable quirks mode, so that it's possible to test unified IR with -d=inlfuncswithclosures=0 without also affecting a bunch of other compilation details. Change-Id: Id1932f332822622aa8617278e82ec6d1a53b1b46 Reviewed-on: https://go-review.googlesource.com/c/go/+/329733 Trust: Matthew Dempsky Reviewed-by: Cuong Manh Le Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot --- src/cmd/compile/internal/base/debug.go | 1 + src/cmd/compile/internal/noder/quirks.go | 5 +---- src/cmd/compile/internal/noder/unified_test.go | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/cmd/compile/internal/base/debug.go b/src/cmd/compile/internal/base/debug.go index fd420219466..e2245e1c26e 100644 --- a/src/cmd/compile/internal/base/debug.go +++ b/src/cmd/compile/internal/base/debug.go @@ -48,6 +48,7 @@ type DebugFlags struct { TypeAssert int `help:"print information about type assertion inlining"` TypecheckInl int `help:"eager typechecking of inline function bodies"` Unified int `help:"enable unified IR construction"` + UnifiedQuirks int `help:"enable unified IR construction's quirks mode"` WB int `help:"print information about write barriers"` ABIWrap int `help:"print information about ABI wrapper generation"` diff --git a/src/cmd/compile/internal/noder/quirks.go b/src/cmd/compile/internal/noder/quirks.go index 28a729f2763..91b4c22025b 100644 --- a/src/cmd/compile/internal/noder/quirks.go +++ b/src/cmd/compile/internal/noder/quirks.go @@ -23,10 +23,7 @@ import ( // quirksMode controls whether behavior specific to satisfying // toolstash -cmp is used. func quirksMode() bool { - // Currently, unified IR doesn't try to be compatible with - // -d=inlfuncswithclosures=1, so we overload this as a flag for - // enabling quirks mode. - return base.Debug.InlFuncsWithClosures == 0 + return base.Debug.UnifiedQuirks != 0 } // posBasesOf returns all of the position bases in the source files, diff --git a/src/cmd/compile/internal/noder/unified_test.go b/src/cmd/compile/internal/noder/unified_test.go index 242fa1282f4..4732892f6c0 100644 --- a/src/cmd/compile/internal/noder/unified_test.go +++ b/src/cmd/compile/internal/noder/unified_test.go @@ -59,7 +59,7 @@ func TestUnifiedCompare(t *testing.T) { } pkgs1 := loadPackages(t, goos, goarch, "-d=unified=0 -d=inlfuncswithclosures=0") - pkgs2 := loadPackages(t, goos, goarch, "-d=unified=1 -d=inlfuncswithclosures=0") + pkgs2 := loadPackages(t, goos, goarch, "-d=unified=1 -d=inlfuncswithclosures=0 -d=unifiedquirks=1") if len(pkgs1) != len(pkgs2) { t.Fatalf("length mismatch: %v != %v", len(pkgs1), len(pkgs2)) From 077100dfcd11b2aba4bd3099d5d28b4ce7de1126 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 21 Jun 2021 22:03:02 -0700 Subject: [PATCH 502/940] [dev.typeparams] cmd/compile: remove special escape analysis tags This CL removes the special escape analysis tags added to support //go:uintptrescapes and calls to external functions. Instead, these are kept as function pragmas. This CL by itself isn't very interesting, but I expect will help with subsequent cleanups I have planned here. Change-Id: Ifb960289a27e0a6295ce2d2f5ec233cac590522b Reviewed-on: https://go-review.googlesource.com/c/go/+/329969 Run-TryBot: Matthew Dempsky Reviewed-by: Cuong Manh Le Trust: Cuong Manh Le Trust: Matthew Dempsky --- src/cmd/compile/internal/escape/escape.go | 21 ++++----- src/cmd/compile/internal/ir/node.go | 19 +++++---- src/cmd/compile/internal/walk/order.go | 52 +++++++++++++---------- 3 files changed, 48 insertions(+), 44 deletions(-) diff --git a/src/cmd/compile/internal/escape/escape.go b/src/cmd/compile/internal/escape/escape.go index e3727bca27c..3a937518ecc 100644 --- a/src/cmd/compile/internal/escape/escape.go +++ b/src/cmd/compile/internal/escape/escape.go @@ -1132,7 +1132,7 @@ func (e *escape) tagHole(ks []hole, fn *ir.Name, param *types.Field) hole { // Call to previously tagged function. - if param.Note == UintptrEscapesNote { + if fn.Func != nil && fn.Func.Pragma&ir.UintptrEscapes != 0 && (param.Type.IsUintptr() || param.IsDDD() && param.Type.Elem().IsUintptr()) { k := e.heapHole() k.uintptrEscapesHack = true return k @@ -2048,15 +2048,6 @@ func HeapAllocReason(n ir.Node) string { return "" } -// This special tag is applied to uintptr variables -// that we believe may hold unsafe.Pointers for -// calls into assembly functions. -const UnsafeUintptrNote = "unsafe-uintptr" - -// This special tag is applied to uintptr parameters of functions -// marked go:uintptrescapes. -const UintptrEscapesNote = "uintptr-escapes" - func (b *batch) paramTag(fn *ir.Func, narg int, f *types.Field) string { name := func() string { if f.Sym != nil { @@ -2072,11 +2063,13 @@ func (b *batch) paramTag(fn *ir.Func, narg int, f *types.Field) string { // This really doesn't have much to do with escape analysis per se, // but we are reusing the ability to annotate an individual function // argument and pass those annotations along to importing code. + fn.Pragma |= ir.UintptrKeepAlive + if f.Type.IsUintptr() { if base.Flag.LowerM != 0 { base.WarnfAt(f.Pos, "assuming %v is unsafe uintptr", name()) } - return UnsafeUintptrNote + return "" } if !f.Type.HasPointers() { // don't bother tagging for scalars @@ -2102,18 +2095,20 @@ func (b *batch) paramTag(fn *ir.Func, narg int, f *types.Field) string { } if fn.Pragma&ir.UintptrEscapes != 0 { + fn.Pragma |= ir.UintptrKeepAlive + if f.Type.IsUintptr() { if base.Flag.LowerM != 0 { base.WarnfAt(f.Pos, "marking %v as escaping uintptr", name()) } - return UintptrEscapesNote + return "" } if f.IsDDD() && f.Type.Elem().IsUintptr() { // final argument is ...uintptr. if base.Flag.LowerM != 0 { base.WarnfAt(f.Pos, "marking %v as escaping ...uintptr", name()) } - return UintptrEscapesNote + return "" } } diff --git a/src/cmd/compile/internal/ir/node.go b/src/cmd/compile/internal/ir/node.go index 9191eeb1d6c..7c3dc10e46d 100644 --- a/src/cmd/compile/internal/ir/node.go +++ b/src/cmd/compile/internal/ir/node.go @@ -436,18 +436,19 @@ func (s NameSet) Sorted(less func(*Name, *Name) bool) []*Name { return res } -type PragmaFlag int16 +type PragmaFlag uint16 const ( // Func pragmas. - Nointerface PragmaFlag = 1 << iota - Noescape // func parameters don't escape - Norace // func must not have race detector annotations - Nosplit // func should not execute on separate stack - Noinline // func should not be inlined - NoCheckPtr // func should not be instrumented by checkptr - CgoUnsafeArgs // treat a pointer to one arg as a pointer to them all - UintptrEscapes // pointers converted to uintptr escape + Nointerface PragmaFlag = 1 << iota + Noescape // func parameters don't escape + Norace // func must not have race detector annotations + Nosplit // func should not execute on separate stack + Noinline // func should not be inlined + NoCheckPtr // func should not be instrumented by checkptr + CgoUnsafeArgs // treat a pointer to one arg as a pointer to them all + UintptrKeepAlive // pointers converted to uintptr must be kept alive (compiler internal only) + UintptrEscapes // pointers converted to uintptr escape // Runtime-only func pragmas. // See ../../../../runtime/README.md for detailed descriptions. diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go index 845bf036571..b9aff032404 100644 --- a/src/cmd/compile/internal/walk/order.go +++ b/src/cmd/compile/internal/walk/order.go @@ -9,7 +9,6 @@ import ( "go/constant" "cmd/compile/internal/base" - "cmd/compile/internal/escape" "cmd/compile/internal/ir" "cmd/compile/internal/reflectdata" "cmd/compile/internal/staticinit" @@ -554,37 +553,46 @@ func (o *orderState) call(nn ir.Node) { n.X = o.expr(n.X, nil) o.exprList(n.Args) - if n.Op() == ir.OCALLINTER { + // Pick out the function callee, if statically known. + // TODO(mdempsky): De-duplicate with similar code in escape analysis. + var callee *ir.Func + switch n.Op() { + case ir.OCALLFUNC: + if fn, ok := n.X.(*ir.Name); ok && fn.Op() == ir.ONAME && fn.Class == ir.PFUNC { + callee = fn.Func + } + case ir.OCALLMETH: + callee = ir.MethodExprName(n.X).Func + } + + if callee == nil || callee.Pragma&ir.UintptrKeepAlive == 0 { return } - keepAlive := func(arg ir.Node) { + + keepAlive := func(args []ir.Node) { // If the argument is really a pointer being converted to uintptr, // arrange for the pointer to be kept alive until the call returns, // by copying it into a temp and marking that temp // still alive when we pop the temp stack. - if arg.Op() == ir.OCONVNOP { - arg := arg.(*ir.ConvExpr) - if arg.X.Type().IsUnsafePtr() { - x := o.copyExpr(arg.X) - arg.X = x - x.SetAddrtaken(true) // ensure SSA keeps the x variable - n.KeepAlive = append(n.KeepAlive, x) + for _, arg := range args { + if arg.Op() == ir.OCONVNOP && arg.Type().IsUintptr() { + arg := arg.(*ir.ConvExpr) + if arg.X.Type().IsUnsafePtr() { + x := o.copyExpr(arg.X) + arg.X = x + x.SetAddrtaken(true) // ensure SSA keeps the x variable + n.KeepAlive = append(n.KeepAlive, x) + } } } } - // Check for "unsafe-uintptr" tag provided by escape analysis. - for i, param := range n.X.Type().Params().FieldSlice() { - if param.Note == escape.UnsafeUintptrNote || param.Note == escape.UintptrEscapesNote { - if arg := n.Args[i]; arg.Op() == ir.OSLICELIT { - arg := arg.(*ir.CompLitExpr) - for _, elt := range arg.List { - keepAlive(elt) - } - } else { - keepAlive(arg) - } - } + last := len(n.Args) - 1 + if n.IsDDD && n.Args[last].Op() == ir.OSLICELIT { + keepAlive(n.Args[:last]) + keepAlive(n.Args[last].(*ir.CompLitExpr).List) + } else { + keepAlive(n.Args) } } From 3e6219c6a9472e266d504d443b065e5a3e265a64 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 22 Jun 2021 01:26:34 -0700 Subject: [PATCH 503/940] [dev.typeparams] cmd/compile: split package escape into multiple files This CL reorganizes the code from package escape into multiple files, so the relationships between bits of code are hopefully easier to follow. Besides moving code around and adding necessary copyright/import declarations, no code is touched at all. Change-Id: Iddd396c3a140f4eb1a7a6266d92a4098118b575b Reviewed-on: https://go-review.googlesource.com/c/go/+/329989 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Trust: Matthew Dempsky Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/escape/assign.go | 120 ++ src/cmd/compile/internal/escape/call.go | 182 +++ src/cmd/compile/internal/escape/escape.go | 1722 +-------------------- src/cmd/compile/internal/escape/expr.go | 340 ++++ src/cmd/compile/internal/escape/graph.go | 324 ++++ src/cmd/compile/internal/escape/leaks.go | 106 ++ src/cmd/compile/internal/escape/solve.go | 289 ++++ src/cmd/compile/internal/escape/stmt.go | 208 +++ src/cmd/compile/internal/escape/utils.go | 215 +++ 9 files changed, 1797 insertions(+), 1709 deletions(-) create mode 100644 src/cmd/compile/internal/escape/assign.go create mode 100644 src/cmd/compile/internal/escape/call.go create mode 100644 src/cmd/compile/internal/escape/expr.go create mode 100644 src/cmd/compile/internal/escape/graph.go create mode 100644 src/cmd/compile/internal/escape/leaks.go create mode 100644 src/cmd/compile/internal/escape/solve.go create mode 100644 src/cmd/compile/internal/escape/stmt.go create mode 100644 src/cmd/compile/internal/escape/utils.go diff --git a/src/cmd/compile/internal/escape/assign.go b/src/cmd/compile/internal/escape/assign.go new file mode 100644 index 00000000000..80697bf37b3 --- /dev/null +++ b/src/cmd/compile/internal/escape/assign.go @@ -0,0 +1,120 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package escape + +import ( + "cmd/compile/internal/base" + "cmd/compile/internal/ir" +) + +// addr evaluates an addressable expression n and returns a hole +// that represents storing into the represented location. +func (e *escape) addr(n ir.Node) hole { + if n == nil || ir.IsBlank(n) { + // Can happen in select case, range, maybe others. + return e.discardHole() + } + + k := e.heapHole() + + switch n.Op() { + default: + base.Fatalf("unexpected addr: %v", n) + case ir.ONAME: + n := n.(*ir.Name) + if n.Class == ir.PEXTERN { + break + } + k = e.oldLoc(n).asHole() + case ir.OLINKSYMOFFSET: + break + case ir.ODOT: + n := n.(*ir.SelectorExpr) + k = e.addr(n.X) + case ir.OINDEX: + n := n.(*ir.IndexExpr) + e.discard(n.Index) + if n.X.Type().IsArray() { + k = e.addr(n.X) + } else { + e.discard(n.X) + } + case ir.ODEREF, ir.ODOTPTR: + e.discard(n) + case ir.OINDEXMAP: + n := n.(*ir.IndexExpr) + e.discard(n.X) + e.assignHeap(n.Index, "key of map put", n) + } + + return k +} + +func (e *escape) addrs(l ir.Nodes) []hole { + var ks []hole + for _, n := range l { + ks = append(ks, e.addr(n)) + } + return ks +} + +func (e *escape) assignHeap(src ir.Node, why string, where ir.Node) { + e.expr(e.heapHole().note(where, why), src) +} + +// assignList evaluates the assignment dsts... = srcs.... +func (e *escape) assignList(dsts, srcs []ir.Node, why string, where ir.Node) { + ks := e.addrs(dsts) + for i, k := range ks { + var src ir.Node + if i < len(srcs) { + src = srcs[i] + } + + if dst := dsts[i]; dst != nil { + // Detect implicit conversion of uintptr to unsafe.Pointer when + // storing into reflect.{Slice,String}Header. + if dst.Op() == ir.ODOTPTR && ir.IsReflectHeaderDataField(dst) { + e.unsafeValue(e.heapHole().note(where, why), src) + continue + } + + // Filter out some no-op assignments for escape analysis. + if src != nil && isSelfAssign(dst, src) { + if base.Flag.LowerM != 0 { + base.WarnfAt(where.Pos(), "%v ignoring self-assignment in %v", e.curfn, where) + } + k = e.discardHole() + } + } + + e.expr(k.note(where, why), src) + } + + e.reassigned(ks, where) +} + +// reassigned marks the locations associated with the given holes as +// reassigned, unless the location represents a variable declared and +// assigned exactly once by where. +func (e *escape) reassigned(ks []hole, where ir.Node) { + if as, ok := where.(*ir.AssignStmt); ok && as.Op() == ir.OAS && as.Y == nil { + if dst, ok := as.X.(*ir.Name); ok && dst.Op() == ir.ONAME && dst.Defn == nil { + // Zero-value assignment for variable declared without an + // explicit initial value. Assume this is its initialization + // statement. + return + } + } + + for _, k := range ks { + loc := k.dst + // Variables declared by range statements are assigned on every iteration. + if n, ok := loc.n.(*ir.Name); ok && n.Defn == where && where.Op() != ir.ORANGE { + continue + } + loc.reassigned = true + } +} diff --git a/src/cmd/compile/internal/escape/call.go b/src/cmd/compile/internal/escape/call.go new file mode 100644 index 00000000000..28a3b679a56 --- /dev/null +++ b/src/cmd/compile/internal/escape/call.go @@ -0,0 +1,182 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package escape + +import ( + "cmd/compile/internal/base" + "cmd/compile/internal/ir" + "cmd/compile/internal/typecheck" + "cmd/compile/internal/types" +) + +// call evaluates a call expressions, including builtin calls. ks +// should contain the holes representing where the function callee's +// results flows; where is the OGO/ODEFER context of the call, if any. +func (e *escape) call(ks []hole, call, where ir.Node) { + topLevelDefer := where != nil && where.Op() == ir.ODEFER && e.loopDepth == 1 + if topLevelDefer { + // force stack allocation of defer record, unless + // open-coded defers are used (see ssa.go) + where.SetEsc(ir.EscNever) + } + + argument := func(k hole, arg ir.Node) { + if topLevelDefer { + // Top level defers arguments don't escape to + // heap, but they do need to last until end of + // function. + k = e.later(k) + } else if where != nil { + k = e.heapHole() + } + + e.expr(k.note(call, "call parameter"), arg) + } + + switch call.Op() { + default: + ir.Dump("esc", call) + base.Fatalf("unexpected call op: %v", call.Op()) + + case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER: + call := call.(*ir.CallExpr) + typecheck.FixVariadicCall(call) + + // Pick out the function callee, if statically known. + var fn *ir.Name + switch call.Op() { + case ir.OCALLFUNC: + switch v := ir.StaticValue(call.X); { + case v.Op() == ir.ONAME && v.(*ir.Name).Class == ir.PFUNC: + fn = v.(*ir.Name) + case v.Op() == ir.OCLOSURE: + fn = v.(*ir.ClosureExpr).Func.Nname + } + case ir.OCALLMETH: + fn = ir.MethodExprName(call.X) + } + + fntype := call.X.Type() + if fn != nil { + fntype = fn.Type() + } + + if ks != nil && fn != nil && e.inMutualBatch(fn) { + for i, result := range fn.Type().Results().FieldSlice() { + e.expr(ks[i], ir.AsNode(result.Nname)) + } + } + + if r := fntype.Recv(); r != nil { + argument(e.tagHole(ks, fn, r), call.X.(*ir.SelectorExpr).X) + } else { + // Evaluate callee function expression. + argument(e.discardHole(), call.X) + } + + args := call.Args + for i, param := range fntype.Params().FieldSlice() { + argument(e.tagHole(ks, fn, param), args[i]) + } + + case ir.OAPPEND: + call := call.(*ir.CallExpr) + args := call.Args + + // Appendee slice may flow directly to the result, if + // it has enough capacity. Alternatively, a new heap + // slice might be allocated, and all slice elements + // might flow to heap. + appendeeK := ks[0] + if args[0].Type().Elem().HasPointers() { + appendeeK = e.teeHole(appendeeK, e.heapHole().deref(call, "appendee slice")) + } + argument(appendeeK, args[0]) + + if call.IsDDD { + appendedK := e.discardHole() + if args[1].Type().IsSlice() && args[1].Type().Elem().HasPointers() { + appendedK = e.heapHole().deref(call, "appended slice...") + } + argument(appendedK, args[1]) + } else { + for _, arg := range args[1:] { + argument(e.heapHole(), arg) + } + } + + case ir.OCOPY: + call := call.(*ir.BinaryExpr) + argument(e.discardHole(), call.X) + + copiedK := e.discardHole() + if call.Y.Type().IsSlice() && call.Y.Type().Elem().HasPointers() { + copiedK = e.heapHole().deref(call, "copied slice") + } + argument(copiedK, call.Y) + + case ir.OPANIC: + call := call.(*ir.UnaryExpr) + argument(e.heapHole(), call.X) + + case ir.OCOMPLEX: + call := call.(*ir.BinaryExpr) + argument(e.discardHole(), call.X) + argument(e.discardHole(), call.Y) + case ir.ODELETE, ir.OPRINT, ir.OPRINTN, ir.ORECOVER: + call := call.(*ir.CallExpr) + for _, arg := range call.Args { + argument(e.discardHole(), arg) + } + case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE: + call := call.(*ir.UnaryExpr) + argument(e.discardHole(), call.X) + + case ir.OUNSAFEADD, ir.OUNSAFESLICE: + call := call.(*ir.BinaryExpr) + argument(ks[0], call.X) + argument(e.discardHole(), call.Y) + } +} + +// tagHole returns a hole for evaluating an argument passed to param. +// ks should contain the holes representing where the function +// callee's results flows. fn is the statically-known callee function, +// if any. +func (e *escape) tagHole(ks []hole, fn *ir.Name, param *types.Field) hole { + // If this is a dynamic call, we can't rely on param.Note. + if fn == nil { + return e.heapHole() + } + + if e.inMutualBatch(fn) { + return e.addr(ir.AsNode(param.Nname)) + } + + // Call to previously tagged function. + + if fn.Func != nil && fn.Func.Pragma&ir.UintptrEscapes != 0 && (param.Type.IsUintptr() || param.IsDDD() && param.Type.Elem().IsUintptr()) { + k := e.heapHole() + k.uintptrEscapesHack = true + return k + } + + var tagKs []hole + + esc := parseLeaks(param.Note) + if x := esc.Heap(); x >= 0 { + tagKs = append(tagKs, e.heapHole().shift(x)) + } + + if ks != nil { + for i := 0; i < numEscResults; i++ { + if x := esc.Result(i); x >= 0 { + tagKs = append(tagKs, ks[i].shift(x)) + } + } + } + + return e.teeHole(tagKs...) +} diff --git a/src/cmd/compile/internal/escape/escape.go b/src/cmd/compile/internal/escape/escape.go index 3a937518ecc..8f75ae8b426 100644 --- a/src/cmd/compile/internal/escape/escape.go +++ b/src/cmd/compile/internal/escape/escape.go @@ -6,15 +6,11 @@ package escape import ( "fmt" - "math" - "strings" "cmd/compile/internal/base" "cmd/compile/internal/ir" "cmd/compile/internal/logopt" - "cmd/compile/internal/typecheck" "cmd/compile/internal/types" - "cmd/internal/src" ) // Escape analysis. @@ -118,90 +114,8 @@ type escape struct { loopDepth int } -// An location represents an abstract location that stores a Go -// variable. -type location struct { - n ir.Node // represented variable or expression, if any - curfn *ir.Func // enclosing function - edges []edge // incoming edges - loopDepth int // loopDepth at declaration - - // resultIndex records the tuple index (starting at 1) for - // PPARAMOUT variables within their function's result type. - // For non-PPARAMOUT variables it's 0. - resultIndex int - - // derefs and walkgen are used during walkOne to track the - // minimal dereferences from the walk root. - derefs int // >= -1 - walkgen uint32 - - // dst and dstEdgeindex track the next immediate assignment - // destination location during walkone, along with the index - // of the edge pointing back to this location. - dst *location - dstEdgeIdx int - - // queued is used by walkAll to track whether this location is - // in the walk queue. - queued bool - - // escapes reports whether the represented variable's address - // escapes; that is, whether the variable must be heap - // allocated. - escapes bool - - // transient reports whether the represented expression's - // address does not outlive the statement; that is, whether - // its storage can be immediately reused. - transient bool - - // paramEsc records the represented parameter's leak set. - paramEsc leaks - - captured bool // has a closure captured this variable? - reassigned bool // has this variable been reassigned? - addrtaken bool // has this variable's address been taken? -} - -// An edge represents an assignment edge between two Go variables. -type edge struct { - src *location - derefs int // >= -1 - notes *note -} - -// Fmt is called from node printing to print information about escape analysis results. -func Fmt(n ir.Node) string { - text := "" - switch n.Esc() { - case ir.EscUnknown: - break - - case ir.EscHeap: - text = "esc(h)" - - case ir.EscNone: - text = "esc(no)" - - case ir.EscNever: - text = "esc(N)" - - default: - text = fmt.Sprintf("esc(%d)", n.Esc()) - } - - if n.Op() == ir.ONAME { - n := n.(*ir.Name) - if loc, ok := n.Opt.(*location); ok && loc.loopDepth != 0 { - if text != "" { - text += " " - } - text += fmt.Sprintf("ld(%d)", loc.loopDepth) - } - } - - return text +func Funcs(all []ir.Node) { + ir.VisitFuncsBottomUp(all, Batch) } // Batch performs escape analysis on a minimal batch of @@ -342,1323 +256,6 @@ func (b *batch) flowClosure(k hole, clo *ir.ClosureExpr) { } } -// Below we implement the methods for walking the AST and recording -// data flow edges. Note that because a sub-expression might have -// side-effects, it's important to always visit the entire AST. -// -// For example, write either: -// -// if x { -// e.discard(n.Left) -// } else { -// e.value(k, n.Left) -// } -// -// or -// -// if x { -// k = e.discardHole() -// } -// e.value(k, n.Left) -// -// Do NOT write: -// -// // BAD: possibly loses side-effects within n.Left -// if !x { -// e.value(k, n.Left) -// } - -// stmt evaluates a single Go statement. -func (e *escape) stmt(n ir.Node) { - if n == nil { - return - } - - lno := ir.SetPos(n) - defer func() { - base.Pos = lno - }() - - if base.Flag.LowerM > 2 { - fmt.Printf("%v:[%d] %v stmt: %v\n", base.FmtPos(base.Pos), e.loopDepth, e.curfn, n) - } - - e.stmts(n.Init()) - - switch n.Op() { - default: - base.Fatalf("unexpected stmt: %v", n) - - case ir.ODCLCONST, ir.ODCLTYPE, ir.OFALL, ir.OINLMARK: - // nop - - case ir.OBREAK, ir.OCONTINUE, ir.OGOTO: - // TODO(mdempsky): Handle dead code? - - case ir.OBLOCK: - n := n.(*ir.BlockStmt) - e.stmts(n.List) - - case ir.ODCL: - // Record loop depth at declaration. - n := n.(*ir.Decl) - if !ir.IsBlank(n.X) { - e.dcl(n.X) - } - - case ir.OLABEL: - n := n.(*ir.LabelStmt) - switch e.labels[n.Label] { - case nonlooping: - if base.Flag.LowerM > 2 { - fmt.Printf("%v:%v non-looping label\n", base.FmtPos(base.Pos), n) - } - case looping: - if base.Flag.LowerM > 2 { - fmt.Printf("%v: %v looping label\n", base.FmtPos(base.Pos), n) - } - e.loopDepth++ - default: - base.Fatalf("label missing tag") - } - delete(e.labels, n.Label) - - case ir.OIF: - n := n.(*ir.IfStmt) - e.discard(n.Cond) - e.block(n.Body) - e.block(n.Else) - - case ir.OFOR, ir.OFORUNTIL: - n := n.(*ir.ForStmt) - e.loopDepth++ - e.discard(n.Cond) - e.stmt(n.Post) - e.block(n.Body) - e.loopDepth-- - - case ir.ORANGE: - // for Key, Value = range X { Body } - n := n.(*ir.RangeStmt) - - // X is evaluated outside the loop. - tmp := e.newLoc(nil, false) - e.expr(tmp.asHole(), n.X) - - e.loopDepth++ - ks := e.addrs([]ir.Node{n.Key, n.Value}) - if n.X.Type().IsArray() { - e.flow(ks[1].note(n, "range"), tmp) - } else { - e.flow(ks[1].deref(n, "range-deref"), tmp) - } - e.reassigned(ks, n) - - e.block(n.Body) - e.loopDepth-- - - case ir.OSWITCH: - n := n.(*ir.SwitchStmt) - - if guard, ok := n.Tag.(*ir.TypeSwitchGuard); ok { - var ks []hole - if guard.Tag != nil { - for _, cas := range n.Cases { - cv := cas.Var - k := e.dcl(cv) // type switch variables have no ODCL. - if cv.Type().HasPointers() { - ks = append(ks, k.dotType(cv.Type(), cas, "switch case")) - } - } - } - e.expr(e.teeHole(ks...), n.Tag.(*ir.TypeSwitchGuard).X) - } else { - e.discard(n.Tag) - } - - for _, cas := range n.Cases { - e.discards(cas.List) - e.block(cas.Body) - } - - case ir.OSELECT: - n := n.(*ir.SelectStmt) - for _, cas := range n.Cases { - e.stmt(cas.Comm) - e.block(cas.Body) - } - case ir.ORECV: - // TODO(mdempsky): Consider e.discard(n.Left). - n := n.(*ir.UnaryExpr) - e.exprSkipInit(e.discardHole(), n) // already visited n.Ninit - case ir.OSEND: - n := n.(*ir.SendStmt) - e.discard(n.Chan) - e.assignHeap(n.Value, "send", n) - - case ir.OAS: - n := n.(*ir.AssignStmt) - e.assignList([]ir.Node{n.X}, []ir.Node{n.Y}, "assign", n) - case ir.OASOP: - n := n.(*ir.AssignOpStmt) - // TODO(mdempsky): Worry about OLSH/ORSH? - e.assignList([]ir.Node{n.X}, []ir.Node{n.Y}, "assign", n) - case ir.OAS2: - n := n.(*ir.AssignListStmt) - e.assignList(n.Lhs, n.Rhs, "assign-pair", n) - - case ir.OAS2DOTTYPE: // v, ok = x.(type) - n := n.(*ir.AssignListStmt) - e.assignList(n.Lhs, n.Rhs, "assign-pair-dot-type", n) - case ir.OAS2MAPR: // v, ok = m[k] - n := n.(*ir.AssignListStmt) - e.assignList(n.Lhs, n.Rhs, "assign-pair-mapr", n) - case ir.OAS2RECV, ir.OSELRECV2: // v, ok = <-ch - n := n.(*ir.AssignListStmt) - e.assignList(n.Lhs, n.Rhs, "assign-pair-receive", n) - - case ir.OAS2FUNC: - n := n.(*ir.AssignListStmt) - e.stmts(n.Rhs[0].Init()) - ks := e.addrs(n.Lhs) - e.call(ks, n.Rhs[0], nil) - e.reassigned(ks, n) - case ir.ORETURN: - n := n.(*ir.ReturnStmt) - results := e.curfn.Type().Results().FieldSlice() - dsts := make([]ir.Node, len(results)) - for i, res := range results { - dsts[i] = res.Nname.(*ir.Name) - } - e.assignList(dsts, n.Results, "return", n) - case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OCLOSE, ir.OCOPY, ir.ODELETE, ir.OPANIC, ir.OPRINT, ir.OPRINTN, ir.ORECOVER: - e.call(nil, n, nil) - case ir.OGO, ir.ODEFER: - n := n.(*ir.GoDeferStmt) - e.stmts(n.Call.Init()) - e.call(nil, n.Call, n) - - case ir.OTAILCALL: - // TODO(mdempsky): Treat like a normal call? esc.go used to just ignore it. - } -} - -func (e *escape) stmts(l ir.Nodes) { - for _, n := range l { - e.stmt(n) - } -} - -// block is like stmts, but preserves loopDepth. -func (e *escape) block(l ir.Nodes) { - old := e.loopDepth - e.stmts(l) - e.loopDepth = old -} - -// expr models evaluating an expression n and flowing the result into -// hole k. -func (e *escape) expr(k hole, n ir.Node) { - if n == nil { - return - } - e.stmts(n.Init()) - e.exprSkipInit(k, n) -} - -func (e *escape) exprSkipInit(k hole, n ir.Node) { - if n == nil { - return - } - - lno := ir.SetPos(n) - defer func() { - base.Pos = lno - }() - - uintptrEscapesHack := k.uintptrEscapesHack - k.uintptrEscapesHack = false - - if uintptrEscapesHack && n.Op() == ir.OCONVNOP && n.(*ir.ConvExpr).X.Type().IsUnsafePtr() { - // nop - } else if k.derefs >= 0 && !n.Type().HasPointers() { - k.dst = &e.blankLoc - } - - switch n.Op() { - default: - base.Fatalf("unexpected expr: %s %v", n.Op().String(), n) - - case ir.OLITERAL, ir.ONIL, ir.OGETG, ir.OTYPE, ir.OMETHEXPR, ir.OLINKSYMOFFSET: - // nop - - case ir.ONAME: - n := n.(*ir.Name) - if n.Class == ir.PFUNC || n.Class == ir.PEXTERN { - return - } - if n.IsClosureVar() && n.Defn == nil { - return // ".this" from method value wrapper - } - e.flow(k, e.oldLoc(n)) - - case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT: - n := n.(*ir.UnaryExpr) - e.discard(n.X) - case ir.OADD, ir.OSUB, ir.OOR, ir.OXOR, ir.OMUL, ir.ODIV, ir.OMOD, ir.OLSH, ir.ORSH, ir.OAND, ir.OANDNOT, ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE: - n := n.(*ir.BinaryExpr) - e.discard(n.X) - e.discard(n.Y) - case ir.OANDAND, ir.OOROR: - n := n.(*ir.LogicalExpr) - e.discard(n.X) - e.discard(n.Y) - case ir.OADDR: - n := n.(*ir.AddrExpr) - e.expr(k.addr(n, "address-of"), n.X) // "address-of" - case ir.ODEREF: - n := n.(*ir.StarExpr) - e.expr(k.deref(n, "indirection"), n.X) // "indirection" - case ir.ODOT, ir.ODOTMETH, ir.ODOTINTER: - n := n.(*ir.SelectorExpr) - e.expr(k.note(n, "dot"), n.X) - case ir.ODOTPTR: - n := n.(*ir.SelectorExpr) - e.expr(k.deref(n, "dot of pointer"), n.X) // "dot of pointer" - case ir.ODOTTYPE, ir.ODOTTYPE2: - n := n.(*ir.TypeAssertExpr) - e.expr(k.dotType(n.Type(), n, "dot"), n.X) - case ir.OINDEX: - n := n.(*ir.IndexExpr) - if n.X.Type().IsArray() { - e.expr(k.note(n, "fixed-array-index-of"), n.X) - } else { - // TODO(mdempsky): Fix why reason text. - e.expr(k.deref(n, "dot of pointer"), n.X) - } - e.discard(n.Index) - case ir.OINDEXMAP: - n := n.(*ir.IndexExpr) - e.discard(n.X) - e.discard(n.Index) - case ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR, ir.OSLICESTR: - n := n.(*ir.SliceExpr) - e.expr(k.note(n, "slice"), n.X) - e.discard(n.Low) - e.discard(n.High) - e.discard(n.Max) - - case ir.OCONV, ir.OCONVNOP: - n := n.(*ir.ConvExpr) - if ir.ShouldCheckPtr(e.curfn, 2) && n.Type().IsUnsafePtr() && n.X.Type().IsPtr() { - // When -d=checkptr=2 is enabled, treat - // conversions to unsafe.Pointer as an - // escaping operation. This allows better - // runtime instrumentation, since we can more - // easily detect object boundaries on the heap - // than the stack. - e.assignHeap(n.X, "conversion to unsafe.Pointer", n) - } else if n.Type().IsUnsafePtr() && n.X.Type().IsUintptr() { - e.unsafeValue(k, n.X) - } else { - e.expr(k, n.X) - } - case ir.OCONVIFACE: - n := n.(*ir.ConvExpr) - if !n.X.Type().IsInterface() && !types.IsDirectIface(n.X.Type()) { - k = e.spill(k, n) - } - e.expr(k.note(n, "interface-converted"), n.X) - case ir.OEFACE: - n := n.(*ir.BinaryExpr) - // Note: n.X is not needed because it can never point to memory that might escape. - e.expr(k, n.Y) - case ir.OIDATA, ir.OSPTR: - n := n.(*ir.UnaryExpr) - e.expr(k, n.X) - case ir.OSLICE2ARRPTR: - // the slice pointer flows directly to the result - n := n.(*ir.ConvExpr) - e.expr(k, n.X) - case ir.ORECV: - n := n.(*ir.UnaryExpr) - e.discard(n.X) - - case ir.OCALLMETH, ir.OCALLFUNC, ir.OCALLINTER, ir.OLEN, ir.OCAP, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCOPY, ir.OUNSAFEADD, ir.OUNSAFESLICE: - e.call([]hole{k}, n, nil) - - case ir.ONEW: - n := n.(*ir.UnaryExpr) - e.spill(k, n) - - case ir.OMAKESLICE: - n := n.(*ir.MakeExpr) - e.spill(k, n) - e.discard(n.Len) - e.discard(n.Cap) - case ir.OMAKECHAN: - n := n.(*ir.MakeExpr) - e.discard(n.Len) - case ir.OMAKEMAP: - n := n.(*ir.MakeExpr) - e.spill(k, n) - e.discard(n.Len) - - case ir.ORECOVER: - // nop - - case ir.OCALLPART: - // Flow the receiver argument to both the closure and - // to the receiver parameter. - - n := n.(*ir.SelectorExpr) - closureK := e.spill(k, n) - - m := n.Selection - - // We don't know how the method value will be called - // later, so conservatively assume the result - // parameters all flow to the heap. - // - // TODO(mdempsky): Change ks into a callback, so that - // we don't have to create this slice? - var ks []hole - for i := m.Type.NumResults(); i > 0; i-- { - ks = append(ks, e.heapHole()) - } - name, _ := m.Nname.(*ir.Name) - paramK := e.tagHole(ks, name, m.Type.Recv()) - - e.expr(e.teeHole(paramK, closureK), n.X) - - case ir.OPTRLIT: - n := n.(*ir.AddrExpr) - e.expr(e.spill(k, n), n.X) - - case ir.OARRAYLIT: - n := n.(*ir.CompLitExpr) - for _, elt := range n.List { - if elt.Op() == ir.OKEY { - elt = elt.(*ir.KeyExpr).Value - } - e.expr(k.note(n, "array literal element"), elt) - } - - case ir.OSLICELIT: - n := n.(*ir.CompLitExpr) - k = e.spill(k, n) - k.uintptrEscapesHack = uintptrEscapesHack // for ...uintptr parameters - - for _, elt := range n.List { - if elt.Op() == ir.OKEY { - elt = elt.(*ir.KeyExpr).Value - } - e.expr(k.note(n, "slice-literal-element"), elt) - } - - case ir.OSTRUCTLIT: - n := n.(*ir.CompLitExpr) - for _, elt := range n.List { - e.expr(k.note(n, "struct literal element"), elt.(*ir.StructKeyExpr).Value) - } - - case ir.OMAPLIT: - n := n.(*ir.CompLitExpr) - e.spill(k, n) - - // Map keys and values are always stored in the heap. - for _, elt := range n.List { - elt := elt.(*ir.KeyExpr) - e.assignHeap(elt.Key, "map literal key", n) - e.assignHeap(elt.Value, "map literal value", n) - } - - case ir.OCLOSURE: - n := n.(*ir.ClosureExpr) - k = e.spill(k, n) - e.closures = append(e.closures, closure{k, n}) - - if fn := n.Func; fn.IsHiddenClosure() { - for _, cv := range fn.ClosureVars { - if loc := e.oldLoc(cv); !loc.captured { - loc.captured = true - - // Ignore reassignments to the variable in straightline code - // preceding the first capture by a closure. - if loc.loopDepth == e.loopDepth { - loc.reassigned = false - } - } - } - - for _, n := range fn.Dcl { - // Add locations for local variables of the - // closure, if needed, in case we're not including - // the closure func in the batch for escape - // analysis (happens for escape analysis called - // from reflectdata.methodWrapper) - if n.Op() == ir.ONAME && n.Opt == nil { - e.with(fn).newLoc(n, false) - } - } - e.walkFunc(fn) - } - - case ir.ORUNES2STR, ir.OBYTES2STR, ir.OSTR2RUNES, ir.OSTR2BYTES, ir.ORUNESTR: - n := n.(*ir.ConvExpr) - e.spill(k, n) - e.discard(n.X) - - case ir.OADDSTR: - n := n.(*ir.AddStringExpr) - e.spill(k, n) - - // Arguments of OADDSTR never escape; - // runtime.concatstrings makes sure of that. - e.discards(n.List) - } -} - -// unsafeValue evaluates a uintptr-typed arithmetic expression looking -// for conversions from an unsafe.Pointer. -func (e *escape) unsafeValue(k hole, n ir.Node) { - if n.Type().Kind() != types.TUINTPTR { - base.Fatalf("unexpected type %v for %v", n.Type(), n) - } - if k.addrtaken { - base.Fatalf("unexpected addrtaken") - } - - e.stmts(n.Init()) - - switch n.Op() { - case ir.OCONV, ir.OCONVNOP: - n := n.(*ir.ConvExpr) - if n.X.Type().IsUnsafePtr() { - e.expr(k, n.X) - } else { - e.discard(n.X) - } - case ir.ODOTPTR: - n := n.(*ir.SelectorExpr) - if ir.IsReflectHeaderDataField(n) { - e.expr(k.deref(n, "reflect.Header.Data"), n.X) - } else { - e.discard(n.X) - } - case ir.OPLUS, ir.ONEG, ir.OBITNOT: - n := n.(*ir.UnaryExpr) - e.unsafeValue(k, n.X) - case ir.OADD, ir.OSUB, ir.OOR, ir.OXOR, ir.OMUL, ir.ODIV, ir.OMOD, ir.OAND, ir.OANDNOT: - n := n.(*ir.BinaryExpr) - e.unsafeValue(k, n.X) - e.unsafeValue(k, n.Y) - case ir.OLSH, ir.ORSH: - n := n.(*ir.BinaryExpr) - e.unsafeValue(k, n.X) - // RHS need not be uintptr-typed (#32959) and can't meaningfully - // flow pointers anyway. - e.discard(n.Y) - default: - e.exprSkipInit(e.discardHole(), n) - } -} - -// discard evaluates an expression n for side-effects, but discards -// its value. -func (e *escape) discard(n ir.Node) { - e.expr(e.discardHole(), n) -} - -func (e *escape) discards(l ir.Nodes) { - for _, n := range l { - e.discard(n) - } -} - -// addr evaluates an addressable expression n and returns a hole -// that represents storing into the represented location. -func (e *escape) addr(n ir.Node) hole { - if n == nil || ir.IsBlank(n) { - // Can happen in select case, range, maybe others. - return e.discardHole() - } - - k := e.heapHole() - - switch n.Op() { - default: - base.Fatalf("unexpected addr: %v", n) - case ir.ONAME: - n := n.(*ir.Name) - if n.Class == ir.PEXTERN { - break - } - k = e.oldLoc(n).asHole() - case ir.OLINKSYMOFFSET: - break - case ir.ODOT: - n := n.(*ir.SelectorExpr) - k = e.addr(n.X) - case ir.OINDEX: - n := n.(*ir.IndexExpr) - e.discard(n.Index) - if n.X.Type().IsArray() { - k = e.addr(n.X) - } else { - e.discard(n.X) - } - case ir.ODEREF, ir.ODOTPTR: - e.discard(n) - case ir.OINDEXMAP: - n := n.(*ir.IndexExpr) - e.discard(n.X) - e.assignHeap(n.Index, "key of map put", n) - } - - return k -} - -func (e *escape) addrs(l ir.Nodes) []hole { - var ks []hole - for _, n := range l { - ks = append(ks, e.addr(n)) - } - return ks -} - -// reassigned marks the locations associated with the given holes as -// reassigned, unless the location represents a variable declared and -// assigned exactly once by where. -func (e *escape) reassigned(ks []hole, where ir.Node) { - if as, ok := where.(*ir.AssignStmt); ok && as.Op() == ir.OAS && as.Y == nil { - if dst, ok := as.X.(*ir.Name); ok && dst.Op() == ir.ONAME && dst.Defn == nil { - // Zero-value assignment for variable declared without an - // explicit initial value. Assume this is its initialization - // statement. - return - } - } - - for _, k := range ks { - loc := k.dst - // Variables declared by range statements are assigned on every iteration. - if n, ok := loc.n.(*ir.Name); ok && n.Defn == where && where.Op() != ir.ORANGE { - continue - } - loc.reassigned = true - } -} - -// assignList evaluates the assignment dsts... = srcs.... -func (e *escape) assignList(dsts, srcs []ir.Node, why string, where ir.Node) { - ks := e.addrs(dsts) - for i, k := range ks { - var src ir.Node - if i < len(srcs) { - src = srcs[i] - } - - if dst := dsts[i]; dst != nil { - // Detect implicit conversion of uintptr to unsafe.Pointer when - // storing into reflect.{Slice,String}Header. - if dst.Op() == ir.ODOTPTR && ir.IsReflectHeaderDataField(dst) { - e.unsafeValue(e.heapHole().note(where, why), src) - continue - } - - // Filter out some no-op assignments for escape analysis. - if src != nil && isSelfAssign(dst, src) { - if base.Flag.LowerM != 0 { - base.WarnfAt(where.Pos(), "%v ignoring self-assignment in %v", e.curfn, where) - } - k = e.discardHole() - } - } - - e.expr(k.note(where, why), src) - } - - e.reassigned(ks, where) -} - -func (e *escape) assignHeap(src ir.Node, why string, where ir.Node) { - e.expr(e.heapHole().note(where, why), src) -} - -// call evaluates a call expressions, including builtin calls. ks -// should contain the holes representing where the function callee's -// results flows; where is the OGO/ODEFER context of the call, if any. -func (e *escape) call(ks []hole, call, where ir.Node) { - topLevelDefer := where != nil && where.Op() == ir.ODEFER && e.loopDepth == 1 - if topLevelDefer { - // force stack allocation of defer record, unless - // open-coded defers are used (see ssa.go) - where.SetEsc(ir.EscNever) - } - - argument := func(k hole, arg ir.Node) { - if topLevelDefer { - // Top level defers arguments don't escape to - // heap, but they do need to last until end of - // function. - k = e.later(k) - } else if where != nil { - k = e.heapHole() - } - - e.expr(k.note(call, "call parameter"), arg) - } - - switch call.Op() { - default: - ir.Dump("esc", call) - base.Fatalf("unexpected call op: %v", call.Op()) - - case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER: - call := call.(*ir.CallExpr) - typecheck.FixVariadicCall(call) - - // Pick out the function callee, if statically known. - var fn *ir.Name - switch call.Op() { - case ir.OCALLFUNC: - switch v := ir.StaticValue(call.X); { - case v.Op() == ir.ONAME && v.(*ir.Name).Class == ir.PFUNC: - fn = v.(*ir.Name) - case v.Op() == ir.OCLOSURE: - fn = v.(*ir.ClosureExpr).Func.Nname - } - case ir.OCALLMETH: - fn = ir.MethodExprName(call.X) - } - - fntype := call.X.Type() - if fn != nil { - fntype = fn.Type() - } - - if ks != nil && fn != nil && e.inMutualBatch(fn) { - for i, result := range fn.Type().Results().FieldSlice() { - e.expr(ks[i], ir.AsNode(result.Nname)) - } - } - - if r := fntype.Recv(); r != nil { - argument(e.tagHole(ks, fn, r), call.X.(*ir.SelectorExpr).X) - } else { - // Evaluate callee function expression. - argument(e.discardHole(), call.X) - } - - args := call.Args - for i, param := range fntype.Params().FieldSlice() { - argument(e.tagHole(ks, fn, param), args[i]) - } - - case ir.OAPPEND: - call := call.(*ir.CallExpr) - args := call.Args - - // Appendee slice may flow directly to the result, if - // it has enough capacity. Alternatively, a new heap - // slice might be allocated, and all slice elements - // might flow to heap. - appendeeK := ks[0] - if args[0].Type().Elem().HasPointers() { - appendeeK = e.teeHole(appendeeK, e.heapHole().deref(call, "appendee slice")) - } - argument(appendeeK, args[0]) - - if call.IsDDD { - appendedK := e.discardHole() - if args[1].Type().IsSlice() && args[1].Type().Elem().HasPointers() { - appendedK = e.heapHole().deref(call, "appended slice...") - } - argument(appendedK, args[1]) - } else { - for _, arg := range args[1:] { - argument(e.heapHole(), arg) - } - } - - case ir.OCOPY: - call := call.(*ir.BinaryExpr) - argument(e.discardHole(), call.X) - - copiedK := e.discardHole() - if call.Y.Type().IsSlice() && call.Y.Type().Elem().HasPointers() { - copiedK = e.heapHole().deref(call, "copied slice") - } - argument(copiedK, call.Y) - - case ir.OPANIC: - call := call.(*ir.UnaryExpr) - argument(e.heapHole(), call.X) - - case ir.OCOMPLEX: - call := call.(*ir.BinaryExpr) - argument(e.discardHole(), call.X) - argument(e.discardHole(), call.Y) - case ir.ODELETE, ir.OPRINT, ir.OPRINTN, ir.ORECOVER: - call := call.(*ir.CallExpr) - for _, arg := range call.Args { - argument(e.discardHole(), arg) - } - case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE: - call := call.(*ir.UnaryExpr) - argument(e.discardHole(), call.X) - - case ir.OUNSAFEADD, ir.OUNSAFESLICE: - call := call.(*ir.BinaryExpr) - argument(ks[0], call.X) - argument(e.discardHole(), call.Y) - } -} - -// tagHole returns a hole for evaluating an argument passed to param. -// ks should contain the holes representing where the function -// callee's results flows. fn is the statically-known callee function, -// if any. -func (e *escape) tagHole(ks []hole, fn *ir.Name, param *types.Field) hole { - // If this is a dynamic call, we can't rely on param.Note. - if fn == nil { - return e.heapHole() - } - - if e.inMutualBatch(fn) { - return e.addr(ir.AsNode(param.Nname)) - } - - // Call to previously tagged function. - - if fn.Func != nil && fn.Func.Pragma&ir.UintptrEscapes != 0 && (param.Type.IsUintptr() || param.IsDDD() && param.Type.Elem().IsUintptr()) { - k := e.heapHole() - k.uintptrEscapesHack = true - return k - } - - var tagKs []hole - - esc := parseLeaks(param.Note) - if x := esc.Heap(); x >= 0 { - tagKs = append(tagKs, e.heapHole().shift(x)) - } - - if ks != nil { - for i := 0; i < numEscResults; i++ { - if x := esc.Result(i); x >= 0 { - tagKs = append(tagKs, ks[i].shift(x)) - } - } - } - - return e.teeHole(tagKs...) -} - -// inMutualBatch reports whether function fn is in the batch of -// mutually recursive functions being analyzed. When this is true, -// fn has not yet been analyzed, so its parameters and results -// should be incorporated directly into the flow graph instead of -// relying on its escape analysis tagging. -func (e *escape) inMutualBatch(fn *ir.Name) bool { - if fn.Defn != nil && fn.Defn.Esc() < escFuncTagged { - if fn.Defn.Esc() == escFuncUnknown { - base.Fatalf("graph inconsistency: %v", fn) - } - return true - } - return false -} - -// An hole represents a context for evaluation a Go -// expression. E.g., when evaluating p in "x = **p", we'd have a hole -// with dst==x and derefs==2. -type hole struct { - dst *location - derefs int // >= -1 - notes *note - - // addrtaken indicates whether this context is taking the address of - // the expression, independent of whether the address will actually - // be stored into a variable. - addrtaken bool - - // uintptrEscapesHack indicates this context is evaluating an - // argument for a //go:uintptrescapes function. - uintptrEscapesHack bool -} - -type note struct { - next *note - where ir.Node - why string -} - -func (k hole) note(where ir.Node, why string) hole { - if where == nil || why == "" { - base.Fatalf("note: missing where/why") - } - if base.Flag.LowerM >= 2 || logopt.Enabled() { - k.notes = ¬e{ - next: k.notes, - where: where, - why: why, - } - } - return k -} - -func (k hole) shift(delta int) hole { - k.derefs += delta - if k.derefs < -1 { - base.Fatalf("derefs underflow: %v", k.derefs) - } - k.addrtaken = delta < 0 - return k -} - -func (k hole) deref(where ir.Node, why string) hole { return k.shift(1).note(where, why) } -func (k hole) addr(where ir.Node, why string) hole { return k.shift(-1).note(where, why) } - -func (k hole) dotType(t *types.Type, where ir.Node, why string) hole { - if !t.IsInterface() && !types.IsDirectIface(t) { - k = k.shift(1) - } - return k.note(where, why) -} - -// teeHole returns a new hole that flows into each hole of ks, -// similar to the Unix tee(1) command. -func (e *escape) teeHole(ks ...hole) hole { - if len(ks) == 0 { - return e.discardHole() - } - if len(ks) == 1 { - return ks[0] - } - // TODO(mdempsky): Optimize if there's only one non-discard hole? - - // Given holes "l1 = _", "l2 = **_", "l3 = *_", ..., create a - // new temporary location ltmp, wire it into place, and return - // a hole for "ltmp = _". - loc := e.newLoc(nil, true) - for _, k := range ks { - // N.B., "p = &q" and "p = &tmp; tmp = q" are not - // semantically equivalent. To combine holes like "l1 - // = _" and "l2 = &_", we'd need to wire them as "l1 = - // *ltmp" and "l2 = ltmp" and return "ltmp = &_" - // instead. - if k.derefs < 0 { - base.Fatalf("teeHole: negative derefs") - } - - e.flow(k, loc) - } - return loc.asHole() -} - -func (e *escape) dcl(n *ir.Name) hole { - if n.Curfn != e.curfn || n.IsClosureVar() { - base.Fatalf("bad declaration of %v", n) - } - loc := e.oldLoc(n) - loc.loopDepth = e.loopDepth - return loc.asHole() -} - -// spill allocates a new location associated with expression n, flows -// its address to k, and returns a hole that flows values to it. It's -// intended for use with most expressions that allocate storage. -func (e *escape) spill(k hole, n ir.Node) hole { - loc := e.newLoc(n, true) - e.flow(k.addr(n, "spill"), loc) - return loc.asHole() -} - -// later returns a new hole that flows into k, but some time later. -// Its main effect is to prevent immediate reuse of temporary -// variables introduced during Order. -func (e *escape) later(k hole) hole { - loc := e.newLoc(nil, false) - e.flow(k, loc) - return loc.asHole() -} - -func (e *escape) newLoc(n ir.Node, transient bool) *location { - if e.curfn == nil { - base.Fatalf("e.curfn isn't set") - } - if n != nil && n.Type() != nil && n.Type().NotInHeap() { - base.ErrorfAt(n.Pos(), "%v is incomplete (or unallocatable); stack allocation disallowed", n.Type()) - } - - if n != nil && n.Op() == ir.ONAME { - n = n.(*ir.Name).Canonical() - } - loc := &location{ - n: n, - curfn: e.curfn, - loopDepth: e.loopDepth, - transient: transient, - } - e.allLocs = append(e.allLocs, loc) - if n != nil { - if n.Op() == ir.ONAME { - n := n.(*ir.Name) - if n.Curfn != e.curfn { - base.Fatalf("curfn mismatch: %v != %v for %v", n.Curfn, e.curfn, n) - } - - if n.Opt != nil { - base.Fatalf("%v already has a location", n) - } - n.Opt = loc - } - } - return loc -} - -func (b *batch) oldLoc(n *ir.Name) *location { - if n.Canonical().Opt == nil { - base.Fatalf("%v has no location", n) - } - return n.Canonical().Opt.(*location) -} - -func (l *location) asHole() hole { - return hole{dst: l} -} - -func (b *batch) flow(k hole, src *location) { - if k.addrtaken { - src.addrtaken = true - } - - dst := k.dst - if dst == &b.blankLoc { - return - } - if dst == src && k.derefs >= 0 { // dst = dst, dst = *dst, ... - return - } - if dst.escapes && k.derefs < 0 { // dst = &src - if base.Flag.LowerM >= 2 || logopt.Enabled() { - pos := base.FmtPos(src.n.Pos()) - if base.Flag.LowerM >= 2 { - fmt.Printf("%s: %v escapes to heap:\n", pos, src.n) - } - explanation := b.explainFlow(pos, dst, src, k.derefs, k.notes, []*logopt.LoggedOpt{}) - if logopt.Enabled() { - var e_curfn *ir.Func // TODO(mdempsky): Fix. - logopt.LogOpt(src.n.Pos(), "escapes", "escape", ir.FuncName(e_curfn), fmt.Sprintf("%v escapes to heap", src.n), explanation) - } - - } - src.escapes = true - return - } - - // TODO(mdempsky): Deduplicate edges? - dst.edges = append(dst.edges, edge{src: src, derefs: k.derefs, notes: k.notes}) -} - -func (b *batch) heapHole() hole { return b.heapLoc.asHole() } -func (b *batch) discardHole() hole { return b.blankLoc.asHole() } - -// walkAll computes the minimal dereferences between all pairs of -// locations. -func (b *batch) walkAll() { - // We use a work queue to keep track of locations that we need - // to visit, and repeatedly walk until we reach a fixed point. - // - // We walk once from each location (including the heap), and - // then re-enqueue each location on its transition from - // transient->!transient and !escapes->escapes, which can each - // happen at most once. So we take Θ(len(e.allLocs)) walks. - - // LIFO queue, has enough room for e.allLocs and e.heapLoc. - todo := make([]*location, 0, len(b.allLocs)+1) - enqueue := func(loc *location) { - if !loc.queued { - todo = append(todo, loc) - loc.queued = true - } - } - - for _, loc := range b.allLocs { - enqueue(loc) - } - enqueue(&b.heapLoc) - - var walkgen uint32 - for len(todo) > 0 { - root := todo[len(todo)-1] - todo = todo[:len(todo)-1] - root.queued = false - - walkgen++ - b.walkOne(root, walkgen, enqueue) - } -} - -// walkOne computes the minimal number of dereferences from root to -// all other locations. -func (b *batch) walkOne(root *location, walkgen uint32, enqueue func(*location)) { - // The data flow graph has negative edges (from addressing - // operations), so we use the Bellman-Ford algorithm. However, - // we don't have to worry about infinite negative cycles since - // we bound intermediate dereference counts to 0. - - root.walkgen = walkgen - root.derefs = 0 - root.dst = nil - - todo := []*location{root} // LIFO queue - for len(todo) > 0 { - l := todo[len(todo)-1] - todo = todo[:len(todo)-1] - - derefs := l.derefs - - // If l.derefs < 0, then l's address flows to root. - addressOf := derefs < 0 - if addressOf { - // For a flow path like "root = &l; l = x", - // l's address flows to root, but x's does - // not. We recognize this by lower bounding - // derefs at 0. - derefs = 0 - - // If l's address flows to a non-transient - // location, then l can't be transiently - // allocated. - if !root.transient && l.transient { - l.transient = false - enqueue(l) - } - } - - if b.outlives(root, l) { - // l's value flows to root. If l is a function - // parameter and root is the heap or a - // corresponding result parameter, then record - // that value flow for tagging the function - // later. - if l.isName(ir.PPARAM) { - if (logopt.Enabled() || base.Flag.LowerM >= 2) && !l.escapes { - if base.Flag.LowerM >= 2 { - fmt.Printf("%s: parameter %v leaks to %s with derefs=%d:\n", base.FmtPos(l.n.Pos()), l.n, b.explainLoc(root), derefs) - } - explanation := b.explainPath(root, l) - if logopt.Enabled() { - var e_curfn *ir.Func // TODO(mdempsky): Fix. - logopt.LogOpt(l.n.Pos(), "leak", "escape", ir.FuncName(e_curfn), - fmt.Sprintf("parameter %v leaks to %s with derefs=%d", l.n, b.explainLoc(root), derefs), explanation) - } - } - l.leakTo(root, derefs) - } - - // If l's address flows somewhere that - // outlives it, then l needs to be heap - // allocated. - if addressOf && !l.escapes { - if logopt.Enabled() || base.Flag.LowerM >= 2 { - if base.Flag.LowerM >= 2 { - fmt.Printf("%s: %v escapes to heap:\n", base.FmtPos(l.n.Pos()), l.n) - } - explanation := b.explainPath(root, l) - if logopt.Enabled() { - var e_curfn *ir.Func // TODO(mdempsky): Fix. - logopt.LogOpt(l.n.Pos(), "escape", "escape", ir.FuncName(e_curfn), fmt.Sprintf("%v escapes to heap", l.n), explanation) - } - } - l.escapes = true - enqueue(l) - continue - } - } - - for i, edge := range l.edges { - if edge.src.escapes { - continue - } - d := derefs + edge.derefs - if edge.src.walkgen != walkgen || edge.src.derefs > d { - edge.src.walkgen = walkgen - edge.src.derefs = d - edge.src.dst = l - edge.src.dstEdgeIdx = i - todo = append(todo, edge.src) - } - } - } -} - -// explainPath prints an explanation of how src flows to the walk root. -func (b *batch) explainPath(root, src *location) []*logopt.LoggedOpt { - visited := make(map[*location]bool) - pos := base.FmtPos(src.n.Pos()) - var explanation []*logopt.LoggedOpt - for { - // Prevent infinite loop. - if visited[src] { - if base.Flag.LowerM >= 2 { - fmt.Printf("%s: warning: truncated explanation due to assignment cycle; see golang.org/issue/35518\n", pos) - } - break - } - visited[src] = true - dst := src.dst - edge := &dst.edges[src.dstEdgeIdx] - if edge.src != src { - base.Fatalf("path inconsistency: %v != %v", edge.src, src) - } - - explanation = b.explainFlow(pos, dst, src, edge.derefs, edge.notes, explanation) - - if dst == root { - break - } - src = dst - } - - return explanation -} - -func (b *batch) explainFlow(pos string, dst, srcloc *location, derefs int, notes *note, explanation []*logopt.LoggedOpt) []*logopt.LoggedOpt { - ops := "&" - if derefs >= 0 { - ops = strings.Repeat("*", derefs) - } - print := base.Flag.LowerM >= 2 - - flow := fmt.Sprintf(" flow: %s = %s%v:", b.explainLoc(dst), ops, b.explainLoc(srcloc)) - if print { - fmt.Printf("%s:%s\n", pos, flow) - } - if logopt.Enabled() { - var epos src.XPos - if notes != nil { - epos = notes.where.Pos() - } else if srcloc != nil && srcloc.n != nil { - epos = srcloc.n.Pos() - } - var e_curfn *ir.Func // TODO(mdempsky): Fix. - explanation = append(explanation, logopt.NewLoggedOpt(epos, "escflow", "escape", ir.FuncName(e_curfn), flow)) - } - - for note := notes; note != nil; note = note.next { - if print { - fmt.Printf("%s: from %v (%v) at %s\n", pos, note.where, note.why, base.FmtPos(note.where.Pos())) - } - if logopt.Enabled() { - var e_curfn *ir.Func // TODO(mdempsky): Fix. - explanation = append(explanation, logopt.NewLoggedOpt(note.where.Pos(), "escflow", "escape", ir.FuncName(e_curfn), - fmt.Sprintf(" from %v (%v)", note.where, note.why))) - } - } - return explanation -} - -func (b *batch) explainLoc(l *location) string { - if l == &b.heapLoc { - return "{heap}" - } - if l.n == nil { - // TODO(mdempsky): Omit entirely. - return "{temp}" - } - if l.n.Op() == ir.ONAME { - return fmt.Sprintf("%v", l.n) - } - return fmt.Sprintf("{storage for %v}", l.n) -} - -// outlives reports whether values stored in l may survive beyond -// other's lifetime if stack allocated. -func (b *batch) outlives(l, other *location) bool { - // The heap outlives everything. - if l.escapes { - return true - } - - // We don't know what callers do with returned values, so - // pessimistically we need to assume they flow to the heap and - // outlive everything too. - if l.isName(ir.PPARAMOUT) { - // Exception: Directly called closures can return - // locations allocated outside of them without forcing - // them to the heap. For example: - // - // var u int // okay to stack allocate - // *(func() *int { return &u }()) = 42 - if containsClosure(other.curfn, l.curfn) && l.curfn.ClosureCalled() { - return false - } - - return true - } - - // If l and other are within the same function, then l - // outlives other if it was declared outside other's loop - // scope. For example: - // - // var l *int - // for { - // l = new(int) - // } - if l.curfn == other.curfn && l.loopDepth < other.loopDepth { - return true - } - - // If other is declared within a child closure of where l is - // declared, then l outlives it. For example: - // - // var l *int - // func() { - // l = new(int) - // } - if containsClosure(l.curfn, other.curfn) { - return true - } - - return false -} - -// containsClosure reports whether c is a closure contained within f. -func containsClosure(f, c *ir.Func) bool { - // Common case. - if f == c { - return false - } - - // Closures within function Foo are named like "Foo.funcN..." - // TODO(mdempsky): Better way to recognize this. - fn := f.Sym().Name - cn := c.Sym().Name - return len(cn) > len(fn) && cn[:len(fn)] == fn && cn[len(fn)] == '.' -} - -// leak records that parameter l leaks to sink. -func (l *location) leakTo(sink *location, derefs int) { - // If sink is a result parameter that doesn't escape (#44614) - // and we can fit return bits into the escape analysis tag, - // then record as a result leak. - if !sink.escapes && sink.isName(ir.PPARAMOUT) && sink.curfn == l.curfn { - ri := sink.resultIndex - 1 - if ri < numEscResults { - // Leak to result parameter. - l.paramEsc.AddResult(ri, derefs) - return - } - } - - // Otherwise, record as heap leak. - l.paramEsc.AddHeap(derefs) -} - func (b *batch) finish(fns []*ir.Func) { // Record parameter tags for package export data. for _, fn := range fns { @@ -1725,107 +322,19 @@ func (b *batch) finish(fns []*ir.Func) { } } -func (l *location) isName(c ir.Class) bool { - return l.n != nil && l.n.Op() == ir.ONAME && l.n.(*ir.Name).Class == c -} - -const numEscResults = 7 - -// An leaks represents a set of assignment flows from a parameter -// to the heap or to any of its function's (first numEscResults) -// result parameters. -type leaks [1 + numEscResults]uint8 - -// Empty reports whether l is an empty set (i.e., no assignment flows). -func (l leaks) Empty() bool { return l == leaks{} } - -// Heap returns the minimum deref count of any assignment flow from l -// to the heap. If no such flows exist, Heap returns -1. -func (l leaks) Heap() int { return l.get(0) } - -// Result returns the minimum deref count of any assignment flow from -// l to its function's i'th result parameter. If no such flows exist, -// Result returns -1. -func (l leaks) Result(i int) int { return l.get(1 + i) } - -// AddHeap adds an assignment flow from l to the heap. -func (l *leaks) AddHeap(derefs int) { l.add(0, derefs) } - -// AddResult adds an assignment flow from l to its function's i'th -// result parameter. -func (l *leaks) AddResult(i, derefs int) { l.add(1+i, derefs) } - -func (l *leaks) setResult(i, derefs int) { l.set(1+i, derefs) } - -func (l leaks) get(i int) int { return int(l[i]) - 1 } - -func (l *leaks) add(i, derefs int) { - if old := l.get(i); old < 0 || derefs < old { - l.set(i, derefs) - } -} - -func (l *leaks) set(i, derefs int) { - v := derefs + 1 - if v < 0 { - base.Fatalf("invalid derefs count: %v", derefs) - } - if v > math.MaxUint8 { - v = math.MaxUint8 - } - - l[i] = uint8(v) -} - -// Optimize removes result flow paths that are equal in length or -// longer than the shortest heap flow path. -func (l *leaks) Optimize() { - // If we have a path to the heap, then there's no use in - // keeping equal or longer paths elsewhere. - if x := l.Heap(); x >= 0 { - for i := 0; i < numEscResults; i++ { - if l.Result(i) >= x { - l.setResult(i, -1) - } +// inMutualBatch reports whether function fn is in the batch of +// mutually recursive functions being analyzed. When this is true, +// fn has not yet been analyzed, so its parameters and results +// should be incorporated directly into the flow graph instead of +// relying on its escape analysis tagging. +func (e *escape) inMutualBatch(fn *ir.Name) bool { + if fn.Defn != nil && fn.Defn.Esc() < escFuncTagged { + if fn.Defn.Esc() == escFuncUnknown { + base.Fatalf("graph inconsistency: %v", fn) } + return true } -} - -var leakTagCache = map[leaks]string{} - -// Encode converts l into a binary string for export data. -func (l leaks) Encode() string { - if l.Heap() == 0 { - // Space optimization: empty string encodes more - // efficiently in export data. - return "" - } - if s, ok := leakTagCache[l]; ok { - return s - } - - n := len(l) - for n > 0 && l[n-1] == 0 { - n-- - } - s := "esc:" + string(l[:n]) - leakTagCache[l] = s - return s -} - -// parseLeaks parses a binary string representing a leaks -func parseLeaks(s string) leaks { - var l leaks - if !strings.HasPrefix(s, "esc:") { - l.AddHeap(0) - return l - } - copy(l[:], s[4:]) - return l -} - -func Funcs(all []ir.Node) { - ir.VisitFuncsBottomUp(all, Batch) + return false } const ( @@ -1843,211 +352,6 @@ const ( nonlooping ) -func isSliceSelfAssign(dst, src ir.Node) bool { - // Detect the following special case. - // - // func (b *Buffer) Foo() { - // n, m := ... - // b.buf = b.buf[n:m] - // } - // - // This assignment is a no-op for escape analysis, - // it does not store any new pointers into b that were not already there. - // However, without this special case b will escape, because we assign to OIND/ODOTPTR. - // Here we assume that the statement will not contain calls, - // that is, that order will move any calls to init. - // Otherwise base ONAME value could change between the moments - // when we evaluate it for dst and for src. - - // dst is ONAME dereference. - var dstX ir.Node - switch dst.Op() { - default: - return false - case ir.ODEREF: - dst := dst.(*ir.StarExpr) - dstX = dst.X - case ir.ODOTPTR: - dst := dst.(*ir.SelectorExpr) - dstX = dst.X - } - if dstX.Op() != ir.ONAME { - return false - } - // src is a slice operation. - switch src.Op() { - case ir.OSLICE, ir.OSLICE3, ir.OSLICESTR: - // OK. - case ir.OSLICEARR, ir.OSLICE3ARR: - // Since arrays are embedded into containing object, - // slice of non-pointer array will introduce a new pointer into b that was not already there - // (pointer to b itself). After such assignment, if b contents escape, - // b escapes as well. If we ignore such OSLICEARR, we will conclude - // that b does not escape when b contents do. - // - // Pointer to an array is OK since it's not stored inside b directly. - // For slicing an array (not pointer to array), there is an implicit OADDR. - // We check that to determine non-pointer array slicing. - src := src.(*ir.SliceExpr) - if src.X.Op() == ir.OADDR { - return false - } - default: - return false - } - // slice is applied to ONAME dereference. - var baseX ir.Node - switch base := src.(*ir.SliceExpr).X; base.Op() { - default: - return false - case ir.ODEREF: - base := base.(*ir.StarExpr) - baseX = base.X - case ir.ODOTPTR: - base := base.(*ir.SelectorExpr) - baseX = base.X - } - if baseX.Op() != ir.ONAME { - return false - } - // dst and src reference the same base ONAME. - return dstX.(*ir.Name) == baseX.(*ir.Name) -} - -// isSelfAssign reports whether assignment from src to dst can -// be ignored by the escape analysis as it's effectively a self-assignment. -func isSelfAssign(dst, src ir.Node) bool { - if isSliceSelfAssign(dst, src) { - return true - } - - // Detect trivial assignments that assign back to the same object. - // - // It covers these cases: - // val.x = val.y - // val.x[i] = val.y[j] - // val.x1.x2 = val.x1.y2 - // ... etc - // - // These assignments do not change assigned object lifetime. - - if dst == nil || src == nil || dst.Op() != src.Op() { - return false - } - - // The expression prefix must be both "safe" and identical. - switch dst.Op() { - case ir.ODOT, ir.ODOTPTR: - // Safe trailing accessors that are permitted to differ. - dst := dst.(*ir.SelectorExpr) - src := src.(*ir.SelectorExpr) - return ir.SameSafeExpr(dst.X, src.X) - case ir.OINDEX: - dst := dst.(*ir.IndexExpr) - src := src.(*ir.IndexExpr) - if mayAffectMemory(dst.Index) || mayAffectMemory(src.Index) { - return false - } - return ir.SameSafeExpr(dst.X, src.X) - default: - return false - } -} - -// mayAffectMemory reports whether evaluation of n may affect the program's -// memory state. If the expression can't affect memory state, then it can be -// safely ignored by the escape analysis. -func mayAffectMemory(n ir.Node) bool { - // We may want to use a list of "memory safe" ops instead of generally - // "side-effect free", which would include all calls and other ops that can - // allocate or change global state. For now, it's safer to start with the latter. - // - // We're ignoring things like division by zero, index out of range, - // and nil pointer dereference here. - - // TODO(rsc): It seems like it should be possible to replace this with - // an ir.Any looking for any op that's not the ones in the case statement. - // But that produces changes in the compiled output detected by buildall. - switch n.Op() { - case ir.ONAME, ir.OLITERAL, ir.ONIL: - return false - - case ir.OADD, ir.OSUB, ir.OOR, ir.OXOR, ir.OMUL, ir.OLSH, ir.ORSH, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OMOD: - n := n.(*ir.BinaryExpr) - return mayAffectMemory(n.X) || mayAffectMemory(n.Y) - - case ir.OINDEX: - n := n.(*ir.IndexExpr) - return mayAffectMemory(n.X) || mayAffectMemory(n.Index) - - case ir.OCONVNOP, ir.OCONV: - n := n.(*ir.ConvExpr) - return mayAffectMemory(n.X) - - case ir.OLEN, ir.OCAP, ir.ONOT, ir.OBITNOT, ir.OPLUS, ir.ONEG, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF: - n := n.(*ir.UnaryExpr) - return mayAffectMemory(n.X) - - case ir.ODOT, ir.ODOTPTR: - n := n.(*ir.SelectorExpr) - return mayAffectMemory(n.X) - - case ir.ODEREF: - n := n.(*ir.StarExpr) - return mayAffectMemory(n.X) - - default: - return true - } -} - -// HeapAllocReason returns the reason the given Node must be heap -// allocated, or the empty string if it doesn't. -func HeapAllocReason(n ir.Node) string { - if n == nil || n.Type() == nil { - return "" - } - - // Parameters are always passed via the stack. - if n.Op() == ir.ONAME { - n := n.(*ir.Name) - if n.Class == ir.PPARAM || n.Class == ir.PPARAMOUT { - return "" - } - } - - if n.Type().Width > ir.MaxStackVarSize { - return "too large for stack" - } - - if (n.Op() == ir.ONEW || n.Op() == ir.OPTRLIT) && n.Type().Elem().Width >= ir.MaxImplicitStackVarSize { - return "too large for stack" - } - - if n.Op() == ir.OCLOSURE && typecheck.ClosureType(n.(*ir.ClosureExpr)).Size() >= ir.MaxImplicitStackVarSize { - return "too large for stack" - } - if n.Op() == ir.OCALLPART && typecheck.PartialCallType(n.(*ir.SelectorExpr)).Size() >= ir.MaxImplicitStackVarSize { - return "too large for stack" - } - - if n.Op() == ir.OMAKESLICE { - n := n.(*ir.MakeExpr) - r := n.Cap - if r == nil { - r = n.Len - } - if !ir.IsSmallIntConst(r) { - return "non-constant size" - } - if t := n.Type(); t.Elem().Width != 0 && ir.Int64Val(r) >= ir.MaxImplicitStackVarSize/t.Elem().Width { - return "too large for stack" - } - } - - return "" -} - func (b *batch) paramTag(fn *ir.Func, narg int, f *types.Field) string { name := func() string { if f.Sym != nil { diff --git a/src/cmd/compile/internal/escape/expr.go b/src/cmd/compile/internal/escape/expr.go new file mode 100644 index 00000000000..5b280c76f1f --- /dev/null +++ b/src/cmd/compile/internal/escape/expr.go @@ -0,0 +1,340 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package escape + +import ( + "cmd/compile/internal/base" + "cmd/compile/internal/ir" + "cmd/compile/internal/types" +) + +// expr models evaluating an expression n and flowing the result into +// hole k. +func (e *escape) expr(k hole, n ir.Node) { + if n == nil { + return + } + e.stmts(n.Init()) + e.exprSkipInit(k, n) +} + +func (e *escape) exprSkipInit(k hole, n ir.Node) { + if n == nil { + return + } + + lno := ir.SetPos(n) + defer func() { + base.Pos = lno + }() + + uintptrEscapesHack := k.uintptrEscapesHack + k.uintptrEscapesHack = false + + if uintptrEscapesHack && n.Op() == ir.OCONVNOP && n.(*ir.ConvExpr).X.Type().IsUnsafePtr() { + // nop + } else if k.derefs >= 0 && !n.Type().HasPointers() { + k.dst = &e.blankLoc + } + + switch n.Op() { + default: + base.Fatalf("unexpected expr: %s %v", n.Op().String(), n) + + case ir.OLITERAL, ir.ONIL, ir.OGETG, ir.OTYPE, ir.OMETHEXPR, ir.OLINKSYMOFFSET: + // nop + + case ir.ONAME: + n := n.(*ir.Name) + if n.Class == ir.PFUNC || n.Class == ir.PEXTERN { + return + } + if n.IsClosureVar() && n.Defn == nil { + return // ".this" from method value wrapper + } + e.flow(k, e.oldLoc(n)) + + case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT: + n := n.(*ir.UnaryExpr) + e.discard(n.X) + case ir.OADD, ir.OSUB, ir.OOR, ir.OXOR, ir.OMUL, ir.ODIV, ir.OMOD, ir.OLSH, ir.ORSH, ir.OAND, ir.OANDNOT, ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE: + n := n.(*ir.BinaryExpr) + e.discard(n.X) + e.discard(n.Y) + case ir.OANDAND, ir.OOROR: + n := n.(*ir.LogicalExpr) + e.discard(n.X) + e.discard(n.Y) + case ir.OADDR: + n := n.(*ir.AddrExpr) + e.expr(k.addr(n, "address-of"), n.X) // "address-of" + case ir.ODEREF: + n := n.(*ir.StarExpr) + e.expr(k.deref(n, "indirection"), n.X) // "indirection" + case ir.ODOT, ir.ODOTMETH, ir.ODOTINTER: + n := n.(*ir.SelectorExpr) + e.expr(k.note(n, "dot"), n.X) + case ir.ODOTPTR: + n := n.(*ir.SelectorExpr) + e.expr(k.deref(n, "dot of pointer"), n.X) // "dot of pointer" + case ir.ODOTTYPE, ir.ODOTTYPE2: + n := n.(*ir.TypeAssertExpr) + e.expr(k.dotType(n.Type(), n, "dot"), n.X) + case ir.OINDEX: + n := n.(*ir.IndexExpr) + if n.X.Type().IsArray() { + e.expr(k.note(n, "fixed-array-index-of"), n.X) + } else { + // TODO(mdempsky): Fix why reason text. + e.expr(k.deref(n, "dot of pointer"), n.X) + } + e.discard(n.Index) + case ir.OINDEXMAP: + n := n.(*ir.IndexExpr) + e.discard(n.X) + e.discard(n.Index) + case ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR, ir.OSLICESTR: + n := n.(*ir.SliceExpr) + e.expr(k.note(n, "slice"), n.X) + e.discard(n.Low) + e.discard(n.High) + e.discard(n.Max) + + case ir.OCONV, ir.OCONVNOP: + n := n.(*ir.ConvExpr) + if ir.ShouldCheckPtr(e.curfn, 2) && n.Type().IsUnsafePtr() && n.X.Type().IsPtr() { + // When -d=checkptr=2 is enabled, treat + // conversions to unsafe.Pointer as an + // escaping operation. This allows better + // runtime instrumentation, since we can more + // easily detect object boundaries on the heap + // than the stack. + e.assignHeap(n.X, "conversion to unsafe.Pointer", n) + } else if n.Type().IsUnsafePtr() && n.X.Type().IsUintptr() { + e.unsafeValue(k, n.X) + } else { + e.expr(k, n.X) + } + case ir.OCONVIFACE: + n := n.(*ir.ConvExpr) + if !n.X.Type().IsInterface() && !types.IsDirectIface(n.X.Type()) { + k = e.spill(k, n) + } + e.expr(k.note(n, "interface-converted"), n.X) + case ir.OEFACE: + n := n.(*ir.BinaryExpr) + // Note: n.X is not needed because it can never point to memory that might escape. + e.expr(k, n.Y) + case ir.OIDATA, ir.OSPTR: + n := n.(*ir.UnaryExpr) + e.expr(k, n.X) + case ir.OSLICE2ARRPTR: + // the slice pointer flows directly to the result + n := n.(*ir.ConvExpr) + e.expr(k, n.X) + case ir.ORECV: + n := n.(*ir.UnaryExpr) + e.discard(n.X) + + case ir.OCALLMETH, ir.OCALLFUNC, ir.OCALLINTER, ir.OLEN, ir.OCAP, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCOPY, ir.OUNSAFEADD, ir.OUNSAFESLICE: + e.call([]hole{k}, n, nil) + + case ir.ONEW: + n := n.(*ir.UnaryExpr) + e.spill(k, n) + + case ir.OMAKESLICE: + n := n.(*ir.MakeExpr) + e.spill(k, n) + e.discard(n.Len) + e.discard(n.Cap) + case ir.OMAKECHAN: + n := n.(*ir.MakeExpr) + e.discard(n.Len) + case ir.OMAKEMAP: + n := n.(*ir.MakeExpr) + e.spill(k, n) + e.discard(n.Len) + + case ir.ORECOVER: + // nop + + case ir.OCALLPART: + // Flow the receiver argument to both the closure and + // to the receiver parameter. + + n := n.(*ir.SelectorExpr) + closureK := e.spill(k, n) + + m := n.Selection + + // We don't know how the method value will be called + // later, so conservatively assume the result + // parameters all flow to the heap. + // + // TODO(mdempsky): Change ks into a callback, so that + // we don't have to create this slice? + var ks []hole + for i := m.Type.NumResults(); i > 0; i-- { + ks = append(ks, e.heapHole()) + } + name, _ := m.Nname.(*ir.Name) + paramK := e.tagHole(ks, name, m.Type.Recv()) + + e.expr(e.teeHole(paramK, closureK), n.X) + + case ir.OPTRLIT: + n := n.(*ir.AddrExpr) + e.expr(e.spill(k, n), n.X) + + case ir.OARRAYLIT: + n := n.(*ir.CompLitExpr) + for _, elt := range n.List { + if elt.Op() == ir.OKEY { + elt = elt.(*ir.KeyExpr).Value + } + e.expr(k.note(n, "array literal element"), elt) + } + + case ir.OSLICELIT: + n := n.(*ir.CompLitExpr) + k = e.spill(k, n) + k.uintptrEscapesHack = uintptrEscapesHack // for ...uintptr parameters + + for _, elt := range n.List { + if elt.Op() == ir.OKEY { + elt = elt.(*ir.KeyExpr).Value + } + e.expr(k.note(n, "slice-literal-element"), elt) + } + + case ir.OSTRUCTLIT: + n := n.(*ir.CompLitExpr) + for _, elt := range n.List { + e.expr(k.note(n, "struct literal element"), elt.(*ir.StructKeyExpr).Value) + } + + case ir.OMAPLIT: + n := n.(*ir.CompLitExpr) + e.spill(k, n) + + // Map keys and values are always stored in the heap. + for _, elt := range n.List { + elt := elt.(*ir.KeyExpr) + e.assignHeap(elt.Key, "map literal key", n) + e.assignHeap(elt.Value, "map literal value", n) + } + + case ir.OCLOSURE: + n := n.(*ir.ClosureExpr) + k = e.spill(k, n) + e.closures = append(e.closures, closure{k, n}) + + if fn := n.Func; fn.IsHiddenClosure() { + for _, cv := range fn.ClosureVars { + if loc := e.oldLoc(cv); !loc.captured { + loc.captured = true + + // Ignore reassignments to the variable in straightline code + // preceding the first capture by a closure. + if loc.loopDepth == e.loopDepth { + loc.reassigned = false + } + } + } + + for _, n := range fn.Dcl { + // Add locations for local variables of the + // closure, if needed, in case we're not including + // the closure func in the batch for escape + // analysis (happens for escape analysis called + // from reflectdata.methodWrapper) + if n.Op() == ir.ONAME && n.Opt == nil { + e.with(fn).newLoc(n, false) + } + } + e.walkFunc(fn) + } + + case ir.ORUNES2STR, ir.OBYTES2STR, ir.OSTR2RUNES, ir.OSTR2BYTES, ir.ORUNESTR: + n := n.(*ir.ConvExpr) + e.spill(k, n) + e.discard(n.X) + + case ir.OADDSTR: + n := n.(*ir.AddStringExpr) + e.spill(k, n) + + // Arguments of OADDSTR never escape; + // runtime.concatstrings makes sure of that. + e.discards(n.List) + } +} + +// unsafeValue evaluates a uintptr-typed arithmetic expression looking +// for conversions from an unsafe.Pointer. +func (e *escape) unsafeValue(k hole, n ir.Node) { + if n.Type().Kind() != types.TUINTPTR { + base.Fatalf("unexpected type %v for %v", n.Type(), n) + } + if k.addrtaken { + base.Fatalf("unexpected addrtaken") + } + + e.stmts(n.Init()) + + switch n.Op() { + case ir.OCONV, ir.OCONVNOP: + n := n.(*ir.ConvExpr) + if n.X.Type().IsUnsafePtr() { + e.expr(k, n.X) + } else { + e.discard(n.X) + } + case ir.ODOTPTR: + n := n.(*ir.SelectorExpr) + if ir.IsReflectHeaderDataField(n) { + e.expr(k.deref(n, "reflect.Header.Data"), n.X) + } else { + e.discard(n.X) + } + case ir.OPLUS, ir.ONEG, ir.OBITNOT: + n := n.(*ir.UnaryExpr) + e.unsafeValue(k, n.X) + case ir.OADD, ir.OSUB, ir.OOR, ir.OXOR, ir.OMUL, ir.ODIV, ir.OMOD, ir.OAND, ir.OANDNOT: + n := n.(*ir.BinaryExpr) + e.unsafeValue(k, n.X) + e.unsafeValue(k, n.Y) + case ir.OLSH, ir.ORSH: + n := n.(*ir.BinaryExpr) + e.unsafeValue(k, n.X) + // RHS need not be uintptr-typed (#32959) and can't meaningfully + // flow pointers anyway. + e.discard(n.Y) + default: + e.exprSkipInit(e.discardHole(), n) + } +} + +// discard evaluates an expression n for side-effects, but discards +// its value. +func (e *escape) discard(n ir.Node) { + e.expr(e.discardHole(), n) +} + +func (e *escape) discards(l ir.Nodes) { + for _, n := range l { + e.discard(n) + } +} + +// spill allocates a new location associated with expression n, flows +// its address to k, and returns a hole that flows values to it. It's +// intended for use with most expressions that allocate storage. +func (e *escape) spill(k hole, n ir.Node) hole { + loc := e.newLoc(n, true) + e.flow(k.addr(n, "spill"), loc) + return loc.asHole() +} diff --git a/src/cmd/compile/internal/escape/graph.go b/src/cmd/compile/internal/escape/graph.go new file mode 100644 index 00000000000..3581fce30de --- /dev/null +++ b/src/cmd/compile/internal/escape/graph.go @@ -0,0 +1,324 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package escape + +import ( + "cmd/compile/internal/base" + "cmd/compile/internal/ir" + "cmd/compile/internal/logopt" + "cmd/compile/internal/types" + "fmt" +) + +// Below we implement the methods for walking the AST and recording +// data flow edges. Note that because a sub-expression might have +// side-effects, it's important to always visit the entire AST. +// +// For example, write either: +// +// if x { +// e.discard(n.Left) +// } else { +// e.value(k, n.Left) +// } +// +// or +// +// if x { +// k = e.discardHole() +// } +// e.value(k, n.Left) +// +// Do NOT write: +// +// // BAD: possibly loses side-effects within n.Left +// if !x { +// e.value(k, n.Left) +// } + +// An location represents an abstract location that stores a Go +// variable. +type location struct { + n ir.Node // represented variable or expression, if any + curfn *ir.Func // enclosing function + edges []edge // incoming edges + loopDepth int // loopDepth at declaration + + // resultIndex records the tuple index (starting at 1) for + // PPARAMOUT variables within their function's result type. + // For non-PPARAMOUT variables it's 0. + resultIndex int + + // derefs and walkgen are used during walkOne to track the + // minimal dereferences from the walk root. + derefs int // >= -1 + walkgen uint32 + + // dst and dstEdgeindex track the next immediate assignment + // destination location during walkone, along with the index + // of the edge pointing back to this location. + dst *location + dstEdgeIdx int + + // queued is used by walkAll to track whether this location is + // in the walk queue. + queued bool + + // escapes reports whether the represented variable's address + // escapes; that is, whether the variable must be heap + // allocated. + escapes bool + + // transient reports whether the represented expression's + // address does not outlive the statement; that is, whether + // its storage can be immediately reused. + transient bool + + // paramEsc records the represented parameter's leak set. + paramEsc leaks + + captured bool // has a closure captured this variable? + reassigned bool // has this variable been reassigned? + addrtaken bool // has this variable's address been taken? +} + +// An edge represents an assignment edge between two Go variables. +type edge struct { + src *location + derefs int // >= -1 + notes *note +} + +func (l *location) asHole() hole { + return hole{dst: l} +} + +// leak records that parameter l leaks to sink. +func (l *location) leakTo(sink *location, derefs int) { + // If sink is a result parameter that doesn't escape (#44614) + // and we can fit return bits into the escape analysis tag, + // then record as a result leak. + if !sink.escapes && sink.isName(ir.PPARAMOUT) && sink.curfn == l.curfn { + ri := sink.resultIndex - 1 + if ri < numEscResults { + // Leak to result parameter. + l.paramEsc.AddResult(ri, derefs) + return + } + } + + // Otherwise, record as heap leak. + l.paramEsc.AddHeap(derefs) +} + +func (l *location) isName(c ir.Class) bool { + return l.n != nil && l.n.Op() == ir.ONAME && l.n.(*ir.Name).Class == c +} + +// An hole represents a context for evaluation a Go +// expression. E.g., when evaluating p in "x = **p", we'd have a hole +// with dst==x and derefs==2. +type hole struct { + dst *location + derefs int // >= -1 + notes *note + + // addrtaken indicates whether this context is taking the address of + // the expression, independent of whether the address will actually + // be stored into a variable. + addrtaken bool + + // uintptrEscapesHack indicates this context is evaluating an + // argument for a //go:uintptrescapes function. + uintptrEscapesHack bool +} + +type note struct { + next *note + where ir.Node + why string +} + +func (k hole) note(where ir.Node, why string) hole { + if where == nil || why == "" { + base.Fatalf("note: missing where/why") + } + if base.Flag.LowerM >= 2 || logopt.Enabled() { + k.notes = ¬e{ + next: k.notes, + where: where, + why: why, + } + } + return k +} + +func (k hole) shift(delta int) hole { + k.derefs += delta + if k.derefs < -1 { + base.Fatalf("derefs underflow: %v", k.derefs) + } + k.addrtaken = delta < 0 + return k +} + +func (k hole) deref(where ir.Node, why string) hole { return k.shift(1).note(where, why) } +func (k hole) addr(where ir.Node, why string) hole { return k.shift(-1).note(where, why) } + +func (k hole) dotType(t *types.Type, where ir.Node, why string) hole { + if !t.IsInterface() && !types.IsDirectIface(t) { + k = k.shift(1) + } + return k.note(where, why) +} + +func (b *batch) flow(k hole, src *location) { + if k.addrtaken { + src.addrtaken = true + } + + dst := k.dst + if dst == &b.blankLoc { + return + } + if dst == src && k.derefs >= 0 { // dst = dst, dst = *dst, ... + return + } + if dst.escapes && k.derefs < 0 { // dst = &src + if base.Flag.LowerM >= 2 || logopt.Enabled() { + pos := base.FmtPos(src.n.Pos()) + if base.Flag.LowerM >= 2 { + fmt.Printf("%s: %v escapes to heap:\n", pos, src.n) + } + explanation := b.explainFlow(pos, dst, src, k.derefs, k.notes, []*logopt.LoggedOpt{}) + if logopt.Enabled() { + var e_curfn *ir.Func // TODO(mdempsky): Fix. + logopt.LogOpt(src.n.Pos(), "escapes", "escape", ir.FuncName(e_curfn), fmt.Sprintf("%v escapes to heap", src.n), explanation) + } + + } + src.escapes = true + return + } + + // TODO(mdempsky): Deduplicate edges? + dst.edges = append(dst.edges, edge{src: src, derefs: k.derefs, notes: k.notes}) +} + +func (b *batch) heapHole() hole { return b.heapLoc.asHole() } +func (b *batch) discardHole() hole { return b.blankLoc.asHole() } + +func (b *batch) oldLoc(n *ir.Name) *location { + if n.Canonical().Opt == nil { + base.Fatalf("%v has no location", n) + } + return n.Canonical().Opt.(*location) +} + +func (e *escape) newLoc(n ir.Node, transient bool) *location { + if e.curfn == nil { + base.Fatalf("e.curfn isn't set") + } + if n != nil && n.Type() != nil && n.Type().NotInHeap() { + base.ErrorfAt(n.Pos(), "%v is incomplete (or unallocatable); stack allocation disallowed", n.Type()) + } + + if n != nil && n.Op() == ir.ONAME { + n = n.(*ir.Name).Canonical() + } + loc := &location{ + n: n, + curfn: e.curfn, + loopDepth: e.loopDepth, + transient: transient, + } + e.allLocs = append(e.allLocs, loc) + if n != nil { + if n.Op() == ir.ONAME { + n := n.(*ir.Name) + if n.Curfn != e.curfn { + base.Fatalf("curfn mismatch: %v != %v for %v", n.Curfn, e.curfn, n) + } + + if n.Opt != nil { + base.Fatalf("%v already has a location", n) + } + n.Opt = loc + } + } + return loc +} + +// teeHole returns a new hole that flows into each hole of ks, +// similar to the Unix tee(1) command. +func (e *escape) teeHole(ks ...hole) hole { + if len(ks) == 0 { + return e.discardHole() + } + if len(ks) == 1 { + return ks[0] + } + // TODO(mdempsky): Optimize if there's only one non-discard hole? + + // Given holes "l1 = _", "l2 = **_", "l3 = *_", ..., create a + // new temporary location ltmp, wire it into place, and return + // a hole for "ltmp = _". + loc := e.newLoc(nil, true) + for _, k := range ks { + // N.B., "p = &q" and "p = &tmp; tmp = q" are not + // semantically equivalent. To combine holes like "l1 + // = _" and "l2 = &_", we'd need to wire them as "l1 = + // *ltmp" and "l2 = ltmp" and return "ltmp = &_" + // instead. + if k.derefs < 0 { + base.Fatalf("teeHole: negative derefs") + } + + e.flow(k, loc) + } + return loc.asHole() +} + +// later returns a new hole that flows into k, but some time later. +// Its main effect is to prevent immediate reuse of temporary +// variables introduced during Order. +func (e *escape) later(k hole) hole { + loc := e.newLoc(nil, false) + e.flow(k, loc) + return loc.asHole() +} + +// Fmt is called from node printing to print information about escape analysis results. +func Fmt(n ir.Node) string { + text := "" + switch n.Esc() { + case ir.EscUnknown: + break + + case ir.EscHeap: + text = "esc(h)" + + case ir.EscNone: + text = "esc(no)" + + case ir.EscNever: + text = "esc(N)" + + default: + text = fmt.Sprintf("esc(%d)", n.Esc()) + } + + if n.Op() == ir.ONAME { + n := n.(*ir.Name) + if loc, ok := n.Opt.(*location); ok && loc.loopDepth != 0 { + if text != "" { + text += " " + } + text += fmt.Sprintf("ld(%d)", loc.loopDepth) + } + } + + return text +} diff --git a/src/cmd/compile/internal/escape/leaks.go b/src/cmd/compile/internal/escape/leaks.go new file mode 100644 index 00000000000..4c848a5ee78 --- /dev/null +++ b/src/cmd/compile/internal/escape/leaks.go @@ -0,0 +1,106 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package escape + +import ( + "cmd/compile/internal/base" + "math" + "strings" +) + +const numEscResults = 7 + +// An leaks represents a set of assignment flows from a parameter +// to the heap or to any of its function's (first numEscResults) +// result parameters. +type leaks [1 + numEscResults]uint8 + +// Empty reports whether l is an empty set (i.e., no assignment flows). +func (l leaks) Empty() bool { return l == leaks{} } + +// Heap returns the minimum deref count of any assignment flow from l +// to the heap. If no such flows exist, Heap returns -1. +func (l leaks) Heap() int { return l.get(0) } + +// Result returns the minimum deref count of any assignment flow from +// l to its function's i'th result parameter. If no such flows exist, +// Result returns -1. +func (l leaks) Result(i int) int { return l.get(1 + i) } + +// AddHeap adds an assignment flow from l to the heap. +func (l *leaks) AddHeap(derefs int) { l.add(0, derefs) } + +// AddResult adds an assignment flow from l to its function's i'th +// result parameter. +func (l *leaks) AddResult(i, derefs int) { l.add(1+i, derefs) } + +func (l *leaks) setResult(i, derefs int) { l.set(1+i, derefs) } + +func (l leaks) get(i int) int { return int(l[i]) - 1 } + +func (l *leaks) add(i, derefs int) { + if old := l.get(i); old < 0 || derefs < old { + l.set(i, derefs) + } +} + +func (l *leaks) set(i, derefs int) { + v := derefs + 1 + if v < 0 { + base.Fatalf("invalid derefs count: %v", derefs) + } + if v > math.MaxUint8 { + v = math.MaxUint8 + } + + l[i] = uint8(v) +} + +// Optimize removes result flow paths that are equal in length or +// longer than the shortest heap flow path. +func (l *leaks) Optimize() { + // If we have a path to the heap, then there's no use in + // keeping equal or longer paths elsewhere. + if x := l.Heap(); x >= 0 { + for i := 0; i < numEscResults; i++ { + if l.Result(i) >= x { + l.setResult(i, -1) + } + } + } +} + +var leakTagCache = map[leaks]string{} + +// Encode converts l into a binary string for export data. +func (l leaks) Encode() string { + if l.Heap() == 0 { + // Space optimization: empty string encodes more + // efficiently in export data. + return "" + } + if s, ok := leakTagCache[l]; ok { + return s + } + + n := len(l) + for n > 0 && l[n-1] == 0 { + n-- + } + s := "esc:" + string(l[:n]) + leakTagCache[l] = s + return s +} + +// parseLeaks parses a binary string representing a leaks +func parseLeaks(s string) leaks { + var l leaks + if !strings.HasPrefix(s, "esc:") { + l.AddHeap(0) + return l + } + copy(l[:], s[4:]) + return l +} diff --git a/src/cmd/compile/internal/escape/solve.go b/src/cmd/compile/internal/escape/solve.go new file mode 100644 index 00000000000..77d6b27dd75 --- /dev/null +++ b/src/cmd/compile/internal/escape/solve.go @@ -0,0 +1,289 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package escape + +import ( + "cmd/compile/internal/base" + "cmd/compile/internal/ir" + "cmd/compile/internal/logopt" + "cmd/internal/src" + "fmt" + "strings" +) + +// walkAll computes the minimal dereferences between all pairs of +// locations. +func (b *batch) walkAll() { + // We use a work queue to keep track of locations that we need + // to visit, and repeatedly walk until we reach a fixed point. + // + // We walk once from each location (including the heap), and + // then re-enqueue each location on its transition from + // transient->!transient and !escapes->escapes, which can each + // happen at most once. So we take Θ(len(e.allLocs)) walks. + + // LIFO queue, has enough room for e.allLocs and e.heapLoc. + todo := make([]*location, 0, len(b.allLocs)+1) + enqueue := func(loc *location) { + if !loc.queued { + todo = append(todo, loc) + loc.queued = true + } + } + + for _, loc := range b.allLocs { + enqueue(loc) + } + enqueue(&b.heapLoc) + + var walkgen uint32 + for len(todo) > 0 { + root := todo[len(todo)-1] + todo = todo[:len(todo)-1] + root.queued = false + + walkgen++ + b.walkOne(root, walkgen, enqueue) + } +} + +// walkOne computes the minimal number of dereferences from root to +// all other locations. +func (b *batch) walkOne(root *location, walkgen uint32, enqueue func(*location)) { + // The data flow graph has negative edges (from addressing + // operations), so we use the Bellman-Ford algorithm. However, + // we don't have to worry about infinite negative cycles since + // we bound intermediate dereference counts to 0. + + root.walkgen = walkgen + root.derefs = 0 + root.dst = nil + + todo := []*location{root} // LIFO queue + for len(todo) > 0 { + l := todo[len(todo)-1] + todo = todo[:len(todo)-1] + + derefs := l.derefs + + // If l.derefs < 0, then l's address flows to root. + addressOf := derefs < 0 + if addressOf { + // For a flow path like "root = &l; l = x", + // l's address flows to root, but x's does + // not. We recognize this by lower bounding + // derefs at 0. + derefs = 0 + + // If l's address flows to a non-transient + // location, then l can't be transiently + // allocated. + if !root.transient && l.transient { + l.transient = false + enqueue(l) + } + } + + if b.outlives(root, l) { + // l's value flows to root. If l is a function + // parameter and root is the heap or a + // corresponding result parameter, then record + // that value flow for tagging the function + // later. + if l.isName(ir.PPARAM) { + if (logopt.Enabled() || base.Flag.LowerM >= 2) && !l.escapes { + if base.Flag.LowerM >= 2 { + fmt.Printf("%s: parameter %v leaks to %s with derefs=%d:\n", base.FmtPos(l.n.Pos()), l.n, b.explainLoc(root), derefs) + } + explanation := b.explainPath(root, l) + if logopt.Enabled() { + var e_curfn *ir.Func // TODO(mdempsky): Fix. + logopt.LogOpt(l.n.Pos(), "leak", "escape", ir.FuncName(e_curfn), + fmt.Sprintf("parameter %v leaks to %s with derefs=%d", l.n, b.explainLoc(root), derefs), explanation) + } + } + l.leakTo(root, derefs) + } + + // If l's address flows somewhere that + // outlives it, then l needs to be heap + // allocated. + if addressOf && !l.escapes { + if logopt.Enabled() || base.Flag.LowerM >= 2 { + if base.Flag.LowerM >= 2 { + fmt.Printf("%s: %v escapes to heap:\n", base.FmtPos(l.n.Pos()), l.n) + } + explanation := b.explainPath(root, l) + if logopt.Enabled() { + var e_curfn *ir.Func // TODO(mdempsky): Fix. + logopt.LogOpt(l.n.Pos(), "escape", "escape", ir.FuncName(e_curfn), fmt.Sprintf("%v escapes to heap", l.n), explanation) + } + } + l.escapes = true + enqueue(l) + continue + } + } + + for i, edge := range l.edges { + if edge.src.escapes { + continue + } + d := derefs + edge.derefs + if edge.src.walkgen != walkgen || edge.src.derefs > d { + edge.src.walkgen = walkgen + edge.src.derefs = d + edge.src.dst = l + edge.src.dstEdgeIdx = i + todo = append(todo, edge.src) + } + } + } +} + +// explainPath prints an explanation of how src flows to the walk root. +func (b *batch) explainPath(root, src *location) []*logopt.LoggedOpt { + visited := make(map[*location]bool) + pos := base.FmtPos(src.n.Pos()) + var explanation []*logopt.LoggedOpt + for { + // Prevent infinite loop. + if visited[src] { + if base.Flag.LowerM >= 2 { + fmt.Printf("%s: warning: truncated explanation due to assignment cycle; see golang.org/issue/35518\n", pos) + } + break + } + visited[src] = true + dst := src.dst + edge := &dst.edges[src.dstEdgeIdx] + if edge.src != src { + base.Fatalf("path inconsistency: %v != %v", edge.src, src) + } + + explanation = b.explainFlow(pos, dst, src, edge.derefs, edge.notes, explanation) + + if dst == root { + break + } + src = dst + } + + return explanation +} + +func (b *batch) explainFlow(pos string, dst, srcloc *location, derefs int, notes *note, explanation []*logopt.LoggedOpt) []*logopt.LoggedOpt { + ops := "&" + if derefs >= 0 { + ops = strings.Repeat("*", derefs) + } + print := base.Flag.LowerM >= 2 + + flow := fmt.Sprintf(" flow: %s = %s%v:", b.explainLoc(dst), ops, b.explainLoc(srcloc)) + if print { + fmt.Printf("%s:%s\n", pos, flow) + } + if logopt.Enabled() { + var epos src.XPos + if notes != nil { + epos = notes.where.Pos() + } else if srcloc != nil && srcloc.n != nil { + epos = srcloc.n.Pos() + } + var e_curfn *ir.Func // TODO(mdempsky): Fix. + explanation = append(explanation, logopt.NewLoggedOpt(epos, "escflow", "escape", ir.FuncName(e_curfn), flow)) + } + + for note := notes; note != nil; note = note.next { + if print { + fmt.Printf("%s: from %v (%v) at %s\n", pos, note.where, note.why, base.FmtPos(note.where.Pos())) + } + if logopt.Enabled() { + var e_curfn *ir.Func // TODO(mdempsky): Fix. + explanation = append(explanation, logopt.NewLoggedOpt(note.where.Pos(), "escflow", "escape", ir.FuncName(e_curfn), + fmt.Sprintf(" from %v (%v)", note.where, note.why))) + } + } + return explanation +} + +func (b *batch) explainLoc(l *location) string { + if l == &b.heapLoc { + return "{heap}" + } + if l.n == nil { + // TODO(mdempsky): Omit entirely. + return "{temp}" + } + if l.n.Op() == ir.ONAME { + return fmt.Sprintf("%v", l.n) + } + return fmt.Sprintf("{storage for %v}", l.n) +} + +// outlives reports whether values stored in l may survive beyond +// other's lifetime if stack allocated. +func (b *batch) outlives(l, other *location) bool { + // The heap outlives everything. + if l.escapes { + return true + } + + // We don't know what callers do with returned values, so + // pessimistically we need to assume they flow to the heap and + // outlive everything too. + if l.isName(ir.PPARAMOUT) { + // Exception: Directly called closures can return + // locations allocated outside of them without forcing + // them to the heap. For example: + // + // var u int // okay to stack allocate + // *(func() *int { return &u }()) = 42 + if containsClosure(other.curfn, l.curfn) && l.curfn.ClosureCalled() { + return false + } + + return true + } + + // If l and other are within the same function, then l + // outlives other if it was declared outside other's loop + // scope. For example: + // + // var l *int + // for { + // l = new(int) + // } + if l.curfn == other.curfn && l.loopDepth < other.loopDepth { + return true + } + + // If other is declared within a child closure of where l is + // declared, then l outlives it. For example: + // + // var l *int + // func() { + // l = new(int) + // } + if containsClosure(l.curfn, other.curfn) { + return true + } + + return false +} + +// containsClosure reports whether c is a closure contained within f. +func containsClosure(f, c *ir.Func) bool { + // Common case. + if f == c { + return false + } + + // Closures within function Foo are named like "Foo.funcN..." + // TODO(mdempsky): Better way to recognize this. + fn := f.Sym().Name + cn := c.Sym().Name + return len(cn) > len(fn) && cn[:len(fn)] == fn && cn[len(fn)] == '.' +} diff --git a/src/cmd/compile/internal/escape/stmt.go b/src/cmd/compile/internal/escape/stmt.go new file mode 100644 index 00000000000..d3e47290d37 --- /dev/null +++ b/src/cmd/compile/internal/escape/stmt.go @@ -0,0 +1,208 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package escape + +import ( + "cmd/compile/internal/base" + "cmd/compile/internal/ir" + "fmt" +) + +// stmt evaluates a single Go statement. +func (e *escape) stmt(n ir.Node) { + if n == nil { + return + } + + lno := ir.SetPos(n) + defer func() { + base.Pos = lno + }() + + if base.Flag.LowerM > 2 { + fmt.Printf("%v:[%d] %v stmt: %v\n", base.FmtPos(base.Pos), e.loopDepth, e.curfn, n) + } + + e.stmts(n.Init()) + + switch n.Op() { + default: + base.Fatalf("unexpected stmt: %v", n) + + case ir.ODCLCONST, ir.ODCLTYPE, ir.OFALL, ir.OINLMARK: + // nop + + case ir.OBREAK, ir.OCONTINUE, ir.OGOTO: + // TODO(mdempsky): Handle dead code? + + case ir.OBLOCK: + n := n.(*ir.BlockStmt) + e.stmts(n.List) + + case ir.ODCL: + // Record loop depth at declaration. + n := n.(*ir.Decl) + if !ir.IsBlank(n.X) { + e.dcl(n.X) + } + + case ir.OLABEL: + n := n.(*ir.LabelStmt) + switch e.labels[n.Label] { + case nonlooping: + if base.Flag.LowerM > 2 { + fmt.Printf("%v:%v non-looping label\n", base.FmtPos(base.Pos), n) + } + case looping: + if base.Flag.LowerM > 2 { + fmt.Printf("%v: %v looping label\n", base.FmtPos(base.Pos), n) + } + e.loopDepth++ + default: + base.Fatalf("label missing tag") + } + delete(e.labels, n.Label) + + case ir.OIF: + n := n.(*ir.IfStmt) + e.discard(n.Cond) + e.block(n.Body) + e.block(n.Else) + + case ir.OFOR, ir.OFORUNTIL: + n := n.(*ir.ForStmt) + e.loopDepth++ + e.discard(n.Cond) + e.stmt(n.Post) + e.block(n.Body) + e.loopDepth-- + + case ir.ORANGE: + // for Key, Value = range X { Body } + n := n.(*ir.RangeStmt) + + // X is evaluated outside the loop. + tmp := e.newLoc(nil, false) + e.expr(tmp.asHole(), n.X) + + e.loopDepth++ + ks := e.addrs([]ir.Node{n.Key, n.Value}) + if n.X.Type().IsArray() { + e.flow(ks[1].note(n, "range"), tmp) + } else { + e.flow(ks[1].deref(n, "range-deref"), tmp) + } + e.reassigned(ks, n) + + e.block(n.Body) + e.loopDepth-- + + case ir.OSWITCH: + n := n.(*ir.SwitchStmt) + + if guard, ok := n.Tag.(*ir.TypeSwitchGuard); ok { + var ks []hole + if guard.Tag != nil { + for _, cas := range n.Cases { + cv := cas.Var + k := e.dcl(cv) // type switch variables have no ODCL. + if cv.Type().HasPointers() { + ks = append(ks, k.dotType(cv.Type(), cas, "switch case")) + } + } + } + e.expr(e.teeHole(ks...), n.Tag.(*ir.TypeSwitchGuard).X) + } else { + e.discard(n.Tag) + } + + for _, cas := range n.Cases { + e.discards(cas.List) + e.block(cas.Body) + } + + case ir.OSELECT: + n := n.(*ir.SelectStmt) + for _, cas := range n.Cases { + e.stmt(cas.Comm) + e.block(cas.Body) + } + case ir.ORECV: + // TODO(mdempsky): Consider e.discard(n.Left). + n := n.(*ir.UnaryExpr) + e.exprSkipInit(e.discardHole(), n) // already visited n.Ninit + case ir.OSEND: + n := n.(*ir.SendStmt) + e.discard(n.Chan) + e.assignHeap(n.Value, "send", n) + + case ir.OAS: + n := n.(*ir.AssignStmt) + e.assignList([]ir.Node{n.X}, []ir.Node{n.Y}, "assign", n) + case ir.OASOP: + n := n.(*ir.AssignOpStmt) + // TODO(mdempsky): Worry about OLSH/ORSH? + e.assignList([]ir.Node{n.X}, []ir.Node{n.Y}, "assign", n) + case ir.OAS2: + n := n.(*ir.AssignListStmt) + e.assignList(n.Lhs, n.Rhs, "assign-pair", n) + + case ir.OAS2DOTTYPE: // v, ok = x.(type) + n := n.(*ir.AssignListStmt) + e.assignList(n.Lhs, n.Rhs, "assign-pair-dot-type", n) + case ir.OAS2MAPR: // v, ok = m[k] + n := n.(*ir.AssignListStmt) + e.assignList(n.Lhs, n.Rhs, "assign-pair-mapr", n) + case ir.OAS2RECV, ir.OSELRECV2: // v, ok = <-ch + n := n.(*ir.AssignListStmt) + e.assignList(n.Lhs, n.Rhs, "assign-pair-receive", n) + + case ir.OAS2FUNC: + n := n.(*ir.AssignListStmt) + e.stmts(n.Rhs[0].Init()) + ks := e.addrs(n.Lhs) + e.call(ks, n.Rhs[0], nil) + e.reassigned(ks, n) + case ir.ORETURN: + n := n.(*ir.ReturnStmt) + results := e.curfn.Type().Results().FieldSlice() + dsts := make([]ir.Node, len(results)) + for i, res := range results { + dsts[i] = res.Nname.(*ir.Name) + } + e.assignList(dsts, n.Results, "return", n) + case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OCLOSE, ir.OCOPY, ir.ODELETE, ir.OPANIC, ir.OPRINT, ir.OPRINTN, ir.ORECOVER: + e.call(nil, n, nil) + case ir.OGO, ir.ODEFER: + n := n.(*ir.GoDeferStmt) + e.stmts(n.Call.Init()) + e.call(nil, n.Call, n) + + case ir.OTAILCALL: + // TODO(mdempsky): Treat like a normal call? esc.go used to just ignore it. + } +} + +func (e *escape) stmts(l ir.Nodes) { + for _, n := range l { + e.stmt(n) + } +} + +// block is like stmts, but preserves loopDepth. +func (e *escape) block(l ir.Nodes) { + old := e.loopDepth + e.stmts(l) + e.loopDepth = old +} + +func (e *escape) dcl(n *ir.Name) hole { + if n.Curfn != e.curfn || n.IsClosureVar() { + base.Fatalf("bad declaration of %v", n) + } + loc := e.oldLoc(n) + loc.loopDepth = e.loopDepth + return loc.asHole() +} diff --git a/src/cmd/compile/internal/escape/utils.go b/src/cmd/compile/internal/escape/utils.go new file mode 100644 index 00000000000..7100926bb85 --- /dev/null +++ b/src/cmd/compile/internal/escape/utils.go @@ -0,0 +1,215 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package escape + +import ( + "cmd/compile/internal/ir" + "cmd/compile/internal/typecheck" +) + +func isSliceSelfAssign(dst, src ir.Node) bool { + // Detect the following special case. + // + // func (b *Buffer) Foo() { + // n, m := ... + // b.buf = b.buf[n:m] + // } + // + // This assignment is a no-op for escape analysis, + // it does not store any new pointers into b that were not already there. + // However, without this special case b will escape, because we assign to OIND/ODOTPTR. + // Here we assume that the statement will not contain calls, + // that is, that order will move any calls to init. + // Otherwise base ONAME value could change between the moments + // when we evaluate it for dst and for src. + + // dst is ONAME dereference. + var dstX ir.Node + switch dst.Op() { + default: + return false + case ir.ODEREF: + dst := dst.(*ir.StarExpr) + dstX = dst.X + case ir.ODOTPTR: + dst := dst.(*ir.SelectorExpr) + dstX = dst.X + } + if dstX.Op() != ir.ONAME { + return false + } + // src is a slice operation. + switch src.Op() { + case ir.OSLICE, ir.OSLICE3, ir.OSLICESTR: + // OK. + case ir.OSLICEARR, ir.OSLICE3ARR: + // Since arrays are embedded into containing object, + // slice of non-pointer array will introduce a new pointer into b that was not already there + // (pointer to b itself). After such assignment, if b contents escape, + // b escapes as well. If we ignore such OSLICEARR, we will conclude + // that b does not escape when b contents do. + // + // Pointer to an array is OK since it's not stored inside b directly. + // For slicing an array (not pointer to array), there is an implicit OADDR. + // We check that to determine non-pointer array slicing. + src := src.(*ir.SliceExpr) + if src.X.Op() == ir.OADDR { + return false + } + default: + return false + } + // slice is applied to ONAME dereference. + var baseX ir.Node + switch base := src.(*ir.SliceExpr).X; base.Op() { + default: + return false + case ir.ODEREF: + base := base.(*ir.StarExpr) + baseX = base.X + case ir.ODOTPTR: + base := base.(*ir.SelectorExpr) + baseX = base.X + } + if baseX.Op() != ir.ONAME { + return false + } + // dst and src reference the same base ONAME. + return dstX.(*ir.Name) == baseX.(*ir.Name) +} + +// isSelfAssign reports whether assignment from src to dst can +// be ignored by the escape analysis as it's effectively a self-assignment. +func isSelfAssign(dst, src ir.Node) bool { + if isSliceSelfAssign(dst, src) { + return true + } + + // Detect trivial assignments that assign back to the same object. + // + // It covers these cases: + // val.x = val.y + // val.x[i] = val.y[j] + // val.x1.x2 = val.x1.y2 + // ... etc + // + // These assignments do not change assigned object lifetime. + + if dst == nil || src == nil || dst.Op() != src.Op() { + return false + } + + // The expression prefix must be both "safe" and identical. + switch dst.Op() { + case ir.ODOT, ir.ODOTPTR: + // Safe trailing accessors that are permitted to differ. + dst := dst.(*ir.SelectorExpr) + src := src.(*ir.SelectorExpr) + return ir.SameSafeExpr(dst.X, src.X) + case ir.OINDEX: + dst := dst.(*ir.IndexExpr) + src := src.(*ir.IndexExpr) + if mayAffectMemory(dst.Index) || mayAffectMemory(src.Index) { + return false + } + return ir.SameSafeExpr(dst.X, src.X) + default: + return false + } +} + +// mayAffectMemory reports whether evaluation of n may affect the program's +// memory state. If the expression can't affect memory state, then it can be +// safely ignored by the escape analysis. +func mayAffectMemory(n ir.Node) bool { + // We may want to use a list of "memory safe" ops instead of generally + // "side-effect free", which would include all calls and other ops that can + // allocate or change global state. For now, it's safer to start with the latter. + // + // We're ignoring things like division by zero, index out of range, + // and nil pointer dereference here. + + // TODO(rsc): It seems like it should be possible to replace this with + // an ir.Any looking for any op that's not the ones in the case statement. + // But that produces changes in the compiled output detected by buildall. + switch n.Op() { + case ir.ONAME, ir.OLITERAL, ir.ONIL: + return false + + case ir.OADD, ir.OSUB, ir.OOR, ir.OXOR, ir.OMUL, ir.OLSH, ir.ORSH, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OMOD: + n := n.(*ir.BinaryExpr) + return mayAffectMemory(n.X) || mayAffectMemory(n.Y) + + case ir.OINDEX: + n := n.(*ir.IndexExpr) + return mayAffectMemory(n.X) || mayAffectMemory(n.Index) + + case ir.OCONVNOP, ir.OCONV: + n := n.(*ir.ConvExpr) + return mayAffectMemory(n.X) + + case ir.OLEN, ir.OCAP, ir.ONOT, ir.OBITNOT, ir.OPLUS, ir.ONEG, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF: + n := n.(*ir.UnaryExpr) + return mayAffectMemory(n.X) + + case ir.ODOT, ir.ODOTPTR: + n := n.(*ir.SelectorExpr) + return mayAffectMemory(n.X) + + case ir.ODEREF: + n := n.(*ir.StarExpr) + return mayAffectMemory(n.X) + + default: + return true + } +} + +// HeapAllocReason returns the reason the given Node must be heap +// allocated, or the empty string if it doesn't. +func HeapAllocReason(n ir.Node) string { + if n == nil || n.Type() == nil { + return "" + } + + // Parameters are always passed via the stack. + if n.Op() == ir.ONAME { + n := n.(*ir.Name) + if n.Class == ir.PPARAM || n.Class == ir.PPARAMOUT { + return "" + } + } + + if n.Type().Width > ir.MaxStackVarSize { + return "too large for stack" + } + + if (n.Op() == ir.ONEW || n.Op() == ir.OPTRLIT) && n.Type().Elem().Width >= ir.MaxImplicitStackVarSize { + return "too large for stack" + } + + if n.Op() == ir.OCLOSURE && typecheck.ClosureType(n.(*ir.ClosureExpr)).Size() >= ir.MaxImplicitStackVarSize { + return "too large for stack" + } + if n.Op() == ir.OCALLPART && typecheck.PartialCallType(n.(*ir.SelectorExpr)).Size() >= ir.MaxImplicitStackVarSize { + return "too large for stack" + } + + if n.Op() == ir.OMAKESLICE { + n := n.(*ir.MakeExpr) + r := n.Cap + if r == nil { + r = n.Len + } + if !ir.IsSmallIntConst(r) { + return "non-constant size" + } + if t := n.Type(); t.Elem().Width != 0 && ir.Int64Val(r) >= ir.MaxImplicitStackVarSize/t.Elem().Width { + return "too large for stack" + } + } + + return "" +} From 63daa774b566d7fe58b3aa82cda9e595929bb777 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Mon, 21 Jun 2021 20:16:37 -0400 Subject: [PATCH 504/940] go/types: guard against checking instantiation when generics is disabled When type checking t[_], where t is a type name, it was possible to leak an error message related to generics. Fix this by guarding on typeparams.Enabled. In order to test this fix, we need to be able to run the new go/types test only if type parameters are disabled. Introduce the .go1 test data suffix (similar to .go2) to control this behavior. Originally found via fuzzing, though the test case was manually simplified. Updates #46404 Change-Id: Ib1e2c27cf974c2a5ca5b9d6d01b84a30ba4d583b Reviewed-on: https://go-review.googlesource.com/c/go/+/329793 Trust: Robert Findley Trust: Robert Griesemer Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/check_test.go | 13 ++++++++----- src/go/types/testdata/fixedbugs/issue46404.go1 | 8 ++++++++ src/go/types/typexpr.go | 8 ++++++-- 3 files changed, 22 insertions(+), 7 deletions(-) create mode 100644 src/go/types/testdata/fixedbugs/issue46404.go1 diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go index 6c3b630a1b6..5a3e57ba44d 100644 --- a/src/go/types/check_test.go +++ b/src/go/types/check_test.go @@ -207,12 +207,15 @@ func checkFiles(t *testing.T, sizes Sizes, goVersion string, filenames []string, t.Fatal("no source files") } + if strings.HasSuffix(filenames[0], ".go2") && !typeparams.Enabled { + t.Skip("type params are not enabled") + } + if strings.HasSuffix(filenames[0], ".go1") && typeparams.Enabled { + t.Skip("type params are enabled") + } + mode := parser.AllErrors - if strings.HasSuffix(filenames[0], ".go2") { - if !typeparams.Enabled { - t.Skip("type params are not enabled") - } - } else { + if !strings.HasSuffix(filenames[0], ".go2") { mode |= typeparams.DisallowParsing } diff --git a/src/go/types/testdata/fixedbugs/issue46404.go1 b/src/go/types/testdata/fixedbugs/issue46404.go1 new file mode 100644 index 00000000000..db604bc1ac3 --- /dev/null +++ b/src/go/types/testdata/fixedbugs/issue46404.go1 @@ -0,0 +1,8 @@ +// Copyright 2021 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 issue46404 + +// Check that we don't type check t[_] as an instantiation. +type t [t /* ERROR not a type */ [_]]_ // ERROR cannot use diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 5185c33fcbf..1738d864a65 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -463,8 +463,12 @@ func (check *Checker) typInternal(e0 ast.Expr, def *Named) (T Type) { } case *ast.IndexExpr: - exprs := typeparams.UnpackExpr(e.Index) - return check.instantiatedType(e.X, exprs, def) + if typeparams.Enabled { + exprs := typeparams.UnpackExpr(e.Index) + return check.instantiatedType(e.X, exprs, def) + } + check.errorf(e0, _NotAType, "%s is not a type", e0) + check.use(e.X) case *ast.ParenExpr: // Generic types must be instantiated before they can be used in any form. From 666315b4d38b99931bb9fd158a76e59928fd2852 Mon Sep 17 00:00:00 2001 From: Xing Gao <18340825824@163.com> Date: Tue, 22 Jun 2021 02:12:29 +0000 Subject: [PATCH 505/940] runtime/internal/atomic: remove incorrect pointer indirection in comment Change-Id: I9d743b7f6b001158299bea4af4aede678654bc8e GitHub-Last-Rev: 7e07834abc861e21030fe4a8eb323bac01e18f7a GitHub-Pull-Request: golang/go#46851 Reviewed-on: https://go-review.googlesource.com/c/go/+/329730 Reviewed-by: Ian Lance Taylor Reviewed-by: Ben Shi --- src/runtime/internal/atomic/atomic_386.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/internal/atomic/atomic_386.s b/src/runtime/internal/atomic/atomic_386.s index 37318e0ad76..724d5152313 100644 --- a/src/runtime/internal/atomic/atomic_386.s +++ b/src/runtime/internal/atomic/atomic_386.s @@ -65,7 +65,7 @@ TEXT ·Xaddint64(SB), NOSPLIT, $0-20 // bool ·Cas64(uint64 *val, uint64 old, uint64 new) // Atomically: -// if(*val == *old){ +// if(*val == old){ // *val = new; // return 1; // } else { From 5bd09e5efccf0d3df89085c9f214f94017f6e969 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 21 Jun 2021 22:20:11 -0700 Subject: [PATCH 506/940] spec: unsafe.Add/Slice are not permitted in statement context Add unsafe.Add and unsafe.Slice to the list of built-in functions which are not permitted in statement context. The compiler and type checker already enforce this restriction, this just fixes a documentation oversight. For #19367. For #40481. Change-Id: Iabc63a8db048eaf40a5f5b5573fdf00b79d54119 Reviewed-on: https://go-review.googlesource.com/c/go/+/329925 Trust: Robert Griesemer Run-TryBot: Robert Griesemer Reviewed-by: Matthew Dempsky Reviewed-by: Rob Pike TryBot-Result: Go Bot --- doc/go_spec.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index 561d44271a2..b59b37fd552 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -4670,7 +4670,7 @@ The following built-in functions are not permitted in statement context:

 append cap complex imag len make new real
-unsafe.Alignof unsafe.Offsetof unsafe.Sizeof
+unsafe.Add unsafe.Alignof unsafe.Offsetof unsafe.Sizeof unsafe.Slice
 

From 0ebd5a8de05823109263bef31b38be8c29d2cd54 Mon Sep 17 00:00:00 2001
From: Ian Lance Taylor 
Date: Mon, 21 Jun 2021 14:48:54 -0700
Subject: [PATCH 507/940] cmd/go: update ToolTags based on GOARCH value

The build.Context ToolTags value is set based on the set of enabled
experiments, which in turn depends on GOARCH. Before this CL the set
of experiments was being set based on GOARCH in the environment.
That is normally fine, but fails with cmd/go when somebody has run
"go env -w GOARCH=val"; in that case cmd/go changes its GOARCH value
after initialization. The new GOARCH value was affect the set of
enabled experiments, which can affect the ToolTags value. With this
CL, we update ToolTags in cmd/go based on the GOARCH value it is using.

This is a pretty ugly fix. We should do something cleaner for 1.18.

Fixes #46815

Change-Id: Ie9416781a168248813c3da8afdc257acdd3fef7e
Reviewed-on: https://go-review.googlesource.com/c/go/+/329930
Trust: Ian Lance Taylor 
Run-TryBot: Ian Lance Taylor 
TryBot-Result: Go Bot 
Reviewed-by: Matthew Dempsky 
---
 src/cmd/go/internal/cfg/cfg.go                |  8 +++++
 .../go/testdata/script/env_cross_build.txt    | 29 +++++++++++++++++++
 src/internal/buildcfg/exp.go                  | 13 +++++++--
 3 files changed, 47 insertions(+), 3 deletions(-)
 create mode 100644 src/cmd/go/testdata/script/env_cross_build.txt

diff --git a/src/cmd/go/internal/cfg/cfg.go b/src/cmd/go/internal/cfg/cfg.go
index b47eb812b59..fc6989097ee 100644
--- a/src/cmd/go/internal/cfg/cfg.go
+++ b/src/cmd/go/internal/cfg/cfg.go
@@ -77,6 +77,14 @@ func defaultContext() build.Context {
 	ctxt.GOOS = envOr("GOOS", ctxt.GOOS)
 	ctxt.GOARCH = envOr("GOARCH", ctxt.GOARCH)
 
+	// The experiments flags are based on GOARCH, so they may
+	// need to change.  TODO: This should be cleaned up.
+	buildcfg.UpdateExperiments(ctxt.GOARCH)
+	ctxt.ToolTags = nil
+	for _, exp := range buildcfg.EnabledExperiments() {
+		ctxt.ToolTags = append(ctxt.ToolTags, "goexperiment."+exp)
+	}
+
 	// The go/build rule for whether cgo is enabled is:
 	//	1. If $CGO_ENABLED is set, respect it.
 	//	2. Otherwise, if this is a cross-compile, disable cgo.
diff --git a/src/cmd/go/testdata/script/env_cross_build.txt b/src/cmd/go/testdata/script/env_cross_build.txt
new file mode 100644
index 00000000000..3feeba6b141
--- /dev/null
+++ b/src/cmd/go/testdata/script/env_cross_build.txt
@@ -0,0 +1,29 @@
+# Test that the corect default GOEXPERIMENT is used when cross
+# building with GOENV (#46815).
+
+# Unset variables set by the TestScript harness. Users typically won't
+# explicitly configure these, and #46815 doesn't repro if they are.
+env GOOS=
+env GOARCH=
+env GOEXPERIMENT=
+
+env GOENV=windows-amd64
+go build internal/abi
+
+env GOENV=ios-arm64
+go build internal/abi
+
+env GOENV=linux-mips
+go build internal/abi
+
+-- windows-amd64 --
+GOOS=windows
+GOARCH=amd64
+
+-- ios-arm64 --
+GOOS=ios
+GOARCH=arm64
+
+-- linux-mips --
+GOOS=linux
+GOARCH=mips
diff --git a/src/internal/buildcfg/exp.go b/src/internal/buildcfg/exp.go
index 2435a79dcec..640aa1934db 100644
--- a/src/internal/buildcfg/exp.go
+++ b/src/internal/buildcfg/exp.go
@@ -18,7 +18,7 @@ import (
 //
 // (This is not necessarily the set of experiments the compiler itself
 // was built with.)
-var Experiment goexperiment.Flags = parseExperiments()
+var Experiment goexperiment.Flags = parseExperiments(GOARCH)
 
 var regabiSupported = GOARCH == "amd64" && (GOOS == "android" || GOOS == "linux" || GOOS == "darwin" || GOOS == "windows")
 
@@ -42,7 +42,7 @@ var experimentBaseline = goexperiment.Flags{
 // Note: must agree with runtime.framepointer_enabled.
 var FramePointerEnabled = GOARCH == "amd64" || GOARCH == "arm64"
 
-func parseExperiments() goexperiment.Flags {
+func parseExperiments(goarch string) goexperiment.Flags {
 	// Start with the statically enabled set of experiments.
 	flags := experimentBaseline
 
@@ -99,7 +99,7 @@ func parseExperiments() goexperiment.Flags {
 	}
 
 	// regabi is only supported on amd64.
-	if GOARCH != "amd64" {
+	if goarch != "amd64" {
 		flags.RegabiWrappers = false
 		flags.RegabiG = false
 		flags.RegabiReflect = false
@@ -165,3 +165,10 @@ func EnabledExperiments() []string {
 func AllExperiments() []string {
 	return expList(&Experiment, nil, true)
 }
+
+// UpdateExperiments updates the Experiment global based on a new GOARCH value.
+// This is only required for cmd/go, which can change GOARCH after
+// program startup due to use of "go env -w".
+func UpdateExperiments(goarch string) {
+	Experiment = parseExperiments(goarch)
+}

From 541612b9746c1c314884af4079bfe8d340aaf953 Mon Sep 17 00:00:00 2001
From: Rob Findley 
Date: Mon, 21 Jun 2021 20:12:20 -0400
Subject: [PATCH 508/940] [dev.typeparams] cmd/gofmt: remove typeparams guards

Remove logic related to guarding against allowing type parameters from
cmd/gofmt. At this point, it was only restricting tests.

Change-Id: Idd198389aaa422636d61af547a37be49f3be6c97
Reviewed-on: https://go-review.googlesource.com/c/go/+/329931
Trust: Robert Findley 
Run-TryBot: Robert Findley 
TryBot-Result: Go Bot 
Reviewed-by: Robert Griesemer 
---
 src/cmd/gofmt/doc.go                     |  3 ---
 src/cmd/gofmt/gofmt_test.go              |  7 -------
 src/cmd/gofmt/gofmt_typeparams_test.go   | 12 ------------
 src/cmd/gofmt/testdata/typeparams.golden |  2 +-
 src/cmd/gofmt/testdata/typeparams.input  |  2 +-
 5 files changed, 2 insertions(+), 24 deletions(-)
 delete mode 100644 src/cmd/gofmt/gofmt_typeparams_test.go

diff --git a/src/cmd/gofmt/doc.go b/src/cmd/gofmt/doc.go
index 68476e7d443..e3406655941 100644
--- a/src/cmd/gofmt/doc.go
+++ b/src/cmd/gofmt/doc.go
@@ -26,9 +26,6 @@ The flags are:
 		Do not print reformatted sources to standard output.
 		If a file's formatting is different from gofmt's, print its name
 		to standard output.
-	-G
-		Allow generic code, using type parameters.
-		See golang.org/issues/43651 for more information.
 	-r rule
 		Apply the rewrite rule to the source before reformatting.
 	-s
diff --git a/src/cmd/gofmt/gofmt_test.go b/src/cmd/gofmt/gofmt_test.go
index f0d3f8780f4..9ef7676214c 100644
--- a/src/cmd/gofmt/gofmt_test.go
+++ b/src/cmd/gofmt/gofmt_test.go
@@ -54,8 +54,6 @@ func gofmtFlags(filename string, maxLines int) string {
 	return ""
 }
 
-var typeParamsEnabled = false
-
 func runTest(t *testing.T, in, out string) {
 	// process flags
 	*simplifyAST = false
@@ -78,11 +76,6 @@ func runTest(t *testing.T, in, out string) {
 		case "-stdin":
 			// fake flag - pretend input is from stdin
 			stdin = true
-		case "-G":
-			// fake flag - test is for generic code
-			if !typeParamsEnabled {
-				return
-			}
 		default:
 			t.Errorf("unrecognized flag name: %s", name)
 		}
diff --git a/src/cmd/gofmt/gofmt_typeparams_test.go b/src/cmd/gofmt/gofmt_typeparams_test.go
deleted file mode 100644
index 10641a77cb2..00000000000
--- a/src/cmd/gofmt/gofmt_typeparams_test.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2021 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 typeparams
-// +build typeparams
-
-package main
-
-func init() {
-	typeParamsEnabled = true
-}
diff --git a/src/cmd/gofmt/testdata/typeparams.golden b/src/cmd/gofmt/testdata/typeparams.golden
index 35f08d13792..f71bd130db4 100644
--- a/src/cmd/gofmt/testdata/typeparams.golden
+++ b/src/cmd/gofmt/testdata/typeparams.golden
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//gofmt -G
+//gofmt
 
 package typeparams
 
diff --git a/src/cmd/gofmt/testdata/typeparams.input b/src/cmd/gofmt/testdata/typeparams.input
index 7f3212c8e4a..5d4c53d9f76 100644
--- a/src/cmd/gofmt/testdata/typeparams.input
+++ b/src/cmd/gofmt/testdata/typeparams.input
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//gofmt -G
+//gofmt
 
 package typeparams
 

From 62095c66e042024fc631a3e9514b637ae4b5ae10 Mon Sep 17 00:00:00 2001
From: Rob Findley 
Date: Tue, 22 Jun 2021 10:13:54 -0400
Subject: [PATCH 509/940] [dev.typeparams] go/types: adjust logic for method
 expression arg naming

CL 325369 improved this logic in types2. Port this improvement back to
go/types.

Change-Id: I5f859cbffd88bb3db09a81c2389269f7bd0869f9
Reviewed-on: https://go-review.googlesource.com/c/go/+/330069
Trust: Robert Findley 
Run-TryBot: Robert Findley 
TryBot-Result: Go Bot 
Reviewed-by: Robert Griesemer 
---
 src/go/types/call.go | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/src/go/types/call.go b/src/go/types/call.go
index 3a04121e984..039c7bbaf59 100644
--- a/src/go/types/call.go
+++ b/src/go/types/call.go
@@ -587,16 +587,15 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
 		if sig.params != nil {
 			params = sig.params.vars
 		}
-		// Be consistent about named/unnamed parameters.
-		needName := true
-		for _, param := range params {
-			if param.Name() == "" {
-				needName = false
-				break
-			}
-		}
+		// Be consistent about named/unnamed parameters. This is not needed
+		// for type-checking, but the newly constructed signature may appear
+		// in an error message and then have mixed named/unnamed parameters.
+		// (An alternative would be to not print parameter names in errors,
+		// but it's useful to see them; this is cheap and method expressions
+		// are rare.)
 		name := ""
-		if needName {
+		if len(params) > 0 && params[0].name != "" {
+			// name needed
 			name = sig.recv.name
 			if name == "" {
 				name = "_"

From c4e0c652fbf3b17cc89f72c6569fe255fe5e1047 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Tue, 22 Jun 2021 18:10:59 -0700
Subject: [PATCH 510/940] [dev.typeparams] cmd/compile: refactor CaptureName

CaptureName currently does a few things: checks if a variable needs to
be captured at all; checks if the variable has already been captured;
and creates and saves a new variable. This full suite of functionality
is useful for noder and irgen, but unified IR and other backend code
only has a need for the last feature.

This CL refactors CaptureName a little bit and extracts out
NewClosureVar as a function usable for callers that don't need the
extra features of CaptureName.

Change-Id: I8a67c6375e44babe53344bf78e335535c57f9607
Reviewed-on: https://go-review.googlesource.com/c/go/+/330193
Trust: Matthew Dempsky 
Trust: Cuong Manh Le 
Run-TryBot: Matthew Dempsky 
TryBot-Result: Go Bot 
Reviewed-by: Cuong Manh Le 
---
 src/cmd/compile/internal/ir/name.go      | 47 +++++++++++++++---------
 src/cmd/compile/internal/noder/reader.go | 13 ++-----
 2 files changed, 33 insertions(+), 27 deletions(-)

diff --git a/src/cmd/compile/internal/ir/name.go b/src/cmd/compile/internal/ir/name.go
index b6c68bc5e01..ff9784df1b1 100644
--- a/src/cmd/compile/internal/ir/name.go
+++ b/src/cmd/compile/internal/ir/name.go
@@ -358,39 +358,52 @@ func (n *Name) Byval() bool {
 	return n.Canonical().flags&nameByval != 0
 }
 
+// NewClosureVar creates a new closure variable for fn to refer to
+// outer variable n.
+func NewClosureVar(pos src.XPos, fn *Func, n *Name) *Name {
+	c := NewNameAt(pos, n.Sym())
+	c.Curfn = fn
+	c.Class = PAUTOHEAP
+	c.SetIsClosureVar(true)
+	c.Defn = n.Canonical()
+	c.Outer = n
+
+	fn.ClosureVars = append(fn.ClosureVars, c)
+
+	return c
+}
+
 // CaptureName returns a Name suitable for referring to n from within function
 // fn or from the package block if fn is nil. If n is a free variable declared
-// within a function that encloses fn, then CaptureName returns a closure
-// variable that refers to n and adds it to fn.ClosureVars. Otherwise, it simply
-// returns n.
+// within a function that encloses fn, then CaptureName returns the closure
+// variable that refers to n within fn, creating it if necessary.
+// Otherwise, it simply returns n.
 func CaptureName(pos src.XPos, fn *Func, n *Name) *Name {
+	if n.Op() != ONAME || n.Curfn == nil {
+		return n // okay to use directly
+	}
 	if n.IsClosureVar() {
 		base.FatalfAt(pos, "misuse of CaptureName on closure variable: %v", n)
 	}
-	if n.Op() != ONAME || n.Curfn == nil || n.Curfn == fn {
-		return n // okay to use directly
+
+	c := n.Innermost
+	if c == nil {
+		c = n
 	}
+	if c.Curfn == fn {
+		return c
+	}
+
 	if fn == nil {
 		base.FatalfAt(pos, "package-block reference to %v, declared in %v", n, n.Curfn)
 	}
 
-	c := n.Innermost
-	if c != nil && c.Curfn == fn {
-		return c
-	}
-
 	// Do not have a closure var for the active closure yet; make one.
-	c = NewNameAt(pos, n.Sym())
-	c.Curfn = fn
-	c.Class = PAUTOHEAP
-	c.SetIsClosureVar(true)
-	c.Defn = n
+	c = NewClosureVar(pos, fn, c)
 
 	// Link into list of active closure variables.
 	// Popped from list in FinishCaptureNames.
-	c.Outer = n.Innermost
 	n.Innermost = c
-	fn.ClosureVars = append(fn.ClosureVars, c)
 
 	return c
 }
diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go
index 4fc9e7a777a..b106e898927 100644
--- a/src/cmd/compile/internal/noder/reader.go
+++ b/src/cmd/compile/internal/noder/reader.go
@@ -1558,20 +1558,13 @@ func (r *reader) funcLit() ir.Node {
 		fn.Nname.Ntype = ir.TypeNodeAt(typPos, xtype2)
 	}
 
-	fn.ClosureVars = make([]*ir.Name, r.len())
-	for i := range fn.ClosureVars {
+	fn.ClosureVars = make([]*ir.Name, 0, r.len())
+	for len(fn.ClosureVars) < cap(fn.ClosureVars) {
 		pos := r.pos()
 		outer := r.useLocal()
 
-		cv := ir.NewNameAt(pos, outer.Sym())
+		cv := ir.NewClosureVar(pos, fn, outer)
 		r.setType(cv, outer.Type())
-		cv.Curfn = fn
-		cv.Class = ir.PAUTOHEAP
-		cv.SetIsClosureVar(true)
-		cv.Defn = outer.Canonical()
-		cv.Outer = outer
-
-		fn.ClosureVars[i] = cv
 	}
 
 	r.addBody(fn)

From 493e177639140d83807ae72b6ea840ce025416ce Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Tue, 22 Jun 2021 18:15:21 -0700
Subject: [PATCH 511/940] [dev.typeparams] cmd/compile: allow typecheck of
 OCHECKNIL

This CL makes OCHECKNIL typecheckable. Simplifies IR construction code
slightly, and gives one convenient place to check for misuse.

Change-Id: I280b8e47eddcac12947a41d6f911b25bc12a66bf
Reviewed-on: https://go-review.googlesource.com/c/go/+/330194
Trust: Matthew Dempsky 
Run-TryBot: Matthew Dempsky 
TryBot-Result: Go Bot 
Reviewed-by: Cuong Manh Le 
---
 src/cmd/compile/internal/typecheck/stmt.go      |  9 +++++++++
 src/cmd/compile/internal/typecheck/typecheck.go |  4 ++++
 src/cmd/compile/internal/walk/builtin.go        |  5 ++---
 src/cmd/compile/internal/walk/closure.go        |  8 +++-----
 src/cmd/compile/internal/walk/order.go          | 12 +-----------
 5 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/src/cmd/compile/internal/typecheck/stmt.go b/src/cmd/compile/internal/typecheck/stmt.go
index 922a01bfbe9..cd00f1b3d11 100644
--- a/src/cmd/compile/internal/typecheck/stmt.go
+++ b/src/cmd/compile/internal/typecheck/stmt.go
@@ -237,6 +237,15 @@ func plural(n int) string {
 	return "s"
 }
 
+// tcCheckNil typechecks an OCHECKNIL node.
+func tcCheckNil(n *ir.UnaryExpr) ir.Node {
+	n.X = Expr(n.X)
+	if !n.X.Type().IsPtrShaped() {
+		base.FatalfAt(n.Pos(), "%L is not pointer shaped", n.X)
+	}
+	return n
+}
+
 // tcFor typechecks an OFOR node.
 func tcFor(n *ir.ForStmt) ir.Node {
 	Stmts(n.Init())
diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go
index b1a4e193d63..0367f7b0341 100644
--- a/src/cmd/compile/internal/typecheck/typecheck.go
+++ b/src/cmd/compile/internal/typecheck/typecheck.go
@@ -876,6 +876,10 @@ func typecheck1(n ir.Node, top int) ir.Node {
 		n := n.(*ir.TailCallStmt)
 		return n
 
+	case ir.OCHECKNIL:
+		n := n.(*ir.UnaryExpr)
+		return tcCheckNil(n)
+
 	case ir.OSELECT:
 		tcSelect(n.(*ir.SelectStmt))
 		return n
diff --git a/src/cmd/compile/internal/walk/builtin.go b/src/cmd/compile/internal/walk/builtin.go
index 62eb4298f4d..be0f4c5208c 100644
--- a/src/cmd/compile/internal/walk/builtin.go
+++ b/src/cmd/compile/internal/walk/builtin.go
@@ -677,9 +677,8 @@ func walkUnsafeSlice(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
 
 	ptr := walkExpr(n.X, init)
 
-	c := ir.NewUnaryExpr(n.Pos(), ir.OCHECKNIL, ptr)
-	c.SetTypecheck(1)
-	init.Append(c)
+	check := ir.NewUnaryExpr(n.Pos(), ir.OCHECKNIL, ptr)
+	init.Append(typecheck.Stmt(check))
 
 	// TODO(mdempsky): checkptr instrumentation. Maybe merge into length
 	// check above, along with nil check? Need to be careful about
diff --git a/src/cmd/compile/internal/walk/closure.go b/src/cmd/compile/internal/walk/closure.go
index feda3c3b4f8..5db907d01dc 100644
--- a/src/cmd/compile/internal/walk/closure.go
+++ b/src/cmd/compile/internal/walk/closure.go
@@ -178,11 +178,9 @@ func walkCallPart(n *ir.SelectorExpr, init *ir.Nodes) ir.Node {
 		n.X = cheapExpr(n.X, init)
 		n.X = walkExpr(n.X, nil)
 
-		tab := typecheck.Expr(ir.NewUnaryExpr(base.Pos, ir.OITAB, n.X))
-
-		c := ir.NewUnaryExpr(base.Pos, ir.OCHECKNIL, tab)
-		c.SetTypecheck(1)
-		init.Append(c)
+		tab := ir.NewUnaryExpr(base.Pos, ir.OITAB, n.X)
+		check := ir.NewUnaryExpr(base.Pos, ir.OCHECKNIL, tab)
+		init.Append(typecheck.Stmt(check))
 	}
 
 	typ := typecheck.PartialCallType(n)
diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go
index b9aff032404..4d40cf890e6 100644
--- a/src/cmd/compile/internal/walk/order.go
+++ b/src/cmd/compile/internal/walk/order.go
@@ -762,7 +762,7 @@ func (o *orderState) stmt(n ir.Node) {
 		o.out = append(o.out, n)
 		o.cleanTemp(t)
 
-	case ir.OCLOSE, ir.ORECV:
+	case ir.OCHECKNIL, ir.OCLOSE, ir.OPANIC, ir.ORECV:
 		n := n.(*ir.UnaryExpr)
 		t := o.markTemp()
 		n.X = o.expr(n.X, nil)
@@ -835,16 +835,6 @@ func (o *orderState) stmt(n ir.Node) {
 		orderBlock(&n.Else, o.free)
 		o.out = append(o.out, n)
 
-	case ir.OPANIC:
-		n := n.(*ir.UnaryExpr)
-		t := o.markTemp()
-		n.X = o.expr(n.X, nil)
-		if !n.X.Type().IsEmptyInterface() {
-			base.FatalfAt(n.Pos(), "bad argument to panic: %L", n.X)
-		}
-		o.out = append(o.out, n)
-		o.cleanTemp(t)
-
 	case ir.ORANGE:
 		// n.Right is the expression being ranged over.
 		// order it, and then make a copy if we need one.

From e59a19ccebe87b84e69625d0b83df6d0fe2499db Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Tue, 22 Jun 2021 20:33:00 -0700
Subject: [PATCH 512/940] [dev.typeparams] cmd/compile: simplify walkGoDefer

order already takes care of wrapping all go/defer function calls, so
there's no need for walk to duplicate that logic: it's never going to
be used.

Change-Id: I54e545404e52ab8f9d60151d1bd2aff4b9bd8b72
Reviewed-on: https://go-review.googlesource.com/c/go/+/330270
Run-TryBot: Matthew Dempsky 
Reviewed-by: Cuong Manh Le 
Trust: Cuong Manh Le 
Trust: Matthew Dempsky 
TryBot-Result: Go Bot 
---
 src/cmd/compile/internal/walk/stmt.go | 130 ++++----------------------
 1 file changed, 17 insertions(+), 113 deletions(-)

diff --git a/src/cmd/compile/internal/walk/stmt.go b/src/cmd/compile/internal/walk/stmt.go
index 0bf76680c46..e1ac6523643 100644
--- a/src/cmd/compile/internal/walk/stmt.go
+++ b/src/cmd/compile/internal/walk/stmt.go
@@ -7,7 +7,6 @@ package walk
 import (
 	"cmd/compile/internal/base"
 	"cmd/compile/internal/ir"
-	"cmd/compile/internal/typecheck"
 )
 
 // The result of walkStmt MUST be assigned back to n, e.g.
@@ -187,33 +186,26 @@ func walkFor(n *ir.ForStmt) ir.Node {
 	return n
 }
 
+// validGoDeferCall reports whether call is a valid call to appear in
+// a go or defer statement; that is, whether it's a regular function
+// call without arguments or results.
+func validGoDeferCall(call ir.Node) bool {
+	if call, ok := call.(*ir.CallExpr); ok && call.Op() == ir.OCALLFUNC && len(call.KeepAlive) == 0 {
+		sig := call.X.Type()
+		return sig.NumParams()+sig.NumResults() == 0
+	}
+	return false
+}
+
 // walkGoDefer walks an OGO or ODEFER node.
 func walkGoDefer(n *ir.GoDeferStmt) ir.Node {
-	var init ir.Nodes
-	switch call := n.Call; call.Op() {
-	case ir.OPRINT, ir.OPRINTN:
-		call := call.(*ir.CallExpr)
-		n.Call = wrapCall(call, &init)
-
-	case ir.ODELETE:
-		call := call.(*ir.CallExpr)
-		n.Call = wrapCall(call, &init)
-
-	case ir.OCOPY:
-		call := call.(*ir.BinaryExpr)
-		n.Call = walkCopy(call, &init, true)
-
-	case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
-		call := call.(*ir.CallExpr)
-		if len(call.KeepAlive) > 0 {
-			n.Call = wrapCall(call, &init)
-		} else {
-			n.Call = walkExpr(call, &init)
-		}
-
-	default:
-		n.Call = walkExpr(call, &init)
+	if !validGoDeferCall(n.Call) {
+		base.FatalfAt(n.Pos(), "invalid %v call: %v", n.Op(), n.Call)
 	}
+
+	var init ir.Nodes
+	n.Call = walkExpr(n.Call, &init)
+
 	if len(init) > 0 {
 		init.Append(n)
 		return ir.NewBlockStmt(n.Pos(), init)
@@ -229,94 +221,6 @@ func walkIf(n *ir.IfStmt) ir.Node {
 	return n
 }
 
-// Rewrite
-//	go builtin(x, y, z)
-// into
-//	go func(a1, a2, a3) {
-//		builtin(a1, a2, a3)
-//	}(x, y, z)
-// for print, println, and delete.
-//
-// Rewrite
-//	go f(x, y, uintptr(unsafe.Pointer(z)))
-// into
-//	go func(a1, a2, a3) {
-//		f(a1, a2, uintptr(a3))
-//	}(x, y, unsafe.Pointer(z))
-// for function contains unsafe-uintptr arguments.
-
-var wrapCall_prgen int
-
-// The result of wrapCall MUST be assigned back to n, e.g.
-// 	n.Left = wrapCall(n.Left, init)
-func wrapCall(n *ir.CallExpr, init *ir.Nodes) ir.Node {
-	if len(n.Init()) != 0 {
-		walkStmtList(n.Init())
-		init.Append(ir.TakeInit(n)...)
-	}
-
-	isBuiltinCall := n.Op() != ir.OCALLFUNC && n.Op() != ir.OCALLMETH && n.Op() != ir.OCALLINTER
-
-	// Turn f(a, b, []T{c, d, e}...) back into f(a, b, c, d, e).
-	if !isBuiltinCall && n.IsDDD {
-		undoVariadic(n)
-	}
-
-	wrapArgs := n.Args
-	// If there's a receiver argument, it needs to be passed through the wrapper too.
-	if n.Op() == ir.OCALLMETH || n.Op() == ir.OCALLINTER {
-		recv := n.X.(*ir.SelectorExpr).X
-		wrapArgs = append([]ir.Node{recv}, wrapArgs...)
-	}
-
-	// origArgs keeps track of what argument is uintptr-unsafe/unsafe-uintptr conversion.
-	origArgs := make([]ir.Node, len(wrapArgs))
-	var funcArgs []*ir.Field
-	for i, arg := range wrapArgs {
-		s := typecheck.LookupNum("a", i)
-		if !isBuiltinCall && arg.Op() == ir.OCONVNOP && arg.Type().IsUintptr() && arg.(*ir.ConvExpr).X.Type().IsUnsafePtr() {
-			origArgs[i] = arg
-			arg = arg.(*ir.ConvExpr).X
-			wrapArgs[i] = arg
-		}
-		funcArgs = append(funcArgs, ir.NewField(base.Pos, s, nil, arg.Type()))
-	}
-	t := ir.NewFuncType(base.Pos, nil, funcArgs, nil)
-
-	wrapCall_prgen++
-	sym := typecheck.LookupNum("wrap·", wrapCall_prgen)
-	fn := typecheck.DeclFunc(sym, t)
-
-	args := ir.ParamNames(t.Type())
-	for i, origArg := range origArgs {
-		if origArg == nil {
-			continue
-		}
-		args[i] = ir.NewConvExpr(base.Pos, origArg.Op(), origArg.Type(), args[i])
-	}
-	if n.Op() == ir.OCALLMETH || n.Op() == ir.OCALLINTER {
-		// Move wrapped receiver argument back to its appropriate place.
-		recv := typecheck.Expr(args[0])
-		n.X.(*ir.SelectorExpr).X = recv
-		args = args[1:]
-	}
-	call := ir.NewCallExpr(base.Pos, n.Op(), n.X, args)
-	if !isBuiltinCall {
-		call.SetOp(ir.OCALL)
-		call.IsDDD = n.IsDDD
-	}
-	fn.Body = []ir.Node{call}
-
-	typecheck.FinishFuncBody()
-
-	typecheck.Func(fn)
-	typecheck.Stmts(fn.Body)
-	typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
-
-	call = ir.NewCallExpr(base.Pos, ir.OCALL, fn.Nname, wrapArgs)
-	return walkExpr(typecheck.Stmt(call), init)
-}
-
 // undoVariadic turns a call to a variadic function of the form
 //
 //      f(a, b, []T{c, d, e}...)

From 1a445dab6676b2a5c0b15b313eabec5a79ea99a3 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Tue, 22 Jun 2021 20:37:42 -0700
Subject: [PATCH 513/940] [dev.typeparams] cmd/compile: remove
 CallExpr.PreserveClosure

This flag is only needed to prevent the directClosureCall optimization
in walkCall, when called for walkGoDefer. But walkGoDefer don't need
to call walkCall: at this point in the compile, the call expression
isn't a real call anymore.

Instead, we just need to walkExpr on the function expression.

Change-Id: I8a5176cfe1bff53700cbd21ed1b479ebd9a839ad
Reviewed-on: https://go-review.googlesource.com/c/go/+/330271
Run-TryBot: Matthew Dempsky 
TryBot-Result: Go Bot 
Reviewed-by: Cuong Manh Le 
Trust: Matthew Dempsky 
---
 src/cmd/compile/internal/ir/expr.go      | 13 ++++++-------
 src/cmd/compile/internal/walk/closure.go |  8 --------
 src/cmd/compile/internal/walk/order.go   |  6 +-----
 src/cmd/compile/internal/walk/stmt.go    |  4 +++-
 4 files changed, 10 insertions(+), 21 deletions(-)

diff --git a/src/cmd/compile/internal/ir/expr.go b/src/cmd/compile/internal/ir/expr.go
index 779793b2f26..b46fd905fe7 100644
--- a/src/cmd/compile/internal/ir/expr.go
+++ b/src/cmd/compile/internal/ir/expr.go
@@ -157,13 +157,12 @@ const (
 type CallExpr struct {
 	miniExpr
 	origNode
-	X               Node
-	Args            Nodes
-	KeepAlive       []*Name // vars to be kept alive until call returns
-	IsDDD           bool
-	Use             CallUse
-	NoInline        bool
-	PreserveClosure bool // disable directClosureCall for this call
+	X         Node
+	Args      Nodes
+	KeepAlive []*Name // vars to be kept alive until call returns
+	IsDDD     bool
+	Use       CallUse
+	NoInline  bool
 }
 
 func NewCallExpr(pos src.XPos, op Op, fun Node, args []Node) *CallExpr {
diff --git a/src/cmd/compile/internal/walk/closure.go b/src/cmd/compile/internal/walk/closure.go
index 5db907d01dc..2b7fe8f926b 100644
--- a/src/cmd/compile/internal/walk/closure.go
+++ b/src/cmd/compile/internal/walk/closure.go
@@ -37,14 +37,6 @@ func directClosureCall(n *ir.CallExpr) {
 		return // leave for walkClosure to handle
 	}
 
-	// If wrapGoDefer() in the order phase has flagged this call,
-	// avoid eliminating the closure even if there is a direct call to
-	// (the closure is needed to simplify the register ABI). See
-	// wrapGoDefer for more details.
-	if n.PreserveClosure {
-		return
-	}
-
 	// We are going to insert captured variables before input args.
 	var params []*types.Field
 	var decls []*ir.Name
diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go
index 4d40cf890e6..c24f80508a0 100644
--- a/src/cmd/compile/internal/walk/order.go
+++ b/src/cmd/compile/internal/walk/order.go
@@ -1564,11 +1564,10 @@ func (o *orderState) wrapGoDefer(n *ir.GoDeferStmt) {
 	// TODO: maybe not wrap if the called function has no arguments and
 	// only in-register results?
 	if len(callArgs) == 0 && call.Op() == ir.OCALLFUNC && callX.Type().NumResults() == 0 {
-		if c, ok := call.(*ir.CallExpr); ok && callX != nil && callX.Op() == ir.OCLOSURE {
+		if callX.Op() == ir.OCLOSURE {
 			clo := callX.(*ir.ClosureExpr)
 			clo.Func.SetClosureCalled(false)
 			clo.IsGoWrap = true
-			c.PreserveClosure = true
 		}
 		return
 	}
@@ -1771,9 +1770,6 @@ func (o *orderState) wrapGoDefer(n *ir.GoDeferStmt) {
 	topcall := ir.NewCallExpr(n.Pos(), ir.OCALL, clo, nil)
 	typecheck.Call(topcall)
 
-	// Tag the call to insure that directClosureCall doesn't undo our work.
-	topcall.PreserveClosure = true
-
 	fn.SetClosureCalled(false)
 
 	// Finally, point the defer statement at the newly generated call.
diff --git a/src/cmd/compile/internal/walk/stmt.go b/src/cmd/compile/internal/walk/stmt.go
index e1ac6523643..2352719da3f 100644
--- a/src/cmd/compile/internal/walk/stmt.go
+++ b/src/cmd/compile/internal/walk/stmt.go
@@ -204,7 +204,9 @@ func walkGoDefer(n *ir.GoDeferStmt) ir.Node {
 	}
 
 	var init ir.Nodes
-	n.Call = walkExpr(n.Call, &init)
+
+	call := n.Call.(*ir.CallExpr)
+	call.X = walkExpr(call.X, &init)
 
 	if len(init) > 0 {
 		init.Append(n)

From 99732b9070ea23c13f7ed9ff8518304e34942ad4 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Tue, 22 Jun 2021 20:53:14 -0700
Subject: [PATCH 514/940] [dev.typeparams] cmd/compile: refactor escape
 analysis of calls

This CL is a prep refactoring for an upcoming CL to move go/defer
wrapping into escape analysis. That CL is unfortunately unavoidably
complex and subtle, so this CL takes care of some more mundane
refactoring details.

Change-Id: Ifbefe1d522a8d57066646be09536437f42e7082c
Reviewed-on: https://go-review.googlesource.com/c/go/+/330251
Run-TryBot: Matthew Dempsky 
TryBot-Result: Go Bot 
Trust: Matthew Dempsky 
Reviewed-by: Cuong Manh Le 
---
 src/cmd/compile/internal/escape/call.go | 78 ++++++++++++++-----------
 src/cmd/compile/internal/escape/expr.go |  2 +-
 src/cmd/compile/internal/escape/stmt.go |  7 +--
 3 files changed, 48 insertions(+), 39 deletions(-)

diff --git a/src/cmd/compile/internal/escape/call.go b/src/cmd/compile/internal/escape/call.go
index 28a3b679a56..8511259d47b 100644
--- a/src/cmd/compile/internal/escape/call.go
+++ b/src/cmd/compile/internal/escape/call.go
@@ -13,26 +13,24 @@ import (
 
 // call evaluates a call expressions, including builtin calls. ks
 // should contain the holes representing where the function callee's
-// results flows; where is the OGO/ODEFER context of the call, if any.
-func (e *escape) call(ks []hole, call, where ir.Node) {
-	topLevelDefer := where != nil && where.Op() == ir.ODEFER && e.loopDepth == 1
-	if topLevelDefer {
-		// force stack allocation of defer record, unless
-		// open-coded defers are used (see ssa.go)
-		where.SetEsc(ir.EscNever)
-	}
+// results flows.
+func (e *escape) call(ks []hole, call ir.Node) {
+	e.callCommon(ks, call, nil)
+}
 
-	argument := func(k hole, arg ir.Node) {
-		if topLevelDefer {
-			// Top level defers arguments don't escape to
-			// heap, but they do need to last until end of
-			// function.
-			k = e.later(k)
-		} else if where != nil {
-			k = e.heapHole()
+func (e *escape) callCommon(ks []hole, call ir.Node, where *ir.GoDeferStmt) {
+	argument := func(k hole, argp *ir.Node) {
+		if where != nil {
+			if where.Esc() == ir.EscNever {
+				// Top-level defers arguments don't escape to heap,
+				// but they do need to last until end of function.
+				k = e.later(k)
+			} else {
+				k = e.heapHole()
+			}
 		}
 
-		e.expr(k.note(call, "call parameter"), arg)
+		e.expr(k.note(call, "call parameter"), *argp)
 	}
 
 	switch call.Op() {
@@ -70,15 +68,15 @@ func (e *escape) call(ks []hole, call, where ir.Node) {
 		}
 
 		if r := fntype.Recv(); r != nil {
-			argument(e.tagHole(ks, fn, r), call.X.(*ir.SelectorExpr).X)
+			argument(e.tagHole(ks, fn, r), &call.X.(*ir.SelectorExpr).X)
 		} else {
 			// Evaluate callee function expression.
-			argument(e.discardHole(), call.X)
+			argument(e.discardHole(), &call.X)
 		}
 
 		args := call.Args
 		for i, param := range fntype.Params().FieldSlice() {
-			argument(e.tagHole(ks, fn, param), args[i])
+			argument(e.tagHole(ks, fn, param), &args[i])
 		}
 
 	case ir.OAPPEND:
@@ -93,54 +91,66 @@ func (e *escape) call(ks []hole, call, where ir.Node) {
 		if args[0].Type().Elem().HasPointers() {
 			appendeeK = e.teeHole(appendeeK, e.heapHole().deref(call, "appendee slice"))
 		}
-		argument(appendeeK, args[0])
+		argument(appendeeK, &args[0])
 
 		if call.IsDDD {
 			appendedK := e.discardHole()
 			if args[1].Type().IsSlice() && args[1].Type().Elem().HasPointers() {
 				appendedK = e.heapHole().deref(call, "appended slice...")
 			}
-			argument(appendedK, args[1])
+			argument(appendedK, &args[1])
 		} else {
-			for _, arg := range args[1:] {
-				argument(e.heapHole(), arg)
+			for i := 1; i < len(args); i++ {
+				argument(e.heapHole(), &args[i])
 			}
 		}
 
 	case ir.OCOPY:
 		call := call.(*ir.BinaryExpr)
-		argument(e.discardHole(), call.X)
+		argument(e.discardHole(), &call.X)
 
 		copiedK := e.discardHole()
 		if call.Y.Type().IsSlice() && call.Y.Type().Elem().HasPointers() {
 			copiedK = e.heapHole().deref(call, "copied slice")
 		}
-		argument(copiedK, call.Y)
+		argument(copiedK, &call.Y)
 
 	case ir.OPANIC:
 		call := call.(*ir.UnaryExpr)
-		argument(e.heapHole(), call.X)
+		argument(e.heapHole(), &call.X)
 
 	case ir.OCOMPLEX:
 		call := call.(*ir.BinaryExpr)
-		argument(e.discardHole(), call.X)
-		argument(e.discardHole(), call.Y)
+		argument(e.discardHole(), &call.X)
+		argument(e.discardHole(), &call.Y)
 	case ir.ODELETE, ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
 		call := call.(*ir.CallExpr)
-		for _, arg := range call.Args {
-			argument(e.discardHole(), arg)
+		for i := range call.Args {
+			argument(e.discardHole(), &call.Args[i])
 		}
 	case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE:
 		call := call.(*ir.UnaryExpr)
-		argument(e.discardHole(), call.X)
+		argument(e.discardHole(), &call.X)
 
 	case ir.OUNSAFEADD, ir.OUNSAFESLICE:
 		call := call.(*ir.BinaryExpr)
-		argument(ks[0], call.X)
-		argument(e.discardHole(), call.Y)
+		argument(ks[0], &call.X)
+		argument(e.discardHole(), &call.Y)
 	}
 }
 
+func (e *escape) goDeferStmt(n *ir.GoDeferStmt) {
+	topLevelDefer := n.Op() == ir.ODEFER && e.loopDepth == 1
+	if topLevelDefer {
+		// force stack allocation of defer record, unless
+		// open-coded defers are used (see ssa.go)
+		n.SetEsc(ir.EscNever)
+	}
+
+	e.stmts(n.Call.Init())
+	e.callCommon(nil, n.Call, n)
+}
+
 // tagHole returns a hole for evaluating an argument passed to param.
 // ks should contain the holes representing where the function
 // callee's results flows. fn is the statically-known callee function,
diff --git a/src/cmd/compile/internal/escape/expr.go b/src/cmd/compile/internal/escape/expr.go
index 5b280c76f1f..cb95221dd51 100644
--- a/src/cmd/compile/internal/escape/expr.go
+++ b/src/cmd/compile/internal/escape/expr.go
@@ -139,7 +139,7 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
 		e.discard(n.X)
 
 	case ir.OCALLMETH, ir.OCALLFUNC, ir.OCALLINTER, ir.OLEN, ir.OCAP, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCOPY, ir.OUNSAFEADD, ir.OUNSAFESLICE:
-		e.call([]hole{k}, n, nil)
+		e.call([]hole{k}, n)
 
 	case ir.ONEW:
 		n := n.(*ir.UnaryExpr)
diff --git a/src/cmd/compile/internal/escape/stmt.go b/src/cmd/compile/internal/escape/stmt.go
index d3e47290d37..0bdb07b2784 100644
--- a/src/cmd/compile/internal/escape/stmt.go
+++ b/src/cmd/compile/internal/escape/stmt.go
@@ -163,7 +163,7 @@ func (e *escape) stmt(n ir.Node) {
 		n := n.(*ir.AssignListStmt)
 		e.stmts(n.Rhs[0].Init())
 		ks := e.addrs(n.Lhs)
-		e.call(ks, n.Rhs[0], nil)
+		e.call(ks, n.Rhs[0])
 		e.reassigned(ks, n)
 	case ir.ORETURN:
 		n := n.(*ir.ReturnStmt)
@@ -174,11 +174,10 @@ func (e *escape) stmt(n ir.Node) {
 		}
 		e.assignList(dsts, n.Results, "return", n)
 	case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OCLOSE, ir.OCOPY, ir.ODELETE, ir.OPANIC, ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
-		e.call(nil, n, nil)
+		e.call(nil, n)
 	case ir.OGO, ir.ODEFER:
 		n := n.(*ir.GoDeferStmt)
-		e.stmts(n.Call.Init())
-		e.call(nil, n.Call, n)
+		e.goDeferStmt(n)
 
 	case ir.OTAILCALL:
 		// TODO(mdempsky): Treat like a normal call? esc.go used to just ignore it.

From 107b1fce6401b7f5fa12f6e51746a2d0c86b65ca Mon Sep 17 00:00:00 2001
From: Cuong Manh Le 
Date: Wed, 23 Jun 2021 14:39:44 +0700
Subject: [PATCH 515/940] [dev.typeparams] cmd/compile: explain why
 expandInline needed

Change-Id: Ica9817675b4eb929a000640f9ae873b75fc5a2e3
Reviewed-on: https://go-review.googlesource.com/c/go/+/330290
Trust: Cuong Manh Le 
Run-TryBot: Cuong Manh Le 
TryBot-Result: Go Bot 
Reviewed-by: Matthew Dempsky 
---
 src/cmd/compile/internal/noder/reader.go | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go
index b106e898927..df9dccc1569 100644
--- a/src/cmd/compile/internal/noder/reader.go
+++ b/src/cmd/compile/internal/noder/reader.go
@@ -1956,8 +1956,9 @@ func (r *reader) inlReturn(ret *ir.ReturnStmt) *ir.BlockStmt {
 // expandInline reads in an extra copy of IR to populate
 // fn.Inl.{Dcl,Body}.
 func expandInline(fn *ir.Func, pri pkgReaderIndex) {
-	// TODO(mdempsky): Remove this function. It's currently needed for
-	// dwarfgen for some reason, but we should be able to provide it
+	// TODO(mdempsky): Remove this function. It's currently needed by
+	// dwarfgen/dwarf.go:preInliningDcls, which requires fn.Inl.Dcl to
+	// create abstract function DIEs. But we should be able to provide it
 	// with the same information some other way.
 
 	fndcls := len(fn.Dcl)

From 70f4ab656575842b3a4ce54960f2c3eb7230e8a6 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Tue, 22 Jun 2021 22:21:09 -0700
Subject: [PATCH 516/940] [dev.typeparams] cmd/compile: remove
 SetClosureCalled(false) hacks

The current go/defer wrapping code goes to some length to clear
ClosureCalled when a function call will end up not being called
directly, and so it will need to use the context register.

But we already have a flag to indicate we need to use the context
register: Needctxt. The real issue here is just that buildssa was
using fn.ClosureCalled instead of fn.Needctxt.

Change-Id: Ic9f5f23b66eb467fc61fa84eacb45d46c54133d2
Reviewed-on: https://go-review.googlesource.com/c/go/+/330329
Trust: Matthew Dempsky 
Run-TryBot: Matthew Dempsky 
Reviewed-by: Cuong Manh Le 
---
 src/cmd/compile/internal/ssagen/ssa.go | 2 +-
 src/cmd/compile/internal/walk/order.go | 9 ---------
 2 files changed, 1 insertion(+), 10 deletions(-)

diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go
index 7a6bf878e1b..659ba02b5bd 100644
--- a/src/cmd/compile/internal/ssagen/ssa.go
+++ b/src/cmd/compile/internal/ssagen/ssa.go
@@ -535,7 +535,7 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func {
 	}
 
 	// Populate closure variables.
-	if !fn.ClosureCalled() {
+	if fn.Needctxt() {
 		clo := s.entryNewValue0(ssa.OpGetClosurePtr, s.f.Config.Types.BytePtr)
 		offset := int64(types.PtrSize) // PtrSize to skip past function entry PC field
 		for _, n := range fn.ClosureVars {
diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go
index c24f80508a0..75657cd3e49 100644
--- a/src/cmd/compile/internal/walk/order.go
+++ b/src/cmd/compile/internal/walk/order.go
@@ -1566,7 +1566,6 @@ func (o *orderState) wrapGoDefer(n *ir.GoDeferStmt) {
 	if len(callArgs) == 0 && call.Op() == ir.OCALLFUNC && callX.Type().NumResults() == 0 {
 		if callX.Op() == ir.OCLOSURE {
 			clo := callX.(*ir.ClosureExpr)
-			clo.Func.SetClosureCalled(false)
 			clo.IsGoWrap = true
 		}
 		return
@@ -1691,12 +1690,6 @@ func (o *orderState) wrapGoDefer(n *ir.GoDeferStmt) {
 			// Deal with "defer returnsafunc()(x, y)" (for
 			// example) by copying the callee expression.
 			fnExpr = mkArgCopy(callX)
-			if callX.Op() == ir.OCLOSURE {
-				// For "defer func(...)", in addition to copying the
-				// closure into a temp, mark it as no longer directly
-				// called.
-				callX.(*ir.ClosureExpr).Func.SetClosureCalled(false)
-			}
 		}
 	}
 
@@ -1770,8 +1763,6 @@ func (o *orderState) wrapGoDefer(n *ir.GoDeferStmt) {
 	topcall := ir.NewCallExpr(n.Pos(), ir.OCALL, clo, nil)
 	typecheck.Call(topcall)
 
-	fn.SetClosureCalled(false)
-
 	// Finally, point the defer statement at the newly generated call.
 	n.Call = topcall
 }

From 9be8303df9e3aa5f4ea1879e82a3edbf54b78dbf Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Tue, 22 Jun 2021 13:45:51 -0700
Subject: [PATCH 517/940] [dev.typeparams] cmd/compile: add ORECOVERFP,
 OGETCALLER{PC,SP} ops

This CLs adds new frontend ops that will be used in the next CL. Split
out separately so generated code is less distracting in the main CL.

Change-Id: I66125e0ec2217bfa05f7b0ea0bc99ada13f563f7
Reviewed-on: https://go-review.googlesource.com/c/go/+/330191
Trust: Matthew Dempsky 
Run-TryBot: Matthew Dempsky 
TryBot-Result: Go Bot 
Reviewed-by: Cherry Mui 
---
 src/cmd/compile/internal/ir/node.go      |   7 +-
 src/cmd/compile/internal/ir/op_string.go | 115 ++++++++++++-----------
 2 files changed, 64 insertions(+), 58 deletions(-)

diff --git a/src/cmd/compile/internal/ir/node.go b/src/cmd/compile/internal/ir/node.go
index 7c3dc10e46d..fa7c9cc2760 100644
--- a/src/cmd/compile/internal/ir/node.go
+++ b/src/cmd/compile/internal/ir/node.go
@@ -237,6 +237,7 @@ const (
 	OSLICE3ARR   // X[Low : High : Max] (X is pointer to array)
 	OSLICEHEADER // sliceheader{Ptr, Len, Cap} (Ptr is unsafe.Pointer, Len is length, Cap is capacity)
 	ORECOVER     // recover()
+	ORECOVERFP   // recover(Args) w/ explicit FP argument
 	ORECV        // <-X
 	ORUNESTR     // Type(X) (Type is string, X is rune)
 	OSELRECV2    // like OAS2: Lhs = Rhs where len(Lhs)=2, len(Rhs)=1, Rhs[0].Op = ORECV (appears as .Var of OCASE)
@@ -318,8 +319,10 @@ const (
 	OLINKSYMOFFSET // offset within a name
 
 	// arch-specific opcodes
-	OTAILCALL // tail call to another function
-	OGETG     // runtime.getg() (read g pointer)
+	OTAILCALL    // tail call to another function
+	OGETG        // runtime.getg() (read g pointer)
+	OGETCALLERPC // runtime.getcallerpc() (continuation PC in caller frame)
+	OGETCALLERSP // runtime.getcallersp() (stack pointer in caller frame)
 
 	OEND
 )
diff --git a/src/cmd/compile/internal/ir/op_string.go b/src/cmd/compile/internal/ir/op_string.go
index 405a0c6b3c9..80c8d09c1e4 100644
--- a/src/cmd/compile/internal/ir/op_string.go
+++ b/src/cmd/compile/internal/ir/op_string.go
@@ -109,65 +109,68 @@ func _() {
 	_ = x[OSLICE3ARR-98]
 	_ = x[OSLICEHEADER-99]
 	_ = x[ORECOVER-100]
-	_ = x[ORECV-101]
-	_ = x[ORUNESTR-102]
-	_ = x[OSELRECV2-103]
-	_ = x[OIOTA-104]
-	_ = x[OREAL-105]
-	_ = x[OIMAG-106]
-	_ = x[OCOMPLEX-107]
-	_ = x[OALIGNOF-108]
-	_ = x[OOFFSETOF-109]
-	_ = x[OSIZEOF-110]
-	_ = x[OUNSAFEADD-111]
-	_ = x[OUNSAFESLICE-112]
-	_ = x[OMETHEXPR-113]
-	_ = x[OBLOCK-114]
-	_ = x[OBREAK-115]
-	_ = x[OCASE-116]
-	_ = x[OCONTINUE-117]
-	_ = x[ODEFER-118]
-	_ = x[OFALL-119]
-	_ = x[OFOR-120]
-	_ = x[OFORUNTIL-121]
-	_ = x[OGOTO-122]
-	_ = x[OIF-123]
-	_ = x[OLABEL-124]
-	_ = x[OGO-125]
-	_ = x[ORANGE-126]
-	_ = x[ORETURN-127]
-	_ = x[OSELECT-128]
-	_ = x[OSWITCH-129]
-	_ = x[OTYPESW-130]
-	_ = x[OFUNCINST-131]
-	_ = x[OTCHAN-132]
-	_ = x[OTMAP-133]
-	_ = x[OTSTRUCT-134]
-	_ = x[OTINTER-135]
-	_ = x[OTFUNC-136]
-	_ = x[OTARRAY-137]
-	_ = x[OTSLICE-138]
-	_ = x[OINLCALL-139]
-	_ = x[OEFACE-140]
-	_ = x[OITAB-141]
-	_ = x[OIDATA-142]
-	_ = x[OSPTR-143]
-	_ = x[OCFUNC-144]
-	_ = x[OCHECKNIL-145]
-	_ = x[OVARDEF-146]
-	_ = x[OVARKILL-147]
-	_ = x[OVARLIVE-148]
-	_ = x[ORESULT-149]
-	_ = x[OINLMARK-150]
-	_ = x[OLINKSYMOFFSET-151]
-	_ = x[OTAILCALL-152]
-	_ = x[OGETG-153]
-	_ = x[OEND-154]
+	_ = x[ORECOVERFP-101]
+	_ = x[ORECV-102]
+	_ = x[ORUNESTR-103]
+	_ = x[OSELRECV2-104]
+	_ = x[OIOTA-105]
+	_ = x[OREAL-106]
+	_ = x[OIMAG-107]
+	_ = x[OCOMPLEX-108]
+	_ = x[OALIGNOF-109]
+	_ = x[OOFFSETOF-110]
+	_ = x[OSIZEOF-111]
+	_ = x[OUNSAFEADD-112]
+	_ = x[OUNSAFESLICE-113]
+	_ = x[OMETHEXPR-114]
+	_ = x[OBLOCK-115]
+	_ = x[OBREAK-116]
+	_ = x[OCASE-117]
+	_ = x[OCONTINUE-118]
+	_ = x[ODEFER-119]
+	_ = x[OFALL-120]
+	_ = x[OFOR-121]
+	_ = x[OFORUNTIL-122]
+	_ = x[OGOTO-123]
+	_ = x[OIF-124]
+	_ = x[OLABEL-125]
+	_ = x[OGO-126]
+	_ = x[ORANGE-127]
+	_ = x[ORETURN-128]
+	_ = x[OSELECT-129]
+	_ = x[OSWITCH-130]
+	_ = x[OTYPESW-131]
+	_ = x[OFUNCINST-132]
+	_ = x[OTCHAN-133]
+	_ = x[OTMAP-134]
+	_ = x[OTSTRUCT-135]
+	_ = x[OTINTER-136]
+	_ = x[OTFUNC-137]
+	_ = x[OTARRAY-138]
+	_ = x[OTSLICE-139]
+	_ = x[OINLCALL-140]
+	_ = x[OEFACE-141]
+	_ = x[OITAB-142]
+	_ = x[OIDATA-143]
+	_ = x[OSPTR-144]
+	_ = x[OCFUNC-145]
+	_ = x[OCHECKNIL-146]
+	_ = x[OVARDEF-147]
+	_ = x[OVARKILL-148]
+	_ = x[OVARLIVE-149]
+	_ = x[ORESULT-150]
+	_ = x[OINLMARK-151]
+	_ = x[OLINKSYMOFFSET-152]
+	_ = x[OTAILCALL-153]
+	_ = x[OGETG-154]
+	_ = x[OGETCALLERPC-155]
+	_ = x[OGETCALLERSP-156]
+	_ = x[OEND-157]
 }
 
-const _Op_name = "XXXNAMENONAMETYPEPACKLITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECVRUNESTRSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFUNSAFEADDUNSAFESLICEMETHEXPRBLOCKBREAKCASECONTINUEDEFERFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWFUNCINSTTCHANTMAPTSTRUCTTINTERTFUNCTARRAYTSLICEINLCALLEFACEITABIDATASPTRCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKLINKSYMOFFSETTAILCALLGETGEND"
+const _Op_name = "XXXNAMENONAMETYPEPACKLITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFUNSAFEADDUNSAFESLICEMETHEXPRBLOCKBREAKCASECONTINUEDEFERFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWFUNCINSTTCHANTMAPTSTRUCTTINTERTFUNCTARRAYTSLICEINLCALLEFACEITABIDATASPTRCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKLINKSYMOFFSETTAILCALLGETGGETCALLERPCGETCALLERSPEND"
 
-var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 37, 39, 42, 48, 52, 58, 64, 73, 85, 94, 103, 115, 124, 136, 138, 141, 151, 158, 165, 172, 176, 180, 188, 196, 205, 213, 216, 221, 228, 235, 241, 250, 258, 266, 272, 276, 285, 292, 296, 299, 306, 314, 321, 327, 330, 336, 343, 351, 355, 362, 370, 372, 374, 376, 378, 380, 382, 387, 392, 400, 403, 412, 415, 419, 427, 434, 443, 456, 459, 462, 465, 468, 471, 474, 480, 483, 486, 492, 496, 499, 503, 508, 513, 519, 524, 528, 533, 541, 549, 555, 564, 575, 582, 586, 593, 601, 605, 609, 613, 620, 627, 635, 641, 650, 661, 669, 674, 679, 683, 691, 696, 700, 703, 711, 715, 717, 722, 724, 729, 735, 741, 747, 753, 761, 766, 770, 777, 783, 788, 794, 800, 807, 812, 816, 821, 825, 830, 838, 844, 851, 858, 864, 871, 884, 892, 896, 899}
+var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 37, 39, 42, 48, 52, 58, 64, 73, 85, 94, 103, 115, 124, 136, 138, 141, 151, 158, 165, 172, 176, 180, 188, 196, 205, 213, 216, 221, 228, 235, 241, 250, 258, 266, 272, 276, 285, 292, 296, 299, 306, 314, 321, 327, 330, 336, 343, 351, 355, 362, 370, 372, 374, 376, 378, 380, 382, 387, 392, 400, 403, 412, 415, 419, 427, 434, 443, 456, 459, 462, 465, 468, 471, 474, 480, 483, 486, 492, 496, 499, 503, 508, 513, 519, 524, 528, 533, 541, 549, 555, 564, 575, 582, 591, 595, 602, 610, 614, 618, 622, 629, 636, 644, 650, 659, 670, 678, 683, 688, 692, 700, 705, 709, 712, 720, 724, 726, 731, 733, 738, 744, 750, 756, 762, 770, 775, 779, 786, 792, 797, 803, 809, 816, 821, 825, 830, 834, 839, 847, 853, 860, 867, 873, 880, 893, 901, 905, 916, 927, 930}
 
 func (i Op) String() string {
 	if i >= Op(len(_Op_index)-1) {

From 574ec1c6457c7779cd20db873fef2e2ed7e31ff1 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Tue, 22 Jun 2021 13:44:18 -0700
Subject: [PATCH 518/940] [dev.typeparams] cmd/compile: desugar ORECOVER into
 ORECOVERFP

Currently ORECOVER is a single operation that both (1) calculates
the (logical) caller frame pointer and (2) calls runtime.gorecover.
This is normally fine, but it's inconvenient for regabi, which wants
to wrap "defer recover()" into "defer func() { recover() }" and
needs (1) and (2) to happen at different times.

The current solution is to apply walkRecover early to split it into
the two steps, but calling it during order is a minor layering
violation. It works well today because the order and walk phases are
closely related anyway and walkRecover is relatively simple, but it
won't work for go/defer wrapping earlier into the frontend.

This CL adds a new, lower-level ORECOVERFP primitive, which represents
just part (2); and OGETCALLER{PC,SP} primitives, which provide a way
to compute (1) in the frontend too.

OGETCALLERPC isn't needed/used today, but it seems worth including for
completeness. Maybe it will be useful at some point for intrinsifying
runtime.getcaller{pc,sp}, like we already do for runtime.getg.

Change-Id: Iaa8ae51e09306c45c147b6759a5b7c24dcc317ca
Reviewed-on: https://go-review.googlesource.com/c/go/+/330192
Run-TryBot: Matthew Dempsky 
TryBot-Result: Go Bot 
Trust: Matthew Dempsky 
Reviewed-by: Cuong Manh Le 
---
 src/cmd/compile/internal/escape/call.go       |  3 ++
 src/cmd/compile/internal/escape/desugar.go    | 37 +++++++++++++++++++
 src/cmd/compile/internal/escape/expr.go       |  7 +---
 src/cmd/compile/internal/ir/expr.go           |  8 +++-
 src/cmd/compile/internal/ssagen/ssa.go        |  8 ++++
 src/cmd/compile/internal/typecheck/func.go    | 15 ++++++++
 .../compile/internal/typecheck/typecheck.go   | 12 ++++++
 src/cmd/compile/internal/walk/builtin.go      | 13 ++-----
 src/cmd/compile/internal/walk/expr.go         |  6 +--
 src/cmd/compile/internal/walk/order.go        | 13 ++-----
 src/cmd/compile/internal/walk/stmt.go         |  2 +-
 src/cmd/compile/internal/walk/walk.go         |  2 +-
 12 files changed, 94 insertions(+), 32 deletions(-)
 create mode 100644 src/cmd/compile/internal/escape/desugar.go

diff --git a/src/cmd/compile/internal/escape/call.go b/src/cmd/compile/internal/escape/call.go
index 8511259d47b..1f2d59af353 100644
--- a/src/cmd/compile/internal/escape/call.go
+++ b/src/cmd/compile/internal/escape/call.go
@@ -123,11 +123,14 @@ func (e *escape) callCommon(ks []hole, call ir.Node, where *ir.GoDeferStmt) {
 		call := call.(*ir.BinaryExpr)
 		argument(e.discardHole(), &call.X)
 		argument(e.discardHole(), &call.Y)
+
 	case ir.ODELETE, ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
 		call := call.(*ir.CallExpr)
+		fixRecoverCall(call)
 		for i := range call.Args {
 			argument(e.discardHole(), &call.Args[i])
 		}
+
 	case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE:
 		call := call.(*ir.UnaryExpr)
 		argument(e.discardHole(), &call.X)
diff --git a/src/cmd/compile/internal/escape/desugar.go b/src/cmd/compile/internal/escape/desugar.go
new file mode 100644
index 00000000000..8b3cc25cf9a
--- /dev/null
+++ b/src/cmd/compile/internal/escape/desugar.go
@@ -0,0 +1,37 @@
+// Copyright 2021 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 escape
+
+import (
+	"cmd/compile/internal/base"
+	"cmd/compile/internal/ir"
+	"cmd/compile/internal/typecheck"
+	"cmd/compile/internal/types"
+)
+
+// TODO(mdempsky): Desugaring doesn't belong during escape analysis,
+// but for now it's the most convenient place for some rewrites.
+
+// fixRecoverCall rewrites an ORECOVER call into ORECOVERFP,
+// adding an explicit frame pointer argument.
+// If call is not an ORECOVER call, it's left unmodified.
+func fixRecoverCall(call *ir.CallExpr) {
+	if call.Op() != ir.ORECOVER {
+		return
+	}
+
+	pos := call.Pos()
+
+	// FP is equal to caller's SP plus FixedFrameSize().
+	var fp ir.Node = ir.NewCallExpr(pos, ir.OGETCALLERSP, nil, nil)
+	if off := base.Ctxt.FixedFrameSize(); off != 0 {
+		fp = ir.NewBinaryExpr(fp.Pos(), ir.OADD, fp, ir.NewInt(off))
+	}
+	// TODO(mdempsky): Replace *int32 with unsafe.Pointer, without upsetting checkptr.
+	fp = ir.NewConvExpr(pos, ir.OCONVNOP, types.NewPtr(types.Types[types.TINT32]), fp)
+
+	call.SetOp(ir.ORECOVERFP)
+	call.Args = []ir.Node{typecheck.Expr(fp)}
+}
diff --git a/src/cmd/compile/internal/escape/expr.go b/src/cmd/compile/internal/escape/expr.go
index cb95221dd51..c10e866990d 100644
--- a/src/cmd/compile/internal/escape/expr.go
+++ b/src/cmd/compile/internal/escape/expr.go
@@ -43,7 +43,7 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
 	default:
 		base.Fatalf("unexpected expr: %s %v", n.Op().String(), n)
 
-	case ir.OLITERAL, ir.ONIL, ir.OGETG, ir.OTYPE, ir.OMETHEXPR, ir.OLINKSYMOFFSET:
+	case ir.OLITERAL, ir.ONIL, ir.OGETG, ir.OGETCALLERPC, ir.OGETCALLERSP, ir.OTYPE, ir.OMETHEXPR, ir.OLINKSYMOFFSET:
 		// nop
 
 	case ir.ONAME:
@@ -138,7 +138,7 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
 		n := n.(*ir.UnaryExpr)
 		e.discard(n.X)
 
-	case ir.OCALLMETH, ir.OCALLFUNC, ir.OCALLINTER, ir.OLEN, ir.OCAP, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCOPY, ir.OUNSAFEADD, ir.OUNSAFESLICE:
+	case ir.OCALLMETH, ir.OCALLFUNC, ir.OCALLINTER, ir.OLEN, ir.OCAP, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCOPY, ir.ORECOVER, ir.OUNSAFEADD, ir.OUNSAFESLICE:
 		e.call([]hole{k}, n)
 
 	case ir.ONEW:
@@ -158,9 +158,6 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
 		e.spill(k, n)
 		e.discard(n.Len)
 
-	case ir.ORECOVER:
-		// nop
-
 	case ir.OCALLPART:
 		// Flow the receiver argument to both the closure and
 		// to the receiver parameter.
diff --git a/src/cmd/compile/internal/ir/expr.go b/src/cmd/compile/internal/ir/expr.go
index b46fd905fe7..4659b99fbf7 100644
--- a/src/cmd/compile/internal/ir/expr.go
+++ b/src/cmd/compile/internal/ir/expr.go
@@ -180,8 +180,12 @@ func (n *CallExpr) SetOp(op Op) {
 	switch op {
 	default:
 		panic(n.no("SetOp " + op.String()))
-	case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH,
-		OAPPEND, ODELETE, OGETG, OMAKE, OPRINT, OPRINTN, ORECOVER:
+	case OAPPEND,
+		OCALL, OCALLFUNC, OCALLINTER, OCALLMETH,
+		ODELETE,
+		OGETG, OGETCALLERPC, OGETCALLERSP,
+		OMAKE, OPRINT, OPRINTN,
+		ORECOVER, ORECOVERFP:
 		n.op = op
 	}
 }
diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go
index 659ba02b5bd..93847a39a39 100644
--- a/src/cmd/compile/internal/ssagen/ssa.go
+++ b/src/cmd/compile/internal/ssagen/ssa.go
@@ -3135,6 +3135,14 @@ func (s *state) expr(n ir.Node) *ssa.Value {
 		n := n.(*ir.CallExpr)
 		return s.newValue1(ssa.OpGetG, n.Type(), s.mem())
 
+	case ir.OGETCALLERPC:
+		n := n.(*ir.CallExpr)
+		return s.newValue0(ssa.OpGetCallerPC, n.Type())
+
+	case ir.OGETCALLERSP:
+		n := n.(*ir.CallExpr)
+		return s.newValue0(ssa.OpGetCallerSP, n.Type())
+
 	case ir.OAPPEND:
 		return s.append(n.(*ir.CallExpr), false)
 
diff --git a/src/cmd/compile/internal/typecheck/func.go b/src/cmd/compile/internal/typecheck/func.go
index bd21977f26b..031279f42c1 100644
--- a/src/cmd/compile/internal/typecheck/func.go
+++ b/src/cmd/compile/internal/typecheck/func.go
@@ -967,6 +967,21 @@ func tcRecover(n *ir.CallExpr) ir.Node {
 	return n
 }
 
+// tcRecoverFP typechecks an ORECOVERFP node.
+func tcRecoverFP(n *ir.CallExpr) ir.Node {
+	if len(n.Args) != 1 {
+		base.FatalfAt(n.Pos(), "wrong number of arguments: %v", n)
+	}
+
+	n.Args[0] = Expr(n.Args[0])
+	if !n.Args[0].Type().IsPtrShaped() {
+		base.FatalfAt(n.Pos(), "%L is not pointer shaped", n.Args[0])
+	}
+
+	n.SetType(types.Types[types.TINTER])
+	return n
+}
+
 // tcUnsafeAdd typechecks an OUNSAFEADD node.
 func tcUnsafeAdd(n *ir.BinaryExpr) *ir.BinaryExpr {
 	if !types.AllowsGoVersion(curpkg(), 1, 17) {
diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go
index 0367f7b0341..f7de43c79f8 100644
--- a/src/cmd/compile/internal/typecheck/typecheck.go
+++ b/src/cmd/compile/internal/typecheck/typecheck.go
@@ -776,6 +776,10 @@ func typecheck1(n ir.Node, top int) ir.Node {
 		n := n.(*ir.CallExpr)
 		return tcRecover(n)
 
+	case ir.ORECOVERFP:
+		n := n.(*ir.CallExpr)
+		return tcRecoverFP(n)
+
 	case ir.OUNSAFEADD:
 		n := n.(*ir.BinaryExpr)
 		return tcUnsafeAdd(n)
@@ -809,6 +813,14 @@ func typecheck1(n ir.Node, top int) ir.Node {
 		n.SetType(types.Types[types.TUINTPTR])
 		return n
 
+	case ir.OGETCALLERPC, ir.OGETCALLERSP:
+		n := n.(*ir.CallExpr)
+		if len(n.Args) != 0 {
+			base.FatalfAt(n.Pos(), "unexpected arguments: %v", n)
+		}
+		n.SetType(types.Types[types.TUINTPTR])
+		return n
+
 	case ir.OCONVNOP:
 		n := n.(*ir.ConvExpr)
 		n.X = Expr(n.X)
diff --git a/src/cmd/compile/internal/walk/builtin.go b/src/cmd/compile/internal/walk/builtin.go
index be0f4c5208c..135eaee6bc6 100644
--- a/src/cmd/compile/internal/walk/builtin.go
+++ b/src/cmd/compile/internal/walk/builtin.go
@@ -641,16 +641,9 @@ func walkPrint(nn *ir.CallExpr, init *ir.Nodes) ir.Node {
 	return walkStmt(typecheck.Stmt(r))
 }
 
-// walkRecover walks an ORECOVER node.
-func walkRecover(nn *ir.CallExpr, init *ir.Nodes) ir.Node {
-	// Call gorecover with the FP of this frame.
-	// FP is equal to caller's SP plus FixedFrameSize().
-	var fp ir.Node = mkcall("getcallersp", types.Types[types.TUINTPTR], init)
-	if off := base.Ctxt.FixedFrameSize(); off != 0 {
-		fp = ir.NewBinaryExpr(fp.Pos(), ir.OADD, fp, ir.NewInt(off))
-	}
-	fp = ir.NewConvExpr(fp.Pos(), ir.OCONVNOP, types.NewPtr(types.Types[types.TINT32]), fp)
-	return mkcall("gorecover", nn.Type(), init, fp)
+// walkRecover walks an ORECOVERFP node.
+func walkRecoverFP(nn *ir.CallExpr, init *ir.Nodes) ir.Node {
+	return mkcall("gorecover", nn.Type(), init, walkExpr(nn.Args[0], init))
 }
 
 func walkUnsafeSlice(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
diff --git a/src/cmd/compile/internal/walk/expr.go b/src/cmd/compile/internal/walk/expr.go
index 2fb907710bb..070954be272 100644
--- a/src/cmd/compile/internal/walk/expr.go
+++ b/src/cmd/compile/internal/walk/expr.go
@@ -82,7 +82,7 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
 		base.Fatalf("walkExpr: switch 1 unknown op %+v", n.Op())
 		panic("unreachable")
 
-	case ir.ONONAME, ir.OGETG:
+	case ir.OGETG, ir.OGETCALLERPC, ir.OGETCALLERSP:
 		return n
 
 	case ir.OTYPE, ir.ONAME, ir.OLITERAL, ir.ONIL, ir.OLINKSYMOFFSET:
@@ -161,8 +161,8 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
 		n := n.(*ir.UnaryExpr)
 		return mkcall("gopanic", nil, init, n.X)
 
-	case ir.ORECOVER:
-		return walkRecover(n.(*ir.CallExpr), init)
+	case ir.ORECOVERFP:
+		return walkRecoverFP(n.(*ir.CallExpr), init)
 
 	case ir.OCFUNC:
 		return n
diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go
index 75657cd3e49..ff8e95b330a 100644
--- a/src/cmd/compile/internal/walk/order.go
+++ b/src/cmd/compile/internal/walk/order.go
@@ -777,10 +777,10 @@ func (o *orderState) stmt(n ir.Node) {
 		o.out = append(o.out, n)
 		o.cleanTemp(t)
 
-	case ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
+	case ir.OPRINT, ir.OPRINTN, ir.ORECOVERFP:
 		n := n.(*ir.CallExpr)
 		t := o.markTemp()
-		o.exprList(n.Args)
+		o.call(n)
 		o.out = append(o.out, n)
 		o.cleanTemp(t)
 
@@ -790,13 +790,6 @@ func (o *orderState) stmt(n ir.Node) {
 		t := o.markTemp()
 		o.init(n.Call)
 		o.call(n.Call)
-		if n.Call.Op() == ir.ORECOVER {
-			// Special handling of "defer recover()". We need to evaluate the FP
-			// argument before wrapping.
-			var init ir.Nodes
-			n.Call = walkRecover(n.Call.(*ir.CallExpr), &init)
-			o.stmtList(init)
-		}
 		o.wrapGoDefer(n)
 		o.out = append(o.out, n)
 		o.cleanTemp(t)
@@ -1270,7 +1263,7 @@ func (o *orderState) expr1(n, lhs ir.Node) ir.Node {
 		ir.OMAKESLICECOPY,
 		ir.ONEW,
 		ir.OREAL,
-		ir.ORECOVER,
+		ir.ORECOVERFP,
 		ir.OSTR2BYTES,
 		ir.OSTR2BYTESTMP,
 		ir.OSTR2RUNES:
diff --git a/src/cmd/compile/internal/walk/stmt.go b/src/cmd/compile/internal/walk/stmt.go
index 2352719da3f..bcc0a3e5173 100644
--- a/src/cmd/compile/internal/walk/stmt.go
+++ b/src/cmd/compile/internal/walk/stmt.go
@@ -49,7 +49,7 @@ func walkStmt(n ir.Node) ir.Node {
 		ir.OPRINT,
 		ir.OPRINTN,
 		ir.OPANIC,
-		ir.ORECOVER,
+		ir.ORECOVERFP,
 		ir.OGETG:
 		if n.Typecheck() == 0 {
 			base.Fatalf("missing typecheck: %+v", n)
diff --git a/src/cmd/compile/internal/walk/walk.go b/src/cmd/compile/internal/walk/walk.go
index 26da6e31457..6e992a91b81 100644
--- a/src/cmd/compile/internal/walk/walk.go
+++ b/src/cmd/compile/internal/walk/walk.go
@@ -343,7 +343,7 @@ func mayCall(n ir.Node) bool {
 			ir.OCAP, ir.OIMAG, ir.OLEN, ir.OREAL,
 			ir.OCONVNOP, ir.ODOT,
 			ir.OCFUNC, ir.OIDATA, ir.OITAB, ir.OSPTR,
-			ir.OBYTES2STRTMP, ir.OGETG, ir.OSLICEHEADER:
+			ir.OBYTES2STRTMP, ir.OGETG, ir.OGETCALLERPC, ir.OGETCALLERSP, ir.OSLICEHEADER:
 			// ok: operations that don't require function calls.
 			// Expand as needed.
 		}

From 0a0e3a3dea72d8d64d4250c9f7649da3b942eae5 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Mon, 21 Jun 2021 22:35:01 -0700
Subject: [PATCH 519/940] [dev.typeparams] cmd/compile: move call logic from
 order.go to escape

This CL moves two bits of related code from order.go to escape
analysis:

1. The recognition of "unsafe uintptr" arguments passed to
syscall-like functions.

2. The wrapping of go/defer function calls in parameter-free function
literals.

As with previous CLs, it would be nice to push this logic even further
forward, but for now escape analysis seems most pragmatic.

A couple side benefits:

1. It allows getting rid of the uintptrEscapesHack kludge.

2. When inserting wrappers, we can move some expressions into the
wrapper and escape analyze them better. For example, the test
expectation changes are all due to slice literals in go/defer calls
where the slice is now constructed at the call site, and can now be
stack allocated.

Change-Id: I73679bcad7fa8d61d2fc52d4cea0dc5ff0de8c0c
Reviewed-on: https://go-review.googlesource.com/c/go/+/330330
Run-TryBot: Matthew Dempsky 
TryBot-Result: Go Bot 
Trust: Matthew Dempsky 
Reviewed-by: Cuong Manh Le 
---
 src/cmd/compile/internal/escape/call.go   | 237 ++++++++++++++--
 src/cmd/compile/internal/escape/escape.go |   9 +-
 src/cmd/compile/internal/escape/expr.go   |   8 +-
 src/cmd/compile/internal/escape/graph.go  |   4 -
 src/cmd/compile/internal/ir/func.go       |  11 +
 src/cmd/compile/internal/walk/order.go    | 317 ----------------------
 src/cmd/compile/internal/walk/stmt.go     |  19 --
 test/escape2.go                           |  12 +-
 test/escape2n.go                          |  12 +-
 test/fixedbugs/issue31573.go              |  30 +-
 10 files changed, 259 insertions(+), 400 deletions(-)

diff --git a/src/cmd/compile/internal/escape/call.go b/src/cmd/compile/internal/escape/call.go
index 1f2d59af353..7b9dbe0dbc6 100644
--- a/src/cmd/compile/internal/escape/call.go
+++ b/src/cmd/compile/internal/escape/call.go
@@ -9,30 +9,35 @@ import (
 	"cmd/compile/internal/ir"
 	"cmd/compile/internal/typecheck"
 	"cmd/compile/internal/types"
+	"cmd/internal/src"
 )
 
 // call evaluates a call expressions, including builtin calls. ks
 // should contain the holes representing where the function callee's
 // results flows.
 func (e *escape) call(ks []hole, call ir.Node) {
-	e.callCommon(ks, call, nil)
+	var init ir.Nodes
+	e.callCommon(ks, call, &init, nil)
+	if len(init) != 0 {
+		call.(*ir.CallExpr).PtrInit().Append(init...)
+	}
 }
 
-func (e *escape) callCommon(ks []hole, call ir.Node, where *ir.GoDeferStmt) {
-	argument := func(k hole, argp *ir.Node) {
-		if where != nil {
-			if where.Esc() == ir.EscNever {
-				// Top-level defers arguments don't escape to heap,
-				// but they do need to last until end of function.
-				k = e.later(k)
-			} else {
-				k = e.heapHole()
-			}
-		}
+func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir.Func) {
+
+	// argumentPragma handles escape analysis of argument *argp to the
+	// given hole. If the function callee is known, pragma is the
+	// function's pragma flags; otherwise 0.
+	argumentFunc := func(fn *ir.Name, k hole, argp *ir.Node) {
+		e.rewriteArgument(argp, init, call, fn, wrapper)
 
 		e.expr(k.note(call, "call parameter"), *argp)
 	}
 
+	argument := func(k hole, argp *ir.Node) {
+		argumentFunc(nil, k, argp)
+	}
+
 	switch call.Op() {
 	default:
 		ir.Dump("esc", call)
@@ -43,6 +48,11 @@ func (e *escape) callCommon(ks []hole, call ir.Node, where *ir.GoDeferStmt) {
 		typecheck.FixVariadicCall(call)
 
 		// Pick out the function callee, if statically known.
+		//
+		// TODO(mdempsky): Change fn from *ir.Name to *ir.Func, but some
+		// functions (e.g., runtime builtins, method wrappers, generated
+		// eq/hash functions) don't have it set. Investigate whether
+		// that's a concern.
 		var fn *ir.Name
 		switch call.Op() {
 		case ir.OCALLFUNC:
@@ -68,15 +78,20 @@ func (e *escape) callCommon(ks []hole, call ir.Node, where *ir.GoDeferStmt) {
 		}
 
 		if r := fntype.Recv(); r != nil {
-			argument(e.tagHole(ks, fn, r), &call.X.(*ir.SelectorExpr).X)
+			dot := call.X.(*ir.SelectorExpr)
+			argumentFunc(fn, e.tagHole(ks, fn, r), &dot.X)
 		} else {
 			// Evaluate callee function expression.
+			//
+			// Note: We use argument and not argumentFunc, because call.X
+			// here may be an argument to runtime.{new,defer}proc, but it's
+			// not an argument to fn itself.
 			argument(e.discardHole(), &call.X)
 		}
 
 		args := call.Args
 		for i, param := range fntype.Params().FieldSlice() {
-			argument(e.tagHole(ks, fn, param), &args[i])
+			argumentFunc(fn, e.tagHole(ks, fn, param), &args[i])
 		}
 
 	case ir.OAPPEND:
@@ -142,16 +157,196 @@ func (e *escape) callCommon(ks []hole, call ir.Node, where *ir.GoDeferStmt) {
 	}
 }
 
+// goDeferStmt analyzes a "go" or "defer" statement.
+//
+// In the process, it also normalizes the statement to always use a
+// simple function call with no arguments and no results. For example,
+// it rewrites:
+//
+//	defer f(x, y)
+//
+// into:
+//
+//	x1, y1 := x, y
+//	defer func() { f(x1, y1) }()
 func (e *escape) goDeferStmt(n *ir.GoDeferStmt) {
-	topLevelDefer := n.Op() == ir.ODEFER && e.loopDepth == 1
-	if topLevelDefer {
+	k := e.heapHole()
+	if n.Op() == ir.ODEFER && e.loopDepth == 1 {
+		// Top-level defer arguments don't escape to the heap,
+		// but they do need to last until they're invoked.
+		k = e.later(e.discardHole())
+
 		// force stack allocation of defer record, unless
 		// open-coded defers are used (see ssa.go)
 		n.SetEsc(ir.EscNever)
 	}
 
-	e.stmts(n.Call.Init())
-	e.callCommon(nil, n.Call, n)
+	call := n.Call
+
+	init := n.PtrInit()
+	init.Append(ir.TakeInit(call)...)
+	e.stmts(*init)
+
+	// If the function is already a zero argument/result function call,
+	// just escape analyze it normally.
+	if call, ok := call.(*ir.CallExpr); ok && call.Op() == ir.OCALLFUNC {
+		if sig := call.X.Type(); sig.NumParams()+sig.NumResults() == 0 {
+			if clo, ok := call.X.(*ir.ClosureExpr); ok && n.Op() == ir.OGO {
+				clo.IsGoWrap = true
+			}
+			e.expr(k, call.X)
+			return
+		}
+	}
+
+	// Create a new no-argument function that we'll hand off to defer.
+	fn := ir.NewClosureFunc(n.Pos(), true)
+	fn.SetWrapper(true)
+	fn.Nname.SetType(types.NewSignature(types.LocalPkg, nil, nil, nil, nil))
+	fn.Body = []ir.Node{call}
+
+	clo := fn.OClosure
+	if n.Op() == ir.OGO {
+		clo.IsGoWrap = true
+	}
+
+	e.callCommon(nil, call, init, fn)
+	e.closures = append(e.closures, closure{e.spill(k, clo), clo})
+
+	// Create new top level call to closure.
+	n.Call = ir.NewCallExpr(call.Pos(), ir.OCALL, clo, nil)
+	ir.WithFunc(e.curfn, func() {
+		typecheck.Stmt(n.Call)
+	})
+}
+
+// rewriteArgument rewrites the argument *argp of the given call expression.
+// fn is the static callee function, if known.
+// wrapper is the go/defer wrapper function for call, if any.
+func (e *escape) rewriteArgument(argp *ir.Node, init *ir.Nodes, call ir.Node, fn *ir.Name, wrapper *ir.Func) {
+	var pragma ir.PragmaFlag
+	if fn != nil && fn.Func != nil {
+		pragma = fn.Func.Pragma
+	}
+
+	// unsafeUintptr rewrites "uintptr(ptr)" arguments to syscall-like
+	// functions, so that ptr is kept alive and/or escaped as
+	// appropriate. unsafeUintptr also reports whether it modified arg0.
+	unsafeUintptr := func(arg0 ir.Node) bool {
+		if pragma&(ir.UintptrKeepAlive|ir.UintptrEscapes) == 0 {
+			return false
+		}
+
+		// If the argument is really a pointer being converted to uintptr,
+		// arrange for the pointer to be kept alive until the call returns,
+		// by copying it into a temp and marking that temp
+		// still alive when we pop the temp stack.
+		if arg0.Op() != ir.OCONVNOP || !arg0.Type().IsUintptr() {
+			return false
+		}
+		arg := arg0.(*ir.ConvExpr)
+
+		if !arg.X.Type().IsUnsafePtr() {
+			return false
+		}
+
+		// Create and declare a new pointer-typed temp variable.
+		tmp := e.wrapExpr(arg.Pos(), &arg.X, init, call, wrapper)
+
+		if pragma&ir.UintptrEscapes != 0 {
+			e.flow(e.heapHole().note(arg, "//go:uintptrescapes"), e.oldLoc(tmp))
+		}
+
+		if pragma&ir.UintptrKeepAlive != 0 {
+			call := call.(*ir.CallExpr)
+
+			// SSA implements CallExpr.KeepAlive using OpVarLive, which
+			// doesn't support PAUTOHEAP variables. I tried changing it to
+			// use OpKeepAlive, but that ran into issues of its own.
+			// For now, the easy solution is to explicitly copy to (yet
+			// another) new temporary variable.
+			keep := tmp
+			if keep.Class == ir.PAUTOHEAP {
+				keep = e.copyExpr(arg.Pos(), tmp, call.PtrInit(), wrapper, false)
+			}
+
+			keep.SetAddrtaken(true) // ensure SSA keeps the tmp variable
+			call.KeepAlive = append(call.KeepAlive, keep)
+		}
+
+		return true
+	}
+
+	visit := func(pos src.XPos, argp *ir.Node) {
+		if unsafeUintptr(*argp) {
+			return
+		}
+
+		if wrapper != nil {
+			e.wrapExpr(pos, argp, init, call, wrapper)
+		}
+	}
+
+	// Peel away any slice lits.
+	if arg := *argp; arg.Op() == ir.OSLICELIT {
+		list := arg.(*ir.CompLitExpr).List
+		for i := range list {
+			visit(arg.Pos(), &list[i])
+		}
+	} else {
+		visit(call.Pos(), argp)
+	}
+}
+
+// wrapExpr replaces *exprp with a temporary variable copy. If wrapper
+// is non-nil, the variable will be captured for use within that
+// function.
+func (e *escape) wrapExpr(pos src.XPos, exprp *ir.Node, init *ir.Nodes, call ir.Node, wrapper *ir.Func) *ir.Name {
+	tmp := e.copyExpr(pos, *exprp, init, e.curfn, true)
+
+	if wrapper != nil {
+		// Currently for "defer i.M()" if i is nil it panics at the point
+		// of defer statement, not when deferred function is called.  We
+		// need to do the nil check outside of the wrapper.
+		if call.Op() == ir.OCALLINTER && exprp == &call.(*ir.CallExpr).X.(*ir.SelectorExpr).X {
+			check := ir.NewUnaryExpr(pos, ir.OCHECKNIL, ir.NewUnaryExpr(pos, ir.OITAB, tmp))
+			init.Append(typecheck.Stmt(check))
+		}
+
+		e.oldLoc(tmp).captured = true
+
+		cv := ir.NewClosureVar(pos, wrapper, tmp)
+		cv.SetType(tmp.Type())
+		tmp = typecheck.Expr(cv).(*ir.Name)
+	}
+
+	*exprp = tmp
+	return tmp
+}
+
+// copyExpr creates and returns a new temporary variable within fn;
+// appends statements to init to declare and initialize it to expr;
+// and escape analyzes the data flow if analyze is true.
+func (e *escape) copyExpr(pos src.XPos, expr ir.Node, init *ir.Nodes, fn *ir.Func, analyze bool) *ir.Name {
+	if ir.HasUniquePos(expr) {
+		pos = expr.Pos()
+	}
+
+	tmp := typecheck.TempAt(pos, fn, expr.Type())
+
+	stmts := []ir.Node{
+		ir.NewDecl(pos, ir.ODCL, tmp),
+		ir.NewAssignStmt(pos, tmp, expr),
+	}
+	typecheck.Stmts(stmts)
+	init.Append(stmts...)
+
+	if analyze {
+		e.newLoc(tmp, false)
+		e.stmts(stmts)
+	}
+
+	return tmp
 }
 
 // tagHole returns a hole for evaluating an argument passed to param.
@@ -170,12 +365,6 @@ func (e *escape) tagHole(ks []hole, fn *ir.Name, param *types.Field) hole {
 
 	// Call to previously tagged function.
 
-	if fn.Func != nil && fn.Func.Pragma&ir.UintptrEscapes != 0 && (param.Type.IsUintptr() || param.IsDDD() && param.Type.Elem().IsUintptr()) {
-		k := e.heapHole()
-		k.uintptrEscapesHack = true
-		return k
-	}
-
 	var tagKs []hole
 
 	esc := parseLeaks(param.Note)
diff --git a/src/cmd/compile/internal/escape/escape.go b/src/cmd/compile/internal/escape/escape.go
index 8f75ae8b426..324d0da3fe5 100644
--- a/src/cmd/compile/internal/escape/escape.go
+++ b/src/cmd/compile/internal/escape/escape.go
@@ -282,6 +282,11 @@ func (b *batch) finish(fns []*ir.Func) {
 
 		// Update n.Esc based on escape analysis results.
 
+		// Omit escape diagnostics for go/defer wrappers, at least for now.
+		// Historically, we haven't printed them, and test cases don't expect them.
+		// TODO(mdempsky): Update tests to expect this.
+		goDeferWrapper := n.Op() == ir.OCLOSURE && n.(*ir.ClosureExpr).Func.Wrapper()
+
 		if loc.escapes {
 			if n.Op() == ir.ONAME {
 				if base.Flag.CompilingRuntime {
@@ -291,7 +296,7 @@ func (b *batch) finish(fns []*ir.Func) {
 					base.WarnfAt(n.Pos(), "moved to heap: %v", n)
 				}
 			} else {
-				if base.Flag.LowerM != 0 {
+				if base.Flag.LowerM != 0 && !goDeferWrapper {
 					base.WarnfAt(n.Pos(), "%v escapes to heap", n)
 				}
 				if logopt.Enabled() {
@@ -301,7 +306,7 @@ func (b *batch) finish(fns []*ir.Func) {
 			}
 			n.SetEsc(ir.EscHeap)
 		} else {
-			if base.Flag.LowerM != 0 && n.Op() != ir.ONAME {
+			if base.Flag.LowerM != 0 && n.Op() != ir.ONAME && !goDeferWrapper {
 				base.WarnfAt(n.Pos(), "%v does not escape", n)
 			}
 			n.SetEsc(ir.EscNone)
diff --git a/src/cmd/compile/internal/escape/expr.go b/src/cmd/compile/internal/escape/expr.go
index c10e866990d..71c8eec6efc 100644
--- a/src/cmd/compile/internal/escape/expr.go
+++ b/src/cmd/compile/internal/escape/expr.go
@@ -30,12 +30,7 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
 		base.Pos = lno
 	}()
 
-	uintptrEscapesHack := k.uintptrEscapesHack
-	k.uintptrEscapesHack = false
-
-	if uintptrEscapesHack && n.Op() == ir.OCONVNOP && n.(*ir.ConvExpr).X.Type().IsUnsafePtr() {
-		// nop
-	} else if k.derefs >= 0 && !n.Type().HasPointers() {
+	if k.derefs >= 0 && !n.Type().HasPointers() {
 		k.dst = &e.blankLoc
 	}
 
@@ -198,7 +193,6 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
 	case ir.OSLICELIT:
 		n := n.(*ir.CompLitExpr)
 		k = e.spill(k, n)
-		k.uintptrEscapesHack = uintptrEscapesHack // for ...uintptr parameters
 
 		for _, elt := range n.List {
 			if elt.Op() == ir.OKEY {
diff --git a/src/cmd/compile/internal/escape/graph.go b/src/cmd/compile/internal/escape/graph.go
index 3581fce30de..6316435dfe4 100644
--- a/src/cmd/compile/internal/escape/graph.go
+++ b/src/cmd/compile/internal/escape/graph.go
@@ -129,10 +129,6 @@ type hole struct {
 	// the expression, independent of whether the address will actually
 	// be stored into a variable.
 	addrtaken bool
-
-	// uintptrEscapesHack indicates this context is evaluating an
-	// argument for a //go:uintptrescapes function.
-	uintptrEscapesHack bool
 }
 
 type note struct {
diff --git a/src/cmd/compile/internal/ir/func.go b/src/cmd/compile/internal/ir/func.go
index 6480becc931..3501f83ab1d 100644
--- a/src/cmd/compile/internal/ir/func.go
+++ b/src/cmd/compile/internal/ir/func.go
@@ -278,6 +278,17 @@ func PkgFuncName(f *Func) string {
 
 var CurFunc *Func
 
+// WithFunc invokes do with CurFunc and base.Pos set to curfn and
+// curfn.Pos(), respectively, and then restores their previous values
+// before returning.
+func WithFunc(curfn *Func, do func()) {
+	oldfn, oldpos := CurFunc, base.Pos
+	defer func() { CurFunc, base.Pos = oldfn, oldpos }()
+
+	CurFunc, base.Pos = curfn, curfn.Pos()
+	do()
+}
+
 func FuncSymName(s *types.Sym) string {
 	return s.Name + "·f"
 }
diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go
index ff8e95b330a..62d9b95be90 100644
--- a/src/cmd/compile/internal/walk/order.go
+++ b/src/cmd/compile/internal/walk/order.go
@@ -552,48 +552,6 @@ func (o *orderState) call(nn ir.Node) {
 
 	n.X = o.expr(n.X, nil)
 	o.exprList(n.Args)
-
-	// Pick out the function callee, if statically known.
-	// TODO(mdempsky): De-duplicate with similar code in escape analysis.
-	var callee *ir.Func
-	switch n.Op() {
-	case ir.OCALLFUNC:
-		if fn, ok := n.X.(*ir.Name); ok && fn.Op() == ir.ONAME && fn.Class == ir.PFUNC {
-			callee = fn.Func
-		}
-	case ir.OCALLMETH:
-		callee = ir.MethodExprName(n.X).Func
-	}
-
-	if callee == nil || callee.Pragma&ir.UintptrKeepAlive == 0 {
-		return
-	}
-
-	keepAlive := func(args []ir.Node) {
-		// If the argument is really a pointer being converted to uintptr,
-		// arrange for the pointer to be kept alive until the call returns,
-		// by copying it into a temp and marking that temp
-		// still alive when we pop the temp stack.
-		for _, arg := range args {
-			if arg.Op() == ir.OCONVNOP && arg.Type().IsUintptr() {
-				arg := arg.(*ir.ConvExpr)
-				if arg.X.Type().IsUnsafePtr() {
-					x := o.copyExpr(arg.X)
-					arg.X = x
-					x.SetAddrtaken(true) // ensure SSA keeps the x variable
-					n.KeepAlive = append(n.KeepAlive, x)
-				}
-			}
-		}
-	}
-
-	last := len(n.Args) - 1
-	if n.IsDDD && n.Args[last].Op() == ir.OSLICELIT {
-		keepAlive(n.Args[:last])
-		keepAlive(n.Args[last].(*ir.CompLitExpr).List)
-	} else {
-		keepAlive(n.Args)
-	}
 }
 
 // mapAssign appends n to o.out.
@@ -790,7 +748,6 @@ func (o *orderState) stmt(n ir.Node) {
 		t := o.markTemp()
 		o.init(n.Call)
 		o.call(n.Call)
-		o.wrapGoDefer(n)
 		o.out = append(o.out, n)
 		o.cleanTemp(t)
 
@@ -1486,280 +1443,6 @@ func (o *orderState) as2ok(n *ir.AssignListStmt) {
 	o.stmt(typecheck.Stmt(as))
 }
 
-var wrapGoDefer_prgen int
-
-// wrapGoDefer wraps the target of a "go" or "defer" statement with a
-// new "function with no arguments" closure. Specifically, it converts
-//
-//   defer f(x, y)
-//
-// to
-//
-//   x1, y1 := x, y
-//   defer func() { f(x1, y1) }()
-//
-// This is primarily to enable a quicker bringup of defers under the
-// new register ABI; by doing this conversion, we can simplify the
-// code in the runtime that invokes defers on the panic path.
-func (o *orderState) wrapGoDefer(n *ir.GoDeferStmt) {
-	call := n.Call
-
-	var callX ir.Node        // thing being called
-	var callArgs []ir.Node   // call arguments
-	var keepAlive []*ir.Name // KeepAlive list from call, if present
-
-	// A helper to recreate the call within the closure.
-	var mkNewCall func(pos src.XPos, op ir.Op, fun ir.Node, args []ir.Node) ir.Node
-
-	// Defer calls come in many shapes and sizes; not all of them
-	// are ir.CallExpr's. Examine the type to see what we're dealing with.
-	switch x := call.(type) {
-	case *ir.CallExpr:
-		callX = x.X
-		callArgs = x.Args
-		keepAlive = x.KeepAlive
-		mkNewCall = func(pos src.XPos, op ir.Op, fun ir.Node, args []ir.Node) ir.Node {
-			newcall := ir.NewCallExpr(pos, op, fun, args)
-			newcall.IsDDD = x.IsDDD
-			return ir.Node(newcall)
-		}
-	case *ir.UnaryExpr: // ex: OCLOSE
-		callArgs = []ir.Node{x.X}
-		mkNewCall = func(pos src.XPos, op ir.Op, fun ir.Node, args []ir.Node) ir.Node {
-			if len(args) != 1 {
-				panic("internal error, expecting single arg")
-			}
-			return ir.Node(ir.NewUnaryExpr(pos, op, args[0]))
-		}
-	case *ir.BinaryExpr: // ex: OCOPY
-		callArgs = []ir.Node{x.X, x.Y}
-		mkNewCall = func(pos src.XPos, op ir.Op, fun ir.Node, args []ir.Node) ir.Node {
-			if len(args) != 2 {
-				panic("internal error, expecting two args")
-			}
-			return ir.Node(ir.NewBinaryExpr(pos, op, args[0], args[1]))
-		}
-	default:
-		panic("unhandled op")
-	}
-
-	// No need to wrap if called func has no args, no receiver, and no results.
-	// However in the case of "defer func() { ... }()" we need to
-	// protect against the possibility of directClosureCall rewriting
-	// things so that the call does have arguments.
-	//
-	// Do wrap method calls (OCALLMETH, OCALLINTER), because it has
-	// a receiver.
-	//
-	// Also do wrap builtin functions, because they may be expanded to
-	// calls with arguments (e.g. ORECOVER).
-	//
-	// TODO: maybe not wrap if the called function has no arguments and
-	// only in-register results?
-	if len(callArgs) == 0 && call.Op() == ir.OCALLFUNC && callX.Type().NumResults() == 0 {
-		if callX.Op() == ir.OCLOSURE {
-			clo := callX.(*ir.ClosureExpr)
-			clo.IsGoWrap = true
-		}
-		return
-	}
-
-	if c, ok := call.(*ir.CallExpr); ok {
-		// To simplify things, turn f(a, b, []T{c, d, e}...) back
-		// into f(a, b, c, d, e) -- when the final call is run through the
-		// type checker below, it will rebuild the proper slice literal.
-		undoVariadic(c)
-		callX = c.X
-		callArgs = c.Args
-	}
-
-	// This is set to true if the closure we're generating escapes
-	// (needs heap allocation).
-	cloEscapes := func() bool {
-		if n.Op() == ir.OGO {
-			// For "go", assume that all closures escape.
-			return true
-		}
-		// For defer, just use whatever result escape analysis
-		// has determined for the defer.
-		return n.Esc() != ir.EscNever
-	}()
-
-	// A helper for making a copy of an argument. Note that it is
-	// not safe to use o.copyExpr(arg) if we're putting a
-	// reference to the temp into the closure (as opposed to
-	// copying it in by value), since in the by-reference case we
-	// need a temporary whose lifetime extends to the end of the
-	// function (as opposed to being local to the current block or
-	// statement being ordered).
-	mkArgCopy := func(arg ir.Node) *ir.Name {
-		t := arg.Type()
-		byval := t.Size() <= 128 || cloEscapes
-		var argCopy *ir.Name
-		if byval {
-			argCopy = o.copyExpr(arg)
-		} else {
-			argCopy = typecheck.Temp(t)
-			o.append(ir.NewAssignStmt(base.Pos, argCopy, arg))
-		}
-		// The value of 128 below is meant to be consistent with code
-		// in escape analysis that picks byval/byaddr based on size.
-		argCopy.SetByval(byval)
-		return argCopy
-	}
-
-	// getUnsafeArg looks for an unsafe.Pointer arg that has been
-	// previously captured into the call's keepalive list, returning
-	// the name node for it if found.
-	getUnsafeArg := func(arg ir.Node) *ir.Name {
-		// Look for uintptr(unsafe.Pointer(name))
-		if arg.Op() != ir.OCONVNOP {
-			return nil
-		}
-		if !arg.Type().IsUintptr() {
-			return nil
-		}
-		if !arg.(*ir.ConvExpr).X.Type().IsUnsafePtr() {
-			return nil
-		}
-		arg = arg.(*ir.ConvExpr).X
-		argname, ok := arg.(*ir.Name)
-		if !ok {
-			return nil
-		}
-		for i := range keepAlive {
-			if argname == keepAlive[i] {
-				return argname
-			}
-		}
-		return nil
-	}
-
-	// Copy the arguments to the function into temps.
-	//
-	// For calls with uintptr(unsafe.Pointer(...)) args that are being
-	// kept alive (see code in (*orderState).call that does this), use
-	// the existing arg copy instead of creating a new copy.
-	unsafeArgs := make([]*ir.Name, len(callArgs))
-	origArgs := callArgs
-	var newNames []*ir.Name
-	for i := range callArgs {
-		arg := callArgs[i]
-		var argname *ir.Name
-		unsafeArgName := getUnsafeArg(arg)
-		if unsafeArgName != nil {
-			// arg has been copied already, use keepalive copy
-			argname = unsafeArgName
-			unsafeArgs[i] = unsafeArgName
-		} else {
-			argname = mkArgCopy(arg)
-		}
-		newNames = append(newNames, argname)
-	}
-
-	// Deal with cases where the function expression (what we're
-	// calling) is not a simple function symbol.
-	var fnExpr *ir.Name
-	var methSelectorExpr *ir.SelectorExpr
-	if callX != nil {
-		switch {
-		case callX.Op() == ir.ODOTMETH || callX.Op() == ir.ODOTINTER:
-			// Handle defer of a method call, e.g. "defer v.MyMethod(x, y)"
-			n := callX.(*ir.SelectorExpr)
-			n.X = mkArgCopy(n.X)
-			methSelectorExpr = n
-			if callX.Op() == ir.ODOTINTER {
-				// Currently for "defer i.M()" if i is nil it panics at the
-				// point of defer statement, not when deferred function is called.
-				// (I think there is an issue discussing what is the intended
-				// behavior but I cannot find it.)
-				// We need to do the nil check outside of the wrapper.
-				tab := typecheck.Expr(ir.NewUnaryExpr(base.Pos, ir.OITAB, n.X))
-				c := ir.NewUnaryExpr(n.Pos(), ir.OCHECKNIL, tab)
-				c.SetTypecheck(1)
-				o.append(c)
-			}
-		case !(callX.Op() == ir.ONAME && callX.(*ir.Name).Class == ir.PFUNC):
-			// Deal with "defer returnsafunc()(x, y)" (for
-			// example) by copying the callee expression.
-			fnExpr = mkArgCopy(callX)
-		}
-	}
-
-	// Create a new no-argument function that we'll hand off to defer.
-	fn := ir.NewClosureFunc(base.Pos, true)
-	fn.Nname.SetType(types.NewSignature(types.LocalPkg, nil, nil, nil, nil))
-	fn.SetWrapper(true)
-
-	// helper for capturing reference to a var declared in an outer scope.
-	capName := func(pos src.XPos, fn *ir.Func, n *ir.Name) *ir.Name {
-		t := n.Type()
-		cv := ir.CaptureName(pos, fn, n)
-		cv.SetType(t)
-		return typecheck.Expr(cv).(*ir.Name)
-	}
-
-	// Call args (x1, y1) need to be captured as part of the newly
-	// created closure.
-	newCallArgs := []ir.Node{}
-	for i := range newNames {
-		var arg ir.Node
-		arg = capName(callArgs[i].Pos(), fn, newNames[i])
-		if unsafeArgs[i] != nil {
-			arg = ir.NewConvExpr(arg.Pos(), origArgs[i].Op(), origArgs[i].Type(), arg)
-		}
-		newCallArgs = append(newCallArgs, arg)
-	}
-	// Also capture the function or method expression (if needed) into
-	// the closure.
-	if fnExpr != nil {
-		callX = capName(callX.Pos(), fn, fnExpr)
-	}
-	if methSelectorExpr != nil {
-		methSelectorExpr.X = capName(callX.Pos(), fn, methSelectorExpr.X.(*ir.Name))
-	}
-
-	// This flags a builtin as opposed to a regular call.
-	irregular := (call.Op() != ir.OCALLFUNC &&
-		call.Op() != ir.OCALLMETH &&
-		call.Op() != ir.OCALLINTER)
-
-	// Construct new function body:  f(x1, y1)
-	op := ir.OCALL
-	if irregular {
-		op = call.Op()
-	}
-	newcall := mkNewCall(call.Pos(), op, callX, newCallArgs)
-
-	// Finalize body, register function on the main decls list.
-	fn.Body = []ir.Node{newcall}
-	ir.FinishCaptureNames(n.Pos(), ir.CurFunc, fn)
-
-	// Create closure expr
-	clo := typecheck.Expr(fn.OClosure).(*ir.ClosureExpr)
-
-	// Set escape properties for closure.
-	if n.Op() == ir.OGO {
-		// For "go", assume that the closure is going to escape.
-		clo.SetEsc(ir.EscHeap)
-		clo.IsGoWrap = true
-	} else {
-		// For defer, just use whatever result escape analysis
-		// has determined for the defer.
-		if n.Esc() == ir.EscNever {
-			clo.SetTransient(true)
-			clo.SetEsc(ir.EscNone)
-		}
-	}
-
-	// Create new top level call to closure over argless function.
-	topcall := ir.NewCallExpr(n.Pos(), ir.OCALL, clo, nil)
-	typecheck.Call(topcall)
-
-	// Finally, point the defer statement at the newly generated call.
-	n.Call = topcall
-}
-
 // isFuncPCIntrinsic returns whether n is a direct call of internal/abi.FuncPCABIxxx functions.
 func isFuncPCIntrinsic(n *ir.CallExpr) bool {
 	if n.Op() != ir.OCALLFUNC || n.X.Op() != ir.ONAME {
diff --git a/src/cmd/compile/internal/walk/stmt.go b/src/cmd/compile/internal/walk/stmt.go
index bcc0a3e5173..0c216d2e8a3 100644
--- a/src/cmd/compile/internal/walk/stmt.go
+++ b/src/cmd/compile/internal/walk/stmt.go
@@ -222,22 +222,3 @@ func walkIf(n *ir.IfStmt) ir.Node {
 	walkStmtList(n.Else)
 	return n
 }
-
-// undoVariadic turns a call to a variadic function of the form
-//
-//      f(a, b, []T{c, d, e}...)
-//
-// back into
-//
-//      f(a, b, c, d, e)
-//
-func undoVariadic(call *ir.CallExpr) {
-	if call.IsDDD {
-		last := len(call.Args) - 1
-		if va := call.Args[last]; va.Op() == ir.OSLICELIT {
-			va := va.(*ir.CompLitExpr)
-			call.Args = append(call.Args[:last], va.List...)
-			call.IsDDD = false
-		}
-	}
-}
diff --git a/test/escape2.go b/test/escape2.go
index 04ab635aa52..e3e5904cde5 100644
--- a/test/escape2.go
+++ b/test/escape2.go
@@ -667,13 +667,13 @@ func foo76e() {
 func foo76f() {
 	for {
 		// TODO: This one really only escapes its scope, but we don't distinguish yet.
-		defer myprint(nil, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$"
+		defer myprint(nil, 1, 2, 3) // ERROR "... argument does not escape$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$"
 	}
 }
 
 func foo76g() {
 	for {
-		defer myprint1(nil, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$"
+		defer myprint1(nil, 1, 2, 3) // ERROR "... argument does not escape$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$"
 	}
 }
 
@@ -1148,16 +1148,16 @@ L100:
 
 func foo121() {
 	for i := 0; i < 10; i++ {
-		defer myprint(nil, i) // ERROR "... argument escapes to heap$" "i escapes to heap$"
-		go myprint(nil, i)    // ERROR "... argument escapes to heap$" "i escapes to heap$"
+		defer myprint(nil, i) // ERROR "... argument does not escape$" "i escapes to heap$"
+		go myprint(nil, i)    // ERROR "... argument does not escape$" "i escapes to heap$"
 	}
 }
 
 // same as foo121 but check across import
 func foo121b() {
 	for i := 0; i < 10; i++ {
-		defer fmt.Printf("%d", i) // ERROR "... argument escapes to heap$" "i escapes to heap$"
-		go fmt.Printf("%d", i)    // ERROR "... argument escapes to heap$" "i escapes to heap$"
+		defer fmt.Printf("%d", i) // ERROR "... argument does not escape$" "i escapes to heap$"
+		go fmt.Printf("%d", i)    // ERROR "... argument does not escape$" "i escapes to heap$"
 	}
 }
 
diff --git a/test/escape2n.go b/test/escape2n.go
index 01a25795f47..57cc1a01639 100644
--- a/test/escape2n.go
+++ b/test/escape2n.go
@@ -667,13 +667,13 @@ func foo76e() {
 func foo76f() {
 	for {
 		// TODO: This one really only escapes its scope, but we don't distinguish yet.
-		defer myprint(nil, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$"
+		defer myprint(nil, 1, 2, 3) // ERROR "... argument does not escape$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$"
 	}
 }
 
 func foo76g() {
 	for {
-		defer myprint1(nil, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$"
+		defer myprint1(nil, 1, 2, 3) // ERROR "... argument does not escape$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$"
 	}
 }
 
@@ -1148,16 +1148,16 @@ L100:
 
 func foo121() {
 	for i := 0; i < 10; i++ {
-		defer myprint(nil, i) // ERROR "... argument escapes to heap$" "i escapes to heap$"
-		go myprint(nil, i)    // ERROR "... argument escapes to heap$" "i escapes to heap$"
+		defer myprint(nil, i) // ERROR "... argument does not escape$" "i escapes to heap$"
+		go myprint(nil, i)    // ERROR "... argument does not escape$" "i escapes to heap$"
 	}
 }
 
 // same as foo121 but check across import
 func foo121b() {
 	for i := 0; i < 10; i++ {
-		defer fmt.Printf("%d", i) // ERROR "... argument escapes to heap$" "i escapes to heap$"
-		go fmt.Printf("%d", i)    // ERROR "... argument escapes to heap$" "i escapes to heap$"
+		defer fmt.Printf("%d", i) // ERROR "... argument does not escape$" "i escapes to heap$"
+		go fmt.Printf("%d", i)    // ERROR "... argument does not escape$" "i escapes to heap$"
 	}
 }
 
diff --git a/test/fixedbugs/issue31573.go b/test/fixedbugs/issue31573.go
index 005910e00d1..eaab5634316 100644
--- a/test/fixedbugs/issue31573.go
+++ b/test/fixedbugs/issue31573.go
@@ -19,31 +19,31 @@ func g() {
 	defer f([]*int{new(int), new(int)}...) // ERROR "\[\]\*int{...} does not escape$" "new\(int\) does not escape$"
 
 	go f()
-	go f(new(int))           // ERROR "... argument escapes to heap$" "new\(int\) escapes to heap$"
-	go f(new(int), new(int)) // ERROR "... argument escapes to heap$" "new\(int\) escapes to heap$"
+	go f(new(int))           // ERROR "... argument does not escape$" "new\(int\) escapes to heap$"
+	go f(new(int), new(int)) // ERROR "... argument does not escape$" "new\(int\) escapes to heap$"
 
 	go f(nil...)
-	go f([]*int{}...)                   // ERROR "\[\]\*int{} escapes to heap$"
-	go f([]*int{new(int)}...)           // ERROR "\[\]\*int{...} escapes to heap$" "new\(int\) escapes to heap$"
-	go f([]*int{new(int), new(int)}...) // ERROR "\[\]\*int{...} escapes to heap$" "new\(int\) escapes to heap$"
+	go f([]*int{}...)                   // ERROR "\[\]\*int{} does not escape$"
+	go f([]*int{new(int)}...)           // ERROR "\[\]\*int{...} does not escape$" "new\(int\) escapes to heap$"
+	go f([]*int{new(int), new(int)}...) // ERROR "\[\]\*int{...} does not escape$" "new\(int\) escapes to heap$"
 
 	for {
 		defer f()
-		defer f(new(int))           // ERROR "... argument escapes to heap$" "new\(int\) escapes to heap$"
-		defer f(new(int), new(int)) // ERROR "... argument escapes to heap$" "new\(int\) escapes to heap$"
+		defer f(new(int))           // ERROR "... argument does not escape$" "new\(int\) escapes to heap$"
+		defer f(new(int), new(int)) // ERROR "... argument does not escape$" "new\(int\) escapes to heap$"
 
 		defer f(nil...)
-		defer f([]*int{}...)                   // ERROR "\[\]\*int{} escapes to heap$"
-		defer f([]*int{new(int)}...)           // ERROR "\[\]\*int{...} escapes to heap$" "new\(int\) escapes to heap$"
-		defer f([]*int{new(int), new(int)}...) // ERROR "\[\]\*int{...} escapes to heap$" "new\(int\) escapes to heap$"
+		defer f([]*int{}...)                   // ERROR "\[\]\*int{} does not escape$"
+		defer f([]*int{new(int)}...)           // ERROR "\[\]\*int{...} does not escape$" "new\(int\) escapes to heap$"
+		defer f([]*int{new(int), new(int)}...) // ERROR "\[\]\*int{...} does not escape$" "new\(int\) escapes to heap$"
 
 		go f()
-		go f(new(int))           // ERROR "... argument escapes to heap$" "new\(int\) escapes to heap$"
-		go f(new(int), new(int)) // ERROR "... argument escapes to heap$" "new\(int\) escapes to heap$"
+		go f(new(int))           // ERROR "... argument does not escape$" "new\(int\) escapes to heap$"
+		go f(new(int), new(int)) // ERROR "... argument does not escape$" "new\(int\) escapes to heap$"
 
 		go f(nil...)
-		go f([]*int{}...)                   // ERROR "\[\]\*int{} escapes to heap$"
-		go f([]*int{new(int)}...)           // ERROR "\[\]\*int{...} escapes to heap$" "new\(int\) escapes to heap$"
-		go f([]*int{new(int), new(int)}...) // ERROR "\[\]\*int{...} escapes to heap$" "new\(int\) escapes to heap$"
+		go f([]*int{}...)                   // ERROR "\[\]\*int{} does not escape$"
+		go f([]*int{new(int)}...)           // ERROR "\[\]\*int{...} does not escape$" "new\(int\) escapes to heap$"
+		go f([]*int{new(int), new(int)}...) // ERROR "\[\]\*int{...} does not escape$" "new\(int\) escapes to heap$"
 	}
 }

From eb691fdd62c9f1dc36c9c9a974ac2ddad677fd99 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Wed, 23 Jun 2021 00:31:16 -0700
Subject: [PATCH 520/940] [dev.typeparams] cmd/compile: escape analysis of
 method expression calls

This CL extends escape analysis to analyze function calls using method
expressions the same as it would a normal method call. That is, it now
analyzes "T.M(recv, args...)" the same as "recv.M(args...)".

This is useful because it means the frontend can eventually stop
supporting both function calls and method calls. We can simply desugar
method calls into function calls, like we already do in the backend to
simplify SSA construction.

Change-Id: I9cd5ec0d534cbcd9860f0014c86e4ae416920c26
Reviewed-on: https://go-review.googlesource.com/c/go/+/330331
Run-TryBot: Matthew Dempsky 
TryBot-Result: Go Bot 
Trust: Matthew Dempsky 
Reviewed-by: Cuong Manh Le 
---
 src/cmd/compile/internal/escape/call.go | 37 +++++++++++++++++--------
 test/escape5.go                         |  3 +-
 2 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/src/cmd/compile/internal/escape/call.go b/src/cmd/compile/internal/escape/call.go
index 7b9dbe0dbc6..850b9cbde28 100644
--- a/src/cmd/compile/internal/escape/call.go
+++ b/src/cmd/compile/internal/escape/call.go
@@ -56,11 +56,15 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
 		var fn *ir.Name
 		switch call.Op() {
 		case ir.OCALLFUNC:
-			switch v := ir.StaticValue(call.X); {
-			case v.Op() == ir.ONAME && v.(*ir.Name).Class == ir.PFUNC:
-				fn = v.(*ir.Name)
-			case v.Op() == ir.OCLOSURE:
+			switch v := ir.StaticValue(call.X); v.Op() {
+			case ir.ONAME:
+				if v := v.(*ir.Name); v.Class == ir.PFUNC {
+					fn = v
+				}
+			case ir.OCLOSURE:
 				fn = v.(*ir.ClosureExpr).Func.Nname
+			case ir.OMETHEXPR:
+				fn = ir.MethodExprName(v)
 			}
 		case ir.OCALLMETH:
 			fn = ir.MethodExprName(call.X)
@@ -77,19 +81,30 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
 			}
 		}
 
-		if r := fntype.Recv(); r != nil {
-			dot := call.X.(*ir.SelectorExpr)
-			argumentFunc(fn, e.tagHole(ks, fn, r), &dot.X)
-		} else {
+		var recvp *ir.Node
+		if call.Op() == ir.OCALLFUNC {
 			// Evaluate callee function expression.
 			//
-			// Note: We use argument and not argumentFunc, because call.X
-			// here may be an argument to runtime.{new,defer}proc, but it's
-			// not an argument to fn itself.
+			// Note: We use argument and not argumentFunc, because while
+			// call.X here may be an argument to runtime.{new,defer}proc,
+			// it's not an argument to fn itself.
 			argument(e.discardHole(), &call.X)
+		} else {
+			recvp = &call.X.(*ir.SelectorExpr).X
 		}
 
 		args := call.Args
+		if recv := fntype.Recv(); recv != nil {
+			if recvp == nil {
+				// Function call using method expression. Recevier argument is
+				// at the front of the regular arguments list.
+				recvp = &args[0]
+				args = args[1:]
+			}
+
+			argumentFunc(fn, e.tagHole(ks, fn, recv), recvp)
+		}
+
 		for i, param := range fntype.Params().FieldSlice() {
 			argumentFunc(fn, e.tagHole(ks, fn, param), &args[i])
 		}
diff --git a/test/escape5.go b/test/escape5.go
index 73acfb46a94..97aaf23b2d1 100644
--- a/test/escape5.go
+++ b/test/escape5.go
@@ -180,8 +180,7 @@ func _() {
 }
 
 func fbad24305() {
-	// BAD u should not be heap allocated
-	var u U // ERROR "moved to heap: u"
+	var u U
 	(*U).M(&u)
 	(*U).N(&u)
 }

From a72a499c24cfcfce2a16ac7c228c2c914c4f36c4 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Wed, 23 Jun 2021 00:49:03 -0700
Subject: [PATCH 521/940] [dev.typeparams] cmd/compile: optimize wrapping of
 constant arguments

When wrapping a go/defer statement like:

	go f(g(), "x", 42)

we were wrapping it like:

	_0, _1, _2, _3 := f, g(), "x", 42
	go func() { _0(_1, _2, _3) }()

This is simple and general (and often necessary), but suboptimal in
some cases, such as this. Instead of evaluating the constant arguments
at the go/defer statement, and storing them into the closure context,
we can just keep them in the wrapped call expression.

This CL changes the code to instead generate (assuming f is a declared
function, not a function-typed variable):

	_0 := g()
	go func() { f(_0, "x", 42) }()

Change-Id: I2bdd4951e7ee93363e1656ecf9b5bd69a121c38a
Reviewed-on: https://go-review.googlesource.com/c/go/+/330332
Run-TryBot: Matthew Dempsky 
TryBot-Result: Go Bot 
Trust: Matthew Dempsky 
Reviewed-by: Cuong Manh Le 
---
 src/cmd/compile/internal/escape/call.go | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/cmd/compile/internal/escape/call.go b/src/cmd/compile/internal/escape/call.go
index 850b9cbde28..b8e28cd46a8 100644
--- a/src/cmd/compile/internal/escape/call.go
+++ b/src/cmd/compile/internal/escape/call.go
@@ -293,6 +293,18 @@ func (e *escape) rewriteArgument(argp *ir.Node, init *ir.Nodes, call ir.Node, fn
 	}
 
 	visit := func(pos src.XPos, argp *ir.Node) {
+		// Optimize a few common constant expressions. By leaving these
+		// untouched in the call expression, we let the wrapper handle
+		// evaluating them, rather than taking up closure context space.
+		switch arg := *argp; arg.Op() {
+		case ir.OLITERAL, ir.ONIL, ir.OMETHEXPR:
+			return
+		case ir.ONAME:
+			if arg.(*ir.Name).Class == ir.PFUNC {
+				return
+			}
+		}
+
 		if unsafeUintptr(*argp) {
 			return
 		}

From 8165256bc2e3298b0d612471d7d2e6c005b984de Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Wed, 23 Jun 2021 12:08:42 -0700
Subject: [PATCH 522/940] [dev.typeparams] cmd/compile/internal/syntax:
 go/ast-style walk API

This CL adds go/ast's Visitor, Walk, and Inspect functions to package
syntax. Having functions with the same API and semantics as their
go/ast counterparts reduces the mental load of context switching
between go/ast and syntax.

It also renames the existing Walk function into Crawl, and marks it as
a deprecated wrapper around Inspect. (I named it "Crawl" because it's
less functional than "Walk"... get it??)

There aren't that many callers to Crawl, so we can probably remove it
in the future. But it doesn't seem pressing, and I'm more concerned
about the risk of forgetting to invert a bool condition somewhere.

Change-Id: Ib2fb275873a1d1a730249c9cb584864cb6ec370e
Reviewed-on: https://go-review.googlesource.com/c/go/+/330429
Run-TryBot: Matthew Dempsky 
Trust: Matthew Dempsky 
Trust: Robert Griesemer 
TryBot-Result: Go Bot 
Reviewed-by: Robert Griesemer 
---
 src/cmd/compile/internal/noder/irgen.go       |  2 +-
 src/cmd/compile/internal/noder/quirks.go      |  8 +--
 src/cmd/compile/internal/noder/writer.go      | 14 ++--
 src/cmd/compile/internal/syntax/walk.go       | 72 +++++++++++++++----
 .../internal/types2/errorcalls_test.go        |  2 +-
 .../compile/internal/types2/issues_test.go    |  2 +-
 .../compile/internal/types2/resolver_test.go  |  4 +-
 7 files changed, 74 insertions(+), 30 deletions(-)

diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go
index aac8b5e6418..9d14b06d3c8 100644
--- a/src/cmd/compile/internal/noder/irgen.go
+++ b/src/cmd/compile/internal/noder/irgen.go
@@ -191,7 +191,7 @@ Outer:
 
 		// Double check for any type-checking inconsistencies. This can be
 		// removed once we're confident in IR generation results.
-		syntax.Walk(p.file, func(n syntax.Node) bool {
+		syntax.Crawl(p.file, func(n syntax.Node) bool {
 			g.validate(n)
 			return false
 		})
diff --git a/src/cmd/compile/internal/noder/quirks.go b/src/cmd/compile/internal/noder/quirks.go
index 91b4c22025b..914c5d2bd71 100644
--- a/src/cmd/compile/internal/noder/quirks.go
+++ b/src/cmd/compile/internal/noder/quirks.go
@@ -36,7 +36,7 @@ func posBasesOf(noders []*noder) []*syntax.PosBase {
 	var bases []*syntax.PosBase
 
 	for _, p := range noders {
-		syntax.Walk(p.file, func(n syntax.Node) bool {
+		syntax.Crawl(p.file, func(n syntax.Node) bool {
 			if b := n.Pos().Base(); !seen[b] {
 				bases = append(bases, b)
 				seen[b] = true
@@ -74,7 +74,7 @@ func importedObjsOf(curpkg *types2.Package, info *types2.Info, noders []*noder)
 	}
 
 	for _, p := range noders {
-		syntax.Walk(p.file, func(n syntax.Node) bool {
+		syntax.Crawl(p.file, func(n syntax.Node) bool {
 			switch n := n.(type) {
 			case *syntax.ConstDecl:
 				assoc(n, n.NameList...)
@@ -167,7 +167,7 @@ func importedObjsOf(curpkg *types2.Package, info *types2.Info, noders []*noder)
 		if n == nil {
 			return
 		}
-		syntax.Walk(n, func(n syntax.Node) bool {
+		syntax.Crawl(n, func(n syntax.Node) bool {
 			switch n := n.(type) {
 			case *syntax.Name:
 				checkdef(n)
@@ -237,7 +237,7 @@ func importedObjsOf(curpkg *types2.Package, info *types2.Info, noders []*noder)
 			}
 
 			if phase >= 5 {
-				syntax.Walk(p.file, func(n syntax.Node) bool {
+				syntax.Crawl(p.file, func(n syntax.Node) bool {
 					if name, ok := n.(*syntax.Name); ok {
 						if obj, ok := info.Uses[name]; ok {
 							resolveObj(name.Pos(), obj)
diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go
index cc749b0d1e5..bc89e1a262a 100644
--- a/src/cmd/compile/internal/noder/writer.go
+++ b/src/cmd/compile/internal/noder/writer.go
@@ -1318,7 +1318,7 @@ func (w *writer) captureVars(expr *syntax.FuncLit) (closureVars []posObj, locals
 			// function literal as the position of the intermediary capture.
 			if quirksMode() && rbracePos == (syntax.Pos{}) {
 				rbracePos = n.Body.Rbrace
-				syntax.Walk(n.Body, visitor)
+				syntax.Crawl(n.Body, visitor)
 				rbracePos = syntax.Pos{}
 				return true
 			}
@@ -1327,17 +1327,17 @@ func (w *writer) captureVars(expr *syntax.FuncLit) (closureVars []posObj, locals
 			// Quirk: typecheck visits (and thus captures) the RHS of
 			// assignment statements before the LHS.
 			if quirksMode() && (n.Op == 0 || n.Op == syntax.Def) {
-				syntax.Walk(n.Rhs, visitor)
-				syntax.Walk(n.Lhs, visitor)
+				syntax.Crawl(n.Rhs, visitor)
+				syntax.Crawl(n.Lhs, visitor)
 				return true
 			}
 		case *syntax.RangeClause:
 			// Quirk: Similarly, it visits the expression to be iterated
 			// over before the iteration variables.
 			if quirksMode() {
-				syntax.Walk(n.X, visitor)
+				syntax.Crawl(n.X, visitor)
 				if n.Lhs != nil {
-					syntax.Walk(n.Lhs, visitor)
+					syntax.Crawl(n.Lhs, visitor)
 				}
 				return true
 			}
@@ -1345,7 +1345,7 @@ func (w *writer) captureVars(expr *syntax.FuncLit) (closureVars []posObj, locals
 
 		return false
 	}
-	syntax.Walk(expr.Body, visitor)
+	syntax.Crawl(expr.Body, visitor)
 
 	return
 }
@@ -1392,7 +1392,7 @@ func (pw *pkgWriter) collectDecls(noders []*noder) {
 	for _, p := range noders {
 		var importedEmbed, importedUnsafe bool
 
-		syntax.Walk(p.file, func(n syntax.Node) bool {
+		syntax.Crawl(p.file, func(n syntax.Node) bool {
 			switch n := n.(type) {
 			case *syntax.File:
 				pw.checkPragmas(n.Pragma, ir.GoBuildPragma, false)
diff --git a/src/cmd/compile/internal/syntax/walk.go b/src/cmd/compile/internal/syntax/walk.go
index c26e97a0d8f..ef213daf7d1 100644
--- a/src/cmd/compile/internal/syntax/walk.go
+++ b/src/cmd/compile/internal/syntax/walk.go
@@ -8,31 +8,73 @@ package syntax
 
 import "fmt"
 
-// Walk traverses a syntax in pre-order: It starts by calling f(root);
-// root must not be nil. If f returns false (== "continue"), Walk calls
+// Inspect traverses an AST in pre-order: It starts by calling
+// f(node); node must not be nil. If f returns true, Inspect invokes f
+// recursively for each of the non-nil children of node, followed by a
+// call of f(nil).
+//
+// See Walk for caveats about shared nodes.
+func Inspect(root Node, f func(Node) bool) {
+	Walk(root, inspector(f))
+}
+
+type inspector func(Node) bool
+
+func (v inspector) Visit(node Node) Visitor {
+	if v(node) {
+		return v
+	}
+	return nil
+}
+
+// Crawl traverses a syntax in pre-order: It starts by calling f(root);
+// root must not be nil. If f returns false (== "continue"), Crawl calls
 // f recursively for each of the non-nil children of that node; if f
-// returns true (== "stop"), Walk does not traverse the respective node's
+// returns true (== "stop"), Crawl does not traverse the respective node's
 // children.
+//
+// See Walk for caveats about shared nodes.
+//
+// Deprecated: Use Inspect instead.
+func Crawl(root Node, f func(Node) bool) {
+	Inspect(root, func(node Node) bool {
+		return node != nil && !f(node)
+	})
+}
+
+// Walk traverses an AST in pre-order: It starts by calling
+// v.Visit(node); node must not be nil. If the visitor w returned by
+// v.Visit(node) is not nil, Walk is invoked recursively with visitor
+// w for each of the non-nil children of node, followed by a call of
+// w.Visit(nil).
+//
 // Some nodes may be shared among multiple parent nodes (e.g., types in
 // field lists such as type T in "a, b, c T"). Such shared nodes are
 // walked multiple times.
 // TODO(gri) Revisit this design. It may make sense to walk those nodes
 //           only once. A place where this matters is types2.TestResolveIdents.
-func Walk(root Node, f func(Node) bool) {
-	w := walker{f}
-	w.node(root)
+func Walk(root Node, v Visitor) {
+	walker{v}.node(root)
+}
+
+// A Visitor's Visit method is invoked for each node encountered by Walk.
+// If the result visitor w is not nil, Walk visits each of the children
+// of node with the visitor w, followed by a call of w.Visit(nil).
+type Visitor interface {
+	Visit(node Node) (w Visitor)
 }
 
 type walker struct {
-	f func(Node) bool
+	v Visitor
 }
 
-func (w *walker) node(n Node) {
+func (w walker) node(n Node) {
 	if n == nil {
 		panic("invalid syntax tree: nil node")
 	}
 
-	if w.f(n) {
+	w.v = w.v.Visit(n)
+	if w.v == nil {
 		return
 	}
 
@@ -285,33 +327,35 @@ func (w *walker) node(n Node) {
 	default:
 		panic(fmt.Sprintf("internal error: unknown node type %T", n))
 	}
+
+	w.v.Visit(nil)
 }
 
-func (w *walker) declList(list []Decl) {
+func (w walker) declList(list []Decl) {
 	for _, n := range list {
 		w.node(n)
 	}
 }
 
-func (w *walker) exprList(list []Expr) {
+func (w walker) exprList(list []Expr) {
 	for _, n := range list {
 		w.node(n)
 	}
 }
 
-func (w *walker) stmtList(list []Stmt) {
+func (w walker) stmtList(list []Stmt) {
 	for _, n := range list {
 		w.node(n)
 	}
 }
 
-func (w *walker) nameList(list []*Name) {
+func (w walker) nameList(list []*Name) {
 	for _, n := range list {
 		w.node(n)
 	}
 }
 
-func (w *walker) fieldList(list []*Field) {
+func (w walker) fieldList(list []*Field) {
 	for _, n := range list {
 		w.node(n)
 	}
diff --git a/src/cmd/compile/internal/types2/errorcalls_test.go b/src/cmd/compile/internal/types2/errorcalls_test.go
index 28bb33aaffd..80b05f9f0f0 100644
--- a/src/cmd/compile/internal/types2/errorcalls_test.go
+++ b/src/cmd/compile/internal/types2/errorcalls_test.go
@@ -18,7 +18,7 @@ func TestErrorCalls(t *testing.T) {
 	}
 
 	for _, file := range files {
-		syntax.Walk(file, func(n syntax.Node) bool {
+		syntax.Crawl(file, func(n syntax.Node) bool {
 			call, _ := n.(*syntax.CallExpr)
 			if call == nil {
 				return false
diff --git a/src/cmd/compile/internal/types2/issues_test.go b/src/cmd/compile/internal/types2/issues_test.go
index e716a480385..aafe8de3676 100644
--- a/src/cmd/compile/internal/types2/issues_test.go
+++ b/src/cmd/compile/internal/types2/issues_test.go
@@ -321,7 +321,7 @@ func TestIssue25627(t *testing.T) {
 			}
 		}
 
-		syntax.Walk(f, func(n syntax.Node) bool {
+		syntax.Crawl(f, func(n syntax.Node) bool {
 			if decl, _ := n.(*syntax.TypeDecl); decl != nil {
 				if tv, ok := info.Types[decl.Type]; ok && decl.Name.Value == "T" {
 					want := strings.Count(src, ";") + 1
diff --git a/src/cmd/compile/internal/types2/resolver_test.go b/src/cmd/compile/internal/types2/resolver_test.go
index aee435ff5fb..a02abce081b 100644
--- a/src/cmd/compile/internal/types2/resolver_test.go
+++ b/src/cmd/compile/internal/types2/resolver_test.go
@@ -143,7 +143,7 @@ func TestResolveIdents(t *testing.T) {
 
 	// check that qualified identifiers are resolved
 	for _, f := range files {
-		syntax.Walk(f, func(n syntax.Node) bool {
+		syntax.Crawl(f, func(n syntax.Node) bool {
 			if s, ok := n.(*syntax.SelectorExpr); ok {
 				if x, ok := s.X.(*syntax.Name); ok {
 					obj := uses[x]
@@ -177,7 +177,7 @@ func TestResolveIdents(t *testing.T) {
 	foundDefs := make(map[*syntax.Name]bool)
 	var both []string
 	for _, f := range files {
-		syntax.Walk(f, func(n syntax.Node) bool {
+		syntax.Crawl(f, func(n syntax.Node) bool {
 			if x, ok := n.(*syntax.Name); ok {
 				var objects int
 				if _, found := uses[x]; found {

From ee4fc0c1bc300f181388ef6dd187ca8b8737efd2 Mon Sep 17 00:00:00 2001
From: Dan Scales 
Date: Fri, 18 Jun 2021 14:09:21 -0700
Subject: [PATCH 523/940] [dev.typeparams] Fix issues related to dictionaries
 and method calls with embedded fields

 - Fix handling of method expressions with embedded fields. Fix an
   incorrect lookup for method expressions, which have only the
   top-level type (and don't have DOT operations for the embedded
   fields). Add the embedded field dot operations into the closure.

 - Don't need a dictionary and so don't build a closure if the last
   embedded field reached in a method expression is an interface value.

 - Fix methodWrapper() to use the computed 'dot' node in the
   generic-only part of the code.

 - For a method expression, don't create a generic wrapper if the last
   embedded field reached before the method lookup is an interface.

Copied cmd/compile/internal/types2/testdata/fixedbugs/issue44688.go2 to
test/typeparam/issue44688.go, made it fully runnable (rather than just
for compilation), and added a bunch more tests.

Change-Id: I90c1aa569e1c7272e986c9d2ae683e553c3a38a1
Reviewed-on: https://go-review.googlesource.com/c/go/+/329550
Run-TryBot: Dan Scales 
TryBot-Result: Go Bot 
Trust: Dan Scales 
Reviewed-by: Keith Randall 
---
 src/cmd/compile/internal/noder/stencil.go     |  30 +++-
 .../compile/internal/reflectdata/reflect.go   |  13 +-
 test/typeparam/issue44688.go                  | 150 ++++++++++++++++++
 3 files changed, 184 insertions(+), 9 deletions(-)
 create mode 100644 test/typeparam/issue44688.go

diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go
index 8b53671dbe2..710289b76c0 100644
--- a/src/cmd/compile/internal/noder/stencil.go
+++ b/src/cmd/compile/internal/noder/stencil.go
@@ -76,8 +76,10 @@ func (g *irgen) stencil() {
 				// generic F, not immediately called
 				closureRequired = true
 			}
-			if n.Op() == ir.OMETHEXPR && len(n.(*ir.SelectorExpr).X.Type().RParams()) > 0 {
-				// T.M, T a type which is generic, not immediately called
+			if n.Op() == ir.OMETHEXPR && len(n.(*ir.SelectorExpr).X.Type().RParams()) > 0 && !types.IsInterfaceMethod(n.(*ir.SelectorExpr).Selection.Type) {
+				// T.M, T a type which is generic, not immediately
+				// called. Not necessary if the method selected is
+				// actually for an embedded interface field.
 				closureRequired = true
 			}
 			if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OFUNCINST {
@@ -156,7 +158,8 @@ func (g *irgen) stencil() {
 					// TODO: only set outer!=nil if this instantiation uses
 					// a type parameter from outer. See comment in buildClosure.
 					return g.buildClosure(outer, x)
-				case x.Op() == ir.OMETHEXPR && len(deref(x.(*ir.SelectorExpr).X.Type()).RParams()) > 0: // TODO: test for ptr-to-method case
+				case x.Op() == ir.OMETHEXPR && len(deref(x.(*ir.SelectorExpr).X.Type()).RParams()) > 0 &&
+					!types.IsInterfaceMethod(x.(*ir.SelectorExpr).Selection.Type): // TODO: test for ptr-to-method case
 					return g.buildClosure(outer, x)
 				}
 				return x
@@ -230,9 +233,14 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
 				}
 			}
 		}
-		t := se.X.Type()
-		baseSym := t.OrigSym
-		baseType := baseSym.Def.(*ir.Name).Type()
+
+		// se.X.Type() is the top-level type of the method expression. To
+		// correctly handle method expressions involving embedded fields,
+		// look up the generic method below using the type of the receiver
+		// of se.Selection, since that will be the type that actually has
+		// the method.
+		recv := deref(se.Selection.Type.Recv().Type)
+		baseType := recv.OrigSym.Def.Type()
 		var gf *ir.Name
 		for _, m := range baseType.Methods().Slice() {
 			if se.Sel == m.Sym {
@@ -382,7 +390,15 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
 	}
 	// Then all the other arguments (including receiver for method expressions).
 	for i := 0; i < typ.NumParams(); i++ {
-		args = append(args, formalParams[i].Nname.(*ir.Name))
+		if x.Op() == ir.OMETHEXPR && i == 0 {
+			// If we are doing a method expression, we need to
+			// explicitly traverse any embedded fields in the receiver
+			// argument in order to call the method instantiation.
+			dot := typecheck.AddImplicitDots(ir.NewSelectorExpr(base.Pos, ir.OXDOT, formalParams[0].Nname.(*ir.Name), x.(*ir.SelectorExpr).Sel))
+			args = append(args, dot.X)
+		} else {
+			args = append(args, formalParams[i].Nname.(*ir.Name))
+		}
 	}
 
 	// Build call itself.
diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go
index 9e070895a0b..52534db70d0 100644
--- a/src/cmd/compile/internal/reflectdata/reflect.go
+++ b/src/cmd/compile/internal/reflectdata/reflect.go
@@ -1786,6 +1786,11 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
 	}
 
 	dot := typecheck.AddImplicitDots(ir.NewSelectorExpr(base.Pos, ir.OXDOT, nthis, method.Sym))
+	if generic && dot.X != nthis && dot.X.Type().IsInterface() {
+		// We followed some embedded fields, and the last type was
+		// actually an interface, so no need for a dictionary.
+		generic = false
+	}
 
 	// generate call
 	// It's not possible to use a tail call when dynamic linking on ppc64le. The
@@ -1824,9 +1829,13 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
 			}
 			args = append(args, getDictionary(".inst."+ir.MethodSym(orig, method.Sym).Name, targs)) // TODO: remove .inst.
 			if indirect {
-				args = append(args, ir.NewStarExpr(base.Pos, nthis))
+				args = append(args, ir.NewStarExpr(base.Pos, dot.X))
+			} else if methodrcvr.IsPtr() && methodrcvr.Elem() == dot.X.Type() {
+				// Case where method call is via a non-pointer
+				// embedded field with a pointer method.
+				args = append(args, typecheck.NodAddrAt(base.Pos, dot.X))
 			} else {
-				args = append(args, nthis)
+				args = append(args, dot.X)
 			}
 			args = append(args, ir.ParamNames(tfn.Type())...)
 
diff --git a/test/typeparam/issue44688.go b/test/typeparam/issue44688.go
new file mode 100644
index 00000000000..d70f94f706d
--- /dev/null
+++ b/test/typeparam/issue44688.go
@@ -0,0 +1,150 @@
+// run -gcflags=-G=3
+//go:build goexperiment.unified
+// +build !goexperiment.unified
+
+// Copyright 2021 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.
+
+// derived & expanded from cmd/compile/internal/types2/testdata/fixedbugs/issue44688.go2
+
+package main
+
+type A1[T any] struct{
+	val T
+}
+
+func (p *A1[T]) m1(val T) {
+	p.val = val
+}
+
+type A2[T any] interface {
+	m2(T)
+}
+
+type B1[T any] struct {
+	filler int
+	*A1[T]
+	A2[T]
+}
+
+type B2[T any] interface {
+	A2[T]
+}
+
+type ImpA2[T any] struct {
+	f T
+}
+
+func (a2 *ImpA2[T]) m2(s T) {
+	a2.f = s
+}
+
+type C[T any] struct {
+	filler1 int
+	filler2 int
+	B1[T]
+}
+
+type D[T any] struct {
+	filler1 int
+	filler2 int
+	filler3 int
+	C[T]
+}
+
+func test1[T any](arg T) {
+	// calling embedded methods
+	var b1 B1[T]
+	b1.A1 = &A1[T]{}
+	b1.A2 = &ImpA2[T]{}
+
+	b1.A1.m1(arg)
+	b1.m1(arg)
+
+	b1.A2.m2(arg)
+	b1.m2(arg)
+
+	var b2 B2[T]
+	b2 = &ImpA2[T]{}
+	b2.m2(arg)
+
+	// a deeper nesting
+	var d D[T]
+	d.C.B1.A1 = &A1[T]{}
+	d.C.B1.A2 = &ImpA2[T]{}
+	d.m1(arg)
+	d.m2(arg)
+
+	// calling method expressions
+	m1x := B1[T].m1
+	m1x(b1, arg)
+	m2x := B2[T].m2
+	m2x(b2, arg)
+
+	// calling method values
+	m1v := b1.m1
+	m1v(arg)
+	m2v := b1.m2
+	m2v(arg)
+	b2v := b2.m2
+	b2v(arg)
+}
+
+func test2() {
+	// calling embedded methods
+	var b1 B1[string]
+	b1.A1 = &A1[string]{}
+	b1.A2 = &ImpA2[string]{}
+
+	b1.A1.m1("")
+	b1.m1("")
+
+	b1.A2.m2("")
+	b1.m2("")
+
+	var b2 B2[string]
+	b2 = &ImpA2[string]{}
+	b2.m2("")
+
+	// a deeper nesting
+	var d D[string]
+	d.C.B1.A1 = &A1[string]{}
+	d.C.B1.A2 = &ImpA2[string]{}
+	d.m1("")
+	d.m2("")
+
+	// calling method expressions
+	m1x := B1[string].m1
+	m1x(b1, "")
+	m2x := B2[string].m2
+	m2x(b2, "")
+
+	// calling method values
+	m1v := b1.m1
+	m1v("")
+	m2v := b1.m2
+	m2v("")
+	b2v := b2.m2
+	b2v("")
+}
+
+// actual test case from issue
+
+type A[T any] struct{}
+
+func (*A[T]) f(T) {}
+
+type B[T any] struct{ A[T] }
+
+func test3() {
+	var b B[string]
+	b.A.f("")
+	b.f("")
+}
+
+func main() {
+	test1[string]("")
+	test2()
+	test3()
+}

From 222ed1b38af0fb6f83f80062092a267dcbd354df Mon Sep 17 00:00:00 2001
From: siddharth 
Date: Mon, 21 Jun 2021 21:50:09 -0400
Subject: [PATCH 524/940] os: enable TestFifoEOF on openbsd

The test successfully runs on currently supported versions (6.8 and
6.9) of openbsd.

Fixes #25877

Change-Id: I2694f08c5596b486453c2ac829f17b8bc455f828
Reviewed-on: https://go-review.googlesource.com/c/go/+/329732
Run-TryBot: Ian Lance Taylor 
TryBot-Result: Go Bot 
Reviewed-by: Ian Lance Taylor 
Trust: Tobias Klauser 
---
 src/os/fifo_test.go | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/src/os/fifo_test.go b/src/os/fifo_test.go
index 9b262f8205a..007ed291293 100644
--- a/src/os/fifo_test.go
+++ b/src/os/fifo_test.go
@@ -26,9 +26,6 @@ func TestFifoEOF(t *testing.T) {
 	switch runtime.GOOS {
 	case "android":
 		t.Skip("skipping on Android; mkfifo syscall not available")
-	case "openbsd":
-		// On OpenBSD 6.2 this test just hangs for some reason.
-		t.Skip("skipping on OpenBSD; issue 25877")
 	}
 
 	dir := t.TempDir()

From 73496e0df0ba4284f460d1955ddf6bb096957c9f Mon Sep 17 00:00:00 2001
From: "Bryan C. Mills" 
Date: Tue, 22 Jun 2021 21:24:57 -0400
Subject: [PATCH 525/940] net: use absDomainName in the Windows lookupPTR test
 helper

The real net code uses subtle heuristics to transform a domain name
to its absolute form. Since lookupPTR isn't checking that
transformation specifically, it should use the real code instead of
using a different heuristic.

Fixes #46882

Change-Id: I503357e0f62059c37c359cd54b44d343c7d5ab2a
Reviewed-on: https://go-review.googlesource.com/c/go/+/330249
Trust: Bryan C. Mills 
Trust: Alex Brainman 
Run-TryBot: Bryan C. Mills 
TryBot-Result: Go Bot 
Reviewed-by: Alex Brainman 
Reviewed-by: Ian Lance Taylor 
---
 src/net/lookup_windows_test.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/net/lookup_windows_test.go b/src/net/lookup_windows_test.go
index 62b61ed6c2f..aa95501d023 100644
--- a/src/net/lookup_windows_test.go
+++ b/src/net/lookup_windows_test.go
@@ -299,7 +299,7 @@ func lookupPTR(name string) (ptr []string, err error) {
 	ptr = make([]string, 0, 10)
 	rx := regexp.MustCompile(`(?m)^Pinging\s+([a-zA-Z0-9.\-]+)\s+\[.*$`)
 	for _, ans := range rx.FindAllStringSubmatch(r, -1) {
-		ptr = append(ptr, ans[1]+".")
+		ptr = append(ptr, absDomainName([]byte(ans[1])))
 	}
 	return
 }

From 44a12e5f33bed2189735d8466b38fe455fe9b752 Mon Sep 17 00:00:00 2001
From: "Bryan C. Mills" 
Date: Wed, 23 Jun 2021 15:28:37 -0400
Subject: [PATCH 526/940] cmd/go: search breadth-first instead of depth-first
 for test dependency cycles

When we are looking for a dependency cycle involving a specific
package, we need to keep track of visited packages in order to avoid
repeatedly traversing a cycle that does not involve that package.

If we're keeping track of all visited packages anyway, we're already
spending O(N) memory on the traversal, so we may as well use
breadth-first search. That not only keeps the bookkeeping simple, but
also guarantees that we will find a shortest path (rather than a
completely arbitrary one).

Fixes #45863

Change-Id: I810c7337857e42dcb83630abbdea75021554be45
Reviewed-on: https://go-review.googlesource.com/c/go/+/330430
Trust: Bryan C. Mills 
Reviewed-by: Jay Conrod 
---
 src/cmd/go/internal/load/test.go              | 50 +++++++++++++------
 .../testdata/script/mod_list_test_cycle.txt   | 23 +++++++++
 2 files changed, 59 insertions(+), 14 deletions(-)
 create mode 100644 src/cmd/go/testdata/script/mod_list_test_cycle.txt

diff --git a/src/cmd/go/internal/load/test.go b/src/cmd/go/internal/load/test.go
index 6baa1db14f0..c8282965669 100644
--- a/src/cmd/go/internal/load/test.go
+++ b/src/cmd/go/internal/load/test.go
@@ -116,7 +116,7 @@ func TestPackagesAndErrors(ctx context.Context, opts PackageOpts, p *Package, co
 			// Can't change that code, because that code is only for loading the
 			// non-test copy of a package.
 			ptestErr = &PackageError{
-				ImportStack:   testImportStack(stk[0], p1, p.ImportPath),
+				ImportStack:   importCycleStack(p1, p.ImportPath),
 				Err:           errors.New("import cycle not allowed in test"),
 				IsImportCycle: true,
 			}
@@ -375,22 +375,44 @@ func TestPackagesAndErrors(ctx context.Context, opts PackageOpts, p *Package, co
 	return pmain, ptest, pxtest
 }
 
-func testImportStack(top string, p *Package, target string) []string {
-	stk := []string{top, p.ImportPath}
-Search:
-	for p.ImportPath != target {
-		for _, p1 := range p.Internal.Imports {
-			if p1.ImportPath == target || str.Contains(p1.Deps, target) {
-				stk = append(stk, p1.ImportPath)
-				p = p1
-				continue Search
+// importCycleStack returns an import stack from p to the package whose import
+// path is target.
+func importCycleStack(p *Package, target string) []string {
+	// importerOf maps each import path to its importer nearest to p.
+	importerOf := map[string]string{p.ImportPath: ""}
+
+	// q is a breadth-first queue of packages to search for target.
+	// Every package added to q has a corresponding entry in pathTo.
+	//
+	// We search breadth-first for two reasons:
+	//
+	// 	1. We want to report the shortest cycle.
+	//
+	// 	2. If p contains multiple cycles, the first cycle we encounter might not
+	// 	   contain target. To ensure termination, we have to break all cycles
+	// 	   other than the first.
+	q := []*Package{p}
+
+	for len(q) > 0 {
+		p := q[0]
+		q = q[1:]
+		if path := p.ImportPath; path == target {
+			var stk []string
+			for path != "" {
+				stk = append(stk, path)
+				path = importerOf[path]
+			}
+			return stk
+		}
+		for _, dep := range p.Internal.Imports {
+			if _, ok := importerOf[dep.ImportPath]; !ok {
+				importerOf[dep.ImportPath] = p.ImportPath
+				q = append(q, dep)
 			}
 		}
-		// Can't happen, but in case it does...
-		stk = append(stk, "")
-		break
 	}
-	return stk
+
+	panic("lost path to cycle")
 }
 
 // recompileForTest copies and replaces certain packages in pmain's dependency
diff --git a/src/cmd/go/testdata/script/mod_list_test_cycle.txt b/src/cmd/go/testdata/script/mod_list_test_cycle.txt
new file mode 100644
index 00000000000..755e50b0767
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_list_test_cycle.txt
@@ -0,0 +1,23 @@
+# https://golang.org/issue/45863: a typo in a test package leading to an
+# import cycle should be diagnosed, instead of causing an infinite loop.
+# The failure mode of this test prior to the fix was a timeout or OOM crash.
+
+go list -e -test -deps ./datastore/sql
+
+-- go.mod --
+module golang.org/issue45863
+
+go 1.17
+-- datastore/datastore_health.go --
+package datastore
+
+import (
+	"golang.org/issue45863/datastore"
+	"golang.org/issue45863/datastore/sql"
+)
+-- datastore/sql/sql.go --
+package sql
+-- datastore/sql/sql_test.go --
+package sql
+
+import _ "golang.org/issue45863/datastore"

From 86d72fa2cba51342ba5617abf43a732f9fd668ca Mon Sep 17 00:00:00 2001
From: Andy Pan 
Date: Wed, 23 Jun 2021 12:59:48 +0800
Subject: [PATCH 527/940] time: handle invalid UTF-8 byte sequences in quote to
 prevent panic

Fixes #46883
Updates CL 267017

Change-Id: I15c307bfb0aaa2877a148d32527681f79df1a650
Reviewed-on: https://go-review.googlesource.com/c/go/+/330289
Reviewed-by: Kevin Burke 
Reviewed-by: Ian Lance Taylor 
Run-TryBot: Ian Lance Taylor 
TryBot-Result: Go Bot 
Trust: Emmanuel Odeke 
---
 src/time/format.go    | 18 +++++++++++++++---
 src/time/time_test.go |  5 +++++
 2 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/src/time/format.go b/src/time/format.go
index 6040ed5aebc..bb173a21c2d 100644
--- a/src/time/format.go
+++ b/src/time/format.go
@@ -751,8 +751,11 @@ type ParseError struct {
 
 // These are borrowed from unicode/utf8 and strconv and replicate behavior in
 // that package, since we can't take a dependency on either.
-const runeSelf = 0x80
-const lowerhex = "0123456789abcdef"
+const (
+	lowerhex  = "0123456789abcdef"
+	runeSelf  = 0x80
+	runeError = '\uFFFD'
+)
 
 func quote(s string) string {
 	buf := make([]byte, 1, len(s)+2) // slice will be at least len(s) + quotes
@@ -765,7 +768,16 @@ func quote(s string) string {
 			// reproduce strconv.Quote's behavior with full fidelity but
 			// given how rarely we expect to hit these edge cases, speed and
 			// conciseness are better.
-			for j := 0; j < len(string(c)) && j < len(s); j++ {
+			var width int
+			if c == runeError {
+				width = 1
+				if i+2 < len(s) && s[i:i+3] == string(runeError) {
+					width = 3
+				}
+			} else {
+				width = len(string(c))
+			}
+			for j := 0; j < width; j++ {
 				buf = append(buf, `\x`...)
 				buf = append(buf, lowerhex[s[i+j]>>4])
 				buf = append(buf, lowerhex[s[i+j]&0xF])
diff --git a/src/time/time_test.go b/src/time/time_test.go
index f272bbd5587..cea5f2d3f5a 100644
--- a/src/time/time_test.go
+++ b/src/time/time_test.go
@@ -917,6 +917,11 @@ var parseDurationErrorTests = []struct {
 	{".s", `".s"`},
 	{"+.s", `"+.s"`},
 	{"1d", `"1d"`},
+	{"\x85\x85", `"\x85\x85"`},
+	{"\xffff", `"\xffff"`},
+	{"hello \xffff world", `"hello \xffff world"`},
+	{"\uFFFD", `"\xef\xbf\xbd"`},                                             // utf8.RuneError
+	{"\uFFFD hello \uFFFD world", `"\xef\xbf\xbd hello \xef\xbf\xbd world"`}, // utf8.RuneError
 	// overflow
 	{"9223372036854775810ns", `"9223372036854775810ns"`},
 	{"9223372036854775808ns", `"9223372036854775808ns"`},

From a9bb38222a06333176cafc5637083e0322277c09 Mon Sep 17 00:00:00 2001
From: "Bryan C. Mills" 
Date: Tue, 22 Jun 2021 21:48:11 -0400
Subject: [PATCH 528/940] net: remove hard-coded timeout in dialClosedPort test
 helper

The helper function claims that dialing a closed port should be
"nearly instantaneous", but that is empirically not the case on
OpenBSD or Windows. The tests do not appear to be particularly
sensitive to the exact upper bound otherwise, so let's just
remove the arbitrary latency assumption.

Fixes #46884

Change-Id: If00c9fdc3063da6aaf60d365d4a2ee2c94dc6df1
Reviewed-on: https://go-review.googlesource.com/c/go/+/330250
Trust: Bryan C. Mills 
Run-TryBot: Bryan C. Mills 
TryBot-Result: Go Bot 
Reviewed-by: Ian Lance Taylor 
---
 src/net/dial_test.go | 51 ++++++++++++++------------------------------
 1 file changed, 16 insertions(+), 35 deletions(-)

diff --git a/src/net/dial_test.go b/src/net/dial_test.go
index f899da10cf8..723038c7a22 100644
--- a/src/net/dial_test.go
+++ b/src/net/dial_test.go
@@ -155,40 +155,27 @@ func slowDialTCP(ctx context.Context, network string, laddr, raddr *TCPAddr) (*T
 	return c, err
 }
 
-func dialClosedPort(t *testing.T) (actual, expected time.Duration) {
-	// Estimate the expected time for this platform.
-	// On Windows, dialing a closed port takes roughly 1 second,
-	// but other platforms should be instantaneous.
-	if runtime.GOOS == "windows" {
-		expected = 1500 * time.Millisecond
-	} else if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
-		expected = 150 * time.Millisecond
-	} else {
-		expected = 95 * time.Millisecond
-	}
+func dialClosedPort(t *testing.T) (dialLatency time.Duration) {
+	// On most platforms, dialing a closed port should be nearly instantaneous —
+	// less than a few hundred milliseconds. However, on some platforms it may be
+	// much slower: on Windows and OpenBSD, it has been observed to take up to a
+	// few seconds.
 
 	l, err := Listen("tcp", "127.0.0.1:0")
 	if err != nil {
-		t.Logf("dialClosedPort: Listen failed: %v", err)
-		return 999 * time.Hour, expected
+		t.Fatalf("dialClosedPort: Listen failed: %v", err)
 	}
 	addr := l.Addr().String()
 	l.Close()
-	// On OpenBSD, interference from TestTCPSelfConnect is mysteriously
-	// causing the first attempt to hang for a few seconds, so we throw
-	// away the first result and keep the second.
-	for i := 1; ; i++ {
-		startTime := time.Now()
-		c, err := Dial("tcp", addr)
-		if err == nil {
-			c.Close()
-		}
-		elapsed := time.Now().Sub(startTime)
-		if i == 2 {
-			t.Logf("dialClosedPort: measured delay %v", elapsed)
-			return elapsed, expected
-		}
+
+	startTime := time.Now()
+	c, err := Dial("tcp", addr)
+	if err == nil {
+		c.Close()
 	}
+	elapsed := time.Now().Sub(startTime)
+	t.Logf("dialClosedPort: measured delay %v", elapsed)
+	return elapsed
 }
 
 func TestDialParallel(t *testing.T) {
@@ -198,10 +185,7 @@ func TestDialParallel(t *testing.T) {
 		t.Skip("both IPv4 and IPv6 are required")
 	}
 
-	closedPortDelay, expectClosedPortDelay := dialClosedPort(t)
-	if closedPortDelay > expectClosedPortDelay {
-		t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay)
-	}
+	closedPortDelay := dialClosedPort(t)
 
 	const instant time.Duration = 0
 	const fallbackDelay = 200 * time.Millisecond
@@ -675,10 +659,7 @@ func TestDialerDualStack(t *testing.T) {
 		t.Skip("both IPv4 and IPv6 are required")
 	}
 
-	closedPortDelay, expectClosedPortDelay := dialClosedPort(t)
-	if closedPortDelay > expectClosedPortDelay {
-		t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay)
-	}
+	closedPortDelay := dialClosedPort(t)
 
 	origTestHookLookupIP := testHookLookupIP
 	defer func() { testHookLookupIP = origTestHookLookupIP }()

From 9bdbf73c98b21c602f1304993176a6db0714f802 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Wed, 23 Jun 2021 14:04:11 -0700
Subject: [PATCH 529/940] [dev.typeparams] cmd/compile: simplify
 writer.collectDecls
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The previous code for walking the syntax AST to find declarations
needed to know whether a declaration appeared within block scope, but
syntax.Crawl (née syntax.Walk) made that somewhat awkward.

This CL simplifies it a little, taking advantage of syntax.Walk's
support for keeping per-subtree state.

Change-Id: I03c7da8c44bec40f88e983852dc6bbab7e6ac13c
Reviewed-on: https://go-review.googlesource.com/c/go/+/330549
Trust: Matthew Dempsky 
Run-TryBot: Matthew Dempsky 
TryBot-Result: Go Bot 
Reviewed-by: Cuong Manh Le 
---
 src/cmd/compile/internal/noder/writer.go | 170 +++++++++++++----------
 1 file changed, 96 insertions(+), 74 deletions(-)

diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go
index bc89e1a262a..889a96ef9ce 100644
--- a/src/cmd/compile/internal/noder/writer.go
+++ b/src/cmd/compile/internal/noder/writer.go
@@ -1386,89 +1386,111 @@ type typeDeclGen struct {
 	gen int
 }
 
+type fileImports struct {
+	importedEmbed, importedUnsafe bool
+}
+
+type declCollector struct {
+	pw         *pkgWriter
+	typegen    *int
+	file       *fileImports
+	withinFunc bool
+}
+
+func (c *declCollector) Visit(n syntax.Node) syntax.Visitor {
+	pw := c.pw
+
+	switch n := n.(type) {
+	case *syntax.File:
+		pw.checkPragmas(n.Pragma, ir.GoBuildPragma, false)
+
+	case *syntax.ImportDecl:
+		pw.checkPragmas(n.Pragma, 0, false)
+
+		switch pkgNameOf(pw.info, n).Imported().Path() {
+		case "embed":
+			c.file.importedEmbed = true
+		case "unsafe":
+			c.file.importedUnsafe = true
+		}
+
+	case *syntax.ConstDecl:
+		pw.checkPragmas(n.Pragma, 0, false)
+
+	case *syntax.FuncDecl:
+		pw.checkPragmas(n.Pragma, funcPragmas, false)
+
+		obj := pw.info.Defs[n.Name].(*types2.Func)
+		pw.funDecls[obj] = n
+
+	case *syntax.TypeDecl:
+		obj := pw.info.Defs[n.Name].(*types2.TypeName)
+		d := typeDeclGen{TypeDecl: n}
+
+		if n.Alias {
+			pw.checkPragmas(n.Pragma, 0, false)
+		} else {
+			pw.checkPragmas(n.Pragma, typePragmas, false)
+
+			// Assign a unique ID to function-scoped defined types.
+			if !isGlobal(obj) {
+				*c.typegen++
+				d.gen = *c.typegen
+			}
+		}
+
+		pw.typDecls[obj] = d
+
+	case *syntax.VarDecl:
+		pw.checkPragmas(n.Pragma, 0, true)
+
+		if p, ok := n.Pragma.(*pragmas); ok && len(p.Embeds) > 0 {
+			if err := checkEmbed(n, c.file.importedEmbed, c.withinFunc); err != nil {
+				pw.errorf(p.Embeds[0].Pos, "%s", err)
+			}
+		}
+
+		// Workaround for #46208. For variable declarations that
+		// declare multiple variables and have an explicit type
+		// expression, the type expression is evaluated multiple
+		// times. This affects toolstash -cmp, because iexport is
+		// sensitive to *types.Type pointer identity.
+		if quirksMode() && n.Type != nil {
+			tv, ok := pw.info.Types[n.Type]
+			assert(ok)
+			assert(tv.IsType())
+			for _, name := range n.NameList {
+				obj := pw.info.Defs[name].(*types2.Var)
+				pw.dups.add(obj.Type(), tv.Type)
+			}
+		}
+
+	case *syntax.BlockStmt:
+		if !c.withinFunc {
+			copy := *c
+			copy.withinFunc = true
+			return ©
+		}
+	}
+
+	return c
+}
+
 func (pw *pkgWriter) collectDecls(noders []*noder) {
 	var typegen int
-
 	for _, p := range noders {
-		var importedEmbed, importedUnsafe bool
+		var file fileImports
 
-		syntax.Crawl(p.file, func(n syntax.Node) bool {
-			switch n := n.(type) {
-			case *syntax.File:
-				pw.checkPragmas(n.Pragma, ir.GoBuildPragma, false)
-
-			case *syntax.ImportDecl:
-				pw.checkPragmas(n.Pragma, 0, false)
-
-				switch pkgNameOf(pw.info, n).Imported().Path() {
-				case "embed":
-					importedEmbed = true
-				case "unsafe":
-					importedUnsafe = true
-				}
-
-			case *syntax.ConstDecl:
-				pw.checkPragmas(n.Pragma, 0, false)
-
-			case *syntax.FuncDecl:
-				pw.checkPragmas(n.Pragma, funcPragmas, false)
-
-				obj := pw.info.Defs[n.Name].(*types2.Func)
-				pw.funDecls[obj] = n
-
-			case *syntax.TypeDecl:
-				obj := pw.info.Defs[n.Name].(*types2.TypeName)
-				d := typeDeclGen{TypeDecl: n}
-
-				if n.Alias {
-					pw.checkPragmas(n.Pragma, 0, false)
-				} else {
-					pw.checkPragmas(n.Pragma, typePragmas, false)
-
-					// Assign a unique ID to function-scoped defined types.
-					if !isGlobal(obj) {
-						typegen++
-						d.gen = typegen
-					}
-				}
-
-				pw.typDecls[obj] = d
-
-			case *syntax.VarDecl:
-				pw.checkPragmas(n.Pragma, 0, true)
-
-				if p, ok := n.Pragma.(*pragmas); ok && len(p.Embeds) > 0 {
-					obj := pw.info.Defs[n.NameList[0]].(*types2.Var)
-					// TODO(mdempsky): isGlobal(obj) gives false positive errors
-					// for //go:embed directives on package-scope blank
-					// variables.
-					if err := checkEmbed(n, importedEmbed, !isGlobal(obj)); err != nil {
-						pw.errorf(p.Embeds[0].Pos, "%s", err)
-					}
-				}
-
-				// Workaround for #46208. For variable declarations that
-				// declare multiple variables and have an explicit type
-				// expression, the type expression is evaluated multiple
-				// times. This affects toolstash -cmp, because iexport is
-				// sensitive to *types.Type pointer identity.
-				if quirksMode() && n.Type != nil {
-					tv, ok := pw.info.Types[n.Type]
-					assert(ok)
-					assert(tv.IsType())
-					for _, name := range n.NameList {
-						obj := pw.info.Defs[name].(*types2.Var)
-						pw.dups.add(obj.Type(), tv.Type)
-					}
-				}
-			}
-			return false
+		syntax.Walk(p.file, &declCollector{
+			pw:      pw,
+			typegen: &typegen,
+			file:    &file,
 		})
 
 		pw.cgoPragmas = append(pw.cgoPragmas, p.pragcgobuf...)
 
 		for _, l := range p.linknames {
-			if !importedUnsafe {
+			if !file.importedUnsafe {
 				pw.errorf(l.pos, "//go:linkname only allowed in Go files that import \"unsafe\"")
 				continue
 			}

From b55cc6687d8f805663e9e803ad5293d1b399ce37 Mon Sep 17 00:00:00 2001
From: Cuong Manh Le 
Date: Wed, 23 Jun 2021 23:56:01 +0700
Subject: [PATCH 530/940] [dev.typeparams] cmd/compile: use r.hasTypeParams in
 typIdx

CL 329571 fold the checking has type params logic, but did not realize
that the instance in typIdx can be folded, too.

Change-Id: I4682af3779535af6a6e843972cada12ba1bae6ae
Reviewed-on: https://go-review.googlesource.com/c/go/+/330389
Trust: Cuong Manh Le 
Run-TryBot: Cuong Manh Le 
TryBot-Result: Go Bot 
Reviewed-by: Matthew Dempsky 
---
 src/cmd/compile/internal/noder/reader.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go
index df9dccc1569..d2fe575ffd4 100644
--- a/src/cmd/compile/internal/noder/reader.go
+++ b/src/cmd/compile/internal/noder/reader.go
@@ -345,7 +345,7 @@ func (pr *pkgReader) typIdx(idx int, implicits, explicits []*types.Type) *types.
 	// TODO(mdempsky): If we're clever, we should be able to still cache
 	// types by tracking which type parameters are used. However, in my
 	// attempts so far, I haven't yet succeeded in being clever enough.
-	if len(implicits)+len(explicits) == 0 {
+	if !r.hasTypeParams() {
 		pr.typs[idx] = typ
 	}
 

From 600a2a4ffb9a273a3a1635b60120ffc768741aa9 Mon Sep 17 00:00:00 2001
From: "Bryan C. Mills" 
Date: Wed, 23 Jun 2021 23:29:10 -0400
Subject: [PATCH 531/940] cmd/go: don't try to add replaced versions that won't
 be selected

In Go 1.12, we added a heuristic to 'go mod tidy' to resolve packages
by adding replaced-but-not-required modules before falling back to
searching for modules from the network. Unfortunately, that heuristic
fails when the replaced version is already lower than the selected
version: adding such a module to the build list doesn't change the
selected version of that module, and so it doesn't make progress
toward resolving the missing package.

Fixes #46659

Change-Id: I75e2387d5290e769f6b0fa1231dcc4605db68597
Reviewed-on: https://go-review.googlesource.com/c/go/+/330432
Trust: Bryan C. Mills 
Run-TryBot: Bryan C. Mills 
TryBot-Result: Go Bot 
Reviewed-by: Jay Conrod 
---
 src/cmd/go/internal/modload/import.go         |  9 +++++
 .../testdata/script/mod_tidy_replace_old.txt  | 34 +++++++++++++++++++
 2 files changed, 43 insertions(+)
 create mode 100644 src/cmd/go/testdata/script/mod_tidy_replace_old.txt

diff --git a/src/cmd/go/internal/modload/import.go b/src/cmd/go/internal/modload/import.go
index 60bd26fb22f..d2bbe5cbe0b 100644
--- a/src/cmd/go/internal/modload/import.go
+++ b/src/cmd/go/internal/modload/import.go
@@ -428,6 +428,15 @@ func queryImport(ctx context.Context, path string, rs *Requirements) (module.Ver
 					mv = module.ZeroPseudoVersion("v0")
 				}
 			}
+			mg, err := rs.Graph(ctx)
+			if err != nil {
+				return module.Version{}, err
+			}
+			if cmpVersion(mg.Selected(mp), mv) >= 0 {
+				// We can't resolve the import by adding mp@mv to the module graph,
+				// because the selected version of mp is already at least mv.
+				continue
+			}
 			mods = append(mods, module.Version{Path: mp, Version: mv})
 		}
 
diff --git a/src/cmd/go/testdata/script/mod_tidy_replace_old.txt b/src/cmd/go/testdata/script/mod_tidy_replace_old.txt
new file mode 100644
index 00000000000..cfd3792600c
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_tidy_replace_old.txt
@@ -0,0 +1,34 @@
+# Regression test for https://golang.org/issue/46659.
+#
+# If a 'replace' directive specifies an older-than-selected version of a module,
+# 'go mod tidy' shouldn't try to add that version to the build list to resolve a
+# missing package: it won't be selected, and would cause the module loader to
+# loop indefinitely trying to resolve the package.
+
+cp go.mod go.mod.orig
+
+! go mod tidy
+! stderr panic
+stderr '^golang\.org/issue46659 imports\n\texample\.com/missingpkg/deprecated: package example\.com/missingpkg/deprecated provided by example\.com/missingpkg at latest version v1\.0\.0 but not at required version v1\.0\.1-beta$'
+
+go mod tidy -e
+
+cmp go.mod go.mod.orig
+
+-- go.mod --
+module golang.org/issue46659
+
+go 1.17
+
+replace example.com/missingpkg v1.0.1-alpha => example.com/missingpkg v1.0.0
+
+require example.com/usemissingpre v1.0.0
+
+require example.com/missingpkg v1.0.1-beta // indirect
+-- m.go --
+package m
+
+import (
+	_ "example.com/missingpkg/deprecated"
+	_ "example.com/usemissingpre"
+)

From df00abc61b415eb05d4df9fd2bf3fdda1aaaaba3 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Thu, 24 Jun 2021 09:07:52 -0700
Subject: [PATCH 532/940] [dev.typeparams] cmd/compile: skip escape analysis
 diagnostics for wrappers

This CL changes escape analysis to skip reporting diagnostics (at
least for parameter tagging) for generated wrappers.

We're inconsistent about when/where wrappers are generated, which made
errorcheck tests of escape analysis unnecessarily brittle to changes
in wrapper generation. This CL addresses this making errorcheck tests
only care about tagging of the actual functions themselves, not the
wrappers too.

Change-Id: Ia1a0b9dabee4d4162b05647f871db03b032c945a
Reviewed-on: https://go-review.googlesource.com/c/go/+/330689
Trust: Matthew Dempsky 
Run-TryBot: Matthew Dempsky 
TryBot-Result: Go Bot 
Reviewed-by: Cuong Manh Le 
---
 src/cmd/compile/internal/escape/escape.go | 17 +++++++++++------
 test/uintptrescapes2.go                   |  2 +-
 2 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/src/cmd/compile/internal/escape/escape.go b/src/cmd/compile/internal/escape/escape.go
index 324d0da3fe5..317bc98473c 100644
--- a/src/cmd/compile/internal/escape/escape.go
+++ b/src/cmd/compile/internal/escape/escape.go
@@ -365,6 +365,11 @@ func (b *batch) paramTag(fn *ir.Func, narg int, f *types.Field) string {
 		return fmt.Sprintf("arg#%d", narg)
 	}
 
+	// Only report diagnostics for user code;
+	// not for wrappers generated around them.
+	// TODO(mdempsky): Generalize this.
+	diagnose := base.Flag.LowerM != 0 && !(fn.Wrapper() || fn.Dupok())
+
 	if len(fn.Body) == 0 {
 		// Assume that uintptr arguments must be held live across the call.
 		// This is most important for syscall.Syscall.
@@ -375,7 +380,7 @@ func (b *batch) paramTag(fn *ir.Func, narg int, f *types.Field) string {
 		fn.Pragma |= ir.UintptrKeepAlive
 
 		if f.Type.IsUintptr() {
-			if base.Flag.LowerM != 0 {
+			if diagnose {
 				base.WarnfAt(f.Pos, "assuming %v is unsafe uintptr", name())
 			}
 			return ""
@@ -390,11 +395,11 @@ func (b *batch) paramTag(fn *ir.Func, narg int, f *types.Field) string {
 		// External functions are assumed unsafe, unless
 		// //go:noescape is given before the declaration.
 		if fn.Pragma&ir.Noescape != 0 {
-			if base.Flag.LowerM != 0 && f.Sym != nil {
+			if diagnose && f.Sym != nil {
 				base.WarnfAt(f.Pos, "%v does not escape", name())
 			}
 		} else {
-			if base.Flag.LowerM != 0 && f.Sym != nil {
+			if diagnose && f.Sym != nil {
 				base.WarnfAt(f.Pos, "leaking param: %v", name())
 			}
 			esc.AddHeap(0)
@@ -407,14 +412,14 @@ func (b *batch) paramTag(fn *ir.Func, narg int, f *types.Field) string {
 		fn.Pragma |= ir.UintptrKeepAlive
 
 		if f.Type.IsUintptr() {
-			if base.Flag.LowerM != 0 {
+			if diagnose {
 				base.WarnfAt(f.Pos, "marking %v as escaping uintptr", name())
 			}
 			return ""
 		}
 		if f.IsDDD() && f.Type.Elem().IsUintptr() {
 			// final argument is ...uintptr.
-			if base.Flag.LowerM != 0 {
+			if diagnose {
 				base.WarnfAt(f.Pos, "marking %v as escaping ...uintptr", name())
 			}
 			return ""
@@ -436,7 +441,7 @@ func (b *batch) paramTag(fn *ir.Func, narg int, f *types.Field) string {
 	esc := loc.paramEsc
 	esc.Optimize()
 
-	if base.Flag.LowerM != 0 && !loc.escapes {
+	if diagnose && !loc.escapes {
 		if esc.Empty() {
 			base.WarnfAt(f.Pos, "%v does not escape", name())
 		}
diff --git a/test/uintptrescapes2.go b/test/uintptrescapes2.go
index 3ff1d940425..656286c0ff2 100644
--- a/test/uintptrescapes2.go
+++ b/test/uintptrescapes2.go
@@ -30,7 +30,7 @@ type T struct{}
 func (T) M1(a uintptr) {} // ERROR "escaping uintptr"
 
 //go:uintptrescapes
-func (T) M2(a ...uintptr) {} // ERROR "escaping ...uintptr" "leaking param: a"
+func (T) M2(a ...uintptr) {} // ERROR "escaping ...uintptr"
 
 func TestF1() {
 	var t int                        // ERROR "moved to heap"

From cce621431a9bce86527b25898a01a7a693cc56a8 Mon Sep 17 00:00:00 2001
From: Cuong Manh Le 
Date: Fri, 25 Jun 2021 01:45:32 +0700
Subject: [PATCH 533/940] cmd/compile: fix wrong type in SSA generation for
 OSLICE2ARRPTR

Fixes #46907

Change-Id: I6a2728d2f2159df583b32f40f6100d3e90c34dd7
Reviewed-on: https://go-review.googlesource.com/c/go/+/330672
Trust: Cuong Manh Le 
Run-TryBot: Cuong Manh Le 
Reviewed-by: Matthew Dempsky 
TryBot-Result: Go Bot 
---
 src/cmd/compile/internal/ssagen/ssa.go |  2 +-
 test/fixedbugs/issue46907.go           | 11 +++++++++++
 2 files changed, 12 insertions(+), 1 deletion(-)
 create mode 100644 test/fixedbugs/issue46907.go

diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go
index 004e084f728..f1dc56e7297 100644
--- a/src/cmd/compile/internal/ssagen/ssa.go
+++ b/src/cmd/compile/internal/ssagen/ssa.go
@@ -3174,7 +3174,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
 		arrlen := s.constInt(types.Types[types.TINT], n.Type().Elem().NumElem())
 		cap := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], v)
 		s.boundsCheck(arrlen, cap, ssa.BoundsConvert, false)
-		return s.newValue1(ssa.OpSlicePtrUnchecked, types.Types[types.TINT], v)
+		return s.newValue1(ssa.OpSlicePtrUnchecked, n.Type(), v)
 
 	case ir.OCALLFUNC:
 		n := n.(*ir.CallExpr)
diff --git a/test/fixedbugs/issue46907.go b/test/fixedbugs/issue46907.go
new file mode 100644
index 00000000000..bd82f4f2b10
--- /dev/null
+++ b/test/fixedbugs/issue46907.go
@@ -0,0 +1,11 @@
+// compile
+
+// Copyright 2021 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
+
+func f(b []byte) []byte {
+	return (*[32]byte)(b[:32])[:]
+}

From c309c89db5aa15e1dad486c49ed4fd1babd23360 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Thu, 24 Jun 2021 10:44:39 -0700
Subject: [PATCH 534/940] reflect: document that InterfaceData is a low-entropy
 RNG

Change-Id: Ie26b9060630e2e774ac23d8492eaaf785bfca6b7
Reviewed-on: https://go-review.googlesource.com/c/go/+/330709
Reviewed-by: Ian Lance Taylor 
Trust: Matthew Dempsky 
---
 src/reflect/value.go | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/reflect/value.go b/src/reflect/value.go
index 6ba6202a1a1..9dce251ac57 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -1381,10 +1381,16 @@ func valueInterface(v Value, safe bool) interface{} {
 	return packEface(v)
 }
 
-// InterfaceData returns the interface v's value as a uintptr pair.
+// InterfaceData returns a pair of unspecified uintptr values.
 // It panics if v's Kind is not Interface.
+//
+// In earlier versions of Go, this function returned the interface's
+// value as a uintptr pair. As of Go 1.4, the implementation of
+// interface values precludes any defined use of InterfaceData.
+//
+// Deprecated: The memory representation of interface values is not
+// compatible with InterfaceData.
 func (v Value) InterfaceData() [2]uintptr {
-	// TODO: deprecate this
 	v.mustBe(Interface)
 	// We treat this as a read operation, so we allow
 	// it even for unexported data, because the caller

From ddb09af1b85ee9ae278ef338df56c4d91c1acd0d Mon Sep 17 00:00:00 2001
From: Dan Scales 
Date: Mon, 7 Jun 2021 18:13:15 -0700
Subject: [PATCH 535/940] [dev.typeparams] cmd/compile:  add derived types and
 subdictionaries to dictionaries

This is code in progress to generate the two main other types of entries
in dictionaries:
 - all types in the instantiated function derived from the type
   arguments (which are currently concrete, but will eventually be
   gcshapes)
 - pointers (i.e. mainly the unique name) to all needed sub-dictionaries

In order to generate these entries, we now generate cached information
gfInfo about generic functions/methods that can be used for creating the
instantiated dictionaries. We use the type substituter to compute the
right type args for instantiated sub-dictionaries.

If infoPrintMode is changed to true, the code prints out all the
information gathered about generic functions, and also the entries in
all the dictionaries that are instantiated. The debug mode also prints
out the locations where we need main dictionaries in non-instantiated
functions.

Other changes:
 - Moved the dictionary generation back to stencil.go from reflect.go,
   since we need to do extra analysis for the new dictionary entries. In
   the process, made getInstantiation generate both the function
   instantiation and the associated dictionary.

 - Put in small change for now in reflect.go, so that we don't try
   generate separate dictionaries for Value[T].get and the
   auto-generated (*Value[T]).get.  The auto-generated wrapper shouldn't really
   need a dictionary.

 - Detected, but not handling yet, a new case which needs
   dictionaries - closures that have function params or captured
   variables whose types are derived from type arguments.

 - Added new tests in dictionaryCapture for use of method
   value/expressions in generic functions and for mutually recursive
   generic functions.

Change-Id: If0cbde8805a9f673a23f5ec798769c85c9c5359b
Reviewed-on: https://go-review.googlesource.com/c/go/+/327311
Trust: Dan Scales 
Run-TryBot: Dan Scales 
TryBot-Result: Go Bot 
Reviewed-by: Keith Randall 
---
 src/cmd/compile/internal/ir/expr.go           |   5 +
 src/cmd/compile/internal/noder/irgen.go       |  13 +
 src/cmd/compile/internal/noder/stencil.go     | 306 ++++++++++++++++--
 .../compile/internal/reflectdata/reflect.go   |  63 ++--
 test/typeparam/dictionaryCapture.go           |  66 ++++
 5 files changed, 398 insertions(+), 55 deletions(-)

diff --git a/src/cmd/compile/internal/ir/expr.go b/src/cmd/compile/internal/ir/expr.go
index 4659b99fbf7..81b2c52b87f 100644
--- a/src/cmd/compile/internal/ir/expr.go
+++ b/src/cmd/compile/internal/ir/expr.go
@@ -700,6 +700,11 @@ func (n *UnaryExpr) SetOp(op Op) {
 	}
 }
 
+// Probably temporary: using Implicit() flag to mark generic function nodes that
+// are called to make getGfInfo analysis easier in one pre-order pass.
+func (n *InstExpr) Implicit() bool     { return n.flags&miniExprImplicit != 0 }
+func (n *InstExpr) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) }
+
 // An InstExpr is a generic function or type instantiation.
 type InstExpr struct {
 	miniExpr
diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go
index 9d14b06d3c8..8f390612506 100644
--- a/src/cmd/compile/internal/noder/irgen.go
+++ b/src/cmd/compile/internal/noder/irgen.go
@@ -96,6 +96,15 @@ func check2(noders []*noder) {
 	}
 }
 
+// gfInfo is information gathered on a generic function.
+type gfInfo struct {
+	tparams      []*types.Type
+	derivedTypes []*types.Type
+	// Node in generic function that requires a subdictionary. Some of these
+	// are not function/method values (not strictly calls).
+	subDictCalls []ir.Node
+}
+
 type irgen struct {
 	target *ir.Package
 	self   *types2.Package
@@ -110,6 +119,10 @@ type irgen struct {
 	instTypeList []*types.Type
 
 	dnum int // for generating unique dictionary variables
+
+	// Map from generic function to information about its type params, derived
+	// types, and subdictionaries.
+	gfInfoMap map[*types.Sym]*gfInfo
 }
 
 func (g *irgen) generate(noders []*noder) {
diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go
index 710289b76c0..1917c95be71 100644
--- a/src/cmd/compile/internal/noder/stencil.go
+++ b/src/cmd/compile/internal/noder/stencil.go
@@ -10,12 +10,15 @@ package noder
 import (
 	"cmd/compile/internal/base"
 	"cmd/compile/internal/ir"
+	"cmd/compile/internal/objw"
 	"cmd/compile/internal/reflectdata"
 	"cmd/compile/internal/typecheck"
 	"cmd/compile/internal/types"
+	"cmd/internal/obj"
 	"cmd/internal/src"
 	"fmt"
 	"go/constant"
+	"strings"
 )
 
 func assert(p bool) {
@@ -24,6 +27,16 @@ func assert(p bool) {
 	}
 }
 
+// Temporary - for outputting information on derived types, dictionaries, sub-dictionaries.
+// Turn off when running tests.
+var infoPrintMode = false
+
+func infoPrint(format string, a ...interface{}) {
+	if infoPrintMode {
+		fmt.Printf(format, a...)
+	}
+}
+
 // stencil scans functions for instantiated generic function calls and creates the
 // required instantiations for simple generic functions. It also creates
 // instantiated methods for all fully-instantiated generic types that have been
@@ -31,6 +44,7 @@ func assert(p bool) {
 // process.
 func (g *irgen) stencil() {
 	g.target.Stencils = make(map[*types.Sym]*ir.Func)
+	g.gfInfoMap = make(map[*types.Sym]*gfInfo)
 
 	// Instantiate the methods of instantiated generic types that we have seen so far.
 	g.instantiateMethods()
@@ -87,7 +101,14 @@ func (g *irgen) stencil() {
 				// instantiation.
 				call := n.(*ir.CallExpr)
 				inst := call.X.(*ir.InstExpr)
-				st := g.getInstantiationForNode(inst)
+				st, dict := g.getInstantiationForNode(inst)
+				if infoPrintMode && g.target.Stencils[decl.Sym()] == nil {
+					if inst.X.Op() == ir.OCALLPART {
+						fmt.Printf("Main dictionary in %v at generic method call: %v - %v\n", decl, inst.X, call)
+					} else {
+						fmt.Printf("Main dictionary in %v at generic function call: %v - %v\n", decl, inst.X, call)
+					}
+				}
 				// Replace the OFUNCINST with a direct reference to the
 				// new stenciled function
 				call.X = st.Nname
@@ -99,7 +120,6 @@ func (g *irgen) stencil() {
 					call.Args.Prepend(inst.X.(*ir.SelectorExpr).X)
 				}
 				// Add dictionary to argument list.
-				dict := reflectdata.GetDictionaryForInstantiation(inst)
 				call.Args.Prepend(dict)
 				// Transform the Call now, which changes OCALL
 				// to OCALLFUNC and does typecheckaste/assignconvfn.
@@ -125,10 +145,9 @@ func (g *irgen) stencil() {
 					}
 				}
 
-				st := g.getInstantiation(gf, targs, true)
+				st, dict := g.getInstantiation(gf, targs, true)
 				call.SetOp(ir.OCALL)
 				call.X = st.Nname
-				dict := reflectdata.GetDictionaryForMethod(gf, targs)
 				call.Args.Prepend(dict, meth.X)
 				// Transform the Call now, which changes OCALL
 				// to OCALLFUNC and does typecheckaste/assignconvfn.
@@ -212,13 +231,14 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
 		// For functions, the target expects a dictionary as its first argument.
 		// For method values, the target expects a dictionary and the receiver
 		// as its first two arguments.
-		target = g.getInstantiation(gf, targs, rcvrValue != nil)
-
-		// The value to use for the dictionary argument.
-		if rcvrValue == nil {
-			dictValue = reflectdata.GetDictionaryForFunc(gf, targs)
-		} else {
-			dictValue = reflectdata.GetDictionaryForMethod(gf, targs)
+		// dictValue is the value to use for the dictionary argument.
+		target, dictValue = g.getInstantiation(gf, targs, rcvrValue != nil)
+		if infoPrintMode && (outer == nil || g.target.Stencils[outer.Sym()] == nil) {
+			if rcvrValue == nil {
+				fmt.Printf("Main dictionary in %v for function value %v\n", outer, inst.X)
+			} else {
+				fmt.Printf("Main dictionary in %v for method value %v\n", outer, inst.X)
+			}
 		}
 	} else { // ir.OMETHEXPR
 		// Method expression T.M where T is a generic type.
@@ -248,8 +268,10 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
 				break
 			}
 		}
-		target = g.getInstantiation(gf, targs, true)
-		dictValue = reflectdata.GetDictionaryForMethod(gf, targs)
+		target, dictValue = g.getInstantiation(gf, targs, true)
+		if infoPrintMode && (outer == nil || g.target.Stencils[outer.Sym()] == nil) {
+			fmt.Printf("Main dictionary in %v for method expression %v\n", outer, x)
+		}
 	}
 
 	// Build a closure to implement a function instantiation.
@@ -444,7 +466,7 @@ func (g *irgen) instantiateMethods() {
 		baseType := baseSym.Def.(*ir.Name).Type()
 		for j, _ := range typ.Methods().Slice() {
 			baseNname := baseType.Methods().Slice()[j].Nname.(*ir.Name)
-			// Eagerly generate the instantiations that implement these methods.
+			// Eagerly generate the instantiations and dictionaries that implement these methods.
 			// We don't use the instantiations here, just generate them (and any
 			// further instantiations those generate, etc.).
 			// Note that we don't set the Func for any methods on instantiated
@@ -452,16 +474,16 @@ func (g *irgen) instantiateMethods() {
 			// Direct method calls go directly to the instantiations, implemented above.
 			// Indirect method calls use wrappers generated in reflectcall. Those wrappers
 			// will use these instantiations if they are needed (for interface tables or reflection).
-			_ = g.getInstantiation(baseNname, typ.RParams(), true)
+			_, _ = g.getInstantiation(baseNname, typ.RParams(), true)
 		}
 	}
 	g.instTypeList = nil
 
 }
 
-// getInstantiationForNode returns the function/method instantiation for a
-// InstExpr node inst.
-func (g *irgen) getInstantiationForNode(inst *ir.InstExpr) *ir.Func {
+// getInstantiationForNode returns the function/method instantiation and
+// dictionary value for a InstExpr node inst.
+func (g *irgen) getInstantiationForNode(inst *ir.InstExpr) (*ir.Func, ir.Node) {
 	if meth, ok := inst.X.(*ir.SelectorExpr); ok {
 		return g.getInstantiation(meth.Selection.Nname.(*ir.Name), typecheck.TypesOf(inst.Targs), true)
 	} else {
@@ -469,10 +491,10 @@ func (g *irgen) getInstantiationForNode(inst *ir.InstExpr) *ir.Func {
 	}
 }
 
-// getInstantiation gets the instantiantion of the function or method nameNode
+// getInstantiation gets the instantiantion and dictionary of the function or method nameNode
 // with the type arguments targs. If the instantiated function is not already
 // cached, then it calls genericSubst to create the new instantiation.
-func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth bool) *ir.Func {
+func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth bool) (*ir.Func, ir.Node) {
 	if nameNode.Func.Body == nil && nameNode.Func.Inl != nil {
 		// If there is no body yet but Func.Inl exists, then we can can
 		// import the whole generic body.
@@ -497,7 +519,7 @@ func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth
 			ir.Dump(fmt.Sprintf("\nstenciled %v", st), st)
 		}
 	}
-	return st
+	return st, g.getDictionary(sym.Name, nameNode, targs)
 }
 
 // Struct containing info needed for doing the substitution as we create the
@@ -994,3 +1016,245 @@ func deref(t *types.Type) *types.Type {
 	}
 	return t
 }
+
+// getDictionary returns the dictionary for the named instantiated function, which
+// is instantiated from generic function or method gf, with the type arguments targs.
+func (g *irgen) getDictionary(name string, gf *ir.Name, targs []*types.Type) ir.Node {
+	if len(targs) == 0 {
+		base.Fatalf("%s should have type arguments", name)
+	}
+
+	// The dictionary for this instantiation is named after the function
+	// and concrete types it is instantiated with.
+	// TODO: decouple this naming from the instantiation naming. The instantiation
+	// naming will be based on GC shapes, this naming must be fully stenciled.
+	if !strings.HasPrefix(name, ".inst.") {
+		base.Fatalf("%s should start in .inst.", name)
+	}
+
+	info := g.getGfInfo(gf)
+
+	name = ".dict." + name[6:]
+
+	// Get a symbol representing the dictionary.
+	sym := typecheck.Lookup(name)
+
+	// Initialize the dictionary, if we haven't yet already.
+	if lsym := sym.Linksym(); len(lsym.P) == 0 {
+		infoPrint("Creating dictionary %v\n", name)
+		off := 0
+		// Emit an entry for each targ (concrete type or gcshape).
+		for _, t := range targs {
+			infoPrint(" * %v\n", t)
+			s := reflectdata.TypeLinksym(t)
+			off = objw.SymPtr(lsym, off, s, 0)
+		}
+		subst := typecheck.Tsubster{
+			Tparams: info.tparams,
+			Targs:   targs,
+		}
+		// Emit an entry for each derived type (after substituting targs)
+		for _, t := range info.derivedTypes {
+			ts := subst.Typ(t)
+			infoPrint(" - %v\n", ts)
+			s := reflectdata.TypeLinksym(ts)
+			off = objw.SymPtr(lsym, off, s, 0)
+		}
+		// Emit an entry for each subdictionary (after substituting targs)
+		// TODO: actually emit symbol for the subdictionary entry
+		for _, n := range info.subDictCalls {
+			if n.Op() == ir.OCALL {
+				call := n.(*ir.CallExpr)
+				if call.X.Op() == ir.OXDOT {
+					subtargs := deref(n.(*ir.CallExpr).X.(*ir.SelectorExpr).X.Type()).RParams()
+					s2targs := make([]*types.Type, len(subtargs))
+					for i, t := range subtargs {
+						s2targs[i] = subst.Typ(t)
+					}
+					sym := typecheck.MakeInstName(ir.MethodSym(call.X.(*ir.SelectorExpr).X.Type(), call.X.(*ir.SelectorExpr).Sel), s2targs, true)
+					infoPrint(" - Subdict .dict.%v\n", sym.Name[6:])
+				} else {
+					inst := n.(*ir.CallExpr).X.(*ir.InstExpr)
+					var nameNode *ir.Name
+					var meth *ir.SelectorExpr
+					var isMeth bool
+					if meth, isMeth = inst.X.(*ir.SelectorExpr); isMeth {
+						nameNode = meth.Selection.Nname.(*ir.Name)
+					} else {
+						nameNode = inst.X.(*ir.Name)
+					}
+					subtargs := typecheck.TypesOf(inst.Targs)
+					for i, t := range subtargs {
+						subtargs[i] = subst.Typ(t)
+					}
+					sym := typecheck.MakeInstName(nameNode.Sym(), subtargs, isMeth)
+					// TODO: This can actually be a static
+					// main dictionary, if all of the subtargs
+					// are concrete types (!HasTParam)
+					infoPrint(" - Subdict .dict.%v\n", sym.Name[6:])
+				}
+			} else if n.Op() == ir.OFUNCINST {
+				inst := n.(*ir.InstExpr)
+				nameNode := inst.X.(*ir.Name)
+				subtargs := typecheck.TypesOf(inst.Targs)
+				for i, t := range subtargs {
+					subtargs[i] = subst.Typ(t)
+				}
+				sym := typecheck.MakeInstName(nameNode.Sym(), subtargs, false)
+				// TODO: This can actually be a static
+				// main dictionary, if all of the subtargs
+				// are concrete types (!HasTParam)
+				infoPrint(" - Subdict .dict.%v\n", sym.Name[6:])
+			} else if n.Op() == ir.OXDOT {
+				selExpr := n.(*ir.SelectorExpr)
+				subtargs := selExpr.X.Type().RParams()
+				s2targs := make([]*types.Type, len(subtargs))
+				for i, t := range subtargs {
+					s2targs[i] = subst.Typ(t)
+				}
+				sym := typecheck.MakeInstName(ir.MethodSym(selExpr.X.Type(), selExpr.Sel), s2targs, true)
+				infoPrint(" - Subdict .dict.%v\n", sym.Name[6:])
+			}
+			// TODO: handle closure cases that need sub-dictionaries
+		}
+		objw.Global(lsym, int32(off), obj.DUPOK|obj.RODATA)
+	}
+
+	// Make a node referencing the dictionary symbol.
+	n := typecheck.NewName(sym)
+	n.SetType(types.Types[types.TUINTPTR]) // should probably be [...]uintptr, but doesn't really matter
+	n.SetTypecheck(1)
+	n.Class = ir.PEXTERN
+	sym.Def = n
+
+	// Return the address of the dictionary.
+	np := typecheck.NodAddr(n)
+	// Note: treat dictionary pointers as uintptrs, so they aren't pointers
+	// with respect to GC. That saves on stack scanning work, write barriers, etc.
+	// We can get away with it because dictionaries are global variables.
+	// TODO: use a cast, or is typing directly ok?
+	np.SetType(types.Types[types.TUINTPTR])
+	np.SetTypecheck(1)
+	return np
+}
+
+// getGfInfo get information for a generic function - type params, derived generic
+// types, and subdictionaries.
+func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo {
+	infop := g.gfInfoMap[gn.Sym()]
+	if infop != nil {
+		return infop
+	}
+
+	var info gfInfo
+	gf := gn.Func
+	recv := gf.Type().Recv()
+	if recv != nil {
+		info.tparams = deref(recv.Type).RParams()
+	} else {
+		info.tparams = make([]*types.Type, len(gn.Type().TParams().FieldSlice()))
+		for i, f := range gn.Type().TParams().FieldSlice() {
+			info.tparams[i] = f.Type
+		}
+	}
+	for _, n := range gf.Dcl {
+		addType(&info, n, n.Type())
+	}
+
+	if infoPrintMode {
+		fmt.Printf(">>> Info for %v\n", gn)
+		for _, t := range info.tparams {
+			fmt.Printf("  Typeparam %v\n", t)
+		}
+		for _, t := range info.derivedTypes {
+			fmt.Printf("  Derived type %v\n", t)
+		}
+	}
+
+	for _, stmt := range gf.Body {
+		ir.Visit(stmt, func(n ir.Node) {
+			if n.Op() == ir.OFUNCINST && !n.(*ir.InstExpr).Implicit() {
+				infoPrint("  Closure&subdictionary required at generic function value %v\n", n.(*ir.InstExpr).X)
+				info.subDictCalls = append(info.subDictCalls, n)
+			} else if n.Op() == ir.OXDOT && !n.(*ir.SelectorExpr).Implicit() &&
+				!n.(*ir.SelectorExpr).X.Type().IsInterface() &&
+				len(n.(*ir.SelectorExpr).X.Type().RParams()) > 0 {
+				// Fix this - doesn't account for embedded fields, etc.
+				field := typecheck.Lookdot1(n.(*ir.SelectorExpr), n.(*ir.SelectorExpr).Sel, n.(*ir.SelectorExpr).X.Type(), n.(*ir.SelectorExpr).X.Type().Fields(), 0)
+				if field == nil {
+					if n.(*ir.SelectorExpr).X.Op() == ir.OTYPE {
+						infoPrint("  Closure&subdictionary required at generic meth expr %v\n", n)
+					} else {
+						infoPrint("  Closure&subdictionary required at generic meth value %v\n", n)
+					}
+					info.subDictCalls = append(info.subDictCalls, n)
+				}
+			}
+			if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OFUNCINST {
+				infoPrint("  Subdictionary at generic function call: %v - %v\n", n.(*ir.CallExpr).X.(*ir.InstExpr).X, n)
+				n.(*ir.CallExpr).X.(*ir.InstExpr).SetImplicit(true)
+				info.subDictCalls = append(info.subDictCalls, n)
+			}
+			if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OXDOT &&
+				!n.(*ir.CallExpr).X.(*ir.SelectorExpr).X.Type().IsInterface() &&
+				len(deref(n.(*ir.CallExpr).X.(*ir.SelectorExpr).X.Type()).RParams()) > 0 {
+				infoPrint("  Subdictionary at generic method call: %v\n", n)
+				n.(*ir.CallExpr).X.(*ir.SelectorExpr).SetImplicit(true)
+				info.subDictCalls = append(info.subDictCalls, n)
+			}
+			if n.Op() == ir.OCLOSURE {
+				oldfn := n.(*ir.ClosureExpr).Func
+				needDict := false
+				if oldfn.Nname.Type().HasTParam() {
+					needDict = true
+					infoPrint("  Subdictionary for closure that has generic params: %v\n", oldfn)
+				} else {
+					for _, cv := range oldfn.ClosureVars {
+						if cv.Type().HasTParam() {
+							needDict = true
+							infoPrint("  Subdictionary for closure that has generic capture: %v\n", oldfn)
+							break
+						}
+					}
+				}
+				if needDict {
+					info.subDictCalls = append(info.subDictCalls, n)
+				}
+			}
+
+			addType(&info, n, n.Type())
+		})
+	}
+	g.gfInfoMap[gn.Sym()] = &info
+	return &info
+}
+
+// addType adds t to info.derivedTypes if it is parameterized type (which is not
+// just a simple type param) that is different from any existing type on
+// info.derivedTypes.
+func addType(info *gfInfo, n ir.Node, t *types.Type) {
+	if t == nil || !t.HasTParam() {
+		return
+	}
+	if t.IsTypeParam() && t.Underlying() == t {
+		return
+	}
+	if t.Kind() == types.TFUNC && n != nil &&
+		(n.Op() != ir.ONAME || n.Name().Class == ir.PFUNC) {
+		// For now, only record function types that are associate with a
+		// local/global variable (a name which is not a named global
+		// function).
+		return
+	}
+	if t.Kind() == types.TSTRUCT && t.IsFuncArgStruct() {
+		// Multiple return values are not a relevant new type (?).
+		return
+	}
+	// Ignore a derived type we've already added.
+	for _, et := range info.derivedTypes {
+		if types.Identical(t, et) {
+			return
+		}
+	}
+	info.derivedTypes = append(info.derivedTypes, t)
+}
diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go
index 52534db70d0..8378fab36d9 100644
--- a/src/cmd/compile/internal/reflectdata/reflect.go
+++ b/src/cmd/compile/internal/reflectdata/reflect.go
@@ -1716,8 +1716,12 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
 		rcvr = rcvr.PtrTo()
 	}
 	generic := false
-	if !rcvr.IsInterface() && len(rcvr.RParams()) > 0 || rcvr.IsPtr() && len(rcvr.Elem().RParams()) > 0 { // TODO: right detection?
-		// TODO: check that we do the right thing when rcvr.IsInterface().
+	if !types.IsInterfaceMethod(method.Type) &&
+		(len(rcvr.RParams()) > 0 ||
+			rcvr.IsPtr() && len(rcvr.Elem().RParams()) > 0) { // TODO: right detection?
+		// Don't need dictionary if we are reaching a method (possibly via
+		// an embedded field) which is an interface method.
+		// TODO: check that we do the right thing when method is an interface method.
 		generic = true
 	}
 	if base.Debug.Unified != 0 {
@@ -1786,12 +1790,6 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
 	}
 
 	dot := typecheck.AddImplicitDots(ir.NewSelectorExpr(base.Pos, ir.OXDOT, nthis, method.Sym))
-	if generic && dot.X != nthis && dot.X.Type().IsInterface() {
-		// We followed some embedded fields, and the last type was
-		// actually an interface, so no need for a dictionary.
-		generic = false
-	}
-
 	// generate call
 	// It's not possible to use a tail call when dynamic linking on ppc64le. The
 	// bad scenario is when a local call is made to the wrapper: the wrapper will
@@ -1815,6 +1813,14 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
 	} else {
 		fn.SetWrapper(true) // ignore frame for panic+recover matching
 		var call *ir.CallExpr
+
+		if generic && dot.X != nthis {
+			// TODO: for now, we don't try to generate dictionary wrappers for
+			// any methods involving embedded fields, because we're not
+			// generating the needed dictionaries in instantiateMethods.
+			generic = false
+		}
+
 		if generic {
 			var args []ir.Node
 			var targs []*types.Type
@@ -1827,7 +1833,17 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
 				fmt.Printf("%s\n", ir.MethodSym(orig, method.Sym).Name)
 				panic("multiple .inst.")
 			}
-			args = append(args, getDictionary(".inst."+ir.MethodSym(orig, method.Sym).Name, targs)) // TODO: remove .inst.
+			// Temporary fix: the wrapper for an auto-generated
+			// pointer/non-pointer receiver method should share the
+			// same dictionary as the corresponding original
+			// (user-written) method.
+			baseOrig := orig
+			if baseOrig.IsPtr() && !method.Type.Recv().Type.IsPtr() {
+				baseOrig = baseOrig.Elem()
+			} else if !baseOrig.IsPtr() && method.Type.Recv().Type.IsPtr() {
+				baseOrig = types.NewPtr(baseOrig)
+			}
+			args = append(args, getDictionary(".inst."+ir.MethodSym(baseOrig, method.Sym).Name, targs)) // TODO: remove .inst.
 			if indirect {
 				args = append(args, ir.NewStarExpr(base.Pos, dot.X))
 			} else if methodrcvr.IsPtr() && methodrcvr.Elem() == dot.X.Type() {
@@ -1852,6 +1868,9 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
 			}
 			target := ir.AsNode(sym.Def)
 			call = ir.NewCallExpr(base.Pos, ir.OCALL, target, args)
+			// Fill-in the generic method node that was not filled in
+			// in instantiateMethod.
+			method.Nname = fn.Nname
 		} else {
 			call = ir.NewCallExpr(base.Pos, ir.OCALL, dot, nil)
 			call.Args = ir.ParamNames(tfn.Type())
@@ -1924,23 +1943,6 @@ func MarkUsedIfaceMethod(n *ir.CallExpr) {
 	r.Type = objabi.R_USEIFACEMETHOD
 }
 
-// getDictionaryForInstantiation returns the dictionary that should be used for invoking
-// the concrete instantiation described by inst.
-func GetDictionaryForInstantiation(inst *ir.InstExpr) ir.Node {
-	targs := typecheck.TypesOf(inst.Targs)
-	if meth, ok := inst.X.(*ir.SelectorExpr); ok {
-		return GetDictionaryForMethod(meth.Selection.Nname.(*ir.Name), targs)
-	}
-	return GetDictionaryForFunc(inst.X.(*ir.Name), targs)
-}
-
-func GetDictionaryForFunc(fn *ir.Name, targs []*types.Type) ir.Node {
-	return getDictionary(typecheck.MakeInstName(fn.Sym(), targs, false).Name, targs)
-}
-func GetDictionaryForMethod(meth *ir.Name, targs []*types.Type) ir.Node {
-	return getDictionary(typecheck.MakeInstName(meth.Sym(), targs, true).Name, targs)
-}
-
 // getDictionary returns the dictionary for the given named generic function
 // or method, with the given type arguments.
 // TODO: pass a reference to the generic function instead? We might need
@@ -1964,14 +1966,7 @@ func getDictionary(name string, targs []*types.Type) ir.Node {
 
 	// Initialize the dictionary, if we haven't yet already.
 	if lsym := sym.Linksym(); len(lsym.P) == 0 {
-		off := 0
-		// Emit an entry for each concrete type.
-		for _, t := range targs {
-			s := TypeLinksym(t)
-			off = objw.SymPtr(lsym, off, s, 0)
-		}
-		// TODO: subdictionaries
-		objw.Global(lsym, int32(off), obj.DUPOK|obj.RODATA)
+		base.Fatalf("Dictionary should have alredy been generated: %v", sym)
 	}
 
 	// Make a node referencing the dictionary symbol.
diff --git a/test/typeparam/dictionaryCapture.go b/test/typeparam/dictionaryCapture.go
index 1b2ee1de910..af508859e1c 100644
--- a/test/typeparam/dictionaryCapture.go
+++ b/test/typeparam/dictionaryCapture.go
@@ -10,12 +10,19 @@
 
 package main
 
+import (
+	"fmt"
+)
+
 func main() {
 	functions()
 	methodExpressions()
+	genMethodExpressions[int](7)
 	methodValues()
+	genMethodValues[int](7)
 	interfaceMethods()
 	globals()
+	recursive()
 }
 
 func g0[T any](x T) {
@@ -72,6 +79,20 @@ func methodExpressions() {
 	is77(f2(x))
 }
 
+func genMethodExpressions[T comparable](want T) {
+	x := s[T]{a: want}
+	f0 := s[T].g0
+	f0(x)
+	f1 := s[T].g1
+	if got := f1(x); got != want {
+		panic(fmt.Sprintf("f1(x) == %d, want %d", got, want))
+	}
+	f2 := s[T].g2
+	if got1, got2 := f2(x); got1 != want || got2 != want {
+		panic(fmt.Sprintf("f2(x) == %d, %d, want %d, %d", got1, got2, want, want))
+	}
+}
+
 func methodValues() {
 	x := s[int]{a:7}
 	f0 := x.g0
@@ -82,6 +103,20 @@ func methodValues() {
 	is77(f2())
 }
 
+func genMethodValues[T comparable](want T) {
+	x := s[T]{a: want}
+	f0 := x.g0
+	f0()
+	f1 := x.g1
+	if got := f1(); got != want {
+		panic(fmt.Sprintf("f1() == %d, want %d", got, want))
+	}
+	f2 := x.g2
+	if got1, got2 := f2(); got1 != want || got2 != want {
+		panic(fmt.Sprintf("f2() == %d, %d, want %d, %d", got1, got2, want, want))
+	}
+}
+
 var x interface{
 	g0()
 	g1()int
@@ -124,3 +159,34 @@ func globals() {
 	is7(ii1())
 	is77(ii2())
 }
+
+
+func recursive() {
+	if got, want := recur1[int](5), 110; got != want {
+		panic(fmt.Sprintf("recur1[int](5) = %d, want = %d", got, want))
+	}
+}
+
+type Integer interface {
+	int | int32 | int64
+}
+
+func recur1[T Integer](n T) T {
+	if n == 0 || n == 1 {
+		return T(1)
+	} else {
+		return n * recur2(n - 1)
+	}
+}
+
+func recur2[T Integer](n T) T {
+	list := make([]T, n)
+	for i, _ := range list {
+		list[i] = T(i+1)
+	}
+	var sum T
+	for _, elt := range list {
+		sum += elt
+	}
+	return sum + recur1(n-1)
+}

From 808dca3b2d305570b3f1e003ff221557405f59b9 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Thu, 24 Jun 2021 12:57:20 -0700
Subject: [PATCH 536/940] [dev.typeparams] cmd/compile: suppress liveness
 diagnostics of wrappers

Similar to the previous CL to suppress escape analysis diagnostics for
method wrappers, suppress liveness analysis diagnostics too. It's
hardly useful to know that all of a wrapper method's arguments are
live at entry.

Change-Id: I0d1e44552c6334ee3b454adc107430232abcb56a
Reviewed-on: https://go-review.googlesource.com/c/go/+/330749
Trust: Matthew Dempsky 
Run-TryBot: Matthew Dempsky 
TryBot-Result: Go Bot 
Reviewed-by: Cuong Manh Le 
---
 src/cmd/compile/internal/liveness/plive.go | 4 ++++
 test/live.go                               | 2 +-
 test/live_regabi.go                        | 2 +-
 3 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/cmd/compile/internal/liveness/plive.go b/src/cmd/compile/internal/liveness/plive.go
index f5c2ef7709e..2705eac4f7b 100644
--- a/src/cmd/compile/internal/liveness/plive.go
+++ b/src/cmd/compile/internal/liveness/plive.go
@@ -1082,6 +1082,10 @@ func (lv *liveness) showlive(v *ssa.Value, live bitvec.BitVec) {
 	if base.Flag.Live == 0 || ir.FuncName(lv.fn) == "init" || strings.HasPrefix(ir.FuncName(lv.fn), ".") {
 		return
 	}
+	if lv.fn.Wrapper() || lv.fn.Dupok() {
+		// Skip reporting liveness information for compiler-generated wrappers.
+		return
+	}
 	if !(v == nil || v.Op.IsCall()) {
 		// Historically we only printed this information at
 		// calls. Keep doing so.
diff --git a/test/live.go b/test/live.go
index 5b14932cae9..856e56f3d29 100644
--- a/test/live.go
+++ b/test/live.go
@@ -688,7 +688,7 @@ type T struct{}
 
 func (*T) Foo(ptr *int) {}
 
-type R struct{ *T } // ERRORAUTO "live at entry to \(\*R\)\.Foo: \.this ptr" "live at entry to R\.Foo: \.this ptr"
+type R struct{ *T }
 
 // issue 18860: output arguments must be live all the time if there is a defer.
 // In particular, at printint r must be live.
diff --git a/test/live_regabi.go b/test/live_regabi.go
index c35a27e4e08..d362ee287d0 100644
--- a/test/live_regabi.go
+++ b/test/live_regabi.go
@@ -683,7 +683,7 @@ type T struct{}
 
 func (*T) Foo(ptr *int) {}
 
-type R struct{ *T } // ERRORAUTO "live at entry to \(\*R\)\.Foo: \.this ptr" "live at entry to R\.Foo: \.this ptr"
+type R struct{ *T }
 
 // issue 18860: output arguments must be live all the time if there is a defer.
 // In particular, at printint r must be live.

From 75ad32377378b4d6fa831b67a7f6aaf68cbe07d4 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Thu, 24 Jun 2021 14:32:21 -0700
Subject: [PATCH 537/940] [dev.typeparams] test: skip -G=3 testing under
 GOEXPERIMENT=unified

In normal build configurations, we test both -G=0 and -G=3 so that we
can test both typecheck and types2. However, GOEXPERIMENT=unified
always uses types2, so testing both is redundant.

Change-Id: I697d2ad916d8b17cfaf4f0b6b32eec380d4e7906
Reviewed-on: https://go-review.googlesource.com/c/go/+/330755
Run-TryBot: Matthew Dempsky 
Trust: Matthew Dempsky 
Reviewed-by: Robert Griesemer 
---
 test/run.go | 63 +++++++++++++++++++++++++++++++++--------------------
 1 file changed, 39 insertions(+), 24 deletions(-)

diff --git a/test/run.go b/test/run.go
index f8bb8c081c7..ad92d8bb79c 100644
--- a/test/run.go
+++ b/test/run.go
@@ -42,13 +42,36 @@ var (
 	linkshared     = flag.Bool("linkshared", false, "")
 	updateErrors   = flag.Bool("update_errors", false, "update error messages in test file based on compiler output")
 	runoutputLimit = flag.Int("l", defaultRunOutputLimit(), "number of parallel runoutput tests to run")
-	generics       = flag.String("G", "0,3", "a comma-separated list of -G compiler flags to test with")
 	force          = flag.Bool("f", false, "run expected-failure generics tests rather than skipping them")
+	generics       = flag.String("G", defaultGLevels, "a comma-separated list of -G compiler flags to test with")
 
 	shard  = flag.Int("shard", 0, "shard index to run. Only applicable if -shards is non-zero.")
 	shards = flag.Int("shards", 0, "number of shards. If 0, all tests are run. This is used by the continuous build.")
 )
 
+var unifiedEnabled, defaultGLevels = func() (bool, string) {
+	// TODO(mdempsky): Change this to just "go env GOEXPERIMENT" after
+	// CL 328751 is merged back to dev.typeparams. In the mean time, we
+	// infer whether the "unified" experiment is default enabled by
+	// inspecting the output from `go tool compile -V`.
+	output := runOutput(goTool(), "tool", "compile", "-V")
+
+	// TODO(mdempsky): This will give false negatives if the unified
+	// experiment is enabled by default, but presumably at that point we
+	// won't need to disable tests for it anymore anyway.
+	enabled := strings.Contains(output, "unified")
+
+	// Normal test runs should test with both -G=0 and -G=3 for types2
+	// coverage. But the unified experiment always uses types2, so
+	// testing with -G=3 is redundant.
+	glevels := "0,3"
+	if enabled {
+		glevels = "0"
+	}
+
+	return enabled, glevels
+}()
+
 // defaultAllCodeGen returns the default value of the -all_codegen
 // flag. By default, we prefer to be fast (returning false), except on
 // the linux-amd64 builder that's already very fast, so we get more
@@ -58,9 +81,8 @@ func defaultAllCodeGen() bool {
 }
 
 var (
-	goos, goarch   string
-	cgoEnabled     bool
-	unifiedEnabled bool
+	goos, goarch string
+	cgoEnabled   bool
 
 	// dirs are the directories to look for *.go files in.
 	// TODO(bradfitz): just use all directories?
@@ -97,26 +119,8 @@ func main() {
 	goos = getenv("GOOS", runtime.GOOS)
 	goarch = getenv("GOARCH", runtime.GOARCH)
 
-	cgoCmd := exec.Command(goTool(), "env", "CGO_ENABLED")
-	cgoEnv, err := cgoCmd.Output()
-	if err != nil {
-		log.Fatalf("running %v: %v", cgoCmd, err)
-	}
-	cgoEnabled, _ = strconv.ParseBool(strings.TrimSpace(string(cgoEnv)))
-
-	// TODO(mdempsky): Change this to just "go env GOEXPERIMENT" after
-	// CL 328751 is merged back to dev.typeparams. In the mean time, we
-	// infer whether the "unified" experiment is defult enabled by
-	// inspecting the output from `go tool compile -V`.
-	compileCmd := exec.Command(goTool(), "tool", "compile", "-V")
-	compileOutput, err := compileCmd.Output()
-	if err != nil {
-		log.Fatalf("running %v: %v", compileCmd, err)
-	}
-	// TODO(mdempsky): This will give false negatives if the unified
-	// experiment is enabled by default, but presumably at that point we
-	// won't need to disable tests for it anymore anyway.
-	unifiedEnabled = strings.Contains(string(compileOutput), "unified")
+	cgoEnv := runOutput(goTool(), "env", "CGO_ENABLED")
+	cgoEnabled, _ = strconv.ParseBool(strings.TrimSpace(cgoEnv))
 
 	findExecCmd()
 
@@ -203,6 +207,17 @@ func main() {
 	}
 }
 
+// runOutput runs the specified command and returns its output as a
+// string. If the command fails, runOutput logs the error and exits.
+func runOutput(name string, args ...string) string {
+	cmd := exec.Command(name, args...)
+	output, err := cmd.Output()
+	if err != nil {
+		log.Fatalf("running %v: %v", cmd, err)
+	}
+	return string(output)
+}
+
 // goTool reports the path of the go tool to use to run the tests.
 // If possible, use the same Go used to run run.go, otherwise
 // fallback to the go version found in the PATH.

From 37f9a8f69d6299783eac8848d87e27eb563500ac Mon Sep 17 00:00:00 2001
From: Rob Findley 
Date: Thu, 24 Jun 2021 11:01:49 -0400
Subject: [PATCH 538/940] go/types: fix a bug in package qualification logic

CL 313035 had a bug, initializing pkgPathMap by walking the imported
package being considered rather than check.pkg.

Fix this, and enhance our tests to exercise this bug as well as other
edge cases.

Also fix error assertions in issues.src to not use quotation marks
inside the error regexp. The check tests only matched the error regexp
up to the first quotation mark.

Fixes #46905

Change-Id: I6aa8eae4bec6495006a5c03fc063db0d66b44cd6
Reviewed-on: https://go-review.googlesource.com/c/go/+/330629
Trust: Robert Findley 
Trust: Robert Griesemer 
Run-TryBot: Robert Findley 
TryBot-Result: Go Bot 
Reviewed-by: Robert Griesemer 
---
 src/go/types/check_test.go             | 15 +++---
 src/go/types/errors.go                 |  2 +-
 src/go/types/issues_test.go            | 72 +++++++++++++++++---------
 src/go/types/testdata/check/issues.src |  4 +-
 4 files changed, 59 insertions(+), 34 deletions(-)

diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go
index 5a3e57ba44d..c85a8e46fbb 100644
--- a/src/go/types/check_test.go
+++ b/src/go/types/check_test.go
@@ -202,7 +202,7 @@ func asGoVersion(s string) string {
 	return ""
 }
 
-func checkFiles(t *testing.T, sizes Sizes, goVersion string, filenames []string, srcs [][]byte, manual bool) {
+func checkFiles(t *testing.T, sizes Sizes, goVersion string, filenames []string, srcs [][]byte, manual bool, imp Importer) {
 	if len(filenames) == 0 {
 		t.Fatal("no source files")
 	}
@@ -252,7 +252,10 @@ func checkFiles(t *testing.T, sizes Sizes, goVersion string, filenames []string,
 		}
 	}
 
-	conf.Importer = importer.Default()
+	conf.Importer = imp
+	if imp == nil {
+		conf.Importer = importer.Default()
+	}
 	conf.Error = func(err error) {
 		if *haltOnError {
 			defer panic(err)
@@ -322,7 +325,7 @@ func TestManual(t *testing.T) {
 func TestLongConstants(t *testing.T) {
 	format := "package longconst\n\nconst _ = %s\nconst _ = %s // ERROR excessively long constant"
 	src := fmt.Sprintf(format, strings.Repeat("1", 9999), strings.Repeat("1", 10001))
-	checkFiles(t, nil, "", []string{"longconst.go"}, [][]byte{[]byte(src)}, false)
+	checkFiles(t, nil, "", []string{"longconst.go"}, [][]byte{[]byte(src)}, false, nil)
 }
 
 // TestIndexRepresentability tests that constant index operands must
@@ -330,7 +333,7 @@ func TestLongConstants(t *testing.T) {
 // represent larger values.
 func TestIndexRepresentability(t *testing.T) {
 	const src = "package index\n\nvar s []byte\nvar _ = s[int64 /* ERROR \"int64\\(1\\) << 40 \\(.*\\) overflows int\" */ (1) << 40]"
-	checkFiles(t, &StdSizes{4, 4}, "", []string{"index.go"}, [][]byte{[]byte(src)}, false)
+	checkFiles(t, &StdSizes{4, 4}, "", []string{"index.go"}, [][]byte{[]byte(src)}, false, nil)
 }
 
 func TestIssue46453(t *testing.T) {
@@ -338,7 +341,7 @@ func TestIssue46453(t *testing.T) {
 		t.Skip("type params are enabled")
 	}
 	const src = "package p\ntype _ comparable // ERROR \"undeclared name: comparable\""
-	checkFiles(t, nil, "", []string{"issue46453.go"}, [][]byte{[]byte(src)}, false)
+	checkFiles(t, nil, "", []string{"issue46453.go"}, [][]byte{[]byte(src)}, false, nil)
 }
 
 func TestCheck(t *testing.T)     { DefPredeclaredTestFuncs(); testDir(t, "check") }
@@ -388,5 +391,5 @@ func testPkg(t *testing.T, filenames []string, goVersion string, manual bool) {
 		}
 		srcs[i] = src
 	}
-	checkFiles(t, nil, goVersion, filenames, srcs, manual)
+	checkFiles(t, nil, goVersion, filenames, srcs, manual, nil)
 }
diff --git a/src/go/types/errors.go b/src/go/types/errors.go
index 19e9ae8d44a..22631064173 100644
--- a/src/go/types/errors.go
+++ b/src/go/types/errors.go
@@ -31,7 +31,7 @@ func (check *Checker) qualifier(pkg *Package) string {
 		if check.pkgPathMap == nil {
 			check.pkgPathMap = make(map[string]map[string]bool)
 			check.seenPkgMap = make(map[*Package]bool)
-			check.markImports(pkg)
+			check.markImports(check.pkg)
 		}
 		// If the same package name was used by multiple packages, display the full path.
 		if len(check.pkgPathMap[pkg.name]) > 1 {
diff --git a/src/go/types/issues_test.go b/src/go/types/issues_test.go
index 44926919efe..519e1995364 100644
--- a/src/go/types/issues_test.go
+++ b/src/go/types/issues_test.go
@@ -577,42 +577,64 @@ func TestIssue44515(t *testing.T) {
 }
 
 func TestIssue43124(t *testing.T) {
-	// TODO(rFindley) enhance the testdata tests to be able to express this type
-	//                of setup.
+	// TODO(rFindley) move this to testdata by enhancing support for importing.
 
 	// All involved packages have the same name (template). Error messages should
 	// disambiguate between text/template and html/template by printing the full
 	// path.
 	const (
 		asrc = `package a; import "text/template"; func F(template.Template) {}; func G(int) {}`
-		bsrc = `package b; import ("a"; "html/template"); func _() { a.F(template.Template{}) }`
-		csrc = `package c; import ("a"; "html/template"); func _() { a.G(template.Template{}) }`
+		bsrc = `
+package b
+
+import (
+	"a"
+	"html/template"
+)
+
+func _() {
+	// Packages should be fully qualified when there is ambiguity within the
+	// error string itself.
+	a.F(template /* ERROR cannot use.*html/template.* as .*text/template */ .Template{})
+}
+`
+		csrc = `
+package c
+
+import (
+	"a"
+	"fmt"
+	"html/template"
+)
+
+// Issue #46905: make sure template is not the first package qualified.
+var _ fmt.Stringer = 1 // ERROR cannot use 1.*as fmt\.Stringer
+
+// Packages should be fully qualified when there is ambiguity in reachable
+// packages. In this case both a (and for that matter html/template) import
+// text/template.
+func _() { a.G(template /* ERROR cannot use .*html/template.*Template */ .Template{}) }
+`
+
+		tsrc = `
+package template
+
+import "text/template"
+
+type T int
+
+// Verify that the current package name also causes disambiguation.
+var _ T = template /* ERROR cannot use.*text/template.* as T value */.Template{}
+`
 	)
 
 	a, err := pkgFor("a", asrc, nil)
 	if err != nil {
 		t.Fatalf("package a failed to typecheck: %v", err)
 	}
-	conf := Config{Importer: importHelper{pkg: a, fallback: importer.Default()}}
+	imp := importHelper{pkg: a, fallback: importer.Default()}
 
-	// Packages should be fully qualified when there is ambiguity within the
-	// error string itself.
-	bast := mustParse(t, bsrc)
-	_, err = conf.Check(bast.Name.Name, fset, []*ast.File{bast}, nil)
-	if err == nil {
-		t.Fatal("package b had no errors")
-	}
-	if !strings.Contains(err.Error(), "text/template") || !strings.Contains(err.Error(), "html/template") {
-		t.Errorf("type checking error for b does not disambiguate package template: %q", err)
-	}
-
-	// ...and also when there is any ambiguity in reachable packages.
-	cast := mustParse(t, csrc)
-	_, err = conf.Check(cast.Name.Name, fset, []*ast.File{cast}, nil)
-	if err == nil {
-		t.Fatal("package c had no errors")
-	}
-	if !strings.Contains(err.Error(), "html/template") {
-		t.Errorf("type checking error for c does not disambiguate package template: %q", err)
-	}
+	checkFiles(t, nil, "", []string{"b.go"}, [][]byte{[]byte(bsrc)}, false, imp)
+	checkFiles(t, nil, "", []string{"c.go"}, [][]byte{[]byte(csrc)}, false, imp)
+	checkFiles(t, nil, "", []string{"t.go"}, [][]byte{[]byte(tsrc)}, false, imp)
 }
diff --git a/src/go/types/testdata/check/issues.src b/src/go/types/testdata/check/issues.src
index e2ac06759ba..74d185cbc34 100644
--- a/src/go/types/testdata/check/issues.src
+++ b/src/go/types/testdata/check/issues.src
@@ -332,7 +332,7 @@ func issue28281g() (... /* ERROR can only use ... with final parameter */ TT)
 func issue26234a(f *syn.File) {
 	// The error message below should refer to the actual package name (syntax)
 	// not the local package name (syn).
-	f.foo /* ERROR f.foo undefined \(type \*syntax.File has no field or method foo\) */
+	f.foo /* ERROR f\.foo undefined \(type \*syntax\.File has no field or method foo\) */
 }
 
 type T struct {
@@ -361,7 +361,7 @@ func issue35895() {
 
 	// Because both t1 and t2 have the same global package name (template),
 	// qualify packages with full path name in this case.
-	var _ t1.Template = t2 /* ERROR cannot use .* \(value of type "html/template".Template\) as "text/template".Template */ .Template{}
+	var _ t1.Template = t2 /* ERROR cannot use .* \(value of type .html/template.\.Template\) as .text/template.\.Template */ .Template{}
 }
 
 func issue42989(s uint) {

From aee209c04426c50bb045e058b4f618ed306b7d62 Mon Sep 17 00:00:00 2001
From: Cuong Manh Le 
Date: Thu, 24 Jun 2021 14:13:39 +0700
Subject: [PATCH 539/940] [dev.typeparams] cmd/compile: catch another mis-used
 OCALLMETH in backend

OCALLMETH is rewritten by walkCall to OCALLFUNC, and other places in
backend have already caught it. So do the same thing in state.expr for
consistency and prevent mis-use in frontend side.

While at it, also remove un-used function getParam.

Change-Id: I03e1ea907e0bcb05fa35fa81804c33b5c9a4d77e
Reviewed-on: https://go-review.googlesource.com/c/go/+/330669
Trust: Cuong Manh Le 
Run-TryBot: Cuong Manh Le 
TryBot-Result: Go Bot 
Reviewed-by: Matthew Dempsky 
---
 src/cmd/compile/internal/ssagen/ssa.go | 18 +++++-------------
 1 file changed, 5 insertions(+), 13 deletions(-)

diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go
index 93847a39a39..9212c5776e1 100644
--- a/src/cmd/compile/internal/ssagen/ssa.go
+++ b/src/cmd/compile/internal/ssagen/ssa.go
@@ -279,18 +279,6 @@ func regAbiForFuncType(ft *types.Func) bool {
 	return np > 0 && strings.Contains(ft.Params.FieldType(np-1).String(), magicLastTypeName)
 }
 
-// getParam returns the Field of ith param of node n (which is a
-// function/method/interface call), where the receiver of a method call is
-// considered as the 0th parameter. This does not include the receiver of an
-// interface call.
-func getParam(n *ir.CallExpr, i int) *types.Field {
-	t := n.X.Type()
-	if n.Op() == ir.OCALLMETH {
-		base.Fatalf("OCALLMETH missed by walkCall")
-	}
-	return t.Params().Field(i)
-}
-
 // dvarint writes a varint v to the funcdata in symbol x and returns the new offset
 func dvarint(x *obj.LSym, off int, v int64) int {
 	if v < 0 || v > 1e9 {
@@ -3127,10 +3115,14 @@ func (s *state) expr(n ir.Node) *ssa.Value {
 		}
 		fallthrough
 
-	case ir.OCALLINTER, ir.OCALLMETH:
+	case ir.OCALLINTER:
 		n := n.(*ir.CallExpr)
 		return s.callResult(n, callNormal)
 
+	case ir.OCALLMETH:
+		base.Fatalf("OCALLMETH missed by walkCall")
+		panic("unreachable")
+
 	case ir.OGETG:
 		n := n.(*ir.CallExpr)
 		return s.newValue1(ssa.OpGetG, n.Type(), s.mem())

From f190a9280ddcaa958610e104a3f6c105fedd3fee Mon Sep 17 00:00:00 2001
From: Cuong Manh Le 
Date: Thu, 24 Jun 2021 22:39:16 +0700
Subject: [PATCH 540/940] [dev.typeparams] cmd/compile: simplify usemethod

By checking for method name first.

Passes toolstash -cmp

Change-Id: I1f4125157a8bc247e4766a882467b805a205a3c2
Reviewed-on: https://go-review.googlesource.com/c/go/+/330670
Trust: Cuong Manh Le 
Run-TryBot: Cuong Manh Le 
TryBot-Result: Go Bot 
Reviewed-by: Matthew Dempsky 
---
 src/cmd/compile/internal/walk/expr.go | 67 ++++++++++++---------------
 1 file changed, 30 insertions(+), 37 deletions(-)

diff --git a/src/cmd/compile/internal/walk/expr.go b/src/cmd/compile/internal/walk/expr.go
index 070954be272..bbf289d90e6 100644
--- a/src/cmd/compile/internal/walk/expr.go
+++ b/src/cmd/compile/internal/walk/expr.go
@@ -931,42 +931,8 @@ func bounded(n ir.Node, max int64) bool {
 	return false
 }
 
-// usemethod checks interface method calls for uses of reflect.Type.Method.
+// usemethod checks calls for uses of reflect.Type.{Method,MethodByName}.
 func usemethod(n *ir.CallExpr) {
-	t := n.X.Type()
-
-	// Looking for either of:
-	//	Method(int) reflect.Method
-	//	MethodByName(string) (reflect.Method, bool)
-	//
-	// TODO(crawshaw): improve precision of match by working out
-	//                 how to check the method name.
-	if n := t.NumParams(); n != 1 {
-		return
-	}
-	if n := t.NumResults(); n != 1 && n != 2 {
-		return
-	}
-	p0 := t.Params().Field(0)
-	res0 := t.Results().Field(0)
-	var res1 *types.Field
-	if t.NumResults() == 2 {
-		res1 = t.Results().Field(1)
-	}
-
-	if res1 == nil {
-		if p0.Type.Kind() != types.TINT {
-			return
-		}
-	} else {
-		if !p0.Type.IsString() {
-			return
-		}
-		if !res1.Type.IsBoolean() {
-			return
-		}
-	}
-
 	// Don't mark reflect.(*rtype).Method, etc. themselves in the reflect package.
 	// Those functions may be alive via the itab, which should not cause all methods
 	// alive. We only want to mark their callers.
@@ -977,10 +943,37 @@ func usemethod(n *ir.CallExpr) {
 		}
 	}
 
-	// Note: Don't rely on res0.Type.String() since its formatting depends on multiple factors
+	dot, ok := n.X.(*ir.SelectorExpr)
+	if !ok {
+		return
+	}
+
+	// Looking for either direct method calls and interface method calls of:
+	//	reflect.Type.Method       - func(int) reflect.Method
+	//	reflect.Type.MethodByName - func(string) (reflect.Method, bool)
+	var pKind types.Kind
+
+	switch dot.Sel.Name {
+	case "Method":
+		pKind = types.TINT
+	case "MethodByName":
+		pKind = types.TSTRING
+	default:
+		return
+	}
+
+	t := dot.Selection.Type
+	if t.NumParams() != 1 || t.Params().Field(0).Type.Kind() != pKind {
+		return
+	}
+	if t.NumResults() == 2 && t.Results().Field(1).Type.Kind() != types.TBOOL {
+		return
+	}
+
+	// Note: Don't rely on Field.Type.String() since its formatting depends on multiple factors
 	//       (including global variables such as numImports - was issue #19028).
 	// Also need to check for reflect package itself (see Issue #38515).
-	if s := res0.Type.Sym(); s != nil && s.Name == "Method" && types.IsReflectPkg(s.Pkg) {
+	if s := t.Results().Field(0).Type.Sym(); s != nil && s.Name == "Method" && types.IsReflectPkg(s.Pkg) {
 		ir.CurFunc.SetReflectMethod(true)
 		// The LSym is initialized at this point. We need to set the attribute on the LSym.
 		ir.CurFunc.LSym.Set(obj.AttrReflectMethod, true)

From 2493c727425547db935a1c6e519bc19d01476380 Mon Sep 17 00:00:00 2001
From: Cuong Manh Le 
Date: Thu, 24 Jun 2021 23:05:09 +0700
Subject: [PATCH 541/940] [dev.typeparams] cmd/compile: rewrite method call
 into method expression during escape analysis

CL 330331 extended escape analysis to analyze method expression calls
the same as normal method calls. We can now simply desugar method calls
into function calls in escape analysis.

To do this, two things must be changed:

 - Folding the rewrite method call to method expression call into an
   export function in typecheck package, so others can re-use it.

 - walkCall now have to call usemethod for method expression calls.
   (It seems to me this is a bug in current tip, because if one write
   (*rtype).Method(typ, i) in package "reflect", then the function won't
   be marked with AttrReflectMethod)

Passes toolstash -cmp.

Change-Id: I4745ab6110b417c7fd32949cc799811a882cd2ec
Reviewed-on: https://go-review.googlesource.com/c/go/+/330671
Trust: Cuong Manh Le 
Run-TryBot: Cuong Manh Le 
TryBot-Result: Go Bot 
Reviewed-by: Matthew Dempsky 
---
 .../internal/devirtualize/devirtualize.go     |  1 -
 src/cmd/compile/internal/escape/call.go       |  1 +
 src/cmd/compile/internal/typecheck/func.go    | 21 ++++++++++++++++++-
 src/cmd/compile/internal/walk/expr.go         | 16 ++------------
 4 files changed, 23 insertions(+), 16 deletions(-)

diff --git a/src/cmd/compile/internal/devirtualize/devirtualize.go b/src/cmd/compile/internal/devirtualize/devirtualize.go
index 60ba208d087..f52499e07f6 100644
--- a/src/cmd/compile/internal/devirtualize/devirtualize.go
+++ b/src/cmd/compile/internal/devirtualize/devirtualize.go
@@ -50,7 +50,6 @@ func Call(call *ir.CallExpr) {
 		if base.Flag.LowerM != 0 {
 			base.WarnfAt(call.Pos(), "devirtualizing %v to %v", sel, typ)
 		}
-		call.SetOp(ir.OCALLMETH)
 		call.X = x
 	case ir.ODOTINTER:
 		// Promoted method from embedded interface-typed field (#42279).
diff --git a/src/cmd/compile/internal/escape/call.go b/src/cmd/compile/internal/escape/call.go
index b8e28cd46a8..62727a8ef86 100644
--- a/src/cmd/compile/internal/escape/call.go
+++ b/src/cmd/compile/internal/escape/call.go
@@ -46,6 +46,7 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
 	case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
 		call := call.(*ir.CallExpr)
 		typecheck.FixVariadicCall(call)
+		typecheck.FixMethodCall(call)
 
 		// Pick out the function callee, if statically known.
 		//
diff --git a/src/cmd/compile/internal/typecheck/func.go b/src/cmd/compile/internal/typecheck/func.go
index 031279f42c1..00770c87cf8 100644
--- a/src/cmd/compile/internal/typecheck/func.go
+++ b/src/cmd/compile/internal/typecheck/func.go
@@ -15,7 +15,7 @@ import (
 	"go/token"
 )
 
-// package all the arguments that match a ... T parameter into a []T.
+// MakeDotArgs package all the arguments that match a ... T parameter into a []T.
 func MakeDotArgs(pos src.XPos, typ *types.Type, args []ir.Node) ir.Node {
 	var n ir.Node
 	if len(args) == 0 {
@@ -57,6 +57,25 @@ func FixVariadicCall(call *ir.CallExpr) {
 	call.IsDDD = true
 }
 
+// FixMethodCall rewrites a method call t.M(...) into a function call T.M(t, ...).
+func FixMethodCall(call *ir.CallExpr) {
+	if call.X.Op() != ir.ODOTMETH {
+		return
+	}
+
+	dot := call.X.(*ir.SelectorExpr)
+
+	fn := Expr(ir.NewSelectorExpr(dot.Pos(), ir.OXDOT, ir.TypeNode(dot.X.Type()), dot.Selection.Sym))
+
+	args := make([]ir.Node, 1+len(call.Args))
+	args[0] = dot.X
+	copy(args[1:], call.Args)
+
+	call.SetOp(ir.OCALLFUNC)
+	call.X = fn
+	call.Args = args
+}
+
 // ClosureType returns the struct type used to hold all the information
 // needed in the closure for clo (clo must be a OCLOSURE node).
 // The address of a variable of the returned type can be cast to a func.
diff --git a/src/cmd/compile/internal/walk/expr.go b/src/cmd/compile/internal/walk/expr.go
index bbf289d90e6..d8bded80758 100644
--- a/src/cmd/compile/internal/walk/expr.go
+++ b/src/cmd/compile/internal/walk/expr.go
@@ -489,7 +489,7 @@ func walkAddString(n *ir.AddStringExpr, init *ir.Nodes) ir.Node {
 
 // walkCall walks an OCALLFUNC, OCALLINTER, or OCALLMETH node.
 func walkCall(n *ir.CallExpr, init *ir.Nodes) ir.Node {
-	if n.Op() == ir.OCALLINTER || n.Op() == ir.OCALLMETH {
+	if n.Op() == ir.OCALLINTER || n.X.Op() == ir.OMETHEXPR {
 		// We expect both interface call reflect.Type.Method and concrete
 		// call reflect.(*rtype).Method.
 		usemethod(n)
@@ -549,20 +549,8 @@ func walkCall1(n *ir.CallExpr, init *ir.Nodes) {
 	}
 	n.SetWalked(true)
 
-	// If this is a method call t.M(...),
-	// rewrite into a function call T.M(t, ...).
-	// TODO(mdempsky): Do this right after type checking.
 	if n.Op() == ir.OCALLMETH {
-		withRecv := make([]ir.Node, len(n.Args)+1)
-		dot := n.X.(*ir.SelectorExpr)
-		withRecv[0] = dot.X
-		copy(withRecv[1:], n.Args)
-		n.Args = withRecv
-
-		dot = ir.NewSelectorExpr(dot.Pos(), ir.OXDOT, ir.TypeNode(dot.X.Type()), dot.Selection.Sym)
-
-		n.SetOp(ir.OCALLFUNC)
-		n.X = typecheck.Expr(dot)
+		typecheck.FixMethodCall(n)
 	}
 
 	args := n.Args

From badb98364b3710933de89bfe579fb8d1f82741c8 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Wed, 23 Jun 2021 14:45:34 -0700
Subject: [PATCH 542/940] [dev.typeparams] cmd/compile: switch CaptureVars to
 use syntax.Walk

This CL refactors CaptureVars to use a visitor type so it's easier to
break out helper functions to review.

It also simplifies the quirks-mode handling of function literals:
instead of trying to maintain information about whether we're inside a
function literal or not, it now just rewrites the recorded position
information for any newly added free variables after walking the
function literal.

(Quirks mode is only for "toolstash -cmp"-style binary output testing
of normal code and will eventually be removed, so I don't think it's
important that this is an O(N^2) algorithm for deeply nested function
literals with lots of free variables.)

Change-Id: I0689984f6d88cf9937d4706d2d8de96415eaeee3
Reviewed-on: https://go-review.googlesource.com/c/go/+/330789
Trust: Matthew Dempsky 
Trust: Robert Griesemer 
Run-TryBot: Matthew Dempsky 
TryBot-Result: Go Bot 
Reviewed-by: Robert Griesemer 
---
 src/cmd/compile/internal/noder/writer.go | 140 +++++++++++++----------
 1 file changed, 82 insertions(+), 58 deletions(-)

diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go
index 889a96ef9ce..cc44a80a42e 100644
--- a/src/cmd/compile/internal/noder/writer.go
+++ b/src/cmd/compile/internal/noder/writer.go
@@ -1264,90 +1264,114 @@ type posObj struct {
 }
 
 // captureVars returns the free variables used by the given function
-// literal.
+// literal. The closureVars result is the list of free variables
+// captured by expr, and localsIdx is a map from free variable to
+// index. See varCaptor's identically named fields for more details.
 func (w *writer) captureVars(expr *syntax.FuncLit) (closureVars []posObj, localsIdx map[types2.Object]int) {
 	scope, ok := w.p.info.Scopes[expr.Type]
 	assert(ok)
 
-	localsIdx = make(map[types2.Object]int)
-
 	// TODO(mdempsky): This code needs to be cleaned up (e.g., to avoid
 	// traversing nested function literals multiple times). This will be
 	// easier after we drop quirks mode.
 
-	var rbracePos syntax.Pos
+	v := varCaptor{
+		w:         w,
+		scope:     scope,
+		localsIdx: make(map[types2.Object]int),
+	}
 
-	var visitor func(n syntax.Node) bool
-	visitor = func(n syntax.Node) bool {
+	syntax.Walk(expr, &v)
 
-		// Constant expressions don't count towards capturing.
-		if n, ok := n.(syntax.Expr); ok {
-			if tv, ok := w.p.info.Types[n]; ok && tv.Value != nil {
-				return true
-			}
+	return v.closureVars, v.localsIdx
+}
+
+// varCaptor implements syntax.Visitor for enumerating free variables
+// used by a function literal.
+type varCaptor struct {
+	w     *writer
+	scope *types2.Scope
+
+	// closureVars lists free variables along with the position where
+	// they first appeared, in order of appearance.
+	closureVars []posObj
+
+	// localsIdx is a map from free variables to their index within
+	// closureVars.
+	localsIdx map[types2.Object]int
+}
+
+func (v *varCaptor) capture(n *syntax.Name) {
+	obj, ok := v.w.p.info.Uses[n].(*types2.Var)
+	if !ok || obj.IsField() {
+		return // not a variable
+	}
+
+	if obj.Parent() == obj.Pkg().Scope() {
+		return // global variable
+	}
+
+	if _, ok := v.localsIdx[obj]; ok {
+		return // already captured
+	}
+
+	for parent := obj.Parent(); parent != obj.Pkg().Scope(); parent = parent.Parent() {
+		if parent == v.scope {
+			return // object declared within our scope
 		}
+	}
 
+	idx := len(v.closureVars)
+	v.closureVars = append(v.closureVars, posObj{n.Pos(), obj})
+	v.localsIdx[obj] = idx
+}
+
+func (v *varCaptor) Visit(n syntax.Node) syntax.Visitor {
+	// Constant expressions don't count towards capturing.
+	if n, ok := n.(syntax.Expr); ok {
+		if tv, ok := v.w.p.info.Types[n]; ok && tv.Value != nil {
+			return nil
+		}
+	}
+
+	if n, ok := n.(*syntax.Name); ok {
+		v.capture(n)
+	}
+
+	if quirksMode() {
 		switch n := n.(type) {
-		case *syntax.Name:
-			if obj, ok := w.p.info.Uses[n].(*types2.Var); ok && !obj.IsField() && obj.Pkg() == w.p.curpkg && obj.Parent() != obj.Pkg().Scope() {
-				// Found a local variable. See if it chains up to scope.
-				parent := obj.Parent()
-				for {
-					if parent == scope {
-						break
-					}
-					if parent == obj.Pkg().Scope() {
-						if _, present := localsIdx[obj]; !present {
-							pos := rbracePos
-							if pos == (syntax.Pos{}) {
-								pos = n.Pos()
-							}
-
-							idx := len(closureVars)
-							closureVars = append(closureVars, posObj{pos, obj})
-							localsIdx[obj] = idx
-						}
-						break
-					}
-					parent = parent.Parent()
-				}
-			}
-
 		case *syntax.FuncLit:
 			// Quirk: typecheck uses the rbrace position position of the
 			// function literal as the position of the intermediary capture.
-			if quirksMode() && rbracePos == (syntax.Pos{}) {
-				rbracePos = n.Body.Rbrace
-				syntax.Crawl(n.Body, visitor)
-				rbracePos = syntax.Pos{}
-				return true
+			end := len(v.closureVars)
+			syntax.Walk(n.Type, v) // unnecessary to walk, but consistent with non-quirks mode
+			syntax.Walk(n.Body, v)
+			for i := end; i < len(v.closureVars); i++ {
+				v.closureVars[i].pos = n.Body.Rbrace
 			}
+			return nil
 
 		case *syntax.AssignStmt:
 			// Quirk: typecheck visits (and thus captures) the RHS of
-			// assignment statements before the LHS.
-			if quirksMode() && (n.Op == 0 || n.Op == syntax.Def) {
-				syntax.Crawl(n.Rhs, visitor)
-				syntax.Crawl(n.Lhs, visitor)
-				return true
+			// assignment statements (but not op= statements) before the LHS.
+			if n.Op == 0 || n.Op == syntax.Def {
+				syntax.Walk(n.Rhs, v)
+				syntax.Walk(n.Lhs, v)
+				return nil
 			}
+
 		case *syntax.RangeClause:
-			// Quirk: Similarly, it visits the expression to be iterated
-			// over before the iteration variables.
-			if quirksMode() {
-				syntax.Crawl(n.X, visitor)
-				if n.Lhs != nil {
-					syntax.Crawl(n.Lhs, visitor)
-				}
-				return true
+			// Quirk: Similarly, typecheck visits the expression to be
+			// iterated over before the iteration variables.
+			syntax.Walk(n.X, v)
+			if n.Lhs != nil {
+				syntax.Walk(n.Lhs, v)
 			}
+			return nil
 		}
-
-		return false
 	}
-	syntax.Crawl(expr.Body, visitor)
 
-	return
+	return v
 }
 
 func (w *writer) exprList(expr syntax.Expr) {

From 3f1a517a45d2e443a327e0b28df17698e299ea50 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Thu, 24 Jun 2021 11:31:56 -0700
Subject: [PATCH 543/940] [dev.typeparams] cmd/compile: refactor "need to emit"
 logic for types

This CL refactors out a single reflectdata.NeedEmit function that
reports whether the current compilation unit needs to emit the runtime
type descriptor and method wrappers for a given type.

As a minor side bonus, this CL also skips compiling the "error.Error"
wrapper in non-runtime packages. Package runtime already
unconditionally emitted the runtime type descriptor for error, so we
just need to make sure it emits the wrapper and other packages don't.

Passes toolstash -cmp.

Change-Id: Ic9ea219dfba8a0a57f2f42f817bdff7618732bff
Reviewed-on: https://go-review.googlesource.com/c/go/+/330754
Trust: Matthew Dempsky 
Run-TryBot: Matthew Dempsky 
TryBot-Result: Go Bot 
Reviewed-by: Cuong Manh Le 
---
 .../compile/internal/reflectdata/reflect.go   | 91 +++++++++++--------
 1 file changed, 55 insertions(+), 36 deletions(-)

diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go
index 8378fab36d9..ba4bbc76313 100644
--- a/src/cmd/compile/internal/reflectdata/reflect.go
+++ b/src/cmd/compile/internal/reflectdata/reflect.go
@@ -927,29 +927,27 @@ func writeType(t *types.Type) *obj.LSym {
 	if t.IsPtr() && t.Sym() == nil && t.Elem().Sym() != nil {
 		tbase = t.Elem()
 	}
+	if tbase.Kind() == types.TFORW {
+		base.Fatalf("unresolved defined type: %v", tbase)
+	}
+
 	dupok := 0
-	if tbase.Sym() == nil {
+	if tbase.Sym() == nil { // TODO(mdempsky): Probably need DUPOK for instantiated types too.
 		dupok = obj.DUPOK
 	}
 
-	if base.Ctxt.Pkgpath != "runtime" || (tbase != types.Types[tbase.Kind()] && tbase != types.ByteType && tbase != types.RuneType && tbase != types.ErrorType) { // int, float, etc
-		// Named types from other files are defined only by those files.
-		// However, as an exception, we can write out instantiated types
-		// in the local package, even if they may be marked as part of
-		// another package (the package of their base generic type).
-		if tbase.Sym() != nil && tbase.Sym().Pkg != types.LocalPkg &&
-			!tbase.IsFullyInstantiated() {
-			if i := typecheck.BaseTypeIndex(t); i >= 0 {
-				lsym.Pkg = tbase.Sym().Pkg.Prefix
-				lsym.SymIdx = int32(i)
-				lsym.Set(obj.AttrIndexed, true)
-			}
-			return lsym
-		}
-		// TODO(mdempsky): Investigate whether this can happen.
-		if tbase.Kind() == types.TFORW {
-			return lsym
+	if !NeedEmit(tbase) {
+		if i := typecheck.BaseTypeIndex(t); i >= 0 {
+			lsym.Pkg = tbase.Sym().Pkg.Prefix
+			lsym.SymIdx = int32(i)
+			lsym.Set(obj.AttrIndexed, true)
 		}
+
+		// TODO(mdempsky): Investigate whether this still happens.
+		// If we know we don't need to emit code for a type,
+		// we should have a link-symbol index for it.
+		// See also TODO in NeedEmit.
+		return lsym
 	}
 
 	ot := 0
@@ -1678,6 +1676,44 @@ func CollectPTabs() {
 	}
 }
 
+// NeedEmit reports whether typ is a type that we need to emit code
+// for (e.g., runtime type descriptors, method wrappers).
+func NeedEmit(typ *types.Type) bool {
+	// TODO(mdempsky): Export data should keep track of which anonymous
+	// and instantiated types were emitted, so at least downstream
+	// packages can skip re-emitting them.
+	//
+	// Perhaps we can just generalize the linker-symbol indexing to
+	// track the index of arbitrary types, not just defined types, and
+	// use its presence to detect this. The same idea would work for
+	// instantiated generic functions too.
+
+	switch sym := typ.Sym(); {
+	case sym == nil:
+		// Anonymous type; possibly never seen before or ever again.
+		// Need to emit to be safe (however, see TODO above).
+		return true
+
+	case sym.Pkg == types.LocalPkg:
+		// Local defined type; our responsibility.
+		return true
+
+	case base.Ctxt.Pkgpath == "runtime" && (sym.Pkg == types.BuiltinPkg || sym.Pkg == ir.Pkgs.Unsafe):
+		// Package runtime is responsible for including code for builtin
+		// types (predeclared and package unsafe).
+		return true
+
+	case typ.IsFullyInstantiated():
+		// Instantiated type; possibly instantiated with unique type arguments.
+		// Need to emit to be safe (however, see TODO above).
+		return true
+
+	default:
+		// Should have been emitted by an imported package.
+		return false
+	}
+}
+
 // Generate a wrapper function to convert from
 // a receiver of type T to a receiver of type U.
 // That is,
@@ -1739,24 +1775,7 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
 		return lsym
 	}
 
-	// imported reports whether typ is a defined type that was declared
-	// in an imported package, and therefore must have been compiled in
-	// that package.
-	importedType := func(typ *types.Type) bool {
-		return typ.Sym() != nil && typ.Sym().Pkg != types.LocalPkg &&
-
-			// Exception: need wrapper for error.Error (#29304).
-			// TODO(mdempsky): Put this in package runtime, like we do for
-			// the type descriptors for predeclared types.
-			typ != types.ErrorType &&
-
-			// Exception: parameterized types may have been instantiated
-			// with new type arguments, so we don't assume they've been
-			// compiled before.
-			!typ.IsFullyInstantiated()
-	}
-
-	if importedType(rcvr) || rcvr.IsPtr() && importedType(rcvr.Elem()) {
+	if !NeedEmit(rcvr) || rcvr.IsPtr() && !NeedEmit(rcvr.Elem()) {
 		return lsym
 	}
 

From f4198f85d505c21eee3f2686466e72daa7413232 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Wed, 23 Jun 2021 21:33:24 -0700
Subject: [PATCH 544/940] [dev.typeparams] cmd/compile: generate wrappers
 within unified IR

This CL extends unified IR to handle creating wrapper methods. There's
relatively little about this code that's actually specific to unified
IR, but rewriting this logic allows a few benefits:

1. It decouples unified IR from reflectdata.methodWrapper, so the
latter code can evolve freely for -G=3's needs. This will also allow
the new code to evolve to unified IR's wrapper needs, which I
anticipate will operate slightly differently.

2. It provided an opportunity to revisit a lot of the code and
simplify/update it to current style. E.g., in the process, I
discovered #46903, which unified IR now gets correctly. (I have not
yet attempted to fix reflectdata.methodWrapper.)

3. It gives a convenient way for unified IR to ensure all of the
wrapper methods it needs are generated correctly.

For now, the wrapper generation is specific to non-quirks mode.

Change-Id: I5798de6b141f29e8eb6a5c563e7049627ff2868a
Reviewed-on: https://go-review.googlesource.com/c/go/+/330569
Trust: Matthew Dempsky 
Run-TryBot: Matthew Dempsky 
TryBot-Result: Go Bot 
Reviewed-by: Cuong Manh Le 
---
 src/cmd/compile/internal/gc/main.go           |   2 +-
 src/cmd/compile/internal/noder/reader.go      | 190 +++++++++++++++++-
 src/cmd/compile/internal/noder/unified.go     |   7 +
 .../compile/internal/reflectdata/reflect.go   |  10 +-
 test/fixedbugs/issue46903.go                  |  32 +++
 test/typeparam/issue44688.go                  |   2 -
 6 files changed, 234 insertions(+), 9 deletions(-)
 create mode 100644 test/fixedbugs/issue46903.go

diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index c0346c02065..c94f19fd47c 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -186,6 +186,7 @@ func Main(archInit func(*ssagen.ArchInfo)) {
 	base.AutogeneratedPos = makePos(src.NewFileBase("", ""), 1, 0)
 
 	typecheck.InitUniverse()
+	typecheck.InitRuntime()
 
 	// Parse and typecheck input.
 	noder.LoadPackage(flag.Args())
@@ -194,7 +195,6 @@ func Main(archInit func(*ssagen.ArchInfo)) {
 
 	// Prepare for backend processing. This must happen before pkginit,
 	// because it generates itabs for initializing global variables.
-	typecheck.InitRuntime()
 	ssagen.InitConfig()
 
 	// Build init task.
diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go
index d2fe575ffd4..3a496816cc2 100644
--- a/src/cmd/compile/internal/noder/reader.go
+++ b/src/cmd/compile/internal/noder/reader.go
@@ -16,6 +16,7 @@ import (
 	"cmd/compile/internal/deadcode"
 	"cmd/compile/internal/dwarfgen"
 	"cmd/compile/internal/ir"
+	"cmd/compile/internal/reflectdata"
 	"cmd/compile/internal/typecheck"
 	"cmd/compile/internal/types"
 	"cmd/internal/obj"
@@ -419,7 +420,7 @@ func (r *reader) interfaceType() *types.Type {
 	if len(fields) == 0 {
 		return types.Types[types.TINTER] // empty interface
 	}
-	return types.NewInterface(tpkg, fields)
+	return r.needWrapper(types.NewInterface(tpkg, fields))
 }
 
 func (r *reader) structType() *types.Type {
@@ -440,7 +441,7 @@ func (r *reader) structType() *types.Type {
 		}
 		fields[i] = f
 	}
-	return types.NewStruct(tpkg, fields)
+	return r.needWrapper(types.NewStruct(tpkg, fields))
 }
 
 func (r *reader) signature(tpkg *types.Pkg, recv *types.Field) *types.Type {
@@ -597,6 +598,10 @@ func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node
 			typ.Methods().Set(methods)
 		}
 
+		if !typ.IsPtr() {
+			r.needWrapper(typ)
+		}
+
 		return name
 
 	case objVar:
@@ -2015,3 +2020,184 @@ func usedLocals(body []ir.Node) ir.NameSet {
 	})
 	return used
 }
+
+// @@@ Method wrappers
+
+// needWrapperTypes lists types for which we may need to generate
+// method wrappers.
+var needWrapperTypes []*types.Type
+
+func (r *reader) needWrapper(typ *types.Type) *types.Type {
+	// TODO(mdempsky): Be more judicious about generating wrappers.
+	// For now, generating all possible wrappers is simple and correct,
+	// but potentially wastes a lot of time/space.
+
+	if typ.IsPtr() {
+		base.Fatalf("bad pointer type: %v", typ)
+	}
+
+	needWrapperTypes = append(needWrapperTypes, typ)
+	return typ
+}
+
+func (r *reader) wrapTypes(target *ir.Package) {
+	// always generate a wrapper for error.Error (#29304)
+	r.needWrapper(types.ErrorType)
+
+	seen := make(map[string]*types.Type)
+	for _, typ := range needWrapperTypes {
+		if typ.Sym() == nil {
+			key := typ.ShortString()
+			if prev := seen[key]; prev != nil {
+				if !types.Identical(typ, prev) {
+					base.Fatalf("collision: types %v and %v have short string %q", typ, prev, key)
+				}
+				continue
+			}
+			seen[key] = typ
+		}
+
+		r.wrapType(typ, target)
+	}
+
+	needWrapperTypes = nil
+}
+
+func (r *reader) wrapType(typ *types.Type, target *ir.Package) {
+	if !typ.IsInterface() {
+		typecheck.CalcMethods(typ)
+	}
+	for _, meth := range typ.AllMethods().Slice() {
+		if meth.Sym.IsBlank() || !meth.IsMethod() {
+			base.FatalfAt(meth.Pos, "invalid method: %v", meth)
+		}
+
+		r.methodWrapper(0, typ, meth, target)
+
+		// For non-interface types, we also want *T wrappers.
+		if !typ.IsInterface() {
+			r.methodWrapper(1, typ, meth, target)
+
+			// For not-in-heap types, *T is a scalar, not pointer shaped,
+			// so the interface wrappers use **T.
+			if typ.NotInHeap() {
+				r.methodWrapper(2, typ, meth, target)
+			}
+		}
+	}
+}
+
+func (r *reader) methodWrapper(derefs int, tbase *types.Type, method *types.Field, target *ir.Package) {
+	wrapper := tbase
+	for i := 0; i < derefs; i++ {
+		wrapper = types.NewPtr(wrapper)
+	}
+
+	sym := ir.MethodSym(wrapper, method.Sym)
+	assert(!sym.Siggen())
+	sym.SetSiggen(true)
+
+	wrappee := method.Type.Recv().Type
+	if types.Identical(wrapper, wrappee) ||
+		!types.IsMethodApplicable(wrapper, method) ||
+		!reflectdata.NeedEmit(tbase) {
+		return
+	}
+
+	// TODO(mdempsky): Use method.Pos instead?
+	pos := base.AutogeneratedPos
+
+	fn := ir.NewFunc(pos)
+	fn.SetDupok(true)   // TODO(mdempsky): Leave unset for local, non-generic wrappers?
+	fn.SetWrapper(true) // TODO(mdempsky): Leave unset for tail calls?
+
+	fn.Nname = ir.NewNameAt(pos, sym)
+	ir.MarkFunc(fn.Nname)
+	fn.Nname.Func = fn
+	fn.Nname.Defn = fn
+
+	sig := newWrapperType(wrapper, method.Type)
+	r.setType(fn.Nname, sig)
+
+	// TODO(mdempsky): De-duplicate with similar logic in funcargs.
+	defParams := func(class ir.Class, params ...*types.Field) {
+		for _, param := range params {
+			name := ir.NewNameAt(param.Pos, param.Sym)
+			name.Class = class
+			r.setType(name, param.Type)
+
+			name.Curfn = fn
+			fn.Dcl = append(fn.Dcl, name)
+
+			param.Nname = name
+		}
+	}
+
+	defParams(ir.PPARAM, sig.Recv())
+	defParams(ir.PPARAM, sig.Params().FieldSlice()...)
+	defParams(ir.PPARAMOUT, sig.Results().FieldSlice()...)
+
+	var recv ir.Node = sig.Recv().Nname.(*ir.Name)
+
+	// For simple *T wrappers around T methods, panicwrap produces a
+	// nicer panic message.
+	if wrapper.IsPtr() && types.Identical(wrapper.Elem(), wrappee) {
+		cond := ir.NewBinaryExpr(pos, ir.OEQ, recv, types.BuiltinPkg.Lookup("nil").Def.(ir.Node))
+		then := []ir.Node{ir.NewCallExpr(pos, ir.OCALL, typecheck.LookupRuntime("panicwrap"), nil)}
+		fn.Body.Append(ir.NewIfStmt(pos, cond, then, nil))
+	}
+
+	// Add implicit derefs, as necessary. typecheck will add one deref,
+	// but not-in-heap types will need another for their **T wrappers.
+	for i := 0; i < derefs; i++ {
+		recv = Implicit(ir.NewStarExpr(pos, recv))
+	}
+
+	args := make([]ir.Node, sig.NumParams())
+	for i, param := range sig.Params().FieldSlice() {
+		args[i] = param.Nname.(*ir.Name)
+	}
+
+	fn.Body.Append(newTailCall(pos, method, recv, args))
+
+	target.Decls = append(target.Decls, fn)
+}
+
+// newWrapperType returns a copy of the given signature type, but with
+// the receiver parameter type substituted with wrapper.
+func newWrapperType(wrapper, sig *types.Type) *types.Type {
+	clone := func(params []*types.Field) []*types.Field {
+		res := make([]*types.Field, len(params))
+		for i, param := range params {
+			sym := param.Sym
+			if sym == nil || sym.Name == "_" {
+				sym = typecheck.LookupNum(".anon", i)
+			}
+			res[i] = types.NewField(param.Pos, sym, param.Type)
+			res[i].SetIsDDD(param.IsDDD())
+		}
+		return res
+	}
+
+	recv := types.NewField(sig.Recv().Pos, typecheck.Lookup(".this"), wrapper)
+	params := clone(sig.Params().FieldSlice())
+	results := clone(sig.Results().FieldSlice())
+
+	return types.NewSignature(types.NoPkg, recv, nil, params, results)
+}
+
+func newTailCall(pos src.XPos, method *types.Field, recv ir.Node, args []ir.Node) ir.Node {
+	// TODO(mdempsky): Support creating OTAILCALL, when possible. See reflectdata.methodWrapper.
+	// Not urgent though, because tail calls are currently incompatible with regabi anyway.
+
+	call := ir.NewCallExpr(pos, ir.OCALL, ir.NewSelectorExpr(pos, ir.OXDOT, recv, method.Sym), args)
+	call.IsDDD = method.Type.IsVariadic()
+
+	if method.Type.NumResults() == 0 {
+		return call
+	}
+
+	ret := ir.NewReturnStmt(pos, nil)
+	ret.Results = []ir.Node{call}
+	return ret
+}
diff --git a/src/cmd/compile/internal/noder/unified.go b/src/cmd/compile/internal/noder/unified.go
index 7a1bb88537a..292fd13c679 100644
--- a/src/cmd/compile/internal/noder/unified.go
+++ b/src/cmd/compile/internal/noder/unified.go
@@ -74,6 +74,8 @@ func unified(noders []*noder) {
 
 	if !quirksMode() {
 		writeNewExportFunc = writeNewExport
+	} else if base.Flag.G != 0 {
+		base.Errorf("cannot use -G and -d=quirksmode together")
 	}
 
 	newReadImportFunc = func(data string, pkg1 *types.Pkg, check *types2.Checker, packages map[string]*types2.Package) (pkg2 *types2.Package, err error) {
@@ -126,6 +128,11 @@ func unified(noders []*noder) {
 	}
 	todoBodies = nil
 
+	if !quirksMode() {
+		// TODO(mdempsky): Investigate generating wrappers in quirks mode too.
+		r.wrapTypes(target)
+	}
+
 	// Don't use range--typecheck can add closures to Target.Decls.
 	for i := 0; i < len(target.Decls); i++ {
 		target.Decls[i] = typecheck.Stmt(target.Decls[i])
diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go
index ba4bbc76313..8421e36b3dd 100644
--- a/src/cmd/compile/internal/reflectdata/reflect.go
+++ b/src/cmd/compile/internal/reflectdata/reflect.go
@@ -1760,10 +1760,6 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
 		// TODO: check that we do the right thing when method is an interface method.
 		generic = true
 	}
-	if base.Debug.Unified != 0 {
-		// TODO(mdempsky): Support dictionaries for unified IR.
-		generic = false
-	}
 	newnam := ir.MethodSym(rcvr, method.Sym)
 	lsym := newnam.Linksym()
 	if newnam.Siggen() {
@@ -1771,6 +1767,12 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
 	}
 	newnam.SetSiggen(true)
 
+	// Except in quirks mode, unified IR creates its own wrappers.
+	// Complain loudly if it missed any.
+	if base.Debug.Unified != 0 && base.Debug.UnifiedQuirks == 0 {
+		base.FatalfAt(method.Pos, "missing wrapper for %+v (%+v, %v) / %+v / %+v", rcvr, orig, types.IsDirectIface(orig), method.Sym, newnam)
+	}
+
 	if !generic && types.Identical(rcvr, method.Type.Recv().Type) {
 		return lsym
 	}
diff --git a/test/fixedbugs/issue46903.go b/test/fixedbugs/issue46903.go
new file mode 100644
index 00000000000..3237a583d54
--- /dev/null
+++ b/test/fixedbugs/issue46903.go
@@ -0,0 +1,32 @@
+// run
+//go:build goexperiment.unified
+// +build goexperiment.unified
+
+// TODO(mdempsky): Enable test unconditionally. This test should pass
+// for non-unified mode too.
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+//go:notinheap
+type A struct{ B }
+type B struct{ x byte }
+type I interface{ M() *B }
+
+func (p *B) M() *B { return p }
+
+var (
+	a A
+	i I = &a
+)
+
+func main() {
+	got, want := i.M(), &a.B
+	if got != want {
+		println(got, "!=", want)
+		panic("FAIL")
+	}
+}
diff --git a/test/typeparam/issue44688.go b/test/typeparam/issue44688.go
index d70f94f706d..de1140b67cf 100644
--- a/test/typeparam/issue44688.go
+++ b/test/typeparam/issue44688.go
@@ -1,6 +1,4 @@
 // run -gcflags=-G=3
-//go:build goexperiment.unified
-// +build !goexperiment.unified
 
 // Copyright 2021 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style

From 9fe7c38d3d7cd8a90e33515981dd00e1233563c9 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Fri, 25 Jun 2021 01:49:26 -0700
Subject: [PATCH 545/940] [dev.typeparams] cmd/compile: fix TestUnifiedCompare

We need to start the capture walk from expr.Body, not expr, otherwise
in quirks mode we'll set all of the captured variables' positions to
expr.Body.Rbrace.

Change-Id: Ic93f2773ae3756c2ec88dac17b4e9fb5a0771734
Reviewed-on: https://go-review.googlesource.com/c/go/+/330889
Trust: Matthew Dempsky 
Run-TryBot: Matthew Dempsky 
TryBot-Result: Go Bot 
Reviewed-by: Cuong Manh Le 
---
 src/cmd/compile/internal/noder/writer.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go
index cc44a80a42e..8765f853623 100644
--- a/src/cmd/compile/internal/noder/writer.go
+++ b/src/cmd/compile/internal/noder/writer.go
@@ -1281,7 +1281,7 @@ func (w *writer) captureVars(expr *syntax.FuncLit) (closureVars []posObj, locals
 		localsIdx: make(map[types2.Object]int),
 	}
 
-	syntax.Walk(expr, &v)
+	syntax.Walk(expr.Body, &v)
 
 	return v.closureVars, v.localsIdx
 }

From 1b60284c0a375de2349540771a3bc1a719ddf52e Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Fri, 25 Jun 2021 01:54:50 -0700
Subject: [PATCH 546/940] [dev.typeparams] cmd/compile: simplify variable
 capturing in unified IR

While initially building out unified IR, I didn't have any indexing
scheme. Everything was written out in order. Consequently, if I wanted
to write A before B, I had to compute A before B.

One particular example of this is handling closure variables: the
reader needs the list of closure variables before it can start reading
the function body, so I had to write them out first, and so I had to
compute them first in a separate, dedicated pass.

However, that constraint went away a while ago. For example, it's now
possible to replace the two-pass closure variable capture with a
single pass. We just write out the function body earlier, but then
wait to write out its index.

I anticipate this approach will make it easier to implement
dictionaries: rather than needing a separate pass to correctly
recognize and handle all of the generics cases, we can just hook into
the existing logic.

Change-Id: Iab1e07f9202cd5d2b6864eef10116960456214df
Reviewed-on: https://go-review.googlesource.com/c/go/+/330851
Trust: Matthew Dempsky 
Run-TryBot: Matthew Dempsky 
TryBot-Result: Go Bot 
Reviewed-by: Cuong Manh Le 
---
 src/cmd/compile/internal/noder/linker.go |   2 -
 src/cmd/compile/internal/noder/reader.go |  54 +++---
 src/cmd/compile/internal/noder/writer.go | 223 ++++++-----------------
 3 files changed, 80 insertions(+), 199 deletions(-)

diff --git a/src/cmd/compile/internal/noder/linker.go b/src/cmd/compile/internal/noder/linker.go
index 72911381605..23e9446759c 100644
--- a/src/cmd/compile/internal/noder/linker.go
+++ b/src/cmd/compile/internal/noder/linker.go
@@ -209,8 +209,6 @@ func (l *linker) relocFuncExt(w *encoder, name *ir.Name) {
 
 		pri, ok := bodyReader[name.Func]
 		assert(ok)
-		w.sync(syncAddBody)
-		w.sync(syncImplicitTypes)
 		w.reloc(relocBody, l.relocIdx(pri.pr, relocBody, pri.idx))
 	}
 
diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go
index 3a496816cc2..0423fcce987 100644
--- a/src/cmd/compile/internal/noder/reader.go
+++ b/src/cmd/compile/internal/noder/reader.go
@@ -105,8 +105,9 @@ type reader struct {
 	// separately so that it doesn't take up space in every reader
 	// instance.
 
-	curfn  *ir.Func
-	locals []*ir.Name
+	curfn       *ir.Func
+	locals      []*ir.Name
+	closureVars []*ir.Name
 
 	funarghack bool
 
@@ -775,10 +776,10 @@ func (r *reader) funcExt(name *ir.Name) {
 				Cost:            int32(r.len()),
 				CanDelayResults: r.bool(),
 			}
-			r.addBody(name.Func)
+			r.addBody(name.Func, r.explicits)
 		}
 	} else {
-		r.addBody(name.Func)
+		r.addBody(name.Func, r.explicits)
 	}
 	r.sync(syncEOF)
 }
@@ -840,25 +841,7 @@ var bodyReader = map[*ir.Func]pkgReaderIndex{}
 // constructed.
 var todoBodies []*ir.Func
 
-// Keep in sync with writer.implicitTypes
-// Also see comment there for why r.implicits and r.explicits should
-// never both be non-empty.
-func (r *reader) implicitTypes() []*types.Type {
-	r.sync(syncImplicitTypes)
-
-	implicits := r.implicits
-	if len(implicits) == 0 {
-		implicits = r.explicits
-	} else {
-		assert(len(r.explicits) == 0)
-	}
-	return implicits
-}
-
-func (r *reader) addBody(fn *ir.Func) {
-	r.sync(syncAddBody)
-
-	implicits := r.implicitTypes()
+func (r *reader) addBody(fn *ir.Func, implicits []*types.Type) {
 	pri := pkgReaderIndex{r.p, r.reloc(relocBody), implicits}
 	bodyReader[fn] = pri
 
@@ -877,7 +860,7 @@ func (pri pkgReaderIndex) funcBody(fn *ir.Func) {
 
 func (r *reader) funcBody(fn *ir.Func) {
 	r.curfn = fn
-	r.locals = fn.ClosureVars
+	r.closureVars = fn.ClosureVars
 
 	// TODO(mdempsky): Get rid of uses of typecheck.NodAddrAt so we
 	// don't have to set ir.CurFunc.
@@ -1004,7 +987,10 @@ func (r *reader) addLocal(name *ir.Name, ctxt ir.Class) {
 
 func (r *reader) useLocal() *ir.Name {
 	r.sync(syncUseObjLocal)
-	return r.locals[r.len()]
+	if r.bool() {
+		return r.locals[r.len()]
+	}
+	return r.closureVars[r.len()]
 }
 
 func (r *reader) openScope() {
@@ -1088,8 +1074,11 @@ func (r *reader) stmt1(tag codeStmt, out *ir.Nodes) ir.Node {
 
 	case stmtAssign:
 		pos := r.pos()
-		names, lhs := r.assignList()
+
+		// TODO(mdempsky): After quirks mode is gone, swap these
+		// statements so we visit LHS before RHS again.
 		rhs := r.exprList()
+		names, lhs := r.assignList()
 
 		if len(rhs) == 0 {
 			for _, name := range names {
@@ -1225,8 +1214,12 @@ func (r *reader) forStmt(label *types.Sym) ir.Node {
 
 	if r.bool() {
 		pos := r.pos()
-		names, lhs := r.assignList()
+
+		// TODO(mdempsky): After quirks mode is gone, swap these
+		// statements so we read LHS before X again.
 		x := r.expr()
+		names, lhs := r.assignList()
+
 		body := r.blockStmt()
 		r.closeAnotherScope()
 
@@ -1572,7 +1565,7 @@ func (r *reader) funcLit() ir.Node {
 		r.setType(cv, outer.Type())
 	}
 
-	r.addBody(fn)
+	r.addBody(fn, r.implicits)
 
 	return fn.OClosure
 }
@@ -1777,8 +1770,9 @@ func InlineCall(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExp
 	r.inlTreeIndex = inlIndex
 	r.inlPosBases = make(map[*src.PosBase]*src.PosBase)
 
-	for _, cv := range r.inlFunc.ClosureVars {
-		r.locals = append(r.locals, cv.Outer)
+	r.closureVars = make([]*ir.Name, len(r.inlFunc.ClosureVars))
+	for i, cv := range r.inlFunc.ClosureVars {
+		r.closureVars[i] = cv.Outer
 	}
 
 	r.funcargs(fn)
diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go
index 8765f853623..04969100f0c 100644
--- a/src/cmd/compile/internal/noder/writer.go
+++ b/src/cmd/compile/internal/noder/writer.go
@@ -97,7 +97,10 @@ type writer struct {
 	explicitIdx map[*types2.TypeParam]int
 
 	// variables declared within this function
-	localsIdx map[types2.Object]int
+	localsIdx map[*types2.Var]int
+
+	closureVars    []posObj
+	closureVarsIdx map[*types2.Var]int
 }
 
 func (pw *pkgWriter) newWriter(k reloc, marker syncMarker) *writer {
@@ -626,11 +629,15 @@ func (w *writer) funcExt(obj *types2.Func) {
 		}
 	}
 
+	sig, block := obj.Type().(*types2.Signature), decl.Body
+	body, closureVars := w.p.bodyIdx(w.p.curpkg, sig, block, w.explicitIdx)
+	assert(len(closureVars) == 0)
+
 	w.sync(syncFuncExt)
 	w.pragmaFlag(pragma)
 	w.linkname(obj)
 	w.bool(false) // stub extension
-	w.addBody(obj.Type().(*types2.Signature), decl.Body, make(map[types2.Object]int))
+	w.reloc(relocBody, body)
 	w.sync(syncEOF)
 }
 
@@ -665,41 +672,9 @@ func (w *writer) pragmaFlag(p ir.PragmaFlag) {
 
 // @@@ Function bodies
 
-func (w *writer) implicitTypes() map[*types2.TypeParam]int {
-	w.sync(syncImplicitTypes)
-
-	// TODO(mdempsky): Theoretically, I think at this point we want to
-	// extend the implicit type parameters list with any new explicit
-	// type parameters.
-	//
-	// However, I believe that's moot: declared functions and methods
-	// have explicit type parameters, but are always declared at package
-	// scope (which has no implicit type parameters); and function
-	// literals can appear within a type-parameterized function (i.e.,
-	// implicit type parameters), but cannot have explicit type
-	// parameters of their own.
-	//
-	// So I think it's safe to just use whichever is non-empty.
-	implicitIdx := w.implicitIdx
-	if len(implicitIdx) == 0 {
-		implicitIdx = w.explicitIdx
-	} else {
-		assert(len(w.explicitIdx) == 0)
-	}
-	return implicitIdx
-}
-
-func (w *writer) addBody(sig *types2.Signature, block *syntax.BlockStmt, localsIdx map[types2.Object]int) {
-	w.sync(syncAddBody)
-
-	implicits := w.implicitTypes()
-	w.reloc(relocBody, w.p.bodyIdx(w.p.curpkg, sig, block, implicits, localsIdx))
-}
-
-func (pw *pkgWriter) bodyIdx(pkg *types2.Package, sig *types2.Signature, block *syntax.BlockStmt, implicitIdx map[*types2.TypeParam]int, localsIdx map[types2.Object]int) int {
+func (pw *pkgWriter) bodyIdx(pkg *types2.Package, sig *types2.Signature, block *syntax.BlockStmt, implicitIdx map[*types2.TypeParam]int) (idx int, closureVars []posObj) {
 	w := pw.newWriter(relocBody, syncFuncBody)
 	w.implicitIdx = implicitIdx
-	w.localsIdx = localsIdx
 
 	w.funcargs(sig)
 	if w.bool(block != nil) {
@@ -707,7 +682,7 @@ func (pw *pkgWriter) bodyIdx(pkg *types2.Package, sig *types2.Signature, block *
 		w.pos(block.Rbrace)
 	}
 
-	return w.flush()
+	return w.flush(), w.closureVars
 }
 
 func (w *writer) funcargs(sig *types2.Signature) {
@@ -730,19 +705,35 @@ func (w *writer) funcarg(param *types2.Var, result bool) {
 	}
 }
 
-func (w *writer) addLocal(obj types2.Object) {
+func (w *writer) addLocal(obj *types2.Var) {
 	w.sync(syncAddLocal)
 	idx := len(w.localsIdx)
 	if enableSync {
 		w.int(idx)
 	}
+	if w.localsIdx == nil {
+		w.localsIdx = make(map[*types2.Var]int)
+	}
 	w.localsIdx[obj] = idx
 }
 
-func (w *writer) useLocal(obj types2.Object) {
+func (w *writer) useLocal(pos syntax.Pos, obj *types2.Var) {
 	w.sync(syncUseObjLocal)
-	idx, ok := w.localsIdx[obj]
-	assert(ok)
+
+	if idx, ok := w.localsIdx[obj]; w.bool(ok) {
+		w.len(idx)
+		return
+	}
+
+	idx, ok := w.closureVarsIdx[obj]
+	if !ok {
+		if w.closureVarsIdx == nil {
+			w.closureVarsIdx = make(map[*types2.Var]int)
+		}
+		idx = len(w.closureVars)
+		w.closureVars = append(w.closureVars, posObj{pos, obj})
+		w.closureVarsIdx[obj] = idx
+	}
 	w.len(idx)
 }
 
@@ -806,8 +797,8 @@ func (w *writer) stmt1(stmt syntax.Stmt) {
 		default:
 			w.code(stmtAssign)
 			w.pos(stmt)
-			w.assignList(stmt.Lhs)
 			w.exprList(stmt.Rhs)
+			w.assignList(stmt.Lhs)
 		}
 
 	case *syntax.BlockStmt:
@@ -877,6 +868,8 @@ func (w *writer) assignList(expr syntax.Expr) {
 	for _, expr := range exprs {
 		if name, ok := expr.(*syntax.Name); ok && name.Value != "_" {
 			if obj, ok := w.p.info.Defs[name]; ok {
+				obj := obj.(*types2.Var)
+
 				w.bool(true)
 				w.pos(obj)
 				w.localIdent(obj)
@@ -923,16 +916,16 @@ func (w *writer) declStmt(decl syntax.Decl) {
 			for i, name := range decl.NameList {
 				w.code(stmtAssign)
 				w.pos(decl)
-				w.assignList(name)
 				w.exprList(values[i])
+				w.assignList(name)
 			}
 			break
 		}
 
 		w.code(stmtAssign)
 		w.pos(decl)
-		w.assignList(namesAsExpr(decl.NameList))
 		w.exprList(decl.Values)
+		w.assignList(namesAsExpr(decl.NameList))
 	}
 }
 
@@ -949,8 +942,8 @@ func (w *writer) forStmt(stmt *syntax.ForStmt) {
 
 	if rang, ok := stmt.Init.(*syntax.RangeClause); w.bool(ok) {
 		w.pos(rang)
-		w.assignList(rang.Lhs)
 		w.expr(rang.X)
+		w.assignList(rang.Lhs)
 	} else {
 		w.pos(stmt)
 		w.stmt(stmt.Init)
@@ -1092,15 +1085,17 @@ func (w *writer) expr(expr syntax.Expr) {
 	}
 
 	if obj != nil {
-		if _, ok := w.localsIdx[obj]; ok {
-			assert(len(targs) == 0)
-			w.code(exprLocal)
-			w.useLocal(obj)
+		if isGlobal(obj) {
+			w.code(exprName)
+			w.obj(obj, targs)
 			return
 		}
 
-		w.code(exprName)
-		w.obj(obj, targs)
+		obj := obj.(*types2.Var)
+		assert(len(targs) == 0)
+
+		w.code(exprLocal)
+		w.useLocal(expr.Pos(), obj)
 		return
 	}
 
@@ -1248,130 +1243,24 @@ func (w *writer) funcLit(expr *syntax.FuncLit) {
 	w.pos(expr.Type) // for QuirksMode
 	w.signature(sig)
 
-	closureVars, localsIdx := w.captureVars(expr)
+	block := expr.Body
+	body, closureVars := w.p.bodyIdx(w.p.curpkg, sig, block, w.implicitIdx)
+
 	w.len(len(closureVars))
-	for _, closureVar := range closureVars {
-		w.pos(closureVar.pos)
-		w.useLocal(closureVar.obj)
+	for _, cv := range closureVars {
+		w.pos(cv.pos)
+		if quirksMode() {
+			cv.pos = expr.Body.Rbrace
+		}
+		w.useLocal(cv.pos, cv.obj)
 	}
 
-	w.addBody(sig, expr.Body, localsIdx)
+	w.reloc(relocBody, body)
 }
 
 type posObj struct {
 	pos syntax.Pos
-	obj types2.Object
-}
-
-// captureVars returns the free variables used by the given function
-// literal. The closureVars result is the list of free variables
-// captured by expr, and localsIdx is a map from free variable to
-// index. See varCaptor's identically named fields for more details.
-func (w *writer) captureVars(expr *syntax.FuncLit) (closureVars []posObj, localsIdx map[types2.Object]int) {
-	scope, ok := w.p.info.Scopes[expr.Type]
-	assert(ok)
-
-	// TODO(mdempsky): This code needs to be cleaned up (e.g., to avoid
-	// traversing nested function literals multiple times). This will be
-	// easier after we drop quirks mode.
-
-	v := varCaptor{
-		w:         w,
-		scope:     scope,
-		localsIdx: make(map[types2.Object]int),
-	}
-
-	syntax.Walk(expr.Body, &v)
-
-	return v.closureVars, v.localsIdx
-}
-
-// varCaptor implements syntax.Visitor for enumerating free variables
-// used by a function literal.
-type varCaptor struct {
-	w     *writer
-	scope *types2.Scope
-
-	// closureVars lists free variables along with the position where
-	// they first appeared, in order of appearance.
-	closureVars []posObj
-
-	// localsIdx is a map from free variables to their index within
-	// closureVars.
-	localsIdx map[types2.Object]int
-}
-
-func (v *varCaptor) capture(n *syntax.Name) {
-	obj, ok := v.w.p.info.Uses[n].(*types2.Var)
-	if !ok || obj.IsField() {
-		return // not a variable
-	}
-
-	if obj.Parent() == obj.Pkg().Scope() {
-		return // global variable
-	}
-
-	if _, ok := v.localsIdx[obj]; ok {
-		return // already captured
-	}
-
-	for parent := obj.Parent(); parent != obj.Pkg().Scope(); parent = parent.Parent() {
-		if parent == v.scope {
-			return // object declared within our scope
-		}
-	}
-
-	idx := len(v.closureVars)
-	v.closureVars = append(v.closureVars, posObj{n.Pos(), obj})
-	v.localsIdx[obj] = idx
-}
-
-func (v *varCaptor) Visit(n syntax.Node) syntax.Visitor {
-	// Constant expressions don't count towards capturing.
-	if n, ok := n.(syntax.Expr); ok {
-		if tv, ok := v.w.p.info.Types[n]; ok && tv.Value != nil {
-			return nil
-		}
-	}
-
-	if n, ok := n.(*syntax.Name); ok {
-		v.capture(n)
-	}
-
-	if quirksMode() {
-		switch n := n.(type) {
-		case *syntax.FuncLit:
-			// Quirk: typecheck uses the rbrace position position of the
-			// function literal as the position of the intermediary capture.
-			end := len(v.closureVars)
-			syntax.Walk(n.Type, v) // unnecessary to walk, but consistent with non-quirks mode
-			syntax.Walk(n.Body, v)
-			for i := end; i < len(v.closureVars); i++ {
-				v.closureVars[i].pos = n.Body.Rbrace
-			}
-			return nil
-
-		case *syntax.AssignStmt:
-			// Quirk: typecheck visits (and thus captures) the RHS of
-			// assignment statements (but not op= statements) before the LHS.
-			if n.Op == 0 || n.Op == syntax.Def {
-				syntax.Walk(n.Rhs, v)
-				syntax.Walk(n.Lhs, v)
-				return nil
-			}
-
-		case *syntax.RangeClause:
-			// Quirk: Similarly, typecheck visits the expression to be
-			// iterated over before the iteration variables.
-			syntax.Walk(n.X, v)
-			if n.Lhs != nil {
-				syntax.Walk(n.Lhs, v)
-			}
-			return nil
-		}
-	}
-
-	return v
+	obj *types2.Var
 }
 
 func (w *writer) exprList(expr syntax.Expr) {

From d01bc571f7e55c7376f34e86be4e5660887bd30c Mon Sep 17 00:00:00 2001
From: Tao Qingyun 
Date: Tue, 22 Jun 2021 00:24:05 +0000
Subject: [PATCH 547/940] runtime: make ncgocall a global counter

ncgocall was stored per M, runtime.NumCgoCall lost the counter when a M die.

Fixes #46789

Change-Id: I85831fbb2713f4c30d1800d07e1f47aa0031970e
GitHub-Last-Rev: cbc15fa870de776d3fbf3b62fc9a5e01792e6a26
GitHub-Pull-Request: golang/go#46842
Reviewed-on: https://go-review.googlesource.com/c/go/+/329729
Run-TryBot: Ian Lance Taylor 
TryBot-Result: Go Bot 
Reviewed-by: Ian Lance Taylor 
Trust: Alexander Rakoczy 
---
 src/runtime/cgocall.go | 2 ++
 src/runtime/debug.go   | 2 +-
 src/runtime/proc.go    | 2 ++
 3 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go
index 0e287d0b8ed..8ffb48a888e 100644
--- a/src/runtime/cgocall.go
+++ b/src/runtime/cgocall.go
@@ -110,6 +110,8 @@ func syscall_cgocaller(fn unsafe.Pointer, args ...uintptr) uintptr {
 	return as.retval
 }
 
+var ncgocall uint64 // number of cgo calls in total for dead m
+
 // Call from Go to C.
 //
 // This must be nosplit because it's used for syscalls on some
diff --git a/src/runtime/debug.go b/src/runtime/debug.go
index f411b226766..82deefa200c 100644
--- a/src/runtime/debug.go
+++ b/src/runtime/debug.go
@@ -45,7 +45,7 @@ func NumCPU() int {
 
 // NumCgoCall returns the number of cgo calls made by the current process.
 func NumCgoCall() int64 {
-	var n int64
+	var n = int64(atomic.Load64(&ncgocall))
 	for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink {
 		n += int64(mp.ncgocall)
 	}
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index 8f1a4439456..4c92588a66e 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -1522,6 +1522,8 @@ found:
 	}
 	unlock(&sched.lock)
 
+	atomic.Xadd64(&ncgocall, int64(m.ncgocall))
+
 	// Release the P.
 	handoffp(releasep())
 	// After this point we must not have write barriers.

From 5160896c69a83f14bc54beb04be4c089333a0387 Mon Sep 17 00:00:00 2001
From: "Bryan C. Mills" 
Date: Wed, 23 Jun 2021 00:50:43 -0400
Subject: [PATCH 548/940] go/types: in TestStdlib, import from source instead
 of export data
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

TestStdlib was failing after running
	rm -r $(go env GOROOT)/pkg/*/cmd
as the builders do when building binary releases.¹

For users who write programs that depend on go/types, it should be
reasonable to run the tests for go/types as part of 'go test all', and
those tests should pass even if they installed Go from a binary
release.

I had originally drafted this as a fallback to import from source only
if the affected packages can't be imported by the default export-data
importer. Unfortunately, I realized that we don't currently have a
builder that tests the actual release (#46900), so it is quite likely
that the fallback path would bit-rot and produce unexpected test
regressions.

So instead, we now unconditionally import from source in TestStdlib.
That makes the test substantially slower (~15s instead of ~5s on my
workstation), but with less risk of regression, and TestStdlib is
skipped in short mode already so short-mode test time is unaffected.

If we change the builders to test the actual release configuration, we
can consider restoring the faster path when export data is available.

¹https://github.com/golang/build/blob/df58bbac082bc87c4a3cdfe336d1ffe60bbaa916/cmd/release/release.go#L533-L545

For #43232

Change-Id: I764ec56926c104053bb2ef23cf258c8f0f773290
Reviewed-on: https://go-review.googlesource.com/c/go/+/330252
Trust: Bryan C. Mills 
Trust: Robert Griesemer 
Run-TryBot: Bryan C. Mills 
TryBot-Result: Go Bot 
Reviewed-by: Robert Griesemer 
---
 src/go/types/stdlib_test.go | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/src/go/types/stdlib_test.go b/src/go/types/stdlib_test.go
index 503d0a6f445..d86a77a110f 100644
--- a/src/go/types/stdlib_test.go
+++ b/src/go/types/stdlib_test.go
@@ -26,9 +26,15 @@ import (
 	. "go/types"
 )
 
+// The cmd/*/internal packages may have been deleted as part of a binary
+// release. Import from source instead.
+//
+// (See https://golang.org/issue/43232 and
+// https://github.com/golang/build/blob/df58bbac082bc87c4a3cdfe336d1ffe60bbaa916/cmd/release/release.go#L533-L545.)
+//
 // Use the same importer for all std lib tests to
 // avoid repeated importing of the same packages.
-var stdLibImporter = importer.Default()
+var stdLibImporter = importer.ForCompiler(token.NewFileSet(), "source", nil)
 
 func TestStdlib(t *testing.T) {
 	testenv.MustHaveGoBuild(t)

From d1916e5e843d0341c2d82edf08335ac181c41bd8 Mon Sep 17 00:00:00 2001
From: "Bryan C. Mills" 
Date: Wed, 23 Jun 2021 22:06:50 -0400
Subject: [PATCH 549/940] go/types: in TestCheck/issues.src, import
 regexp/syntax instead of cmd/compile/internal/syntax

TestCheck/issues.src was failing after running
	rm -r $(go env GOROOT)/pkg/*/cmd
as the builders do when building binary releases.

For users who write programs that depend on go/types, it should be
reasonable for end users to run the tests for go/types as part of 'go
test all', and those tests should pass even if they installed Go from
a binary release.

The test case in issues.src was importing cmd/compile/internal/syntax
in order to check the reported package name.

I tried to fix the problem by having the test import from source
instead of from export data. Unfortunately, that changed the behavior
under test: the go/types.Package.Imports reports (and is documented to
report) a different set of imported packages when loading from source
as compared to when loading from export data.

For this particular test, after CL 313035 that difference resulted in
go/types treating the "syntax" name as ambiguous when importing from
source, because a transitive dependency on "regexp/syntax" is found
when loading from source but omitted when loading from export data.

The simple fix to make the package unambiguous again is to adapt the
test to import regexp/syntax directly. That not only makes the package
unambiguous with all importers, but also avoids depending on a
cmd-internal package that cannot be loaded from export data in binary
distributions of the Go toolchain.

For #43232

Change-Id: Iba45a680ea20d26daa86ac538fd8f1938e8b73ab
Reviewed-on: https://go-review.googlesource.com/c/go/+/330431
Trust: Bryan C. Mills 
Run-TryBot: Bryan C. Mills 
TryBot-Result: Go Bot 
Reviewed-by: Robert Findley 
---
 src/go/types/testdata/check/issues.src | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/go/types/testdata/check/issues.src b/src/go/types/testdata/check/issues.src
index 74d185cbc34..55fe220337f 100644
--- a/src/go/types/testdata/check/issues.src
+++ b/src/go/types/testdata/check/issues.src
@@ -6,7 +6,7 @@ package issues
 
 import (
 	"fmt"
-	syn "cmd/compile/internal/syntax"
+	syn "regexp/syntax"
 	t1 "text/template"
 	t2 "html/template"
 )
@@ -329,10 +329,10 @@ func (... /* ERROR can only use ... with final parameter */ TT) f()
 func issue28281g() (... /* ERROR can only use ... with final parameter */ TT)
 
 // Issue #26234: Make various field/method lookup errors easier to read by matching cmd/compile's output
-func issue26234a(f *syn.File) {
+func issue26234a(f *syn.Prog) {
 	// The error message below should refer to the actual package name (syntax)
 	// not the local package name (syn).
-	f.foo /* ERROR f\.foo undefined \(type \*syntax\.File has no field or method foo\) */
+	f.foo /* ERROR f\.foo undefined \(type \*syntax\.Prog has no field or method foo\) */
 }
 
 type T struct {
@@ -357,7 +357,7 @@ func issue35895() {
 	var _ T = 0 // ERROR cannot use 0 \(untyped int constant\) as T
 
 	// There is only one package with name syntax imported, only use the (global) package name in error messages.
-	var _ *syn.File = 0 // ERROR cannot use 0 \(untyped int constant\) as \*syntax.File
+	var _ *syn.Prog = 0 // ERROR cannot use 0 \(untyped int constant\) as \*syntax.Prog
 
 	// Because both t1 and t2 have the same global package name (template),
 	// qualify packages with full path name in this case.

From ed01ceaf4838cd67fd802df481769fa9ae9d0440 Mon Sep 17 00:00:00 2001
From: Cherry Mui 
Date: Fri, 25 Jun 2021 15:58:38 -0400
Subject: [PATCH 550/940] runtime/race: use race build tag on syso_test.go

All other test files in the runtime/race package have race build
tag, except syso_test.go. The test is only relevant if the race
detector is supported. So apply the build tag.

Fixes #46931.

Change-Id: Icdb94214d3821b4ccf61133412ef39b4d7cc7691
Reviewed-on: https://go-review.googlesource.com/c/go/+/331050
Trust: Cherry Mui 
Reviewed-by: Elias Naur 
Run-TryBot: Cherry Mui 
TryBot-Result: Go Bot 
---
 src/runtime/race/syso_test.go | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/src/runtime/race/syso_test.go b/src/runtime/race/syso_test.go
index cbce5a8f184..f5095737a4f 100644
--- a/src/runtime/race/syso_test.go
+++ b/src/runtime/race/syso_test.go
@@ -2,14 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build !android && !js && !ppc64le
-// +build !android,!js,!ppc64le
-
-// Note: we don't run on Android or ppc64 because if there is any non-race test
-// file in this package, the OS tries to link the .syso file into the
-// test (even when we're not in race mode), which fails. I'm not sure
-// why, but easiest to just punt - as long as a single builder runs
-// this test, we're good.
+//go:build race
+// +build race
 
 package race
 

From 942edc750292060450fda38835c452f6125447c3 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Fri, 25 Jun 2021 10:04:51 -0700
Subject: [PATCH 551/940] [dev.typeparams] cmd/compile: rename
 types.Type.{Short,Long}String to {Link,Name}String

The original names "ShortString" and "LongString" refer back to the
fmt verbs used to request their formatting styles. However, I always
get confused working with them, in particular because (1) the
"ShortString" description, which uses package-path qualification, is
actually generally longer than the "LongString" description, which
uses package-name qualification; and (2) the documentation mentions
how they're often used, but doesn't actually describe why they're safe
for those purposes.

This CL renames them to "LinkString" and "NameString", respectively,
based on their primary use cases. It also attempts to more completely
describe the strings they return and how they can be used correctly.

Change-Id: I9158ae3eafa8ac53da31a78c7a6d929dc0199afe
Reviewed-on: https://go-review.googlesource.com/c/go/+/330910
Trust: Matthew Dempsky 
Run-TryBot: Matthew Dempsky 
TryBot-Result: Go Bot 
Reviewed-by: Robert Griesemer 
---
 src/cmd/compile/internal/noder/reader.go      |  4 +-
 .../compile/internal/reflectdata/reflect.go   |  8 ++--
 src/cmd/compile/internal/typecheck/stmt.go    |  2 +-
 src/cmd/compile/internal/types/fmt.go         | 38 ++++++++++++++-----
 src/cmd/compile/internal/types/type.go        |  2 +-
 src/cmd/compile/internal/walk/order.go        |  4 +-
 6 files changed, 39 insertions(+), 19 deletions(-)

diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go
index 0423fcce987..459e1d1703c 100644
--- a/src/cmd/compile/internal/noder/reader.go
+++ b/src/cmd/compile/internal/noder/reader.go
@@ -631,7 +631,7 @@ func (r *reader) mangle(sym *types.Sym) *types.Sym {
 			}
 			// TODO(mdempsky): We need the linker to replace "" in the symbol
 			// names here.
-			buf.WriteString(targ.ShortString())
+			buf.WriteString(targ.LinkString())
 		}
 	}
 	buf.WriteByte(']')
@@ -2041,7 +2041,7 @@ func (r *reader) wrapTypes(target *ir.Package) {
 	seen := make(map[string]*types.Type)
 	for _, typ := range needWrapperTypes {
 		if typ.Sym() == nil {
-			key := typ.ShortString()
+			key := typ.LinkString()
 			if prev := seen[key]; prev != nil {
 				if !types.Identical(typ, prev) {
 					base.Fatalf("collision: types %v and %v have short string %q", typ, prev, key)
diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go
index 8421e36b3dd..316c7eb2935 100644
--- a/src/cmd/compile/internal/reflectdata/reflect.go
+++ b/src/cmd/compile/internal/reflectdata/reflect.go
@@ -717,7 +717,7 @@ func dcommontype(lsym *obj.LSym, t *types.Type) int {
 	}
 
 	exported := false
-	p := t.LongString()
+	p := t.NameString()
 	// If we're writing out type T,
 	// we are very likely to write out type *T as well.
 	// Use the string "*T"[1:] for "T", so that the two
@@ -781,11 +781,11 @@ func dcommontype(lsym *obj.LSym, t *types.Type) int {
 // TrackSym returns the symbol for tracking use of field/method f, assumed
 // to be a member of struct/interface type t.
 func TrackSym(t *types.Type, f *types.Field) *obj.LSym {
-	return base.PkgLinksym("go.track", t.ShortString()+"."+f.Sym.Name, obj.ABI0)
+	return base.PkgLinksym("go.track", t.LinkString()+"."+f.Sym.Name, obj.ABI0)
 }
 
 func TypeSymPrefix(prefix string, t *types.Type) *types.Sym {
-	p := prefix + "." + t.ShortString()
+	p := prefix + "." + t.LinkString()
 	s := types.TypeSymLookup(p)
 
 	// This function is for looking up type-related generated functions
@@ -833,7 +833,7 @@ func TypePtr(t *types.Type) *ir.AddrExpr {
 // ITabAddr returns an expression representing a pointer to the itab
 // for concrete type typ implementing interface iface.
 func ITabAddr(typ, iface *types.Type) *ir.AddrExpr {
-	s, existed := ir.Pkgs.Itab.LookupOK(typ.ShortString() + "," + iface.ShortString())
+	s, existed := ir.Pkgs.Itab.LookupOK(typ.LinkString() + "," + iface.LinkString())
 	lsym := s.Linksym()
 
 	if !existed {
diff --git a/src/cmd/compile/internal/typecheck/stmt.go b/src/cmd/compile/internal/typecheck/stmt.go
index cd00f1b3d11..313491ba0b8 100644
--- a/src/cmd/compile/internal/typecheck/stmt.go
+++ b/src/cmd/compile/internal/typecheck/stmt.go
@@ -678,7 +678,7 @@ func (s *typeSet) add(pos src.XPos, typ *types.Type) {
 	// LongString does not uniquely identify types, so we need to
 	// disambiguate collisions with types.Identical.
 	// TODO(mdempsky): Add a method that *is* unique.
-	ls := typ.LongString()
+	ls := typ.NameString()
 	prevs := s.m[ls]
 	for _, prev := range prevs {
 		if types.Identical(typ, prev.typ) {
diff --git a/src/cmd/compile/internal/types/fmt.go b/src/cmd/compile/internal/types/fmt.go
index b4d1f6c8bbd..095b795d036 100644
--- a/src/cmd/compile/internal/types/fmt.go
+++ b/src/cmd/compile/internal/types/fmt.go
@@ -242,17 +242,37 @@ func (t *Type) String() string {
 	return tconv(t, 0, fmtGo)
 }
 
-// ShortString generates a short description of t.
-// It is used in autogenerated method names, reflection,
-// and itab names.
-func (t *Type) ShortString() string {
+// LinkString returns an unexpanded string description of t, suitable
+// for use in link symbols. "Unexpanded" here means that the
+// description uses `"".` to qualify identifiers from the current
+// package, and "expansion" refers to the renaming step performed by
+// the linker to replace these qualifiers with proper `path/to/pkg.`
+// qualifiers.
+//
+// After expansion, the description corresponds to type identity. That
+// is, for any pair of types t1 and t2, Identical(t1, t2) and
+// expand(t1.LinkString()) == expand(t2.LinkString()) report the same
+// value.
+//
+// Within a single compilation unit, LinkString always returns the
+// same unexpanded description for identical types. Thus it's safe to
+// use as a map key to implement a type-identity-keyed map. However,
+// make sure all LinkString calls used for this purpose happen within
+// the same compile process; the string keys are not stable across
+// multiple processes.
+func (t *Type) LinkString() string {
 	return tconv(t, 0, fmtTypeID)
 }
 
-// LongString generates a complete description of t.
-// It is useful for reflection,
-// or when a unique fingerprint or hash of a type is required.
-func (t *Type) LongString() string {
+// NameString generates a user-readable, mostly unique string
+// description of t. NameString always returns the same description
+// for identical types, even across compilation units.
+//
+// NameString qualifies identifiers by package name, so it has
+// collisions when different packages share the same names and
+// identifiers. It also does not distinguish function-scope defined
+// types from package-scoped defined types or from each other.
+func (t *Type) NameString() string {
 	return tconv(t, 0, fmtTypeIDName)
 }
 
@@ -677,7 +697,7 @@ func FmtConst(v constant.Value, sharp bool) string {
 
 // TypeHash computes a hash value for type t to use in type switch statements.
 func TypeHash(t *Type) uint32 {
-	p := t.LongString()
+	p := t.NameString()
 
 	// Using MD5 is overkill, but reduces accidental collisions.
 	h := md5.Sum([]byte(p))
diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go
index 075009d6a3b..7f750007972 100644
--- a/src/cmd/compile/internal/types/type.go
+++ b/src/cmd/compile/internal/types/type.go
@@ -2129,7 +2129,7 @@ func TypeSymLookup(name string) *Sym {
 }
 
 func TypeSymName(t *Type) string {
-	name := t.ShortString()
+	name := t.LinkString()
 	// Use a separate symbol name for Noalg types for #17752.
 	if TypeHasNoAlg(t) {
 		name = "noalg." + name
diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go
index 62d9b95be90..59701613c35 100644
--- a/src/cmd/compile/internal/walk/order.go
+++ b/src/cmd/compile/internal/walk/order.go
@@ -78,7 +78,7 @@ func (o *orderState) newTemp(t *types.Type, clear bool) *ir.Name {
 	var v *ir.Name
 	// Note: LongString is close to the type equality we want,
 	// but not exactly. We still need to double-check with types.Identical.
-	key := t.LongString()
+	key := t.NameString()
 	a := o.free[key]
 	for i, n := range a {
 		if types.Identical(t, n.Type()) {
@@ -370,7 +370,7 @@ func (o *orderState) markTemp() ordermarker {
 // which must have been returned by markTemp.
 func (o *orderState) popTemp(mark ordermarker) {
 	for _, n := range o.temp[mark:] {
-		key := n.Type().LongString()
+		key := n.Type().NameString()
 		o.free[key] = append(o.free[key], n)
 	}
 	o.temp = o.temp[:mark]

From ed647b16d02da4571c22baac23c302f2d888b88b Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Fri, 25 Jun 2021 10:15:40 -0700
Subject: [PATCH 552/940] [dev.typeparams] cmd/compile: use Type.LinkString for
 map keys

This CL changes typecheck and order to use Type.LinkString for
computing map keys instead of Type.NameString. As mentioned in the
LinkString docs (added by the previous CL), LinkString reliably maps
type identity to string equality as long as the LinkString calls all
happen within the same compilation unit (which they do here).

This eliminates the need for subsequent types.Identical checks.

Change-Id: I32ff591e69d6f23f2dc6ebd5af343618ebe89013
Reviewed-on: https://go-review.googlesource.com/c/go/+/330911
Run-TryBot: Matthew Dempsky 
TryBot-Result: Go Bot 
Trust: Matthew Dempsky 
Reviewed-by: Robert Griesemer 
---
 .../compile/internal/reflectdata/reflect.go   |  9 +++++--
 src/cmd/compile/internal/typecheck/stmt.go    | 25 ++++++-------------
 src/cmd/compile/internal/walk/order.go        | 24 +++++++-----------
 3 files changed, 23 insertions(+), 35 deletions(-)

diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go
index 316c7eb2935..351aaab399a 100644
--- a/src/cmd/compile/internal/reflectdata/reflect.go
+++ b/src/cmd/compile/internal/reflectdata/reflect.go
@@ -1388,7 +1388,7 @@ func WriteBasicTypes() {
 
 type typeAndStr struct {
 	t       *types.Type
-	short   string
+	short   string // "short" here means NameString
 	regular string
 }
 
@@ -1401,8 +1401,13 @@ func (a typesByString) Less(i, j int) bool {
 	}
 	// When the only difference between the types is whether
 	// they refer to byte or uint8, such as **byte vs **uint8,
-	// the types' ShortStrings can be identical.
+	// the types' NameStrings can be identical.
 	// To preserve deterministic sort ordering, sort these by String().
+	//
+	// TODO(mdempsky): This all seems suspect. Using LinkString would
+	// avoid naming collisions, and there shouldn't be a reason to care
+	// about "byte" vs "uint8": they share the same runtime type
+	// descriptor anyway.
 	if a[i].regular != a[j].regular {
 		return a[i].regular < a[j].regular
 	}
diff --git a/src/cmd/compile/internal/typecheck/stmt.go b/src/cmd/compile/internal/typecheck/stmt.go
index 313491ba0b8..54cf508acc1 100644
--- a/src/cmd/compile/internal/typecheck/stmt.go
+++ b/src/cmd/compile/internal/typecheck/stmt.go
@@ -662,29 +662,18 @@ func tcSwitchType(n *ir.SwitchStmt) {
 }
 
 type typeSet struct {
-	m map[string][]typeSetEntry
-}
-
-type typeSetEntry struct {
-	pos src.XPos
-	typ *types.Type
+	m map[string]src.XPos
 }
 
 func (s *typeSet) add(pos src.XPos, typ *types.Type) {
 	if s.m == nil {
-		s.m = make(map[string][]typeSetEntry)
+		s.m = make(map[string]src.XPos)
 	}
 
-	// LongString does not uniquely identify types, so we need to
-	// disambiguate collisions with types.Identical.
-	// TODO(mdempsky): Add a method that *is* unique.
-	ls := typ.NameString()
-	prevs := s.m[ls]
-	for _, prev := range prevs {
-		if types.Identical(typ, prev.typ) {
-			base.ErrorfAt(pos, "duplicate case %v in type switch\n\tprevious case at %s", typ, base.FmtPos(prev.pos))
-			return
-		}
+	ls := typ.LinkString()
+	if prev, ok := s.m[ls]; ok {
+		base.ErrorfAt(pos, "duplicate case %v in type switch\n\tprevious case at %s", typ, base.FmtPos(prev))
+		return
 	}
-	s.m[ls] = append(prevs, typeSetEntry{pos, typ})
+	s.m[ls] = pos
 }
diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go
index 59701613c35..9912feba637 100644
--- a/src/cmd/compile/internal/walk/order.go
+++ b/src/cmd/compile/internal/walk/order.go
@@ -51,7 +51,7 @@ import (
 type orderState struct {
 	out  []ir.Node             // list of generated statements
 	temp []*ir.Name            // stack of temporary variables
-	free map[string][]*ir.Name // free list of unused temporaries, by type.LongString().
+	free map[string][]*ir.Name // free list of unused temporaries, by type.LinkString().
 	edit func(ir.Node) ir.Node // cached closure of o.exprNoLHS
 }
 
@@ -76,20 +76,14 @@ func (o *orderState) append(stmt ir.Node) {
 // If clear is true, newTemp emits code to zero the temporary.
 func (o *orderState) newTemp(t *types.Type, clear bool) *ir.Name {
 	var v *ir.Name
-	// Note: LongString is close to the type equality we want,
-	// but not exactly. We still need to double-check with types.Identical.
-	key := t.NameString()
-	a := o.free[key]
-	for i, n := range a {
-		if types.Identical(t, n.Type()) {
-			v = a[i]
-			a[i] = a[len(a)-1]
-			a = a[:len(a)-1]
-			o.free[key] = a
-			break
+	key := t.LinkString()
+	if a := o.free[key]; len(a) > 0 {
+		v = a[len(a)-1]
+		if !types.Identical(t, v.Type()) {
+			base.Fatalf("expected %L to have type %v", v, t)
 		}
-	}
-	if v == nil {
+		o.free[key] = a[:len(a)-1]
+	} else {
 		v = typecheck.Temp(t)
 	}
 	if clear {
@@ -370,7 +364,7 @@ func (o *orderState) markTemp() ordermarker {
 // which must have been returned by markTemp.
 func (o *orderState) popTemp(mark ordermarker) {
 	for _, n := range o.temp[mark:] {
-		key := n.Type().NameString()
+		key := n.Type().LinkString()
 		o.free[key] = append(o.free[key], n)
 	}
 	o.temp = o.temp[:mark]

From d417b8cf87bd8e0f8362aa1cc9b7dadd221731c9 Mon Sep 17 00:00:00 2001
From: Cuong Manh Le 
Date: Fri, 25 Jun 2021 14:01:54 +0700
Subject: [PATCH 553/940] [dev.typeparams] cmd/compile: clarify comment about
 checking reflect.Method in usemethod

Followup discussion in CL 330670.

Change-Id: Icec2d5d5715666a6967e18ac9ab3d802b47569da
Reviewed-on: https://go-review.googlesource.com/c/go/+/330830
Trust: Cuong Manh Le 
Run-TryBot: Cuong Manh Le 
TryBot-Result: Go Bot 
Reviewed-by: Matthew Dempsky 
---
 src/cmd/compile/internal/walk/expr.go | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/cmd/compile/internal/walk/expr.go b/src/cmd/compile/internal/walk/expr.go
index d8bded80758..6928f2ac706 100644
--- a/src/cmd/compile/internal/walk/expr.go
+++ b/src/cmd/compile/internal/walk/expr.go
@@ -958,9 +958,8 @@ func usemethod(n *ir.CallExpr) {
 		return
 	}
 
-	// Note: Don't rely on Field.Type.String() since its formatting depends on multiple factors
-	//       (including global variables such as numImports - was issue #19028).
-	// Also need to check for reflect package itself (see Issue #38515).
+	// Check that first result type is "reflect.Method". Note that we have to check sym name and sym package
+	// separately, as we can't check for exact string "reflect.Method" reliably (e.g., see #19028 and #38515).
 	if s := t.Results().Field(0).Type.Sym(); s != nil && s.Name == "Method" && types.IsReflectPkg(s.Pkg) {
 		ir.CurFunc.SetReflectMethod(true)
 		// The LSym is initialized at this point. We need to set the attribute on the LSym.

From 942bcc2d4f4e66b617c225aed1ba4d4d42a08ed2 Mon Sep 17 00:00:00 2001
From: Cuong Manh Le 
Date: Sat, 26 Jun 2021 13:57:51 +0700
Subject: [PATCH 554/940] [dev.typeparams] cmd/compile: fix wrong AST
 generation in devirtualization

CL 330671 moved rewrite method calls to escape analysis. It accidently
made the AST invalid, by removing the OCALLMETH set operation during
devirtualization pass.

Change-Id: I862ffd7f880de55969d7784d9e7b3c38894f6b68
Reviewed-on: https://go-review.googlesource.com/c/go/+/330832
Trust: Cuong Manh Le 
Run-TryBot: Cuong Manh Le 
TryBot-Result: Go Bot 
Reviewed-by: Matthew Dempsky 
---
 src/cmd/compile/internal/devirtualize/devirtualize.go | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/cmd/compile/internal/devirtualize/devirtualize.go b/src/cmd/compile/internal/devirtualize/devirtualize.go
index f52499e07f6..60ba208d087 100644
--- a/src/cmd/compile/internal/devirtualize/devirtualize.go
+++ b/src/cmd/compile/internal/devirtualize/devirtualize.go
@@ -50,6 +50,7 @@ func Call(call *ir.CallExpr) {
 		if base.Flag.LowerM != 0 {
 			base.WarnfAt(call.Pos(), "devirtualizing %v to %v", sel, typ)
 		}
+		call.SetOp(ir.OCALLMETH)
 		call.X = x
 	case ir.ODOTINTER:
 		// Promoted method from embedded interface-typed field (#42279).

From 180c338c6893c2e8b7f4692ed62f92a1ed0cd1e8 Mon Sep 17 00:00:00 2001
From: Cuong Manh Le 
Date: Sat, 26 Jun 2021 14:34:56 +0700
Subject: [PATCH 555/940] [dev.typeparams] cmd/compile: restore check for
 OCALLMETH in walkCall

Since when walkCall1 still need to handle OCALLMETH.

Change-Id: Iadb12a0965169c63f97978c96412012ef4fa02df
Reviewed-on: https://go-review.googlesource.com/c/go/+/330833
Trust: Cuong Manh Le 
Run-TryBot: Cuong Manh Le 
Reviewed-by: Matthew Dempsky 
---
 src/cmd/compile/internal/walk/expr.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/cmd/compile/internal/walk/expr.go b/src/cmd/compile/internal/walk/expr.go
index 6928f2ac706..86c6d445012 100644
--- a/src/cmd/compile/internal/walk/expr.go
+++ b/src/cmd/compile/internal/walk/expr.go
@@ -489,7 +489,7 @@ func walkAddString(n *ir.AddStringExpr, init *ir.Nodes) ir.Node {
 
 // walkCall walks an OCALLFUNC, OCALLINTER, or OCALLMETH node.
 func walkCall(n *ir.CallExpr, init *ir.Nodes) ir.Node {
-	if n.Op() == ir.OCALLINTER || n.X.Op() == ir.OMETHEXPR {
+	if n.Op() == ir.OCALLINTER || n.Op() == ir.OCALLMETH || n.X.Op() == ir.OMETHEXPR {
 		// We expect both interface call reflect.Type.Method and concrete
 		// call reflect.(*rtype).Method.
 		usemethod(n)

From 0cf71f7f92c2623a132ab3257690826643d548af Mon Sep 17 00:00:00 2001
From: Cuong Manh Le 
Date: Fri, 25 Jun 2021 22:24:29 +0700
Subject: [PATCH 556/940] [dev.typeparams] cmd/compile: rewrite method calls
 during typecheck

CL 330671 move rewriting method call to method expression to escape
analysis. This CL move the rewriting up further, into typecheck. It
helps simplify the code for dowstream passes, as they now only have to
deal with OCALLFUNC.

There're two notes:

 - For -G=3, we can't rewrite d.M() where d is an instantiated receiver
   in transformCall, but let irgen.stencil to rewrite it.

 - Escape analysis still have to check for rewriting method calls, as
   the devirtualization pass can still generate OCALLMETH.

Does not pass toolstash, since when the export data now contains method
expression calls instead of method calls.

Change-Id: I77465ef04d50dc4efedddca7eb55b3fc9483db0e
Reviewed-on: https://go-review.googlesource.com/c/go/+/330831
Trust: Cuong Manh Le 
Run-TryBot: Cuong Manh Le 
TryBot-Result: Go Bot 
Reviewed-by: Matthew Dempsky 
---
 src/cmd/compile/internal/escape/call.go     |  2 +-
 src/cmd/compile/internal/inline/inl.go      | 79 +++++++++------------
 src/cmd/compile/internal/noder/reader.go    |  3 +-
 src/cmd/compile/internal/noder/transform.go |  3 +
 src/cmd/compile/internal/typecheck/func.go  |  1 +
 src/cmd/compile/internal/walk/convert.go    |  4 +-
 src/cmd/compile/internal/walk/expr.go       | 11 +--
 src/cmd/compile/internal/walk/order.go      | 19 +++--
 src/cmd/compile/internal/walk/stmt.go       |  1 -
 src/cmd/compile/internal/walk/walk.go       |  2 +-
 10 files changed, 65 insertions(+), 60 deletions(-)

diff --git a/src/cmd/compile/internal/escape/call.go b/src/cmd/compile/internal/escape/call.go
index 62727a8ef86..46bfe65aff1 100644
--- a/src/cmd/compile/internal/escape/call.go
+++ b/src/cmd/compile/internal/escape/call.go
@@ -68,7 +68,7 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
 				fn = ir.MethodExprName(v)
 			}
 		case ir.OCALLMETH:
-			fn = ir.MethodExprName(call.X)
+			base.FatalfAt(call.Pos(), "OCALLMETH missed by typecheck")
 		}
 
 		fntype := call.X.Type()
diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go
index 0620191bbf6..3086d093c04 100644
--- a/src/cmd/compile/internal/inline/inl.go
+++ b/src/cmd/compile/internal/inline/inl.go
@@ -273,6 +273,19 @@ func (v *hairyVisitor) doNode(n ir.Node) bool {
 				}
 			}
 		}
+		if n.X.Op() == ir.OMETHEXPR {
+			if meth := ir.MethodExprName(n.X); meth != nil {
+				fn := meth.Func
+				if fn != nil && types.IsRuntimePkg(fn.Sym().Pkg) && fn.Sym().Name == "heapBits.nextArena" {
+					// Special case: explicitly allow
+					// mid-stack inlining of
+					// runtime.heapBits.next even though
+					// it calls slow-path
+					// runtime.heapBits.nextArena.
+					break
+				}
+			}
+		}
 
 		if ir.IsIntrinsicCall(n) {
 			// Treat like any other node.
@@ -287,28 +300,8 @@ func (v *hairyVisitor) doNode(n ir.Node) bool {
 		// Call cost for non-leaf inlining.
 		v.budget -= v.extraCallCost
 
-	// Call is okay if inlinable and we have the budget for the body.
 	case ir.OCALLMETH:
-		n := n.(*ir.CallExpr)
-		t := n.X.Type()
-		if t == nil {
-			base.Fatalf("no function type for [%p] %+v\n", n.X, n.X)
-		}
-		fn := ir.MethodExprName(n.X).Func
-		if types.IsRuntimePkg(fn.Sym().Pkg) && fn.Sym().Name == "heapBits.nextArena" {
-			// Special case: explicitly allow
-			// mid-stack inlining of
-			// runtime.heapBits.next even though
-			// it calls slow-path
-			// runtime.heapBits.nextArena.
-			break
-		}
-		if fn.Inl != nil {
-			v.budget -= fn.Inl.Cost
-			break
-		}
-		// Call cost for non-leaf inlining.
-		v.budget -= v.extraCallCost
+		base.FatalfAt(n.Pos(), "OCALLMETH missed by typecheck")
 
 	// Things that are too hairy, irrespective of the budget
 	case ir.OCALL, ir.OCALLINTER:
@@ -575,7 +568,9 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.No
 	case ir.ODEFER, ir.OGO:
 		n := n.(*ir.GoDeferStmt)
 		switch call := n.Call; call.Op() {
-		case ir.OCALLFUNC, ir.OCALLMETH:
+		case ir.OCALLMETH:
+			base.FatalfAt(call.Pos(), "OCALLMETH missed by typecheck")
+		case ir.OCALLFUNC:
 			call := call.(*ir.CallExpr)
 			call.NoInline = true
 		}
@@ -585,11 +580,18 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.No
 	case ir.OCLOSURE:
 		return n
 	case ir.OCALLMETH:
-		// Prevent inlining some reflect.Value methods when using checkptr,
-		// even when package reflect was compiled without it (#35073).
+		base.FatalfAt(n.Pos(), "OCALLMETH missed by typecheck")
+	case ir.OCALLFUNC:
 		n := n.(*ir.CallExpr)
-		if s := ir.MethodExprName(n.X).Sym(); base.Debug.Checkptr != 0 && types.IsReflectPkg(s.Pkg) && (s.Name == "Value.UnsafeAddr" || s.Name == "Value.Pointer") {
-			return n
+		if n.X.Op() == ir.OMETHEXPR {
+			// Prevent inlining some reflect.Value methods when using checkptr,
+			// even when package reflect was compiled without it (#35073).
+			if meth := ir.MethodExprName(n.X); meth != nil {
+				s := meth.Sym()
+				if base.Debug.Checkptr != 0 && types.IsReflectPkg(s.Pkg) && (s.Name == "Value.UnsafeAddr" || s.Name == "Value.Pointer") {
+					return n
+				}
+			}
 		}
 	}
 
@@ -611,7 +613,9 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.No
 	// transmogrify this node itself unless inhibited by the
 	// switch at the top of this function.
 	switch n.Op() {
-	case ir.OCALLFUNC, ir.OCALLMETH:
+	case ir.OCALLMETH:
+		base.FatalfAt(n.Pos(), "OCALLMETH missed by typecheck")
+	case ir.OCALLFUNC:
 		n := n.(*ir.CallExpr)
 		if n.NoInline {
 			return n
@@ -631,19 +635,8 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.No
 		if fn := inlCallee(call.X); fn != nil && fn.Inl != nil {
 			n = mkinlcall(call, fn, maxCost, inlMap, edit)
 		}
-
 	case ir.OCALLMETH:
-		call = n.(*ir.CallExpr)
-		if base.Flag.LowerM > 3 {
-			fmt.Printf("%v:call to meth %v\n", ir.Line(n), call.X.(*ir.SelectorExpr).Sel)
-		}
-
-		// typecheck should have resolved ODOTMETH->type, whose nname points to the actual function.
-		if call.X.Type() == nil {
-			base.Fatalf("no function type for [%p] %+v\n", call.X, call.X)
-		}
-
-		n = mkinlcall(call, ir.MethodExprName(call.X).Func, maxCost, inlMap, edit)
+		base.FatalfAt(n.Pos(), "OCALLMETH missed by typecheck")
 	}
 
 	base.Pos = lno
@@ -723,7 +716,7 @@ var SSADumpInline = func(*ir.Func) {}
 // instead.
 var NewInline = func(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExpr { return nil }
 
-// If n is a call node (OCALLFUNC or OCALLMETH), and fn is an ONAME node for a
+// If n is a OCALLFUNC node, and fn is an ONAME node for a
 // function with an inlinable body, return an OINLCALL node that can replace n.
 // The returned node's Ninit has the parameter assignments, the Nbody is the
 // inlined function body, and (List, Rlist) contain the (input, output)
@@ -906,11 +899,7 @@ func oldInline(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExpr
 	as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
 	as.Def = true
 	if call.Op() == ir.OCALLMETH {
-		sel := call.X.(*ir.SelectorExpr)
-		if sel.X == nil {
-			base.Fatalf("method call without receiver: %+v", call)
-		}
-		as.Rhs.Append(sel.X)
+		base.FatalfAt(call.Pos(), "OCALLMETH missed by typecheck")
 	}
 	as.Rhs.Append(call.Args...)
 
diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go
index 459e1d1703c..e5ad3f4b8ef 100644
--- a/src/cmd/compile/internal/noder/reader.go
+++ b/src/cmd/compile/internal/noder/reader.go
@@ -1807,8 +1807,7 @@ func InlineCall(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExp
 
 	var args ir.Nodes
 	if call.Op() == ir.OCALLMETH {
-		assert(call.X.Op() == ir.ODOTMETH)
-		args.Append(call.X.(*ir.SelectorExpr).X)
+		base.FatalfAt(call.Pos(), "OCALLMETH missed by typecheck")
 	}
 	args.Append(call.Args...)
 
diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go
index 946d335f076..30d6e34ae4e 100644
--- a/src/cmd/compile/internal/noder/transform.go
+++ b/src/cmd/compile/internal/noder/transform.go
@@ -149,6 +149,9 @@ func transformCall(n *ir.CallExpr) {
 	}
 
 	typecheckaste(ir.OCALL, n.X, n.IsDDD, t.Params(), n.Args)
+	if l.Op() == ir.ODOTMETH && len(deref(n.X.Type().Recv().Type).RParams()) == 0 {
+		typecheck.FixMethodCall(n)
+	}
 	if t.NumResults() == 1 {
 		n.SetType(l.Type().Results().Field(0).Type)
 
diff --git a/src/cmd/compile/internal/typecheck/func.go b/src/cmd/compile/internal/typecheck/func.go
index 00770c87cf8..20b991be56a 100644
--- a/src/cmd/compile/internal/typecheck/func.go
+++ b/src/cmd/compile/internal/typecheck/func.go
@@ -516,6 +516,7 @@ func tcCall(n *ir.CallExpr, top int) ir.Node {
 	}
 
 	typecheckaste(ir.OCALL, n.X, n.IsDDD, t.Params(), n.Args, func() string { return fmt.Sprintf("argument to %v", n.X) })
+	FixMethodCall(n)
 	if t.NumResults() == 0 {
 		return n
 	}
diff --git a/src/cmd/compile/internal/walk/convert.go b/src/cmd/compile/internal/walk/convert.go
index 5297332f6b0..e659ee59f14 100644
--- a/src/cmd/compile/internal/walk/convert.go
+++ b/src/cmd/compile/internal/walk/convert.go
@@ -462,7 +462,9 @@ func walkCheckPtrArithmetic(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
 	// TODO(mdempsky): Make stricter. We only need to exempt
 	// reflect.Value.Pointer and reflect.Value.UnsafeAddr.
 	switch n.X.Op() {
-	case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
+	case ir.OCALLMETH:
+		base.FatalfAt(n.X.Pos(), "OCALLMETH missed by typecheck")
+	case ir.OCALLFUNC, ir.OCALLINTER:
 		return n
 	}
 
diff --git a/src/cmd/compile/internal/walk/expr.go b/src/cmd/compile/internal/walk/expr.go
index 86c6d445012..f7675c3b7d0 100644
--- a/src/cmd/compile/internal/walk/expr.go
+++ b/src/cmd/compile/internal/walk/expr.go
@@ -167,7 +167,7 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
 	case ir.OCFUNC:
 		return n
 
-	case ir.OCALLINTER, ir.OCALLFUNC, ir.OCALLMETH:
+	case ir.OCALLINTER, ir.OCALLFUNC:
 		n := n.(*ir.CallExpr)
 		return walkCall(n, init)
 
@@ -487,9 +487,12 @@ func walkAddString(n *ir.AddStringExpr, init *ir.Nodes) ir.Node {
 	return r1
 }
 
-// walkCall walks an OCALLFUNC, OCALLINTER, or OCALLMETH node.
+// walkCall walks an OCALLFUNC or OCALLINTER node.
 func walkCall(n *ir.CallExpr, init *ir.Nodes) ir.Node {
-	if n.Op() == ir.OCALLINTER || n.Op() == ir.OCALLMETH || n.X.Op() == ir.OMETHEXPR {
+	if n.Op() == ir.OCALLMETH {
+		base.FatalfAt(n.Pos(), "OCALLMETH missed by typecheck")
+	}
+	if n.Op() == ir.OCALLINTER || n.X.Op() == ir.OMETHEXPR {
 		// We expect both interface call reflect.Type.Method and concrete
 		// call reflect.(*rtype).Method.
 		usemethod(n)
@@ -550,7 +553,7 @@ func walkCall1(n *ir.CallExpr, init *ir.Nodes) {
 	n.SetWalked(true)
 
 	if n.Op() == ir.OCALLMETH {
-		typecheck.FixMethodCall(n)
+		base.FatalfAt(n.Pos(), "OCALLMETH missed by typecheck")
 	}
 
 	args := n.Args
diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go
index 9912feba637..16a124d2ff1 100644
--- a/src/cmd/compile/internal/walk/order.go
+++ b/src/cmd/compile/internal/walk/order.go
@@ -506,15 +506,18 @@ func (o *orderState) init(n ir.Node) {
 }
 
 // call orders the call expression n.
-// n.Op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY.
+// n.Op is OCALLFUNC/OCALLINTER or a builtin like OCOPY.
 func (o *orderState) call(nn ir.Node) {
 	if len(nn.Init()) > 0 {
 		// Caller should have already called o.init(nn).
 		base.Fatalf("%v with unexpected ninit", nn.Op())
 	}
+	if nn.Op() == ir.OCALLMETH {
+		base.FatalfAt(nn.Pos(), "OCALLMETH missed by typecheck")
+	}
 
 	// Builtin functions.
-	if nn.Op() != ir.OCALLFUNC && nn.Op() != ir.OCALLMETH && nn.Op() != ir.OCALLINTER {
+	if nn.Op() != ir.OCALLFUNC && nn.Op() != ir.OCALLINTER {
 		switch n := nn.(type) {
 		default:
 			base.Fatalf("unexpected call: %+v", n)
@@ -707,7 +710,7 @@ func (o *orderState) stmt(n ir.Node) {
 		o.out = append(o.out, n)
 
 	// Special: handle call arguments.
-	case ir.OCALLFUNC, ir.OCALLINTER, ir.OCALLMETH:
+	case ir.OCALLFUNC, ir.OCALLINTER:
 		n := n.(*ir.CallExpr)
 		t := o.markTemp()
 		o.call(n)
@@ -1147,7 +1150,10 @@ func (o *orderState) expr1(n, lhs ir.Node) ir.Node {
 
 	case ir.OCONVNOP:
 		n := n.(*ir.ConvExpr)
-		if n.Type().IsKind(types.TUNSAFEPTR) && n.X.Type().IsKind(types.TUINTPTR) && (n.X.Op() == ir.OCALLFUNC || n.X.Op() == ir.OCALLINTER || n.X.Op() == ir.OCALLMETH) {
+		if n.X.Op() == ir.OCALLMETH {
+			base.FatalfAt(n.X.Pos(), "OCALLMETH missed by typecheck")
+		}
+		if n.Type().IsKind(types.TUNSAFEPTR) && n.X.Type().IsKind(types.TUINTPTR) && (n.X.Op() == ir.OCALLFUNC || n.X.Op() == ir.OCALLINTER) {
 			call := n.X.(*ir.CallExpr)
 			// When reordering unsafe.Pointer(f()) into a separate
 			// statement, the conversion and function call must stay
@@ -1200,9 +1206,12 @@ func (o *orderState) expr1(n, lhs ir.Node) ir.Node {
 		o.out = append(o.out, nif)
 		return r
 
+	case ir.OCALLMETH:
+		base.FatalfAt(n.Pos(), "OCALLMETH missed by typecheck")
+		panic("unreachable")
+
 	case ir.OCALLFUNC,
 		ir.OCALLINTER,
-		ir.OCALLMETH,
 		ir.OCAP,
 		ir.OCOMPLEX,
 		ir.OCOPY,
diff --git a/src/cmd/compile/internal/walk/stmt.go b/src/cmd/compile/internal/walk/stmt.go
index 0c216d2e8a3..4581bca3dfe 100644
--- a/src/cmd/compile/internal/walk/stmt.go
+++ b/src/cmd/compile/internal/walk/stmt.go
@@ -40,7 +40,6 @@ func walkStmt(n ir.Node) ir.Node {
 		ir.OAS2MAPR,
 		ir.OCLOSE,
 		ir.OCOPY,
-		ir.OCALLMETH,
 		ir.OCALLINTER,
 		ir.OCALL,
 		ir.OCALLFUNC,
diff --git a/src/cmd/compile/internal/walk/walk.go b/src/cmd/compile/internal/walk/walk.go
index 6e992a91b81..f687127fee3 100644
--- a/src/cmd/compile/internal/walk/walk.go
+++ b/src/cmd/compile/internal/walk/walk.go
@@ -308,7 +308,7 @@ func mayCall(n ir.Node) bool {
 		default:
 			base.FatalfAt(n.Pos(), "mayCall %+v", n)
 
-		case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER,
+		case ir.OCALLFUNC, ir.OCALLINTER,
 			ir.OUNSAFEADD, ir.OUNSAFESLICE:
 			return true
 

From 27e3b797bb6f3bc88b83897ae337aa83904c2a1a Mon Sep 17 00:00:00 2001
From: Cuong Manh Le 
Date: Sat, 26 Jun 2021 15:28:16 +0700
Subject: [PATCH 557/940] [dev.typeparams] cmd/compile: remove OCALLMETH Fatals
 in SSA generation

CL 330831 moved rewrite method calls to typecheck pass, then add Fatalf
check for mis-used of OCALLMETH in all frontend passes. The check in SSA
generation pass is now redundant.

Change-Id: If959b774ab3c3aeefabf32333f77b9a93c156ce3
Reviewed-on: https://go-review.googlesource.com/c/go/+/330834
Trust: Cuong Manh Le 
Run-TryBot: Cuong Manh Le 
TryBot-Result: Go Bot 
Reviewed-by: Matthew Dempsky 
---
 src/cmd/compile/internal/ssagen/ssa.go | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go
index 2bf34b0a84d..8367751dd59 100644
--- a/src/cmd/compile/internal/ssagen/ssa.go
+++ b/src/cmd/compile/internal/ssagen/ssa.go
@@ -3119,10 +3119,6 @@ func (s *state) expr(n ir.Node) *ssa.Value {
 		n := n.(*ir.CallExpr)
 		return s.callResult(n, callNormal)
 
-	case ir.OCALLMETH:
-		base.Fatalf("OCALLMETH missed by walkCall")
-		panic("unreachable")
-
 	case ir.OGETG:
 		n := n.(*ir.CallExpr)
 		return s.newValue1(ssa.OpGetG, n.Type(), s.mem())
@@ -4860,8 +4856,6 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
 			// not the point of defer statement.
 			s.maybeNilCheckClosure(closure, k)
 		}
-	case ir.OCALLMETH:
-		base.Fatalf("OCALLMETH missed by walkCall")
 	case ir.OCALLINTER:
 		if fn.Op() != ir.ODOTINTER {
 			s.Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op())
@@ -4951,9 +4945,6 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
 		// Write args.
 		t := n.X.Type()
 		args := n.Args
-		if n.Op() == ir.OCALLMETH {
-			base.Fatalf("OCALLMETH missed by walkCall")
-		}
 
 		for _, p := range params.InParams() { // includes receiver for interface calls
 			ACArgs = append(ACArgs, p.Type)

From 3ea0fcfe15663a7fb62f8570cc5991dc0f7c0260 Mon Sep 17 00:00:00 2001
From: Cuong Manh Le 
Date: Sun, 27 Jun 2021 00:51:16 +0700
Subject: [PATCH 558/940] [dev.typeparams] cmd/compile: do not skip
 TestUnifiedCompare in short mode

Instead, just testing the runtime package in short mode instead of std.
So trybot can help catching any mistake earlier.

Change-Id: I5bc859a59afa13a10d436a798258ac154c7d27b2
Reviewed-on: https://go-review.googlesource.com/c/go/+/330836
Trust: Cuong Manh Le 
Run-TryBot: Cuong Manh Le 
TryBot-Result: Go Bot 
Reviewed-by: Matthew Dempsky 
---
 src/cmd/compile/internal/noder/unified_test.go | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/src/cmd/compile/internal/noder/unified_test.go b/src/cmd/compile/internal/noder/unified_test.go
index 4732892f6c0..ca91b49fbbe 100644
--- a/src/cmd/compile/internal/noder/unified_test.go
+++ b/src/cmd/compile/internal/noder/unified_test.go
@@ -16,7 +16,7 @@ import (
 )
 
 var (
-	flagPkgs     = flag.String("pkgs", "std", "list of packages to compare")
+	flagPkgs     = flag.String("pkgs", "std", "list of packages to compare (ignored in -short mode)")
 	flagAll      = flag.Bool("all", false, "enable testing of all GOOS/GOARCH targets")
 	flagParallel = flag.Bool("parallel", false, "test GOOS/GOARCH targets in parallel")
 )
@@ -37,10 +37,6 @@ var (
 // command's -run flag for subtest matching is recommended for less
 // powerful machines.
 func TestUnifiedCompare(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping test in short mode")
-	}
-
 	targets, err := exec.Command("go", "tool", "dist", "list").Output()
 	if err != nil {
 		t.Fatal(err)
@@ -112,11 +108,17 @@ type pkg struct {
 
 func loadPackages(t *testing.T, goos, goarch, gcflags string) []pkg {
 	args := []string{"list", "-e", "-export", "-json", "-gcflags=all=" + gcflags, "--"}
-	args = append(args, strings.Fields(*flagPkgs)...)
+	if testing.Short() {
+		t.Log("short testing mode; only testing package runtime")
+		args = append(args, "runtime")
+	} else {
+		args = append(args, strings.Fields(*flagPkgs)...)
+	}
 
 	cmd := exec.Command("go", args...)
 	cmd.Env = append(os.Environ(), "GOOS="+goos, "GOARCH="+goarch)
 	cmd.Stderr = os.Stderr
+	t.Logf("running %v", cmd)
 	stdout, err := cmd.StdoutPipe()
 	if err != nil {
 		t.Fatal(err)

From d44ed5d14486728e2f9dfb9f682f37d6fb4024cb Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Sat, 26 Jun 2021 12:44:53 -0700
Subject: [PATCH 559/940] [dev.typeparams] cmd/compile: add method value
 wrappers to unified IR

Method value wrappers will need dictionary support too, so bring them
under the unified IR umbrella as well.

Change-Id: Iec36bb04efdf59843d1b00f55d2c44bc841fa2ef
Reviewed-on: https://go-review.googlesource.com/c/go/+/331190
Run-TryBot: Matthew Dempsky 
TryBot-Result: Go Bot 
Reviewed-by: Cuong Manh Le 
Trust: Matthew Dempsky 
---
 src/cmd/compile/internal/noder/reader.go | 141 ++++++++++++++++-------
 1 file changed, 99 insertions(+), 42 deletions(-)

diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go
index e5ad3f4b8ef..66c0e99d114 100644
--- a/src/cmd/compile/internal/noder/reader.go
+++ b/src/cmd/compile/internal/noder/reader.go
@@ -2065,6 +2065,8 @@ func (r *reader) wrapType(typ *types.Type, target *ir.Package) {
 			base.FatalfAt(meth.Pos, "invalid method: %v", meth)
 		}
 
+		r.methodValueWrapper(typ, meth, target)
+
 		r.methodWrapper(0, typ, meth, target)
 
 		// For non-interface types, we also want *T wrappers.
@@ -2100,21 +2102,81 @@ func (r *reader) methodWrapper(derefs int, tbase *types.Type, method *types.Fiel
 	// TODO(mdempsky): Use method.Pos instead?
 	pos := base.AutogeneratedPos
 
+	fn := r.newWrapperFunc(pos, sym, wrapper, method, target)
+
+	var recv ir.Node = fn.Nname.Type().Recv().Nname.(*ir.Name)
+
+	// For simple *T wrappers around T methods, panicwrap produces a
+	// nicer panic message.
+	if wrapper.IsPtr() && types.Identical(wrapper.Elem(), wrappee) {
+		cond := ir.NewBinaryExpr(pos, ir.OEQ, recv, types.BuiltinPkg.Lookup("nil").Def.(ir.Node))
+		then := []ir.Node{ir.NewCallExpr(pos, ir.OCALL, typecheck.LookupRuntime("panicwrap"), nil)}
+		fn.Body.Append(ir.NewIfStmt(pos, cond, then, nil))
+	}
+
+	// typecheck will add one implicit deref, if necessary,
+	// but not-in-heap types require more for their **T wrappers.
+	for i := 1; i < derefs; i++ {
+		recv = Implicit(ir.NewStarExpr(pos, recv))
+	}
+
+	addTailCall(pos, fn, recv, method)
+}
+
+func (r *reader) methodValueWrapper(tbase *types.Type, method *types.Field, target *ir.Package) {
+	recvType := tbase
+	if !tbase.IsInterface() {
+		recvType = method.Type.Recv().Type
+		if !types.Identical(tbase, types.ReceiverBaseType(recvType)) {
+			return
+		}
+	}
+
+	sym := ir.MethodSymSuffix(recvType, method.Sym, "-fm")
+	assert(!sym.Uniq())
+	sym.SetUniq(true)
+
+	// TODO(mdempsky): Fix typecheck to not depend on creation of
+	// imported method value wrappers.
+	if false && !reflectdata.NeedEmit(tbase) {
+		return
+	}
+
+	// TODO(mdempsky): Use method.Pos instead?
+	pos := base.AutogeneratedPos
+
+	fn := r.newWrapperFunc(pos, sym, nil, method, target)
+	fn.SetNeedctxt(true)
+	sym.Def = fn
+
+	// Declare and initialize variable holding receiver.
+	recv := ir.NewNameAt(pos, typecheck.Lookup(".this"))
+	recv.Class = ir.PAUTOHEAP
+	recv.SetType(recvType)
+	recv.Curfn = fn
+	recv.SetIsClosureVar(true)
+	recv.SetByval(true)
+	fn.ClosureVars = append(fn.ClosureVars, recv)
+
+	addTailCall(pos, fn, recv, method)
+}
+
+func (r *reader) newWrapperFunc(pos src.XPos, sym *types.Sym, wrapper *types.Type, method *types.Field, target *ir.Package) *ir.Func {
 	fn := ir.NewFunc(pos)
-	fn.SetDupok(true)   // TODO(mdempsky): Leave unset for local, non-generic wrappers?
-	fn.SetWrapper(true) // TODO(mdempsky): Leave unset for tail calls?
+	fn.SetDupok(true) // TODO(mdempsky): Leave unset for local, non-generic wrappers?
 
-	fn.Nname = ir.NewNameAt(pos, sym)
-	ir.MarkFunc(fn.Nname)
-	fn.Nname.Func = fn
-	fn.Nname.Defn = fn
+	name := ir.NewNameAt(pos, sym)
+	ir.MarkFunc(name)
+	name.Func = fn
+	name.Defn = fn
+	fn.Nname = name
 
-	sig := newWrapperType(wrapper, method.Type)
-	r.setType(fn.Nname, sig)
+	sig := newWrapperType(wrapper, method)
+	r.setType(name, sig)
 
 	// TODO(mdempsky): De-duplicate with similar logic in funcargs.
-	defParams := func(class ir.Class, params ...*types.Field) {
-		for _, param := range params {
+	defParams := func(class ir.Class, params *types.Type) {
+		for _, param := range params.FieldSlice() {
 			name := ir.NewNameAt(param.Pos, param.Sym)
 			name.Class = class
 			r.setType(name, param.Type)
@@ -2126,39 +2188,20 @@ func (r *reader) methodWrapper(derefs int, tbase *types.Type, method *types.Fiel
 		}
 	}
 
-	defParams(ir.PPARAM, sig.Recv())
-	defParams(ir.PPARAM, sig.Params().FieldSlice()...)
-	defParams(ir.PPARAMOUT, sig.Results().FieldSlice()...)
-
-	var recv ir.Node = sig.Recv().Nname.(*ir.Name)
-
-	// For simple *T wrappers around T methods, panicwrap produces a
-	// nicer panic message.
-	if wrapper.IsPtr() && types.Identical(wrapper.Elem(), wrappee) {
-		cond := ir.NewBinaryExpr(pos, ir.OEQ, recv, types.BuiltinPkg.Lookup("nil").Def.(ir.Node))
-		then := []ir.Node{ir.NewCallExpr(pos, ir.OCALL, typecheck.LookupRuntime("panicwrap"), nil)}
-		fn.Body.Append(ir.NewIfStmt(pos, cond, then, nil))
-	}
-
-	// Add implicit derefs, as necessary. typecheck will add one deref,
-	// but not-in-heap types will need another for their **T wrappers.
-	for i := 0; i < derefs; i++ {
-		recv = Implicit(ir.NewStarExpr(pos, recv))
-	}
-
-	args := make([]ir.Node, sig.NumParams())
-	for i, param := range sig.Params().FieldSlice() {
-		args[i] = param.Nname.(*ir.Name)
-	}
-
-	fn.Body.Append(newTailCall(pos, method, recv, args))
+	defParams(ir.PPARAM, sig.Recvs())
+	defParams(ir.PPARAM, sig.Params())
+	defParams(ir.PPARAMOUT, sig.Results())
 
 	target.Decls = append(target.Decls, fn)
+
+	return fn
 }
 
 // newWrapperType returns a copy of the given signature type, but with
-// the receiver parameter type substituted with wrapper.
-func newWrapperType(wrapper, sig *types.Type) *types.Type {
+// the receiver parameter type substituted with recvType.
+// If recvType is nil, newWrapperType returns a signature
+// without a receiver parameter.
+func newWrapperType(recvType *types.Type, method *types.Field) *types.Type {
 	clone := func(params []*types.Field) []*types.Field {
 		res := make([]*types.Field, len(params))
 		for i, param := range params {
@@ -2172,25 +2215,39 @@ func newWrapperType(wrapper, sig *types.Type) *types.Type {
 		return res
 	}
 
-	recv := types.NewField(sig.Recv().Pos, typecheck.Lookup(".this"), wrapper)
+	sig := method.Type
+
+	var recv *types.Field
+	if recvType != nil {
+		recv = types.NewField(sig.Recv().Pos, typecheck.Lookup(".this"), recvType)
+	}
 	params := clone(sig.Params().FieldSlice())
 	results := clone(sig.Results().FieldSlice())
 
 	return types.NewSignature(types.NoPkg, recv, nil, params, results)
 }
 
-func newTailCall(pos src.XPos, method *types.Field, recv ir.Node, args []ir.Node) ir.Node {
+func addTailCall(pos src.XPos, fn *ir.Func, recv ir.Node, method *types.Field) {
+	sig := fn.Nname.Type()
+	args := make([]ir.Node, sig.NumParams())
+	for i, param := range sig.Params().FieldSlice() {
+		args[i] = param.Nname.(*ir.Name)
+	}
+
 	// TODO(mdempsky): Support creating OTAILCALL, when possible. See reflectdata.methodWrapper.
 	// Not urgent though, because tail calls are currently incompatible with regabi anyway.
 
+	fn.SetWrapper(true) // TODO(mdempsky): Leave unset for tail calls?
+
 	call := ir.NewCallExpr(pos, ir.OCALL, ir.NewSelectorExpr(pos, ir.OXDOT, recv, method.Sym), args)
 	call.IsDDD = method.Type.IsVariadic()
 
 	if method.Type.NumResults() == 0 {
-		return call
+		fn.Body.Append(call)
+		return
 	}
 
 	ret := ir.NewReturnStmt(pos, nil)
 	ret.Results = []ir.Node{call}
-	return ret
+	fn.Body.Append(ret)
 }

From c95464f0ea3f87232b1f3937d1b37da6f335f336 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Fri, 25 Jun 2021 13:24:10 -0700
Subject: [PATCH 560/940] internal/buildcfg: refactor GOEXPERIMENT parsing code
 somewhat

This CL extracts out a ParseGOEXPERIMENT helper function that parses
GOOS/GOARCH/GOEXPERIMENT values and returns active and baseline
experiment flag sets and an error value, without affecting any global
state. This will be used in the subsequent CL for 'go env' support for
GOEXPERIMENT to validate configuration changes.

The existing package initialization for Experiment and
experimentBaseline and also UpdateExperiments are updated to use it as
well.

Change-Id: Ic2ed3fd36d2a6f7f3d8172fccb865e02505c0052
Reviewed-on: https://go-review.googlesource.com/c/go/+/331109
Run-TryBot: Matthew Dempsky 
TryBot-Result: Go Bot 
Reviewed-by: Ian Lance Taylor 
Trust: Matthew Dempsky 
---
 src/cmd/go/internal/cfg/cfg.go |  2 +-
 src/internal/buildcfg/exp.go   | 65 +++++++++++++++++++++-------------
 2 files changed, 41 insertions(+), 26 deletions(-)

diff --git a/src/cmd/go/internal/cfg/cfg.go b/src/cmd/go/internal/cfg/cfg.go
index fc6989097ee..57a3c1ff6fb 100644
--- a/src/cmd/go/internal/cfg/cfg.go
+++ b/src/cmd/go/internal/cfg/cfg.go
@@ -79,7 +79,7 @@ func defaultContext() build.Context {
 
 	// The experiments flags are based on GOARCH, so they may
 	// need to change.  TODO: This should be cleaned up.
-	buildcfg.UpdateExperiments(ctxt.GOARCH)
+	buildcfg.UpdateExperiments(ctxt.GOOS, ctxt.GOARCH, envOr("GOEXPERIMENT", buildcfg.DefaultGOEXPERIMENT))
 	ctxt.ToolTags = nil
 	for _, exp := range buildcfg.EnabledExperiments() {
 		ctxt.ToolTags = append(ctxt.ToolTags, "goexperiment."+exp)
diff --git a/src/internal/buildcfg/exp.go b/src/internal/buildcfg/exp.go
index 640aa1934db..9a60253aab9 100644
--- a/src/internal/buildcfg/exp.go
+++ b/src/internal/buildcfg/exp.go
@@ -6,7 +6,6 @@ package buildcfg
 
 import (
 	"fmt"
-	"os"
 	"reflect"
 	"strings"
 
@@ -18,20 +17,19 @@ import (
 //
 // (This is not necessarily the set of experiments the compiler itself
 // was built with.)
-var Experiment goexperiment.Flags = parseExperiments(GOARCH)
-
-var regabiSupported = GOARCH == "amd64" && (GOOS == "android" || GOOS == "linux" || GOOS == "darwin" || GOOS == "windows")
-
+//
 // experimentBaseline specifies the experiment flags that are enabled by
 // default in the current toolchain. This is, in effect, the "control"
 // configuration and any variation from this is an experiment.
-var experimentBaseline = goexperiment.Flags{
-	RegabiWrappers: regabiSupported,
-	RegabiG:        regabiSupported,
-	RegabiReflect:  regabiSupported,
-	RegabiDefer:    regabiSupported,
-	RegabiArgs:     regabiSupported,
-}
+var Experiment, experimentBaseline = func() (goexperiment.Flags, goexperiment.Flags) {
+	flags, baseline, err := ParseGOEXPERIMENT(GOOS, GOARCH, envOr("GOEXPERIMENT", defaultGOEXPERIMENT))
+	if err != nil {
+		Error = err
+	}
+	return flags, baseline
+}()
+
+const DefaultGOEXPERIMENT = defaultGOEXPERIMENT
 
 // FramePointerEnabled enables the use of platform conventions for
 // saving frame pointers.
@@ -42,16 +40,29 @@ var experimentBaseline = goexperiment.Flags{
 // Note: must agree with runtime.framepointer_enabled.
 var FramePointerEnabled = GOARCH == "amd64" || GOARCH == "arm64"
 
-func parseExperiments(goarch string) goexperiment.Flags {
+// ParseGOEXPERIMENT parses a (GOOS, GOARCH, GOEXPERIMENT)
+// configuration tuple and returns the enabled and baseline experiment
+// flag sets.
+//
+// TODO(mdempsky): Move to internal/goexperiment.
+func ParseGOEXPERIMENT(goos, goarch, goexp string) (flags, baseline goexperiment.Flags, err error) {
+	regabiSupported := goarch == "amd64" && (goos == "android" || goos == "linux" || goos == "darwin" || goos == "windows")
+
+	baseline = goexperiment.Flags{
+		RegabiWrappers: regabiSupported,
+		RegabiG:        regabiSupported,
+		RegabiReflect:  regabiSupported,
+		RegabiDefer:    regabiSupported,
+		RegabiArgs:     regabiSupported,
+	}
+
 	// Start with the statically enabled set of experiments.
-	flags := experimentBaseline
+	flags = baseline
 
 	// Pick up any changes to the baseline configuration from the
 	// GOEXPERIMENT environment. This can be set at make.bash time
 	// and overridden at build time.
-	env := envOr("GOEXPERIMENT", defaultGOEXPERIMENT)
-
-	if env != "" {
+	if goexp != "" {
 		// Create a map of known experiment names.
 		names := make(map[string]func(bool))
 		rv := reflect.ValueOf(&flags).Elem()
@@ -74,7 +85,7 @@ func parseExperiments(goarch string) goexperiment.Flags {
 		}
 
 		// Parse names.
-		for _, f := range strings.Split(env, ",") {
+		for _, f := range strings.Split(goexp, ",") {
 			if f == "" {
 				continue
 			}
@@ -91,8 +102,8 @@ func parseExperiments(goarch string) goexperiment.Flags {
 			}
 			set, ok := names[f]
 			if !ok {
-				fmt.Printf("unknown experiment %s\n", f)
-				os.Exit(2)
+				err = fmt.Errorf("unknown GOEXPERIMENT %s", f)
+				return
 			}
 			set(val)
 		}
@@ -108,12 +119,12 @@ func parseExperiments(goarch string) goexperiment.Flags {
 	}
 	// Check regabi dependencies.
 	if flags.RegabiG && !flags.RegabiWrappers {
-		Error = fmt.Errorf("GOEXPERIMENT regabig requires regabiwrappers")
+		err = fmt.Errorf("GOEXPERIMENT regabig requires regabiwrappers")
 	}
 	if flags.RegabiArgs && !(flags.RegabiWrappers && flags.RegabiG && flags.RegabiReflect && flags.RegabiDefer) {
-		Error = fmt.Errorf("GOEXPERIMENT regabiargs requires regabiwrappers,regabig,regabireflect,regabidefer")
+		err = fmt.Errorf("GOEXPERIMENT regabiargs requires regabiwrappers,regabig,regabireflect,regabidefer")
 	}
-	return flags
+	return
 }
 
 // expList returns the list of lower-cased experiment names for
@@ -169,6 +180,10 @@ func AllExperiments() []string {
 // UpdateExperiments updates the Experiment global based on a new GOARCH value.
 // This is only required for cmd/go, which can change GOARCH after
 // program startup due to use of "go env -w".
-func UpdateExperiments(goarch string) {
-	Experiment = parseExperiments(goarch)
+func UpdateExperiments(goos, goarch, goexperiment string) {
+	var err error
+	Experiment, experimentBaseline, err = ParseGOEXPERIMENT(goos, goarch, goexperiment)
+	if err != nil {
+		Error = err
+	}
 }

From 1b995f91a526ff165952218848c3173026a8dc53 Mon Sep 17 00:00:00 2001
From: Cuong Manh Le 
Date: Sun, 27 Jun 2021 01:28:38 +0700
Subject: [PATCH 561/940] [dev.typeparams] cmd/compile: rename OCALLPART to
 OMETHVALUE

Go spec call them "method values", not "partial calls". Note that
we use "OMETHVALUE" (as opposed to "OMETHODVALUE") to be consistent
with "OMETHEXPR".

Change-Id: I1efd985d4b567a1b4b20aeb603eb82db579edbd5
Reviewed-on: https://go-review.googlesource.com/c/go/+/330837
Trust: Cuong Manh Le 
Run-TryBot: Cuong Manh Le 
TryBot-Result: Go Bot 
Reviewed-by: Matthew Dempsky 
---
 src/cmd/compile/internal/escape/escape.go     |   2 +-
 src/cmd/compile/internal/escape/expr.go       |   2 +-
 src/cmd/compile/internal/escape/utils.go      |   2 +-
 src/cmd/compile/internal/inline/inl.go        |   2 +-
 src/cmd/compile/internal/ir/expr.go           |   6 +-
 src/cmd/compile/internal/ir/fmt.go            |   4 +-
 src/cmd/compile/internal/ir/func.go           |   8 +-
 src/cmd/compile/internal/ir/node.go           |   4 +-
 src/cmd/compile/internal/ir/op_string.go      | 168 +++++++++---------
 src/cmd/compile/internal/ir/scc.go            |   2 +-
 src/cmd/compile/internal/noder/expr.go        |   4 +-
 src/cmd/compile/internal/noder/helpers.go     |   4 +-
 src/cmd/compile/internal/noder/stencil.go     |  10 +-
 src/cmd/compile/internal/noder/transform.go   |   4 +-
 src/cmd/compile/internal/pkginit/initorder.go |   2 +-
 src/cmd/compile/internal/typecheck/const.go   |   2 +-
 src/cmd/compile/internal/typecheck/crawler.go |   2 +-
 src/cmd/compile/internal/typecheck/expr.go    |   2 +-
 src/cmd/compile/internal/typecheck/func.go    |   4 +-
 src/cmd/compile/internal/typecheck/iexport.go |   4 +-
 src/cmd/compile/internal/typecheck/iimport.go |   6 +-
 src/cmd/compile/internal/walk/closure.go      |   2 +-
 src/cmd/compile/internal/walk/expr.go         |   4 +-
 src/cmd/compile/internal/walk/order.go        |   2 +-
 24 files changed, 126 insertions(+), 126 deletions(-)

diff --git a/src/cmd/compile/internal/escape/escape.go b/src/cmd/compile/internal/escape/escape.go
index 317bc98473c..04d0c2356c1 100644
--- a/src/cmd/compile/internal/escape/escape.go
+++ b/src/cmd/compile/internal/escape/escape.go
@@ -315,7 +315,7 @@ func (b *batch) finish(fns []*ir.Func) {
 				case ir.OCLOSURE:
 					n := n.(*ir.ClosureExpr)
 					n.SetTransient(true)
-				case ir.OCALLPART:
+				case ir.OMETHVALUE:
 					n := n.(*ir.SelectorExpr)
 					n.SetTransient(true)
 				case ir.OSLICELIT:
diff --git a/src/cmd/compile/internal/escape/expr.go b/src/cmd/compile/internal/escape/expr.go
index 71c8eec6efc..dfcd55734ab 100644
--- a/src/cmd/compile/internal/escape/expr.go
+++ b/src/cmd/compile/internal/escape/expr.go
@@ -153,7 +153,7 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
 		e.spill(k, n)
 		e.discard(n.Len)
 
-	case ir.OCALLPART:
+	case ir.OMETHVALUE:
 		// Flow the receiver argument to both the closure and
 		// to the receiver parameter.
 
diff --git a/src/cmd/compile/internal/escape/utils.go b/src/cmd/compile/internal/escape/utils.go
index 7100926bb85..1ac4cc60290 100644
--- a/src/cmd/compile/internal/escape/utils.go
+++ b/src/cmd/compile/internal/escape/utils.go
@@ -193,7 +193,7 @@ func HeapAllocReason(n ir.Node) string {
 	if n.Op() == ir.OCLOSURE && typecheck.ClosureType(n.(*ir.ClosureExpr)).Size() >= ir.MaxImplicitStackVarSize {
 		return "too large for stack"
 	}
-	if n.Op() == ir.OCALLPART && typecheck.PartialCallType(n.(*ir.SelectorExpr)).Size() >= ir.MaxImplicitStackVarSize {
+	if n.Op() == ir.OMETHVALUE && typecheck.PartialCallType(n.(*ir.SelectorExpr)).Size() >= ir.MaxImplicitStackVarSize {
 		return "too large for stack"
 	}
 
diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go
index 3086d093c04..a6961e4e4d1 100644
--- a/src/cmd/compile/internal/inline/inl.go
+++ b/src/cmd/compile/internal/inline/inl.go
@@ -416,7 +416,7 @@ func (v *hairyVisitor) doNode(n ir.Node) bool {
 		// and don't charge for the OBLOCK itself. The ++ undoes the -- below.
 		v.budget++
 
-	case ir.OCALLPART, ir.OSLICELIT:
+	case ir.OMETHVALUE, ir.OSLICELIT:
 		v.budget-- // Hack for toolstash -cmp.
 
 	case ir.OMETHEXPR:
diff --git a/src/cmd/compile/internal/ir/expr.go b/src/cmd/compile/internal/ir/expr.go
index 81b2c52b87f..919cb3362fe 100644
--- a/src/cmd/compile/internal/ir/expr.go
+++ b/src/cmd/compile/internal/ir/expr.go
@@ -519,7 +519,7 @@ type SelectorExpr struct {
 	Sel *types.Sym
 	// The actual selected field - may not be filled in until typechecking.
 	Selection *types.Field
-	Prealloc  *Name // preallocated storage for OCALLPART, if any
+	Prealloc  *Name // preallocated storage for OMETHVALUE, if any
 }
 
 func NewSelectorExpr(pos src.XPos, op Op, x Node, sel *types.Sym) *SelectorExpr {
@@ -533,7 +533,7 @@ func (n *SelectorExpr) SetOp(op Op) {
 	switch op {
 	default:
 		panic(n.no("SetOp " + op.String()))
-	case OXDOT, ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OCALLPART, OMETHEXPR:
+	case OXDOT, ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OMETHVALUE, OMETHEXPR:
 		n.op = op
 	}
 }
@@ -1098,7 +1098,7 @@ func MethodExprName(n Node) *Name {
 // MethodExprFunc is like MethodExprName, but returns the types.Field instead.
 func MethodExprFunc(n Node) *types.Field {
 	switch n.Op() {
-	case ODOTMETH, OMETHEXPR, OCALLPART:
+	case ODOTMETH, OMETHEXPR, OMETHVALUE:
 		return n.(*SelectorExpr).Selection
 	}
 	base.Fatalf("unexpected node: %v (%v)", n, n.Op())
diff --git a/src/cmd/compile/internal/ir/fmt.go b/src/cmd/compile/internal/ir/fmt.go
index d9cc5f109f5..ae62d5f51b9 100644
--- a/src/cmd/compile/internal/ir/fmt.go
+++ b/src/cmd/compile/internal/ir/fmt.go
@@ -237,7 +237,7 @@ var OpPrec = []int{
 	ODOTTYPE:       8,
 	ODOT:           8,
 	OXDOT:          8,
-	OCALLPART:      8,
+	OMETHVALUE:     8,
 	OMETHEXPR:      8,
 	OPLUS:          7,
 	ONOT:           7,
@@ -757,7 +757,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
 		n := n.(*StructKeyExpr)
 		fmt.Fprintf(s, "%v:%v", n.Field, n.Value)
 
-	case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH, OCALLPART, OMETHEXPR:
+	case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH, OMETHVALUE, OMETHEXPR:
 		n := n.(*SelectorExpr)
 		exprFmt(n.X, s, nprec)
 		if n.Sel == nil {
diff --git a/src/cmd/compile/internal/ir/func.go b/src/cmd/compile/internal/ir/func.go
index 3501f83ab1d..3b9e36d4c59 100644
--- a/src/cmd/compile/internal/ir/func.go
+++ b/src/cmd/compile/internal/ir/func.go
@@ -40,14 +40,14 @@ import (
 // constructs a fresh node.
 //
 // A method value (t.M) is represented by ODOTMETH/ODOTINTER
-// when it is called directly and by OCALLPART otherwise.
+// when it is called directly and by OMETHVALUE otherwise.
 // These are like method expressions, except that for ODOTMETH/ODOTINTER,
 // the method name is stored in Sym instead of Right.
-// Each OCALLPART ends up being implemented as a new
+// Each OMETHVALUE ends up being implemented as a new
 // function, a bit like a closure, with its own ODCLFUNC.
-// The OCALLPART uses n.Func to record the linkage to
+// The OMETHVALUE uses n.Func to record the linkage to
 // the generated ODCLFUNC, but there is no
-// pointer from the Func back to the OCALLPART.
+// pointer from the Func back to the OMETHVALUE.
 type Func struct {
 	miniNode
 	Body Nodes
diff --git a/src/cmd/compile/internal/ir/node.go b/src/cmd/compile/internal/ir/node.go
index fa7c9cc2760..f6eae58b040 100644
--- a/src/cmd/compile/internal/ir/node.go
+++ b/src/cmd/compile/internal/ir/node.go
@@ -159,7 +159,6 @@ const (
 	OCALLFUNC  // X(Args) (function call f(args))
 	OCALLMETH  // X(Args) (direct method call x.Method(args))
 	OCALLINTER // X(Args) (interface method call x.Method(args))
-	OCALLPART  // X.Sel (method expression x.Method, not called)
 	OCAP       // cap(X)
 	OCLOSE     // close(X)
 	OCLOSURE   // func Type { Func.Closure.Body } (func literal)
@@ -250,7 +249,8 @@ const (
 	OSIZEOF      // unsafe.Sizeof(X)
 	OUNSAFEADD   // unsafe.Add(X, Y)
 	OUNSAFESLICE // unsafe.Slice(X, Y)
-	OMETHEXPR    // method expression
+	OMETHEXPR    // X(Args) (method expression T.Method(args), first argument is the method receiver)
+	OMETHVALUE   // X.Sel   (method expression t.Method, not called)
 
 	// statements
 	OBLOCK // { List } (block of code)
diff --git a/src/cmd/compile/internal/ir/op_string.go b/src/cmd/compile/internal/ir/op_string.go
index 80c8d09c1e4..05a37a60b1d 100644
--- a/src/cmd/compile/internal/ir/op_string.go
+++ b/src/cmd/compile/internal/ir/op_string.go
@@ -41,88 +41,88 @@ func _() {
 	_ = x[OCALLFUNC-30]
 	_ = x[OCALLMETH-31]
 	_ = x[OCALLINTER-32]
-	_ = x[OCALLPART-33]
-	_ = x[OCAP-34]
-	_ = x[OCLOSE-35]
-	_ = x[OCLOSURE-36]
-	_ = x[OCOMPLIT-37]
-	_ = x[OMAPLIT-38]
-	_ = x[OSTRUCTLIT-39]
-	_ = x[OARRAYLIT-40]
-	_ = x[OSLICELIT-41]
-	_ = x[OPTRLIT-42]
-	_ = x[OCONV-43]
-	_ = x[OCONVIFACE-44]
-	_ = x[OCONVNOP-45]
-	_ = x[OCOPY-46]
-	_ = x[ODCL-47]
-	_ = x[ODCLFUNC-48]
-	_ = x[ODCLCONST-49]
-	_ = x[ODCLTYPE-50]
-	_ = x[ODELETE-51]
-	_ = x[ODOT-52]
-	_ = x[ODOTPTR-53]
-	_ = x[ODOTMETH-54]
-	_ = x[ODOTINTER-55]
-	_ = x[OXDOT-56]
-	_ = x[ODOTTYPE-57]
-	_ = x[ODOTTYPE2-58]
-	_ = x[OEQ-59]
-	_ = x[ONE-60]
-	_ = x[OLT-61]
-	_ = x[OLE-62]
-	_ = x[OGE-63]
-	_ = x[OGT-64]
-	_ = x[ODEREF-65]
-	_ = x[OINDEX-66]
-	_ = x[OINDEXMAP-67]
-	_ = x[OKEY-68]
-	_ = x[OSTRUCTKEY-69]
-	_ = x[OLEN-70]
-	_ = x[OMAKE-71]
-	_ = x[OMAKECHAN-72]
-	_ = x[OMAKEMAP-73]
-	_ = x[OMAKESLICE-74]
-	_ = x[OMAKESLICECOPY-75]
-	_ = x[OMUL-76]
-	_ = x[ODIV-77]
-	_ = x[OMOD-78]
-	_ = x[OLSH-79]
-	_ = x[ORSH-80]
-	_ = x[OAND-81]
-	_ = x[OANDNOT-82]
-	_ = x[ONEW-83]
-	_ = x[ONOT-84]
-	_ = x[OBITNOT-85]
-	_ = x[OPLUS-86]
-	_ = x[ONEG-87]
-	_ = x[OOROR-88]
-	_ = x[OPANIC-89]
-	_ = x[OPRINT-90]
-	_ = x[OPRINTN-91]
-	_ = x[OPAREN-92]
-	_ = x[OSEND-93]
-	_ = x[OSLICE-94]
-	_ = x[OSLICEARR-95]
-	_ = x[OSLICESTR-96]
-	_ = x[OSLICE3-97]
-	_ = x[OSLICE3ARR-98]
-	_ = x[OSLICEHEADER-99]
-	_ = x[ORECOVER-100]
-	_ = x[ORECOVERFP-101]
-	_ = x[ORECV-102]
-	_ = x[ORUNESTR-103]
-	_ = x[OSELRECV2-104]
-	_ = x[OIOTA-105]
-	_ = x[OREAL-106]
-	_ = x[OIMAG-107]
-	_ = x[OCOMPLEX-108]
-	_ = x[OALIGNOF-109]
-	_ = x[OOFFSETOF-110]
-	_ = x[OSIZEOF-111]
-	_ = x[OUNSAFEADD-112]
-	_ = x[OUNSAFESLICE-113]
-	_ = x[OMETHEXPR-114]
+	_ = x[OCAP-33]
+	_ = x[OCLOSE-34]
+	_ = x[OCLOSURE-35]
+	_ = x[OCOMPLIT-36]
+	_ = x[OMAPLIT-37]
+	_ = x[OSTRUCTLIT-38]
+	_ = x[OARRAYLIT-39]
+	_ = x[OSLICELIT-40]
+	_ = x[OPTRLIT-41]
+	_ = x[OCONV-42]
+	_ = x[OCONVIFACE-43]
+	_ = x[OCONVNOP-44]
+	_ = x[OCOPY-45]
+	_ = x[ODCL-46]
+	_ = x[ODCLFUNC-47]
+	_ = x[ODCLCONST-48]
+	_ = x[ODCLTYPE-49]
+	_ = x[ODELETE-50]
+	_ = x[ODOT-51]
+	_ = x[ODOTPTR-52]
+	_ = x[ODOTMETH-53]
+	_ = x[ODOTINTER-54]
+	_ = x[OXDOT-55]
+	_ = x[ODOTTYPE-56]
+	_ = x[ODOTTYPE2-57]
+	_ = x[OEQ-58]
+	_ = x[ONE-59]
+	_ = x[OLT-60]
+	_ = x[OLE-61]
+	_ = x[OGE-62]
+	_ = x[OGT-63]
+	_ = x[ODEREF-64]
+	_ = x[OINDEX-65]
+	_ = x[OINDEXMAP-66]
+	_ = x[OKEY-67]
+	_ = x[OSTRUCTKEY-68]
+	_ = x[OLEN-69]
+	_ = x[OMAKE-70]
+	_ = x[OMAKECHAN-71]
+	_ = x[OMAKEMAP-72]
+	_ = x[OMAKESLICE-73]
+	_ = x[OMAKESLICECOPY-74]
+	_ = x[OMUL-75]
+	_ = x[ODIV-76]
+	_ = x[OMOD-77]
+	_ = x[OLSH-78]
+	_ = x[ORSH-79]
+	_ = x[OAND-80]
+	_ = x[OANDNOT-81]
+	_ = x[ONEW-82]
+	_ = x[ONOT-83]
+	_ = x[OBITNOT-84]
+	_ = x[OPLUS-85]
+	_ = x[ONEG-86]
+	_ = x[OOROR-87]
+	_ = x[OPANIC-88]
+	_ = x[OPRINT-89]
+	_ = x[OPRINTN-90]
+	_ = x[OPAREN-91]
+	_ = x[OSEND-92]
+	_ = x[OSLICE-93]
+	_ = x[OSLICEARR-94]
+	_ = x[OSLICESTR-95]
+	_ = x[OSLICE3-96]
+	_ = x[OSLICE3ARR-97]
+	_ = x[OSLICEHEADER-98]
+	_ = x[ORECOVER-99]
+	_ = x[ORECOVERFP-100]
+	_ = x[ORECV-101]
+	_ = x[ORUNESTR-102]
+	_ = x[OSELRECV2-103]
+	_ = x[OIOTA-104]
+	_ = x[OREAL-105]
+	_ = x[OIMAG-106]
+	_ = x[OCOMPLEX-107]
+	_ = x[OALIGNOF-108]
+	_ = x[OOFFSETOF-109]
+	_ = x[OSIZEOF-110]
+	_ = x[OUNSAFEADD-111]
+	_ = x[OUNSAFESLICE-112]
+	_ = x[OMETHEXPR-113]
+	_ = x[OMETHVALUE-114]
 	_ = x[OBLOCK-115]
 	_ = x[OBREAK-116]
 	_ = x[OCASE-117]
@@ -168,9 +168,9 @@ func _() {
 	_ = x[OEND-157]
 }
 
-const _Op_name = "XXXNAMENONAMETYPEPACKLITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFUNSAFEADDUNSAFESLICEMETHEXPRBLOCKBREAKCASECONTINUEDEFERFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWFUNCINSTTCHANTMAPTSTRUCTTINTERTFUNCTARRAYTSLICEINLCALLEFACEITABIDATASPTRCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKLINKSYMOFFSETTAILCALLGETGGETCALLERPCGETCALLERSPEND"
+const _Op_name = "XXXNAMENONAMETYPEPACKLITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFUNSAFEADDUNSAFESLICEMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWFUNCINSTTCHANTMAPTSTRUCTTINTERTFUNCTARRAYTSLICEINLCALLEFACEITABIDATASPTRCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKLINKSYMOFFSETTAILCALLGETGGETCALLERPCGETCALLERSPEND"
 
-var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 37, 39, 42, 48, 52, 58, 64, 73, 85, 94, 103, 115, 124, 136, 138, 141, 151, 158, 165, 172, 176, 180, 188, 196, 205, 213, 216, 221, 228, 235, 241, 250, 258, 266, 272, 276, 285, 292, 296, 299, 306, 314, 321, 327, 330, 336, 343, 351, 355, 362, 370, 372, 374, 376, 378, 380, 382, 387, 392, 400, 403, 412, 415, 419, 427, 434, 443, 456, 459, 462, 465, 468, 471, 474, 480, 483, 486, 492, 496, 499, 503, 508, 513, 519, 524, 528, 533, 541, 549, 555, 564, 575, 582, 591, 595, 602, 610, 614, 618, 622, 629, 636, 644, 650, 659, 670, 678, 683, 688, 692, 700, 705, 709, 712, 720, 724, 726, 731, 733, 738, 744, 750, 756, 762, 770, 775, 779, 786, 792, 797, 803, 809, 816, 821, 825, 830, 834, 839, 847, 853, 860, 867, 873, 880, 893, 901, 905, 916, 927, 930}
+var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 37, 39, 42, 48, 52, 58, 64, 73, 85, 94, 103, 115, 124, 136, 138, 141, 151, 158, 165, 172, 176, 180, 188, 196, 205, 208, 213, 220, 227, 233, 242, 250, 258, 264, 268, 277, 284, 288, 291, 298, 306, 313, 319, 322, 328, 335, 343, 347, 354, 362, 364, 366, 368, 370, 372, 374, 379, 384, 392, 395, 404, 407, 411, 419, 426, 435, 448, 451, 454, 457, 460, 463, 466, 472, 475, 478, 484, 488, 491, 495, 500, 505, 511, 516, 520, 525, 533, 541, 547, 556, 567, 574, 583, 587, 594, 602, 606, 610, 614, 621, 628, 636, 642, 651, 662, 670, 679, 684, 689, 693, 701, 706, 710, 713, 721, 725, 727, 732, 734, 739, 745, 751, 757, 763, 771, 776, 780, 787, 793, 798, 804, 810, 817, 822, 826, 831, 835, 840, 848, 854, 861, 868, 874, 881, 894, 902, 906, 917, 928, 931}
 
 func (i Op) String() string {
 	if i >= Op(len(_Op_index)-1) {
diff --git a/src/cmd/compile/internal/ir/scc.go b/src/cmd/compile/internal/ir/scc.go
index 83c6074170b..2cfceaa1f62 100644
--- a/src/cmd/compile/internal/ir/scc.go
+++ b/src/cmd/compile/internal/ir/scc.go
@@ -90,7 +90,7 @@ func (v *bottomUpVisitor) visit(n *Func) uint32 {
 			if n := n.(*Name); n.Class == PFUNC {
 				do(n.Defn)
 			}
-		case ODOTMETH, OCALLPART, OMETHEXPR:
+		case ODOTMETH, OMETHVALUE, OMETHEXPR:
 			if fn := MethodExprName(n); fn != nil {
 				do(fn.Defn)
 			}
diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go
index 98dc504ee98..017e98986fb 100644
--- a/src/cmd/compile/internal/noder/expr.go
+++ b/src/cmd/compile/internal/noder/expr.go
@@ -196,7 +196,7 @@ func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node {
 	}
 }
 
-// selectorExpr resolves the choice of ODOT, ODOTPTR, OCALLPART (eventually
+// selectorExpr resolves the choice of ODOT, ODOTPTR, OMETHVALUE (eventually
 // ODOTMETH & ODOTINTER), and OMETHEXPR and deals with embedded fields here rather
 // than in typecheck.go.
 func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.SelectorExpr) ir.Node {
@@ -273,7 +273,7 @@ func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.Selecto
 				// the base generic type. The instantiated type may not
 				// have method bodies filled in, if it was imported.
 				method := recvType.Methods().Index(last).Nname.(*ir.Name)
-				n = ir.NewSelectorExpr(pos, ir.OCALLPART, x, typecheck.Lookup(expr.Sel.Value))
+				n = ir.NewSelectorExpr(pos, ir.OMETHVALUE, x, typecheck.Lookup(expr.Sel.Value))
 				n.(*ir.SelectorExpr).Selection = types.NewField(pos, method.Sym(), method.Type())
 				n.(*ir.SelectorExpr).Selection.Nname = method
 				typed(method.Type(), n)
diff --git a/src/cmd/compile/internal/noder/helpers.go b/src/cmd/compile/internal/noder/helpers.go
index 456df312a6d..6ab318318bb 100644
--- a/src/cmd/compile/internal/noder/helpers.go
+++ b/src/cmd/compile/internal/noder/helpers.go
@@ -166,7 +166,7 @@ func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool)
 	case *ir.ClosureExpr:
 		fun.Func.SetClosureCalled(true)
 	case *ir.SelectorExpr:
-		if fun.Op() == ir.OCALLPART {
+		if fun.Op() == ir.OMETHVALUE {
 			op := ir.ODOTMETH
 			if fun.X.Type().IsInterface() {
 				op = ir.ODOTINTER
@@ -251,7 +251,7 @@ func DotMethod(pos src.XPos, x ir.Node, index int) *ir.SelectorExpr {
 
 	// Method value.
 	typ := typecheck.NewMethodType(method.Type, nil)
-	return dot(pos, typ, ir.OCALLPART, x, method)
+	return dot(pos, typ, ir.OMETHVALUE, x, method)
 }
 
 // MethodExpr returns a OMETHEXPR node with the indicated index into the methods
diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go
index 1917c95be71..60d56c206f6 100644
--- a/src/cmd/compile/internal/noder/stencil.go
+++ b/src/cmd/compile/internal/noder/stencil.go
@@ -103,7 +103,7 @@ func (g *irgen) stencil() {
 				inst := call.X.(*ir.InstExpr)
 				st, dict := g.getInstantiationForNode(inst)
 				if infoPrintMode && g.target.Stencils[decl.Sym()] == nil {
-					if inst.X.Op() == ir.OCALLPART {
+					if inst.X.Op() == ir.OMETHVALUE {
 						fmt.Printf("Main dictionary in %v at generic method call: %v - %v\n", decl, inst.X, call)
 					} else {
 						fmt.Printf("Main dictionary in %v at generic function call: %v - %v\n", decl, inst.X, call)
@@ -112,7 +112,7 @@ func (g *irgen) stencil() {
 				// Replace the OFUNCINST with a direct reference to the
 				// new stenciled function
 				call.X = st.Nname
-				if inst.X.Op() == ir.OCALLPART {
+				if inst.X.Op() == ir.OMETHVALUE {
 					// When we create an instantiation of a method
 					// call, we make it a function. So, move the
 					// receiver to be the first arg of the function
@@ -218,7 +218,7 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
 		if inst.X.Op() == ir.ONAME {
 			// Instantiating a generic function call.
 			gf = inst.X.(*ir.Name)
-		} else if inst.X.Op() == ir.OCALLPART {
+		} else if inst.X.Op() == ir.OMETHVALUE {
 			// Instantiating a method value x.M.
 			se := inst.X.(*ir.SelectorExpr)
 			rcvrValue = se.X
@@ -826,7 +826,7 @@ func (subst *subster) node(n ir.Node) ir.Node {
 			// instantiated receiver type. We need to do this now,
 			// since the access/selection to the method for the real
 			// type is very different from the selection for the type
-			// param. m will be transformed to an OCALLPART node. It
+			// param. m will be transformed to an OMETHVALUE node. It
 			// will be transformed to an ODOTMETH or ODOTINTER node if
 			// we find in the OCALL case below that the method value
 			// is actually called.
@@ -841,7 +841,7 @@ func (subst *subster) node(n ir.Node) ir.Node {
 				// type argument.
 				m = transformConvCall(m.(*ir.CallExpr))
 
-			case ir.OCALLPART:
+			case ir.OMETHVALUE:
 				// Redo the transformation of OXDOT, now that we
 				// know the method value is being called. Then
 				// transform the call.
diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go
index 30d6e34ae4e..660c4a19e66 100644
--- a/src/cmd/compile/internal/noder/transform.go
+++ b/src/cmd/compile/internal/noder/transform.go
@@ -564,7 +564,7 @@ func transformAsOp(n *ir.AssignOpStmt) {
 }
 
 // transformDot transforms an OXDOT (or ODOT) or ODOT, ODOTPTR, ODOTMETH,
-// ODOTINTER, or OCALLPART, as appropriate. It adds in extra nodes as needed to
+// ODOTINTER, or OMETHVALUE, as appropriate. It adds in extra nodes as needed to
 // access embedded fields. Corresponds to typecheck.tcDot.
 func transformDot(n *ir.SelectorExpr, isCall bool) ir.Node {
 	assert(n.Type() != nil && n.Typecheck() == 1)
@@ -588,7 +588,7 @@ func transformDot(n *ir.SelectorExpr, isCall bool) ir.Node {
 	assert(f != nil)
 
 	if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && !isCall {
-		n.SetOp(ir.OCALLPART)
+		n.SetOp(ir.OMETHVALUE)
 		if len(n.X.Type().RParams()) > 0 || n.X.Type().IsPtr() && len(n.X.Type().Elem().RParams()) > 0 {
 			// TODO: MethodValueWrapper needed for generics?
 			// Or did we successfully desugar all that at stencil time?
diff --git a/src/cmd/compile/internal/pkginit/initorder.go b/src/cmd/compile/internal/pkginit/initorder.go
index 97d69629fba..0aad63a69f6 100644
--- a/src/cmd/compile/internal/pkginit/initorder.go
+++ b/src/cmd/compile/internal/pkginit/initorder.go
@@ -304,7 +304,7 @@ func (d *initDeps) visit(n ir.Node) {
 		n := n.(*ir.ClosureExpr)
 		d.inspectList(n.Func.Body)
 
-	case ir.ODOTMETH, ir.OCALLPART, ir.OMETHEXPR:
+	case ir.ODOTMETH, ir.OMETHVALUE, ir.OMETHEXPR:
 		d.foundDep(ir.MethodExprName(n))
 	}
 }
diff --git a/src/cmd/compile/internal/typecheck/const.go b/src/cmd/compile/internal/typecheck/const.go
index 761b0437940..f8150d249a6 100644
--- a/src/cmd/compile/internal/typecheck/const.go
+++ b/src/cmd/compile/internal/typecheck/const.go
@@ -901,7 +901,7 @@ func evalunsafe(n ir.Node) int64 {
 		switch tsel.Op() {
 		case ir.ODOT, ir.ODOTPTR:
 			break
-		case ir.OCALLPART:
+		case ir.OMETHVALUE:
 			base.Errorf("invalid expression %v: argument is a method value", n)
 			return 0
 		default:
diff --git a/src/cmd/compile/internal/typecheck/crawler.go b/src/cmd/compile/internal/typecheck/crawler.go
index 655ac6e4654..9a348b9f374 100644
--- a/src/cmd/compile/internal/typecheck/crawler.go
+++ b/src/cmd/compile/internal/typecheck/crawler.go
@@ -201,7 +201,7 @@ func (p *crawler) markInlBody(n *ir.Name) {
 			p.checkGenericType(n.Type())
 		case ir.OTYPE:
 			p.checkGenericType(n.Type())
-		case ir.OCALLPART:
+		case ir.OMETHVALUE:
 			// Okay, because we don't yet inline indirect
 			// calls to method values.
 		case ir.OCLOSURE:
diff --git a/src/cmd/compile/internal/typecheck/expr.go b/src/cmd/compile/internal/typecheck/expr.go
index d52f0110728..f039cbab08d 100644
--- a/src/cmd/compile/internal/typecheck/expr.go
+++ b/src/cmd/compile/internal/typecheck/expr.go
@@ -541,7 +541,7 @@ func tcDot(n *ir.SelectorExpr, top int) ir.Node {
 	}
 
 	if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && top&ctxCallee == 0 {
-		n.SetOp(ir.OCALLPART)
+		n.SetOp(ir.OMETHVALUE)
 		n.SetType(MethodValueWrapper(n).Type())
 	}
 	return n
diff --git a/src/cmd/compile/internal/typecheck/func.go b/src/cmd/compile/internal/typecheck/func.go
index 20b991be56a..f4fcfddcf17 100644
--- a/src/cmd/compile/internal/typecheck/func.go
+++ b/src/cmd/compile/internal/typecheck/func.go
@@ -126,7 +126,7 @@ func ClosureType(clo *ir.ClosureExpr) *types.Type {
 }
 
 // PartialCallType returns the struct type used to hold all the information
-// needed in the closure for n (n must be a OCALLPART node).
+// needed in the closure for n (n must be a OMETHVALUE node).
 // The address of a variable of the returned type can be cast to a func.
 func PartialCallType(n *ir.SelectorExpr) *types.Type {
 	t := types.NewStruct(types.NoPkg, []*types.Field{
@@ -225,7 +225,7 @@ func fnpkg(fn *ir.Name) *types.Pkg {
 //
 // TODO(mdempsky): Move into walk. This isn't part of type checking.
 func MethodValueWrapper(dot *ir.SelectorExpr) *ir.Func {
-	if dot.Op() != ir.OCALLPART {
+	if dot.Op() != ir.OMETHVALUE {
 		base.Fatalf("MethodValueWrapper: unexpected %v (%v)", dot, dot.Op())
 	}
 
diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go
index 10d4bd6e7ee..b17af815ec8 100644
--- a/src/cmd/compile/internal/typecheck/iexport.go
+++ b/src/cmd/compile/internal/typecheck/iexport.go
@@ -1775,7 +1775,7 @@ func (w *exportWriter) expr(n ir.Node) {
 	// case OSTRUCTKEY:
 	//	unreachable - handled in case OSTRUCTLIT by elemList
 
-	case ir.OXDOT, ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH, ir.OCALLPART, ir.OMETHEXPR:
+	case ir.OXDOT, ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH, ir.OMETHVALUE, ir.OMETHEXPR:
 		n := n.(*ir.SelectorExpr)
 		if go117ExportTypes {
 			// For go117ExportTypes, we usually see all ops except
@@ -1792,7 +1792,7 @@ func (w *exportWriter) expr(n ir.Node) {
 			if n.Op() == ir.ODOT || n.Op() == ir.ODOTPTR || n.Op() == ir.ODOTINTER {
 				w.exoticField(n.Selection)
 			}
-			// n.Selection is not required for OMETHEXPR, ODOTMETH, and OCALLPART. It will
+			// n.Selection is not required for OMETHEXPR, ODOTMETH, and OMETHVALUE. It will
 			// be reconstructed during import.  n.Selection is computed during
 			// transformDot() for OXDOT.
 		}
diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go
index d94f649a452..7b61260e798 100644
--- a/src/cmd/compile/internal/typecheck/iimport.go
+++ b/src/cmd/compile/internal/typecheck/iimport.go
@@ -1357,7 +1357,7 @@ func (r *importReader) node() ir.Node {
 	// case OSTRUCTKEY:
 	//	unreachable - handled in case OSTRUCTLIT by elemList
 
-	case ir.OXDOT, ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH, ir.OCALLPART, ir.OMETHEXPR:
+	case ir.OXDOT, ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH, ir.OMETHVALUE, ir.OMETHEXPR:
 		// For !go117ExportTypes,  we should only see OXDOT.
 		// For go117ExportTypes, we usually see all the other ops, but can see
 		// OXDOT for generic functions.
@@ -1373,12 +1373,12 @@ func (r *importReader) node() ir.Node {
 			switch op {
 			case ir.ODOT, ir.ODOTPTR, ir.ODOTINTER:
 				n.Selection = r.exoticField()
-			case ir.ODOTMETH, ir.OCALLPART, ir.OMETHEXPR:
+			case ir.ODOTMETH, ir.OMETHVALUE, ir.OMETHEXPR:
 				// These require a Lookup to link to the correct declaration.
 				rcvrType := expr.Type()
 				typ := n.Type()
 				n.Selection = Lookdot(n, rcvrType, 1)
-				if op == ir.OCALLPART || op == ir.OMETHEXPR {
+				if op == ir.OMETHVALUE || op == ir.OMETHEXPR {
 					// Lookdot clobbers the opcode and type, undo that.
 					n.SetOp(op)
 					n.SetType(typ)
diff --git a/src/cmd/compile/internal/walk/closure.go b/src/cmd/compile/internal/walk/closure.go
index 2b7fe8f926b..f399a26689f 100644
--- a/src/cmd/compile/internal/walk/closure.go
+++ b/src/cmd/compile/internal/walk/closure.go
@@ -156,7 +156,7 @@ func closureArgs(clo *ir.ClosureExpr) []ir.Node {
 	return args
 }
 
-func walkCallPart(n *ir.SelectorExpr, init *ir.Nodes) ir.Node {
+func walkMethodValue(n *ir.SelectorExpr, init *ir.Nodes) ir.Node {
 	// Create closure in the form of a composite literal.
 	// For x.M with receiver (x) type T, the generated code looks like:
 	//
diff --git a/src/cmd/compile/internal/walk/expr.go b/src/cmd/compile/internal/walk/expr.go
index f7675c3b7d0..19fb1885264 100644
--- a/src/cmd/compile/internal/walk/expr.go
+++ b/src/cmd/compile/internal/walk/expr.go
@@ -308,8 +308,8 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
 	case ir.OCLOSURE:
 		return walkClosure(n.(*ir.ClosureExpr), init)
 
-	case ir.OCALLPART:
-		return walkCallPart(n.(*ir.SelectorExpr), init)
+	case ir.OMETHVALUE:
+		return walkMethodValue(n.(*ir.SelectorExpr), init)
 	}
 
 	// No return! Each case must return (or panic),
diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go
index 16a124d2ff1..007af03d4bb 100644
--- a/src/cmd/compile/internal/walk/order.go
+++ b/src/cmd/compile/internal/walk/order.go
@@ -1275,7 +1275,7 @@ func (o *orderState) expr1(n, lhs ir.Node) ir.Node {
 		}
 		return n
 
-	case ir.OCALLPART:
+	case ir.OMETHVALUE:
 		n := n.(*ir.SelectorExpr)
 		n.X = o.expr(n.X, nil)
 		if n.Transient() {

From 20a04f60417b60ab5c1ce2dfcdefce1ff57f5914 Mon Sep 17 00:00:00 2001
From: Cuong Manh Le 
Date: Sun, 27 Jun 2021 01:31:03 +0700
Subject: [PATCH 562/940] [dev.typeparams] cmd/compile: delay method value
 wrapper generation until walk

As walk already create the wrapper if necessary.

With this change, test/inline.go need to be changed to use
errorcheckwithauto, for matching "inlining call to ..." in autogenerated
position for method value wrapper, since when we don't generate the
wrapper immediately during typecheck.

Change-Id: I9ffbec9ad3c2b7295546976e2fa517336c13c89b
Reviewed-on: https://go-review.googlesource.com/c/go/+/330838
Trust: Cuong Manh Le 
Run-TryBot: Cuong Manh Le 
TryBot-Result: Go Bot 
Reviewed-by: Matthew Dempsky 
---
 src/cmd/compile/internal/typecheck/expr.go | 2 +-
 test/inline.go                             | 6 ++++--
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/src/cmd/compile/internal/typecheck/expr.go b/src/cmd/compile/internal/typecheck/expr.go
index f039cbab08d..7e974dfda86 100644
--- a/src/cmd/compile/internal/typecheck/expr.go
+++ b/src/cmd/compile/internal/typecheck/expr.go
@@ -542,7 +542,7 @@ func tcDot(n *ir.SelectorExpr, top int) ir.Node {
 
 	if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && top&ctxCallee == 0 {
 		n.SetOp(ir.OMETHVALUE)
-		n.SetType(MethodValueWrapper(n).Type())
+		n.SetType(NewMethodType(n.Type(), nil))
 	}
 	return n
 }
diff --git a/test/inline.go b/test/inline.go
index 472a941dca3..2cda07b2da9 100644
--- a/test/inline.go
+++ b/test/inline.go
@@ -1,4 +1,4 @@
-// errorcheck -0 -m -d=inlfuncswithclosures=1
+// errorcheckwithauto -0 -m -d=inlfuncswithclosures=1
 
 // Copyright 2015 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
@@ -169,6 +169,7 @@ func k() (T, int, int) { return T{}, 0, 0 } // ERROR "can inline k"
 
 func _() { // ERROR "can inline _"
 	T.meth(k()) // ERROR "inlining call to k" "inlining call to T.meth"
+	// ERRORAUTO "inlining call to T.meth"
 }
 
 func small1() { // ERROR "can inline small1"
@@ -232,12 +233,13 @@ Loop:
 // Issue #18493 - make sure we can do inlining of functions with a method value
 type T1 struct{}
 
-func (a T1) meth(val int) int { // ERROR "can inline T1.meth" "inlining call to T1.meth"
+func (a T1) meth(val int) int { // ERROR "can inline T1.meth"
 	return val + 5
 }
 
 func getMeth(t1 T1) func(int) int { // ERROR "can inline getMeth"
 	return t1.meth // ERROR "t1.meth escapes to heap"
+	// ERRORAUTO "inlining call to T1.meth"
 }
 
 func ii() { // ERROR "can inline ii"

From a8861b907dc9d6fece2d515e45dc5091ffd4be63 Mon Sep 17 00:00:00 2001
From: Cuong Manh Le 
Date: Sun, 27 Jun 2021 22:10:03 +0700
Subject: [PATCH 563/940] [dev.typeparams] cmd/compile: port CL 330838 for -G=3

So next CL can move MethodValueWrapper to walk, since when walk is now
the only place which uses this function.

Change-Id: Id3be359bfc38efb022451cb7f9e53c2868fe7e12
Reviewed-on: https://go-review.googlesource.com/c/go/+/330840
Trust: Cuong Manh Le 
Run-TryBot: Cuong Manh Le 
TryBot-Result: Go Bot 
Reviewed-by: Matthew Dempsky 
---
 src/cmd/compile/internal/noder/transform.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go
index 660c4a19e66..c3fa8042f2c 100644
--- a/src/cmd/compile/internal/noder/transform.go
+++ b/src/cmd/compile/internal/noder/transform.go
@@ -594,7 +594,7 @@ func transformDot(n *ir.SelectorExpr, isCall bool) ir.Node {
 			// Or did we successfully desugar all that at stencil time?
 			return n
 		}
-		n.SetType(typecheck.MethodValueWrapper(n).Type())
+		n.SetType(typecheck.NewMethodType(n.Type(), nil))
 	}
 	return n
 }

From f99b3fe2ab6b142bc49b653c6547655cb7114625 Mon Sep 17 00:00:00 2001
From: Cuong Manh Le 
Date: Sun, 27 Jun 2021 22:25:21 +0700
Subject: [PATCH 564/940] [dev.typeparams] cmd/compile: move MethodValueWrapper
 to walk

walk is the only pass that use the function, so un-export it, too.

Change-Id: I32ec64d1c15fda7bb54bd8efa528ed32c102876d
Reviewed-on: https://go-review.googlesource.com/c/go/+/330841
Trust: Cuong Manh Le 
Run-TryBot: Cuong Manh Le 
TryBot-Result: Go Bot 
Reviewed-by: Matthew Dempsky 
---
 src/cmd/compile/internal/typecheck/func.go | 80 ----------------------
 src/cmd/compile/internal/walk/closure.go   | 80 +++++++++++++++++++++-
 2 files changed, 79 insertions(+), 81 deletions(-)

diff --git a/src/cmd/compile/internal/typecheck/func.go b/src/cmd/compile/internal/typecheck/func.go
index f4fcfddcf17..5f9f8c6ebdc 100644
--- a/src/cmd/compile/internal/typecheck/func.go
+++ b/src/cmd/compile/internal/typecheck/func.go
@@ -218,86 +218,6 @@ func fnpkg(fn *ir.Name) *types.Pkg {
 	return fn.Sym().Pkg
 }
 
-// MethodValueWrapper returns the DCLFUNC node representing the
-// wrapper function (*-fm) needed for the given method value. If the
-// wrapper function hasn't already been created yet, it's created and
-// added to Target.Decls.
-//
-// TODO(mdempsky): Move into walk. This isn't part of type checking.
-func MethodValueWrapper(dot *ir.SelectorExpr) *ir.Func {
-	if dot.Op() != ir.OMETHVALUE {
-		base.Fatalf("MethodValueWrapper: unexpected %v (%v)", dot, dot.Op())
-	}
-
-	t0 := dot.Type()
-	meth := dot.Sel
-	rcvrtype := dot.X.Type()
-	sym := ir.MethodSymSuffix(rcvrtype, meth, "-fm")
-
-	if sym.Uniq() {
-		return sym.Def.(*ir.Func)
-	}
-	sym.SetUniq(true)
-
-	savecurfn := ir.CurFunc
-	saveLineNo := base.Pos
-	ir.CurFunc = nil
-
-	// Set line number equal to the line number where the method is declared.
-	if pos := dot.Selection.Pos; pos.IsKnown() {
-		base.Pos = pos
-	}
-	// Note: !dot.Selection.Pos.IsKnown() happens for method expressions where
-	// the method is implicitly declared. The Error method of the
-	// built-in error type is one such method.  We leave the line
-	// number at the use of the method expression in this
-	// case. See issue 29389.
-
-	tfn := ir.NewFuncType(base.Pos, nil,
-		NewFuncParams(t0.Params(), true),
-		NewFuncParams(t0.Results(), false))
-
-	fn := DeclFunc(sym, tfn)
-	fn.SetDupok(true)
-	fn.SetNeedctxt(true)
-	fn.SetWrapper(true)
-
-	// Declare and initialize variable holding receiver.
-	ptr := ir.NewNameAt(base.Pos, Lookup(".this"))
-	ptr.Class = ir.PAUTOHEAP
-	ptr.SetType(rcvrtype)
-	ptr.Curfn = fn
-	ptr.SetIsClosureVar(true)
-	ptr.SetByval(true)
-	fn.ClosureVars = append(fn.ClosureVars, ptr)
-
-	call := ir.NewCallExpr(base.Pos, ir.OCALL, ir.NewSelectorExpr(base.Pos, ir.OXDOT, ptr, meth), nil)
-	call.Args = ir.ParamNames(tfn.Type())
-	call.IsDDD = tfn.Type().IsVariadic()
-
-	var body ir.Node = call
-	if t0.NumResults() != 0 {
-		ret := ir.NewReturnStmt(base.Pos, nil)
-		ret.Results = []ir.Node{call}
-		body = ret
-	}
-
-	fn.Body = []ir.Node{body}
-	FinishFuncBody()
-
-	Func(fn)
-	// Need to typecheck the body of the just-generated wrapper.
-	// typecheckslice() requires that Curfn is set when processing an ORETURN.
-	ir.CurFunc = fn
-	Stmts(fn.Body)
-	sym.Def = fn
-	Target.Decls = append(Target.Decls, fn)
-	ir.CurFunc = savecurfn
-	base.Pos = saveLineNo
-
-	return fn
-}
-
 // tcClosure typechecks an OCLOSURE node. It also creates the named
 // function associated with the closure.
 // TODO: This creation of the named function should probably really be done in a
diff --git a/src/cmd/compile/internal/walk/closure.go b/src/cmd/compile/internal/walk/closure.go
index f399a26689f..a86ed2ab805 100644
--- a/src/cmd/compile/internal/walk/closure.go
+++ b/src/cmd/compile/internal/walk/closure.go
@@ -179,7 +179,7 @@ func walkMethodValue(n *ir.SelectorExpr, init *ir.Nodes) ir.Node {
 
 	clos := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ), nil)
 	clos.SetEsc(n.Esc())
-	clos.List = []ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, typecheck.MethodValueWrapper(n).Nname), n.X}
+	clos.List = []ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, methodValueWrapper(n).Nname), n.X}
 
 	addr := typecheck.NodAddr(clos)
 	addr.SetEsc(n.Esc())
@@ -198,3 +198,81 @@ func walkMethodValue(n *ir.SelectorExpr, init *ir.Nodes) ir.Node {
 
 	return walkExpr(cfn, init)
 }
+
+// methodValueWrapper returns the DCLFUNC node representing the
+// wrapper function (*-fm) needed for the given method value. If the
+// wrapper function hasn't already been created yet, it's created and
+// added to typecheck.Target.Decls.
+func methodValueWrapper(dot *ir.SelectorExpr) *ir.Func {
+	if dot.Op() != ir.OMETHVALUE {
+		base.Fatalf("methodValueWrapper: unexpected %v (%v)", dot, dot.Op())
+	}
+
+	t0 := dot.Type()
+	meth := dot.Sel
+	rcvrtype := dot.X.Type()
+	sym := ir.MethodSymSuffix(rcvrtype, meth, "-fm")
+
+	if sym.Uniq() {
+		return sym.Def.(*ir.Func)
+	}
+	sym.SetUniq(true)
+
+	savecurfn := ir.CurFunc
+	saveLineNo := base.Pos
+	ir.CurFunc = nil
+
+	// Set line number equal to the line number where the method is declared.
+	if pos := dot.Selection.Pos; pos.IsKnown() {
+		base.Pos = pos
+	}
+	// Note: !dot.Selection.Pos.IsKnown() happens for method expressions where
+	// the method is implicitly declared. The Error method of the
+	// built-in error type is one such method.  We leave the line
+	// number at the use of the method expression in this
+	// case. See issue 29389.
+
+	tfn := ir.NewFuncType(base.Pos, nil,
+		typecheck.NewFuncParams(t0.Params(), true),
+		typecheck.NewFuncParams(t0.Results(), false))
+
+	fn := typecheck.DeclFunc(sym, tfn)
+	fn.SetDupok(true)
+	fn.SetNeedctxt(true)
+	fn.SetWrapper(true)
+
+	// Declare and initialize variable holding receiver.
+	ptr := ir.NewNameAt(base.Pos, typecheck.Lookup(".this"))
+	ptr.Class = ir.PAUTOHEAP
+	ptr.SetType(rcvrtype)
+	ptr.Curfn = fn
+	ptr.SetIsClosureVar(true)
+	ptr.SetByval(true)
+	fn.ClosureVars = append(fn.ClosureVars, ptr)
+
+	call := ir.NewCallExpr(base.Pos, ir.OCALL, ir.NewSelectorExpr(base.Pos, ir.OXDOT, ptr, meth), nil)
+	call.Args = ir.ParamNames(tfn.Type())
+	call.IsDDD = tfn.Type().IsVariadic()
+
+	var body ir.Node = call
+	if t0.NumResults() != 0 {
+		ret := ir.NewReturnStmt(base.Pos, nil)
+		ret.Results = []ir.Node{call}
+		body = ret
+	}
+
+	fn.Body = []ir.Node{body}
+	typecheck.FinishFuncBody()
+
+	typecheck.Func(fn)
+	// Need to typecheck the body of the just-generated wrapper.
+	// typecheckslice() requires that Curfn is set when processing an ORETURN.
+	ir.CurFunc = fn
+	typecheck.Stmts(fn.Body)
+	sym.Def = fn
+	typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
+	ir.CurFunc = savecurfn
+	base.Pos = saveLineNo
+
+	return fn
+}

From 361159c05507b7f6c28e29575c02a6b7b6656f84 Mon Sep 17 00:00:00 2001
From: Koichi Shiraishi 
Date: Sun, 27 Jun 2021 11:50:17 +0900
Subject: [PATCH 565/940] cmd/cgo: fix 'see gmp.go' to 'see doc.go'

Change-Id: I303edc9dfbf4185b5b461b121ab504f6ed9f8630
Reviewed-on: https://go-review.googlesource.com/c/go/+/330839
Reviewed-by: Ian Lance Taylor 
Trust: Dmitri Shuralyov 
---
 src/cmd/cgo/main.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index 03a662e689d..c6a0c525e64 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Cgo; see gmp.go for an overview.
+// Cgo; see doc.go for an overview.
 
 // TODO(rsc):
 //	Emit correct line number annotations.

From 901510ed4ef1a979321f33159b534e374290ef65 Mon Sep 17 00:00:00 2001
From: hao 
Date: Fri, 28 May 2021 03:40:12 +0000
Subject: [PATCH 566/940] cmd/link/internal/ld: skip the windows ASLR test when
 CGO_ENABLED=0

the test case is still using gcc when CGO is disabled.

Change-Id: I2d255bfaeb92816c8343ab72fd7984b6632d421d
GitHub-Last-Rev: de14748bd54c7db8687263a7c37080ec884d982a
GitHub-Pull-Request: golang/go#46120
Reviewed-on: https://go-review.googlesource.com/c/go/+/319169
Reviewed-by: Cherry Mui 
Run-TryBot: Cherry Mui 
TryBot-Result: Go Bot 
Trust: Dmitri Shuralyov 
---
 src/cmd/link/internal/ld/ld_test.go | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/cmd/link/internal/ld/ld_test.go b/src/cmd/link/internal/ld/ld_test.go
index ca764632c3d..3702a4d08f5 100644
--- a/src/cmd/link/internal/ld/ld_test.go
+++ b/src/cmd/link/internal/ld/ld_test.go
@@ -174,6 +174,8 @@ func TestWindowsBuildmodeCSharedASLR(t *testing.T) {
 		t.Skip("skipping windows amd64/386 only test")
 	}
 
+	testenv.MustHaveCGO(t)
+
 	t.Run("aslr", func(t *testing.T) {
 		testWindowsBuildmodeCSharedASLR(t, true)
 	})

From a1d27269d698d684497d0dc61c968a1c2dbe00b3 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Sat, 19 Jun 2021 03:35:15 -0700
Subject: [PATCH 567/940] cmd/go: prep for 'go env' refactoring

This CL refactors code a little to make it easier to add GOEXPERIMENT
support in the future.

Change-Id: I87903056f7863049e58be72047b2b8a60a213baf
Reviewed-on: https://go-review.googlesource.com/c/go/+/329654
Run-TryBot: Matthew Dempsky 
Trust: Matthew Dempsky 
TryBot-Result: Go Bot 
Reviewed-by: Bryan C. Mills 
---
 src/cmd/go/internal/envcmd/env.go        | 210 ++++++++++++-----------
 src/cmd/go/main.go                       |  64 +++----
 src/cmd/go/testdata/script/env_unset.txt |  23 +++
 3 files changed, 170 insertions(+), 127 deletions(-)
 create mode 100644 src/cmd/go/testdata/script/env_unset.txt

diff --git a/src/cmd/go/internal/envcmd/env.go b/src/cmd/go/internal/envcmd/env.go
index b30c37ab27c..d88dcce5c0a 100644
--- a/src/cmd/go/internal/envcmd/env.go
+++ b/src/cmd/go/internal/envcmd/env.go
@@ -10,6 +10,7 @@ import (
 	"encoding/json"
 	"fmt"
 	"go/build"
+	"internal/buildcfg"
 	"io"
 	"os"
 	"path/filepath"
@@ -197,6 +198,21 @@ func runEnv(ctx context.Context, cmd *base.Command, args []string) {
 	if *envU && *envW {
 		base.Fatalf("go env: cannot use -u with -w")
 	}
+
+	// Handle 'go env -w' and 'go env -u' before calling buildcfg.Check,
+	// so they can be used to recover from an invalid configuration.
+	if *envW {
+		runEnvW(args)
+		return
+	}
+
+	if *envU {
+		runEnvU(args)
+		return
+	}
+
+	buildcfg.Check()
+
 	env := cfg.CmdEnv
 	env = append(env, ExtraEnvVars()...)
 
@@ -206,14 +222,7 @@ func runEnv(ctx context.Context, cmd *base.Command, args []string) {
 
 	// Do we need to call ExtraEnvVarsCostly, which is a bit expensive?
 	needCostly := false
-	if *envU || *envW {
-		// We're overwriting or removing default settings,
-		// so it doesn't really matter what the existing settings are.
-		//
-		// Moreover, we haven't validated the new settings yet, so it is
-		// important that we NOT perform any actions based on them,
-		// such as initializing the builder to compute other variables.
-	} else if len(args) == 0 {
+	if len(args) == 0 {
 		// We're listing all environment variables ("go env"),
 		// including the expensive ones.
 		needCostly = true
@@ -238,95 +247,6 @@ func runEnv(ctx context.Context, cmd *base.Command, args []string) {
 		env = append(env, ExtraEnvVarsCostly()...)
 	}
 
-	if *envW {
-		// Process and sanity-check command line.
-		if len(args) == 0 {
-			base.Fatalf("go env -w: no KEY=VALUE arguments given")
-		}
-		osEnv := make(map[string]string)
-		for _, e := range cfg.OrigEnv {
-			if i := strings.Index(e, "="); i >= 0 {
-				osEnv[e[:i]] = e[i+1:]
-			}
-		}
-		add := make(map[string]string)
-		for _, arg := range args {
-			i := strings.Index(arg, "=")
-			if i < 0 {
-				base.Fatalf("go env -w: arguments must be KEY=VALUE: invalid argument: %s", arg)
-			}
-			key, val := arg[:i], arg[i+1:]
-			if err := checkEnvWrite(key, val); err != nil {
-				base.Fatalf("go env -w: %v", err)
-			}
-			if _, ok := add[key]; ok {
-				base.Fatalf("go env -w: multiple values for key: %s", key)
-			}
-			add[key] = val
-			if osVal := osEnv[key]; osVal != "" && osVal != val {
-				fmt.Fprintf(os.Stderr, "warning: go env -w %s=... does not override conflicting OS environment variable\n", key)
-			}
-		}
-
-		goos, okGOOS := add["GOOS"]
-		goarch, okGOARCH := add["GOARCH"]
-		if okGOOS || okGOARCH {
-			if !okGOOS {
-				goos = cfg.Goos
-			}
-			if !okGOARCH {
-				goarch = cfg.Goarch
-			}
-			if err := work.CheckGOOSARCHPair(goos, goarch); err != nil {
-				base.Fatalf("go env -w: %v", err)
-			}
-		}
-
-		gotmp, okGOTMP := add["GOTMPDIR"]
-		if okGOTMP {
-			if !filepath.IsAbs(gotmp) && gotmp != "" {
-				base.Fatalf("go env -w: GOTMPDIR must be an absolute path")
-			}
-		}
-
-		updateEnvFile(add, nil)
-		return
-	}
-
-	if *envU {
-		// Process and sanity-check command line.
-		if len(args) == 0 {
-			base.Fatalf("go env -u: no arguments given")
-		}
-		del := make(map[string]bool)
-		for _, arg := range args {
-			if err := checkEnvWrite(arg, ""); err != nil {
-				base.Fatalf("go env -u: %v", err)
-			}
-			del[arg] = true
-		}
-		if del["GOOS"] || del["GOARCH"] {
-			goos, goarch := cfg.Goos, cfg.Goarch
-			if del["GOOS"] {
-				goos = getOrigEnv("GOOS")
-				if goos == "" {
-					goos = build.Default.GOOS
-				}
-			}
-			if del["GOARCH"] {
-				goarch = getOrigEnv("GOARCH")
-				if goarch == "" {
-					goarch = build.Default.GOARCH
-				}
-			}
-			if err := work.CheckGOOSARCHPair(goos, goarch); err != nil {
-				base.Fatalf("go env -u: %v", err)
-			}
-		}
-		updateEnvFile(nil, del)
-		return
-	}
-
 	if len(args) > 0 {
 		if *envJson {
 			var es []cfg.EnvVar
@@ -351,6 +271,102 @@ func runEnv(ctx context.Context, cmd *base.Command, args []string) {
 	PrintEnv(os.Stdout, env)
 }
 
+func runEnvW(args []string) {
+	// Process and sanity-check command line.
+	if len(args) == 0 {
+		base.Fatalf("go env -w: no KEY=VALUE arguments given")
+	}
+	osEnv := make(map[string]string)
+	for _, e := range cfg.OrigEnv {
+		if i := strings.Index(e, "="); i >= 0 {
+			osEnv[e[:i]] = e[i+1:]
+		}
+	}
+	add := make(map[string]string)
+	for _, arg := range args {
+		i := strings.Index(arg, "=")
+		if i < 0 {
+			base.Fatalf("go env -w: arguments must be KEY=VALUE: invalid argument: %s", arg)
+		}
+		key, val := arg[:i], arg[i+1:]
+		if err := checkEnvWrite(key, val); err != nil {
+			base.Fatalf("go env -w: %v", err)
+		}
+		if _, ok := add[key]; ok {
+			base.Fatalf("go env -w: multiple values for key: %s", key)
+		}
+		add[key] = val
+		if osVal := osEnv[key]; osVal != "" && osVal != val {
+			fmt.Fprintf(os.Stderr, "warning: go env -w %s=... does not override conflicting OS environment variable\n", key)
+		}
+	}
+
+	if err := checkBuildConfig(add, nil); err != nil {
+		base.Fatalf("go env -w: %v", err)
+	}
+
+	gotmp, okGOTMP := add["GOTMPDIR"]
+	if okGOTMP {
+		if !filepath.IsAbs(gotmp) && gotmp != "" {
+			base.Fatalf("go env -w: GOTMPDIR must be an absolute path")
+		}
+	}
+
+	updateEnvFile(add, nil)
+}
+
+func runEnvU(args []string) {
+	// Process and sanity-check command line.
+	if len(args) == 0 {
+		base.Fatalf("go env -u: no arguments given")
+	}
+	del := make(map[string]bool)
+	for _, arg := range args {
+		if err := checkEnvWrite(arg, ""); err != nil {
+			base.Fatalf("go env -u: %v", err)
+		}
+		del[arg] = true
+	}
+
+	if err := checkBuildConfig(nil, del); err != nil {
+		base.Fatalf("go env -u: %v", err)
+	}
+
+	updateEnvFile(nil, del)
+}
+
+// checkBuildConfig checks whether the build configuration is valid
+// after the specified configuration environment changes are applied.
+func checkBuildConfig(add map[string]string, del map[string]bool) error {
+	// get returns the value for key after applying add and del and
+	// reports whether it changed. cur should be the current value
+	// (i.e., before applying changes) and def should be the default
+	// value (i.e., when no environment variables are provided at all).
+	get := func(key, cur, def string) (string, bool) {
+		if val, ok := add[key]; ok {
+			return val, true
+		}
+		if del[key] {
+			val := getOrigEnv(key)
+			if val == "" {
+				val = def
+			}
+			return val, true
+		}
+		return cur, false
+	}
+
+	goos, okGOOS := get("GOOS", cfg.Goos, build.Default.GOOS)
+	goarch, okGOARCH := get("GOARCH", cfg.Goarch, build.Default.GOARCH)
+	if okGOOS || okGOARCH {
+		if err := work.CheckGOOSARCHPair(goos, goarch); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
 // PrintEnv prints the environment variables to w.
 func PrintEnv(w io.Writer, env []cfg.EnvVar) {
 	for _, e := range env {
diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go
index 02174a56ff0..16361e02ca7 100644
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -145,24 +145,6 @@ func main() {
 		os.Exit(2)
 	}
 
-	if err := buildcfg.Error; err != nil {
-		fmt.Fprintf(os.Stderr, "go: %v\n", buildcfg.Error)
-		os.Exit(2)
-	}
-
-	// Set environment (GOOS, GOARCH, etc) explicitly.
-	// In theory all the commands we invoke should have
-	// the same default computation of these as we do,
-	// but in practice there might be skew
-	// This makes sure we all agree.
-	cfg.OrigEnv = os.Environ()
-	cfg.CmdEnv = envcmd.MkEnv()
-	for _, env := range cfg.CmdEnv {
-		if os.Getenv(env.Name) != env.Value {
-			os.Setenv(env.Name, env.Value)
-		}
-	}
-
 BigCmdLoop:
 	for bigCmd := base.Go; ; {
 		for _, cmd := range bigCmd.Commands {
@@ -188,18 +170,7 @@ BigCmdLoop:
 			if !cmd.Runnable() {
 				continue
 			}
-			cmd.Flag.Usage = func() { cmd.Usage() }
-			if cmd.CustomFlags {
-				args = args[1:]
-			} else {
-				base.SetFromGOFLAGS(&cmd.Flag)
-				cmd.Flag.Parse(args[1:])
-				args = cmd.Flag.Args()
-			}
-			ctx := maybeStartTrace(context.Background())
-			ctx, span := trace.StartSpan(ctx, fmt.Sprint("Running ", cmd.Name(), " command"))
-			cmd.Run(ctx, cmd, args)
-			span.Done()
+			invoke(cmd, args)
 			base.Exit()
 			return
 		}
@@ -213,6 +184,39 @@ BigCmdLoop:
 	}
 }
 
+func invoke(cmd *base.Command, args []string) {
+	// 'go env' handles checking the build config
+	if cmd != envcmd.CmdEnv {
+		buildcfg.Check()
+	}
+
+	// Set environment (GOOS, GOARCH, etc) explicitly.
+	// In theory all the commands we invoke should have
+	// the same default computation of these as we do,
+	// but in practice there might be skew
+	// This makes sure we all agree.
+	cfg.OrigEnv = os.Environ()
+	cfg.CmdEnv = envcmd.MkEnv()
+	for _, env := range cfg.CmdEnv {
+		if os.Getenv(env.Name) != env.Value {
+			os.Setenv(env.Name, env.Value)
+		}
+	}
+
+	cmd.Flag.Usage = func() { cmd.Usage() }
+	if cmd.CustomFlags {
+		args = args[1:]
+	} else {
+		base.SetFromGOFLAGS(&cmd.Flag)
+		cmd.Flag.Parse(args[1:])
+		args = cmd.Flag.Args()
+	}
+	ctx := maybeStartTrace(context.Background())
+	ctx, span := trace.StartSpan(ctx, fmt.Sprint("Running ", cmd.Name(), " command"))
+	cmd.Run(ctx, cmd, args)
+	span.Done()
+}
+
 func init() {
 	base.Usage = mainUsage
 }
diff --git a/src/cmd/go/testdata/script/env_unset.txt b/src/cmd/go/testdata/script/env_unset.txt
new file mode 100644
index 00000000000..35fbb0a8a20
--- /dev/null
+++ b/src/cmd/go/testdata/script/env_unset.txt
@@ -0,0 +1,23 @@
+# Test that we can unset variables, even if initially invalid,
+# as long as resulting config is valid.
+
+env GOENV=badenv
+env GOOS=
+env GOARCH=
+
+! go env
+stderr '^cmd/go: unsupported GOOS/GOARCH pair bados/badarch$'
+
+! go env -u GOOS
+stderr '^go env -u: unsupported GOOS/GOARCH pair \w+/badarch$'
+
+! go env -u GOARCH
+stderr '^go env -u: unsupported GOOS/GOARCH pair bados/\w+$'
+
+go env -u GOOS GOARCH
+
+go env
+
+-- badenv --
+GOOS=bados
+GOARCH=badarch

From 956c81bfe60306e49e26f7edd4f48cbc24c8fe28 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Wed, 16 Jun 2021 15:10:57 -0700
Subject: [PATCH 568/940] cmd/go: add GOEXPERIMENT to `go env` output

This CL adds GOEXPERIMENT to `go env` output, and also makes it
configurable via `GOENV`. Thanks to Baokun Lee's CL 304350 for the
test and initial work on this.

Fixes #45226.

Change-Id: Ie7f92a8a503b6a2a4df3f6598f0b2bf2915e2e7d
Reviewed-on: https://go-review.googlesource.com/c/go/+/328751
Run-TryBot: Matthew Dempsky 
TryBot-Result: Go Bot 
Reviewed-by: Bryan C. Mills 
Trust: Bryan C. Mills 
Trust: Matthew Dempsky 
---
 src/cmd/go/alldocs.go                    |  6 ++++++
 src/cmd/go/internal/envcmd/env.go        |  8 ++++++++
 src/cmd/go/internal/help/helpdoc.go      |  6 ++++++
 src/cmd/go/testdata/script/env_exp.txt   | 17 +++++++++++++++++
 src/cmd/go/testdata/script/env_unset.txt |  7 +++++++
 src/cmd/go/testdata/script/env_write.txt |  6 ++++++
 6 files changed, 50 insertions(+)
 create mode 100644 src/cmd/go/testdata/script/env_exp.txt

diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
index fd95da23eb0..90eb3e2a00b 100644
--- a/src/cmd/go/alldocs.go
+++ b/src/cmd/go/alldocs.go
@@ -1903,6 +1903,12 @@
 // 	GCCGOTOOLDIR
 // 		If set, where to find gccgo tools, such as cgo.
 // 		The default is based on how gccgo was configured.
+// 	GOEXPERIMENT
+// 		Comma-separated list of toolchain experiments to enable or disable.
+// 		The list of available experiments may change arbitrarily over time.
+// 		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.
diff --git a/src/cmd/go/internal/envcmd/env.go b/src/cmd/go/internal/envcmd/env.go
index d88dcce5c0a..1553d263914 100644
--- a/src/cmd/go/internal/envcmd/env.go
+++ b/src/cmd/go/internal/envcmd/env.go
@@ -73,6 +73,7 @@ func MkEnv() []cfg.EnvVar {
 		{Name: "GOCACHE", Value: cache.DefaultDir()},
 		{Name: "GOENV", Value: envFile},
 		{Name: "GOEXE", Value: cfg.ExeSuffix},
+		{Name: "GOEXPERIMENT", Value: buildcfg.GOEXPERIMENT()},
 		{Name: "GOFLAGS", Value: cfg.Getenv("GOFLAGS")},
 		{Name: "GOHOSTARCH", Value: runtime.GOARCH},
 		{Name: "GOHOSTOS", Value: runtime.GOOS},
@@ -364,6 +365,13 @@ func checkBuildConfig(add map[string]string, del map[string]bool) error {
 		}
 	}
 
+	goexperiment, okGOEXPERIMENT := get("GOEXPERIMENT", buildcfg.GOEXPERIMENT(), "")
+	if okGOEXPERIMENT {
+		if _, _, err := buildcfg.ParseGOEXPERIMENT(goos, goarch, goexperiment); err != nil {
+			return err
+		}
+	}
+
 	return nil
 }
 
diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go
index b552777e3e0..490ff1fb7cf 100644
--- a/src/cmd/go/internal/help/helpdoc.go
+++ b/src/cmd/go/internal/help/helpdoc.go
@@ -610,6 +610,12 @@ Special-purpose environment variables:
 	GCCGOTOOLDIR
 		If set, where to find gccgo tools, such as cgo.
 		The default is based on how gccgo was configured.
+	GOEXPERIMENT
+		Comma-separated list of toolchain experiments to enable or disable.
+		The list of available experiments may change arbitrarily over time.
+		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.
diff --git a/src/cmd/go/testdata/script/env_exp.txt b/src/cmd/go/testdata/script/env_exp.txt
new file mode 100644
index 00000000000..681512d87c6
--- /dev/null
+++ b/src/cmd/go/testdata/script/env_exp.txt
@@ -0,0 +1,17 @@
+# Test GOEXPERIMENT variable
+
+# go env shows default empty GOEXPERIMENT
+go env
+stdout GOEXPERIMENT=
+
+# go env shows valid experiments
+env GOEXPERIMENT=fieldtrack,staticlockranking
+go env GOEXPERIMENT
+stdout '.*fieldtrack.*staticlockranking.*'
+go env
+stdout 'GOEXPERIMENT=.*fieldtrack.*staticlockranking.*'
+
+# go env rejects unknown experiments
+env GOEXPERIMENT=bad
+! go env GOEXPERIMENT
+stderr 'unknown GOEXPERIMENT bad'
diff --git a/src/cmd/go/testdata/script/env_unset.txt b/src/cmd/go/testdata/script/env_unset.txt
index 35fbb0a8a20..4e0f2495098 100644
--- a/src/cmd/go/testdata/script/env_unset.txt
+++ b/src/cmd/go/testdata/script/env_unset.txt
@@ -4,6 +4,12 @@
 env GOENV=badenv
 env GOOS=
 env GOARCH=
+env GOEXPERIMENT=
+
+! go env
+stderr '^go(\.exe)?: unknown GOEXPERIMENT badexp$'
+
+go env -u GOEXPERIMENT
 
 ! go env
 stderr '^cmd/go: unsupported GOOS/GOARCH pair bados/badarch$'
@@ -21,3 +27,4 @@ go env
 -- badenv --
 GOOS=bados
 GOARCH=badarch
+GOEXPERIMENT=badexp
diff --git a/src/cmd/go/testdata/script/env_write.txt b/src/cmd/go/testdata/script/env_write.txt
index 4fa39df1044..b5e97391679 100644
--- a/src/cmd/go/testdata/script/env_write.txt
+++ b/src/cmd/go/testdata/script/env_write.txt
@@ -179,3 +179,9 @@ stderr 'unsupported GOOS/GOARCH.*windows/mips$'
 stderr 'go env -w: GOMODCACHE entry is relative; must be absolute path: "~/test"'
 ! go env -w GOMODCACHE=./test
 stderr 'go env -w: GOMODCACHE entry is relative; must be absolute path: "./test"'
+
+# go env -w checks validity of GOEXPERIMENT
+env GOEXPERIMENT=
+! go env -w GOEXPERIMENT=badexp
+stderr 'unknown GOEXPERIMENT badexp'
+go env -w GOEXPERIMENT=fieldtrack

From 64e6c75924a57306d8009cef4802b0b9ca4b7891 Mon Sep 17 00:00:00 2001
From: Dan Scales 
Date: Mon, 28 Jun 2021 11:50:26 -0700
Subject: [PATCH 569/940] [dev.typeparams] cmd/compile: port fix for issue46725
 to transform.go

Allow fix for issue46725 to work for -G=3 mode.

Change-Id: Id522fbc2278cf878cb3f95b3205a2122c164ae29
Reviewed-on: https://go-review.googlesource.com/c/go/+/331470
Trust: Dan Scales 
Run-TryBot: Dan Scales 
TryBot-Result: Go Bot 
Reviewed-by: Matthew Dempsky 
---
 src/cmd/compile/internal/noder/transform.go     | 14 +++++++++++++-
 src/cmd/compile/internal/typecheck/stmt.go      |  2 +-
 src/cmd/compile/internal/typecheck/typecheck.go |  6 +++---
 test/run.go                                     |  1 -
 4 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go
index c3fa8042f2c..7a685c4b470 100644
--- a/src/cmd/compile/internal/noder/transform.go
+++ b/src/cmd/compile/internal/noder/transform.go
@@ -329,8 +329,20 @@ assignOK:
 		r.Use = ir.CallUseList
 		rtyp := r.Type()
 
+		mismatched := false
+		failed := false
 		for i := range lhs {
-			checkLHS(i, rtyp.Field(i).Type)
+			result := rtyp.Field(i).Type
+			checkLHS(i, result)
+
+			if lhs[i].Type() == nil || result == nil {
+				failed = true
+			} else if lhs[i] != ir.BlankNode && !types.Identical(lhs[i].Type(), result) {
+				mismatched = true
+			}
+		}
+		if mismatched && !failed {
+			typecheck.RewriteMultiValueCall(stmt, r)
 		}
 		return
 	}
diff --git a/src/cmd/compile/internal/typecheck/stmt.go b/src/cmd/compile/internal/typecheck/stmt.go
index 54cf508acc1..f1275f29c07 100644
--- a/src/cmd/compile/internal/typecheck/stmt.go
+++ b/src/cmd/compile/internal/typecheck/stmt.go
@@ -217,7 +217,7 @@ assignOK:
 			}
 		}
 		if mismatched && !failed {
-			rewriteMultiValueCall(stmt, r)
+			RewriteMultiValueCall(stmt, r)
 		}
 		return
 	}
diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go
index f7de43c79f8..232c0e66ef3 100644
--- a/src/cmd/compile/internal/typecheck/typecheck.go
+++ b/src/cmd/compile/internal/typecheck/typecheck.go
@@ -962,12 +962,12 @@ func typecheckargs(n ir.InitNode) {
 	}
 
 	// Rewrite f(g()) into t1, t2, ... = g(); f(t1, t2, ...).
-	rewriteMultiValueCall(n, list[0])
+	RewriteMultiValueCall(n, list[0])
 }
 
-// rewriteMultiValueCall rewrites multi-valued f() to use temporaries,
+// RewriteMultiValueCall rewrites multi-valued f() to use temporaries,
 // so the backend wouldn't need to worry about tuple-valued expressions.
-func rewriteMultiValueCall(n ir.InitNode, call ir.Node) {
+func RewriteMultiValueCall(n ir.InitNode, call ir.Node) {
 	// If we're outside of function context, then this call will
 	// be executed during the generated init function. However,
 	// init.go hasn't yet created it. Instead, associate the
diff --git a/test/run.go b/test/run.go
index ad92d8bb79c..d04f7d20ed8 100644
--- a/test/run.go
+++ b/test/run.go
@@ -2131,7 +2131,6 @@ var excludedFiles = map[string]bool{
 	"fixedbugs/issue4232.go":   true, // types2 reports (correct) extra errors
 	"fixedbugs/issue4452.go":   true, // types2 reports (correct) extra errors
 	"fixedbugs/issue4510.go":   true, // types2 reports different (but ok) line numbers
-	"fixedbugs/issue46725.go":  true, // fix applied to typecheck needs to be ported to irgen/transform
 	"fixedbugs/issue5609.go":   true, // types2 needs a better error message
 	"fixedbugs/issue7525b.go":  true, // types2 reports init cycle error on different line - ok otherwise
 	"fixedbugs/issue7525c.go":  true, // types2 reports init cycle error on different line - ok otherwise

From 5385e2386b64b10960c1b40113ee7dae271c8369 Mon Sep 17 00:00:00 2001
From: Mia Zhu 
Date: Mon, 28 Jun 2021 17:10:56 +0000
Subject: [PATCH 570/940] runtime/internal/atomic: drop Cas64 pointer
 indirection in comments

Change-Id: Ieff0065cbd81e045594ce12e10338b0666816d70
GitHub-Last-Rev: d842f5cb3e5d75f87957c068f6accc9d4a4ac224
GitHub-Pull-Request: golang/go#46949
Reviewed-on: https://go-review.googlesource.com/c/go/+/331309
Trust: Keith Randall 
Run-TryBot: Ian Lance Taylor 
TryBot-Result: Go Bot 
Reviewed-by: Ian Lance Taylor 
---
 src/runtime/internal/atomic/atomic_amd64.s   | 2 +-
 src/runtime/internal/atomic/atomic_arm64.s   | 2 +-
 src/runtime/internal/atomic/atomic_mips64x.s | 2 +-
 src/runtime/internal/atomic/atomic_ppc64x.s  | 2 +-
 src/runtime/internal/atomic/atomic_riscv64.s | 3 ++-
 5 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/src/runtime/internal/atomic/atomic_amd64.s b/src/runtime/internal/atomic/atomic_amd64.s
index 57cd59dd8cc..d21514b36b9 100644
--- a/src/runtime/internal/atomic/atomic_amd64.s
+++ b/src/runtime/internal/atomic/atomic_amd64.s
@@ -37,7 +37,7 @@ TEXT ·Cas(SB),NOSPLIT,$0-17
 
 // bool	·Cas64(uint64 *val, uint64 old, uint64 new)
 // Atomically:
-//	if(*val == *old){
+//	if(*val == old){
 //		*val = new;
 //		return 1;
 //	} else {
diff --git a/src/runtime/internal/atomic/atomic_arm64.s b/src/runtime/internal/atomic/atomic_arm64.s
index e9467afecd7..5f77d92deba 100644
--- a/src/runtime/internal/atomic/atomic_arm64.s
+++ b/src/runtime/internal/atomic/atomic_arm64.s
@@ -192,7 +192,7 @@ ok:
 
 // bool ·Cas64(uint64 *ptr, uint64 old, uint64 new)
 // Atomically:
-//      if(*val == *old){
+//      if(*val == old){
 //              *val = new;
 //              return 1;
 //      } else {
diff --git a/src/runtime/internal/atomic/atomic_mips64x.s b/src/runtime/internal/atomic/atomic_mips64x.s
index fba668f94a8..fedfc4a175c 100644
--- a/src/runtime/internal/atomic/atomic_mips64x.s
+++ b/src/runtime/internal/atomic/atomic_mips64x.s
@@ -37,7 +37,7 @@ cas_fail:
 
 // bool	cas64(uint64 *ptr, uint64 old, uint64 new)
 // Atomically:
-//	if(*val == *old){
+//	if(*val == old){
 //		*val = new;
 //		return 1;
 //	} else {
diff --git a/src/runtime/internal/atomic/atomic_ppc64x.s b/src/runtime/internal/atomic/atomic_ppc64x.s
index dca26cb334a..226b3b62162 100644
--- a/src/runtime/internal/atomic/atomic_ppc64x.s
+++ b/src/runtime/internal/atomic/atomic_ppc64x.s
@@ -107,7 +107,7 @@ cas_fail:
 
 // bool	·Cas64(uint64 *ptr, uint64 old, uint64 new)
 // Atomically:
-//	if(*val == *old){
+//	if(*val == old){
 //		*val = new;
 //		return 1;
 //	} else {
diff --git a/src/runtime/internal/atomic/atomic_riscv64.s b/src/runtime/internal/atomic/atomic_riscv64.s
index ec05302a784..21d5adcdbc5 100644
--- a/src/runtime/internal/atomic/atomic_riscv64.s
+++ b/src/runtime/internal/atomic/atomic_riscv64.s
@@ -30,8 +30,9 @@
 
 #include "textflag.h"
 
+// func Cas(ptr *uint64, old, new uint64) bool
 // Atomically:
-//      if(*val == *old){
+//      if(*val == old){
 //              *val = new;
 //              return 1;
 //      } else {

From 1519271a939ad27da133318dc4bde7e6a41a35b5 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky 
Date: Fri, 25 Jun 2021 11:17:43 -0700
Subject: [PATCH 571/940] spec: change unsafe.Slice((*T)(nil), 0) to return
 []T(nil)

Updates #46742.

Change-Id: I044933a657cd1a5cdb29863e49751df5fe9c258a
Reviewed-on: https://go-review.googlesource.com/c/go/+/331069
Run-TryBot: Matthew Dempsky 
Trust: Matthew Dempsky 
Trust: Robert Griesemer 
Reviewed-by: Robert Griesemer 
---
 doc/go_spec.html     | 10 ++++++++--
 src/unsafe/unsafe.go |  5 ++++-
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/doc/go_spec.html b/doc/go_spec.html
index b59b37fd552..e0602418e80 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,6 +1,6 @@
 
 
@@ -6789,11 +6789,17 @@ and whose length and capacity are len:
 (*[len]ArbitraryType)(unsafe.Pointer(ptr))[:]
 
+

+As a special case, if ptr is nil and len is zero, +Slice returns nil. +

+

The len argument must be of integer type or an untyped constant. A constant len argument must be non-negative and representable by a value of type int; if it is an untyped constant it is given type int. -If ptr is nil or len is negative at run time, +At run time, if len is negative, +or if ptr is nil and len is not zero, a run-time panic occurs.

diff --git a/src/unsafe/unsafe.go b/src/unsafe/unsafe.go index ecbd28c523e..eaf72c96181 100644 --- a/src/unsafe/unsafe.go +++ b/src/unsafe/unsafe.go @@ -221,8 +221,11 @@ func Add(ptr Pointer, len IntegerType) Pointer // // (*[len]ArbitraryType)(unsafe.Pointer(ptr))[:] // +// As a special case, if ptr is nil and len is zero, Slice returns nil. +// // The len argument must be of integer type or an untyped constant. // A constant len argument must be non-negative and representable by a value of type int; // if it is an untyped constant it is given type int. -// If ptr is nil or len is negative at run time, a run-time panic occurs. +// At run time, if len is negative, or if ptr is nil and len is not zero, +// a run-time panic occurs. func Slice(ptr *ArbitraryType, len IntegerType) []ArbitraryType From 4bb0847b088eb3eb6122a18a87e1ca7756281dcc Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 25 Jun 2021 11:07:28 -0700 Subject: [PATCH 572/940] cmd/compile,runtime: change unsafe.Slice((*T)(nil), 0) to return []T(nil) This CL removes the unconditional OCHECKNIL check added in walkUnsafeSlice by instead passing it as a pointer to runtime.unsafeslice, and hiding the check behind a `len == 0` check. While here, this CL also implements checkptr functionality for unsafe.Slice and disallows use of unsafe.Slice with //go:notinheap types. Updates #46742. Change-Id: I743a445ac124304a4d7322a7fe089c4a21b9a655 Reviewed-on: https://go-review.googlesource.com/c/go/+/331070 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Trust: Matthew Dempsky Reviewed-by: Keith Randall --- src/cmd/compile/internal/typecheck/builtin.go | 5 ++-- .../internal/typecheck/builtin/runtime.go | 5 ++-- src/cmd/compile/internal/typecheck/func.go | 7 +++++ src/cmd/compile/internal/walk/builtin.go | 26 +++++++------------ src/runtime/checkptr.go | 21 ++++++++++++++- src/runtime/checkptr_test.go | 2 ++ src/runtime/slice.go | 24 ++++++++++++++--- src/runtime/testdata/testprog/checkptr.go | 13 ++++++++++ test/unsafebuiltins.go | 7 +++-- 9 files changed, 83 insertions(+), 27 deletions(-) diff --git a/src/cmd/compile/internal/typecheck/builtin.go b/src/cmd/compile/internal/typecheck/builtin.go index 67a894c7edd..833b17b4148 100644 --- a/src/cmd/compile/internal/typecheck/builtin.go +++ b/src/cmd/compile/internal/typecheck/builtin.go @@ -138,6 +138,7 @@ var runtimeDecls = [...]struct { {"growslice", funcTag, 116}, {"unsafeslice", funcTag, 117}, {"unsafeslice64", funcTag, 118}, + {"unsafeslicecheckptr", funcTag, 118}, {"memmove", funcTag, 119}, {"memclrNoHeapPointers", funcTag, 120}, {"memclrHasPointers", funcTag, 120}, @@ -341,8 +342,8 @@ func runtimeTypes() []*types.Type { typs[114] = newSig(params(typs[1], typs[15], typs[15], typs[7]), params(typs[7])) typs[115] = types.NewSlice(typs[2]) typs[116] = newSig(params(typs[1], typs[115], typs[15]), params(typs[115])) - typs[117] = newSig(params(typs[1], typs[15]), nil) - typs[118] = newSig(params(typs[1], typs[22]), nil) + typs[117] = newSig(params(typs[1], typs[7], typs[15]), nil) + typs[118] = newSig(params(typs[1], typs[7], typs[22]), nil) typs[119] = newSig(params(typs[3], typs[3], typs[5]), nil) typs[120] = newSig(params(typs[7], typs[5]), nil) typs[121] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6])) diff --git a/src/cmd/compile/internal/typecheck/builtin/runtime.go b/src/cmd/compile/internal/typecheck/builtin/runtime.go index ebeaeae79ec..2b29ea3c08c 100644 --- a/src/cmd/compile/internal/typecheck/builtin/runtime.go +++ b/src/cmd/compile/internal/typecheck/builtin/runtime.go @@ -183,8 +183,9 @@ func makeslice(typ *byte, len int, cap int) unsafe.Pointer func makeslice64(typ *byte, len int64, cap int64) unsafe.Pointer func makeslicecopy(typ *byte, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer func growslice(typ *byte, old []any, cap int) (ary []any) -func unsafeslice(typ *byte, len int) -func unsafeslice64(typ *byte, len int64) +func unsafeslice(typ *byte, ptr unsafe.Pointer, len int) +func unsafeslice64(typ *byte, ptr unsafe.Pointer, len int64) +func unsafeslicecheckptr(typ *byte, ptr unsafe.Pointer, len int64) func memmove(to *any, frm *any, length uintptr) func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr) diff --git a/src/cmd/compile/internal/typecheck/func.go b/src/cmd/compile/internal/typecheck/func.go index a6dfbbf569a..fbcc784627d 100644 --- a/src/cmd/compile/internal/typecheck/func.go +++ b/src/cmd/compile/internal/typecheck/func.go @@ -1018,7 +1018,14 @@ func tcUnsafeSlice(n *ir.BinaryExpr) *ir.BinaryExpr { t := n.X.Type() if !t.IsPtr() { base.Errorf("first argument to unsafe.Slice must be pointer; have %L", t) + } else if t.Elem().NotInHeap() { + // TODO(mdempsky): This can be relaxed, but should only affect the + // Go runtime itself. End users should only see //go:notinheap + // types due to incomplete C structs in cgo, and those types don't + // have a meaningful size anyway. + base.Errorf("unsafe.Slice of incomplete (or unallocatable) type not allowed") } + if !checkunsafeslice(&n.Y) { n.SetType(nil) return n diff --git a/src/cmd/compile/internal/walk/builtin.go b/src/cmd/compile/internal/walk/builtin.go index 62eb4298f4d..1f08e4d3128 100644 --- a/src/cmd/compile/internal/walk/builtin.go +++ b/src/cmd/compile/internal/walk/builtin.go @@ -654,36 +654,28 @@ func walkRecover(nn *ir.CallExpr, init *ir.Nodes) ir.Node { } func walkUnsafeSlice(n *ir.BinaryExpr, init *ir.Nodes) ir.Node { + ptr := safeExpr(n.X, init) len := safeExpr(n.Y, init) fnname := "unsafeslice64" - argtype := types.Types[types.TINT64] + lenType := types.Types[types.TINT64] // Type checking guarantees that TIDEAL len/cap are positive and fit in an int. // The case of len or cap overflow when converting TUINT or TUINTPTR to TINT // will be handled by the negative range checks in unsafeslice during runtime. - if len.Type().IsKind(types.TIDEAL) || len.Type().Size() <= types.Types[types.TUINT].Size() { + if ir.ShouldCheckPtr(ir.CurFunc, 1) { + fnname = "unsafeslicecheckptr" + // for simplicity, unsafeslicecheckptr always uses int64 + } else if len.Type().IsKind(types.TIDEAL) || len.Type().Size() <= types.Types[types.TUINT].Size() { fnname = "unsafeslice" - argtype = types.Types[types.TINT] + lenType = types.Types[types.TINT] } t := n.Type() - // Call runtime.unsafeslice[64] to check that the length argument is - // non-negative and smaller than the max length allowed for the - // element type. + // Call runtime.unsafeslice{,64,checkptr} to check ptr and len. fn := typecheck.LookupRuntime(fnname) - init.Append(mkcall1(fn, nil, init, reflectdata.TypePtr(t.Elem()), typecheck.Conv(len, argtype))) - - ptr := walkExpr(n.X, init) - - c := ir.NewUnaryExpr(n.Pos(), ir.OCHECKNIL, ptr) - c.SetTypecheck(1) - init.Append(c) - - // TODO(mdempsky): checkptr instrumentation. Maybe merge into length - // check above, along with nil check? Need to be careful about - // notinheap pointers though: can't pass them as unsafe.Pointer. + init.Append(mkcall1(fn, nil, init, reflectdata.TypePtr(t.Elem()), typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR]), typecheck.Conv(len, lenType))) h := ir.NewSliceHeaderExpr(n.Pos(), t, typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR]), diff --git a/src/runtime/checkptr.go b/src/runtime/checkptr.go index 59891a06a56..d42950844b5 100644 --- a/src/runtime/checkptr.go +++ b/src/runtime/checkptr.go @@ -16,11 +16,30 @@ func checkptrAlignment(p unsafe.Pointer, elem *_type, n uintptr) { } // Check that (*[n]elem)(p) doesn't straddle multiple heap objects. - if size := n * elem.size; size > 1 && checkptrBase(p) != checkptrBase(add(p, size-1)) { + // TODO(mdempsky): Fix #46938 so we don't need to worry about overflow here. + if checkptrStraddles(p, n*elem.size) { throw("checkptr: converted pointer straddles multiple allocations") } } +// checkptrStraddles reports whether the first size-bytes of memory +// addressed by ptr is known to straddle more than one Go allocation. +func checkptrStraddles(ptr unsafe.Pointer, size uintptr) bool { + if size <= 1 { + return false + } + + end := add(ptr, size-1) + if uintptr(end) < uintptr(ptr) { + return true + } + + // TODO(mdempsky): Detect when [ptr, end] contains Go allocations, + // but neither ptr nor end point into one themselves. + + return checkptrBase(ptr) != checkptrBase(end) +} + func checkptrArithmetic(p unsafe.Pointer, originals []unsafe.Pointer) { if 0 < uintptr(p) && uintptr(p) < minLegalPointer { throw("checkptr: pointer arithmetic computed bad pointer value") diff --git a/src/runtime/checkptr_test.go b/src/runtime/checkptr_test.go index 194cc1243a9..2a5c364e97b 100644 --- a/src/runtime/checkptr_test.go +++ b/src/runtime/checkptr_test.go @@ -30,6 +30,8 @@ func TestCheckPtr(t *testing.T) { {"CheckPtrArithmetic2", "fatal error: checkptr: pointer arithmetic result points to invalid allocation\n"}, {"CheckPtrSize", "fatal error: checkptr: converted pointer straddles multiple allocations\n"}, {"CheckPtrSmall", "fatal error: checkptr: pointer arithmetic computed bad pointer value\n"}, + {"CheckPtrSliceOK", ""}, + {"CheckPtrSliceFail", "fatal error: checkptr: unsafe.Slice result straddles multiple allocations\n"}, } for _, tc := range testCases { diff --git a/src/runtime/slice.go b/src/runtime/slice.go index f9d4154acfd..01cdcaeee3b 100644 --- a/src/runtime/slice.go +++ b/src/runtime/slice.go @@ -112,19 +112,37 @@ func makeslice64(et *_type, len64, cap64 int64) unsafe.Pointer { return makeslice(et, len, cap) } -func unsafeslice(et *_type, len int) { +func unsafeslice(et *_type, ptr unsafe.Pointer, len int) { + if len == 0 { + return + } + + if ptr == nil { + panic(errorString("unsafe.Slice: ptr is nil and len is not zero")) + } + mem, overflow := math.MulUintptr(et.size, uintptr(len)) if overflow || mem > maxAlloc || len < 0 { panicunsafeslicelen() } } -func unsafeslice64(et *_type, len64 int64) { +func unsafeslice64(et *_type, ptr unsafe.Pointer, len64 int64) { len := int(len64) if int64(len) != len64 { panicunsafeslicelen() } - unsafeslice(et, len) + unsafeslice(et, ptr, len) +} + +func unsafeslicecheckptr(et *_type, ptr unsafe.Pointer, len64 int64) { + unsafeslice64(et, ptr, len64) + + // Check that underlying array doesn't straddle multiple heap objects. + // unsafeslice64 has already checked for overflow. + if checkptrStraddles(ptr, uintptr(len64)*et.size) { + throw("checkptr: unsafe.Slice result straddles multiple allocations") + } } func panicunsafeslicelen() { diff --git a/src/runtime/testdata/testprog/checkptr.go b/src/runtime/testdata/testprog/checkptr.go index e0a2794f4c1..f76b64ad96f 100644 --- a/src/runtime/testdata/testprog/checkptr.go +++ b/src/runtime/testdata/testprog/checkptr.go @@ -13,6 +13,8 @@ func init() { register("CheckPtrArithmetic2", CheckPtrArithmetic2) register("CheckPtrSize", CheckPtrSize) register("CheckPtrSmall", CheckPtrSmall) + register("CheckPtrSliceOK", CheckPtrSliceOK) + register("CheckPtrSliceFail", CheckPtrSliceFail) } func CheckPtrAlignmentNoPtr() { @@ -49,3 +51,14 @@ func CheckPtrSize() { func CheckPtrSmall() { sink2 = unsafe.Pointer(uintptr(1)) } + +func CheckPtrSliceOK() { + p := new([4]int64) + sink2 = unsafe.Slice(&p[1], 3) +} + +func CheckPtrSliceFail() { + p := new(int64) + sink2 = p + sink2 = unsafe.Slice(p, 100) +} diff --git a/test/unsafebuiltins.go b/test/unsafebuiltins.go index c10f8084a75..4c940aa8559 100644 --- a/test/unsafebuiltins.go +++ b/test/unsafebuiltins.go @@ -30,8 +30,11 @@ func main() { assert(len(s) == len(p)) assert(cap(s) == len(p)) - // nil pointer - mustPanic(func() { _ = unsafe.Slice((*int)(nil), 0) }) + // nil pointer with zero length returns nil + assert(unsafe.Slice((*int)(nil), 0) == nil) + + // nil pointer with positive length panics + mustPanic(func() { _ = unsafe.Slice((*int)(nil), 1) }) // negative length var neg int = -1 From dfa8fd861ca99614f03ce409584c4f9ea3e6a3da Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Mon, 28 Jun 2021 10:57:26 -0700 Subject: [PATCH 573/940] [dev.typeparams] cmd/compile: add a field (method) name for function in TestABIUtilsInterfaces Not having a field name for the method is not really correct, and makes it look like an embedded field. In fact, currently types.CalcSize() in abitest() is creating an error that is not actually reported. Change-Id: I98c3a4abf5b6d610d9c3c56ce1042078374b5417 Reviewed-on: https://go-review.googlesource.com/c/go/+/331469 Run-TryBot: Dan Scales TryBot-Result: Go Bot Trust: Dan Scales Reviewed-by: Than McIntosh --- src/cmd/compile/internal/test/abiutils_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cmd/compile/internal/test/abiutils_test.go b/src/cmd/compile/internal/test/abiutils_test.go index b752c486126..b7901be69b6 100644 --- a/src/cmd/compile/internal/test/abiutils_test.go +++ b/src/cmd/compile/internal/test/abiutils_test.go @@ -310,7 +310,7 @@ func TestABIUtilsInterfaces(t *testing.T) { pei := types.NewPtr(ei) // *interface{} fldt := mkFuncType(types.FakeRecvType(), []*types.Type{}, []*types.Type{types.UntypedString}) - field := types.NewField(src.NoXPos, nil, fldt) + field := types.NewField(src.NoXPos, typecheck.Lookup("f"), fldt) nei := types.NewInterface(types.LocalPkg, []*types.Field{field}) i16 := types.Types[types.TINT16] tb := types.Types[types.TBOOL] @@ -322,12 +322,12 @@ func TestABIUtilsInterfaces(t *testing.T) { IN 0: R{ I0 I1 I2 } spilloffset: 0 typ: struct { int16; int16; bool } IN 1: R{ I3 I4 } spilloffset: 8 typ: interface {} IN 2: R{ I5 I6 } spilloffset: 24 typ: interface {} - IN 3: R{ I7 I8 } spilloffset: 40 typ: interface { () untyped string } + IN 3: R{ I7 I8 } spilloffset: 40 typ: interface { .f() untyped string } IN 4: R{ } offset: 0 typ: *interface {} - IN 5: R{ } offset: 8 typ: interface { () untyped string } + IN 5: R{ } offset: 8 typ: interface { .f() untyped string } IN 6: R{ } offset: 24 typ: int16 OUT 0: R{ I0 I1 } spilloffset: -1 typ: interface {} - OUT 1: R{ I2 I3 } spilloffset: -1 typ: interface { () untyped string } + OUT 1: R{ I2 I3 } spilloffset: -1 typ: interface { .f() untyped string } OUT 2: R{ I4 } spilloffset: -1 typ: *interface {} offsetToSpillArea: 32 spillAreaSize: 56 `) From e2e05af6e189131162b533184eb04de5d597d544 Mon Sep 17 00:00:00 2001 From: eric fang Date: Mon, 21 Jun 2021 02:11:25 +0000 Subject: [PATCH 574/940] cmd/internal/obj/arm64: fix an encoding error of CMPW instruction For arm64 CMP, ADD and other similar extended register instructions, if there is no extension, the default extion is LSL<<0, but the default encoding value (the value of 'option' field) of 32-bit instruction and 64-bit instruction is different, 32-bit is 2 and 64-bit is 3. But the current assembler incorrectly encodes the value of 32-bit instruction to 3. This CL fixes this error. Change-Id: I0e09af2c9c5047a4ed2db7d1183290283db9c31c Reviewed-on: https://go-review.googlesource.com/c/go/+/329749 Reviewed-by: eric fang Reviewed-by: Cherry Mui Run-TryBot: eric fang Run-TryBot: Cherry Mui Trust: Dmitri Shuralyov --- src/cmd/asm/internal/asm/testdata/arm64.s | 3 ++- src/cmd/internal/obj/arm64/asm7.go | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s index 5f1e68545ba..d8a20edfc13 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64.s +++ b/src/cmd/asm/internal/asm/testdata/arm64.s @@ -89,7 +89,7 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8 CMP R1<<33, R2 CMP R22.SXTX, RSP // ffe336eb CMP $0x22220000, RSP // CMP $572653568, RSP // 5b44a4d2ff633beb - CMPW $0x22220000, RSP // CMPW $572653568, RSP // 5b44a452ff633b6b + CMPW $0x22220000, RSP // CMPW $572653568, RSP // 5b44a452ff433b6b CCMN MI, ZR, R1, $4 // e44341ba // MADD Rn,Rm,Ra,Rd MADD R1, R2, R3, R4 // 6408019b @@ -377,6 +377,7 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8 MOVD $0x1000100010001000, RSP // MOVD $1152939097061330944, RSP // ff8304b2 MOVW $0x10001000, RSP // MOVW $268439552, RSP // ff830432 ADDW $0x10001000, R1 // ADDW $268439552, R1 // fb83043221001b0b + ADDW $0x22220000, RSP, R3 // ADDW $572653568, RSP, R3 // 5b44a452e3433b0b // move a large constant to a Vd. VMOVS $0x80402010, V11 // VMOVS $2151686160, V11 diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go index b8c3cd97c76..d99afa3d276 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -4333,8 +4333,10 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { if p.To.Reg == REG_RSP && isADDSop(p.As) { c.ctxt.Diag("illegal destination register: %v\n", p) } + lsl0 := LSL0_64 if isADDWop(p.As) || isANDWop(p.As) { o1 = c.omovconst(AMOVW, p, &p.From, REGTMP) + lsl0 = LSL0_32 } else { o1 = c.omovconst(AMOVD, p, &p.From, REGTMP) } @@ -4350,7 +4352,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { if p.To.Reg == REGSP || r == REGSP { o2 = c.opxrrr(p, p.As, false) o2 |= REGTMP & 31 << 16 - o2 |= LSL0_64 + o2 |= uint32(lsl0) } else { o2 = c.oprrr(p, p.As) o2 |= REGTMP & 31 << 16 /* shift is 0 */ From fd4b587da3f9a2bde193a5b9fd2ba96667e08f2d Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Tue, 29 Jun 2021 10:11:31 +0700 Subject: [PATCH 575/940] cmd/compile: suppress details error for invalid variadic argument type CL 255241 made error message involving variadic calls clearer. To do it, we added a check that the type of variadic argument must be a slice. That's why the compiler crashes for invalid variadic argument type. Instead, we can just omit the details error message, and report not enough arguments error, which matches the behavior of go/types and types2. Fixes #46957 Change-Id: I638d7e8f031f0ee344d5d802104fd93a60aae00a Reviewed-on: https://go-review.googlesource.com/c/go/+/331569 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/typecheck/typecheck.go | 17 ++++++++++++----- test/fixedbugs/issue46957.go | 13 +++++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) create mode 100644 test/fixedbugs/issue46957.go diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go index bf52941b2cf..359f6623696 100644 --- a/src/cmd/compile/internal/typecheck/typecheck.go +++ b/src/cmd/compile/internal/typecheck/typecheck.go @@ -1460,15 +1460,22 @@ toomany: } func errorDetails(nl ir.Nodes, tstruct *types.Type, isddd bool) string { - // If we don't know any type at a call site, let's suppress any return - // message signatures. See Issue https://golang.org/issues/19012. + // Suppress any return message signatures if: + // + // (1) We don't know any type at a call site (see #19012). + // (2) Any node has an unknown type. + // (3) Invalid type for variadic parameter (see #46957). if tstruct == nil { - return "" + return "" // case 1 } - // If any node has an unknown type, suppress it as well + + if isddd && !nl[len(nl)-1].Type().IsSlice() { + return "" // case 3 + } + for _, n := range nl { if n.Type() == nil { - return "" + return "" // case 2 } } return fmt.Sprintf("\n\thave %s\n\twant %v", fmtSignature(nl, isddd), tstruct) diff --git a/test/fixedbugs/issue46957.go b/test/fixedbugs/issue46957.go new file mode 100644 index 00000000000..f3ed3c3def0 --- /dev/null +++ b/test/fixedbugs/issue46957.go @@ -0,0 +1,13 @@ +// errorcheck + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func f(a int, b ...int) {} + +func main() { + f(nil...) // ERROR "not enough arguments in call to f$" +} From 3463852b7631adbdd65646539fc87d967dcd13e6 Mon Sep 17 00:00:00 2001 From: tkawakita Date: Wed, 30 Jun 2021 00:46:05 +0900 Subject: [PATCH 576/940] math/big: fix typo of comment (`BytesScanner` to `ByteScanner`) Change-Id: I0c2d26d6ede1452008992efbea7392162da65014 Reviewed-on: https://go-review.googlesource.com/c/go/+/331651 Reviewed-by: Robert Griesemer Reviewed-by: Ian Lance Taylor --- src/math/big/int.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/math/big/int.go b/src/math/big/int.go index 65f32487b58..7647346486c 100644 --- a/src/math/big/int.go +++ b/src/math/big/int.go @@ -425,7 +425,7 @@ func (z *Int) SetString(s string, base int) (*Int, bool) { return z.setFromScanner(strings.NewReader(s), base) } -// setFromScanner implements SetString given an io.BytesScanner. +// setFromScanner implements SetString given an io.ByteScanner. // For documentation see comments of SetString. func (z *Int) setFromScanner(r io.ByteScanner, base int) (*Int, bool) { if _, _, err := z.scan(r, base); err != nil { From e294b8a49e5ff157041b4ac6c3c3413dafd13673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Levi=EF=BC=88=E3=83=AA=E3=83=BC=E3=83=90=E3=82=A4=EF=BC=89?= <19405788+lescoggi@users.noreply.github.com> Date: Tue, 29 Jun 2021 12:45:52 +0000 Subject: [PATCH 577/940] doc/go1.17: fix typo "MacOS" -> "macOS" Change-Id: Ie2ada2bf875a93b1cc9e86a81c8a25de39ce4752 GitHub-Last-Rev: 462753db015949eb88c6c4e64b6aae1a49ac89b4 GitHub-Pull-Request: golang/go#46962 Reviewed-on: https://go-review.googlesource.com/c/go/+/331589 Reviewed-by: Ian Lance Taylor Reviewed-by: Dmitri Shuralyov --- doc/go1.17.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 22896c8c273..3551ba46c8c 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -401,7 +401,7 @@ func Foo() bool {

Go 1.17 implements a new way of passing function arguments and results using - registers instead of the stack. This work is enabled for Linux, MacOS, and + registers instead of the stack. This work is enabled for Linux, macOS, and Windows on the 64-bit x86 architecture (the linux/amd64, darwin/amd64, windows/amd64 ports). For a representative set of Go packages and programs, benchmarking has shown From 5fa6bbc669c22f05deb421c324b90b30ae3caa08 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Sat, 26 Jun 2021 18:18:16 -0700 Subject: [PATCH 578/940] [dev.typeparams] cmd/compile: clean up instantiation and dictionary naming Separate generation of instantiation and dictionary name generation. Add code to add subdictionaries to a dictionary. Not quite working yet, as we need to trigger generation of the subdictionaries for methods. Change-Id: I0d46053eba695b217630b06ef2f990f6a0b52d83 Reviewed-on: https://go-review.googlesource.com/c/go/+/331209 Trust: Keith Randall Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/noder/stencil.go | 55 +++++++++---------- .../compile/internal/reflectdata/reflect.go | 22 ++------ src/cmd/compile/internal/typecheck/subr.go | 51 ++++++++++++----- 3 files changed, 68 insertions(+), 60 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 60d56c206f6..49781ddc074 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -18,7 +18,6 @@ import ( "cmd/internal/src" "fmt" "go/constant" - "strings" ) func assert(p bool) { @@ -519,7 +518,7 @@ func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth ir.Dump(fmt.Sprintf("\nstenciled %v", st), st) } } - return st, g.getDictionary(sym.Name, nameNode, targs) + return st, g.getDictionaryValue(nameNode, targs, isMeth) } // Struct containing info needed for doing the substitution as we create the @@ -1017,31 +1016,21 @@ func deref(t *types.Type) *types.Type { return t } -// getDictionary returns the dictionary for the named instantiated function, which -// is instantiated from generic function or method gf, with the type arguments targs. -func (g *irgen) getDictionary(name string, gf *ir.Name, targs []*types.Type) ir.Node { +// getDictionarySym returns the dictionary for the named generic function gf, which +// is instantiated with the type arguments targs. +func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) *types.Sym { if len(targs) == 0 { - base.Fatalf("%s should have type arguments", name) - } - - // The dictionary for this instantiation is named after the function - // and concrete types it is instantiated with. - // TODO: decouple this naming from the instantiation naming. The instantiation - // naming will be based on GC shapes, this naming must be fully stenciled. - if !strings.HasPrefix(name, ".inst.") { - base.Fatalf("%s should start in .inst.", name) + base.Fatalf("%s should have type arguments", gf.Sym().Name) } info := g.getGfInfo(gf) - name = ".dict." + name[6:] - // Get a symbol representing the dictionary. - sym := typecheck.Lookup(name) + sym := typecheck.MakeDictName(gf.Sym(), targs, isMeth) // Initialize the dictionary, if we haven't yet already. if lsym := sym.Linksym(); len(lsym.P) == 0 { - infoPrint("Creating dictionary %v\n", name) + infoPrint("Creating dictionary %v\n", sym.Name) off := 0 // Emit an entry for each targ (concrete type or gcshape). for _, t := range targs { @@ -1061,8 +1050,8 @@ func (g *irgen) getDictionary(name string, gf *ir.Name, targs []*types.Type) ir. off = objw.SymPtr(lsym, off, s, 0) } // Emit an entry for each subdictionary (after substituting targs) - // TODO: actually emit symbol for the subdictionary entry for _, n := range info.subDictCalls { + var sym *types.Sym if n.Op() == ir.OCALL { call := n.(*ir.CallExpr) if call.X.Op() == ir.OXDOT { @@ -1071,8 +1060,7 @@ func (g *irgen) getDictionary(name string, gf *ir.Name, targs []*types.Type) ir. for i, t := range subtargs { s2targs[i] = subst.Typ(t) } - sym := typecheck.MakeInstName(ir.MethodSym(call.X.(*ir.SelectorExpr).X.Type(), call.X.(*ir.SelectorExpr).Sel), s2targs, true) - infoPrint(" - Subdict .dict.%v\n", sym.Name[6:]) + sym = typecheck.MakeDictName(ir.MethodSym(call.X.(*ir.SelectorExpr).X.Type(), call.X.(*ir.SelectorExpr).Sel), s2targs, true) } else { inst := n.(*ir.CallExpr).X.(*ir.InstExpr) var nameNode *ir.Name @@ -1087,11 +1075,10 @@ func (g *irgen) getDictionary(name string, gf *ir.Name, targs []*types.Type) ir. for i, t := range subtargs { subtargs[i] = subst.Typ(t) } - sym := typecheck.MakeInstName(nameNode.Sym(), subtargs, isMeth) + sym = g.getDictionarySym(nameNode, subtargs, isMeth) // TODO: This can actually be a static // main dictionary, if all of the subtargs // are concrete types (!HasTParam) - infoPrint(" - Subdict .dict.%v\n", sym.Name[6:]) } } else if n.Op() == ir.OFUNCINST { inst := n.(*ir.InstExpr) @@ -1100,11 +1087,10 @@ func (g *irgen) getDictionary(name string, gf *ir.Name, targs []*types.Type) ir. for i, t := range subtargs { subtargs[i] = subst.Typ(t) } - sym := typecheck.MakeInstName(nameNode.Sym(), subtargs, false) + sym = g.getDictionarySym(nameNode, subtargs, false) // TODO: This can actually be a static // main dictionary, if all of the subtargs // are concrete types (!HasTParam) - infoPrint(" - Subdict .dict.%v\n", sym.Name[6:]) } else if n.Op() == ir.OXDOT { selExpr := n.(*ir.SelectorExpr) subtargs := selExpr.X.Type().RParams() @@ -1112,13 +1098,26 @@ func (g *irgen) getDictionary(name string, gf *ir.Name, targs []*types.Type) ir. for i, t := range subtargs { s2targs[i] = subst.Typ(t) } - sym := typecheck.MakeInstName(ir.MethodSym(selExpr.X.Type(), selExpr.Sel), s2targs, true) - infoPrint(" - Subdict .dict.%v\n", sym.Name[6:]) + sym = typecheck.MakeDictName(ir.MethodSym(selExpr.X.Type(), selExpr.Sel), s2targs, true) + } + // TODO: handle closure cases that need sub-dictionaries, get rid of conditional + if sym != nil { + // TODO: uncomment once we're sure all the + // subdictionaries are created correctly. + // Methods above aren't yet generating dictionaries recursively yet. + //off = objw.SymPtr(lsym, off, sym.Linksym(), 0) + infoPrint(" - Subdict %v\n", sym.Name) } - // TODO: handle closure cases that need sub-dictionaries } objw.Global(lsym, int32(off), obj.DUPOK|obj.RODATA) + + // Add any new, fully instantiated types seen during the substitution to g.instTypeList. + g.instTypeList = append(g.instTypeList, subst.InstTypeList...) } + return sym +} +func (g *irgen) getDictionaryValue(gf *ir.Name, targs []*types.Type, isMeth bool) ir.Node { + sym := g.getDictionarySym(gf, targs, isMeth) // Make a node referencing the dictionary symbol. n := typecheck.NewName(sym) diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index 351aaab399a..27522ca85e5 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -1869,7 +1869,7 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy } else if !baseOrig.IsPtr() && method.Type.Recv().Type.IsPtr() { baseOrig = types.NewPtr(baseOrig) } - args = append(args, getDictionary(".inst."+ir.MethodSym(baseOrig, method.Sym).Name, targs)) // TODO: remove .inst. + args = append(args, getDictionary(ir.MethodSym(baseOrig, method.Sym), targs)) if indirect { args = append(args, ir.NewStarExpr(base.Pos, dot.X)) } else if methodrcvr.IsPtr() && methodrcvr.Elem() == dot.X.Type() { @@ -1971,28 +1971,16 @@ func MarkUsedIfaceMethod(n *ir.CallExpr) { // getDictionary returns the dictionary for the given named generic function // or method, with the given type arguments. -// TODO: pass a reference to the generic function instead? We might need -// that to look up protodictionaries. -func getDictionary(name string, targs []*types.Type) ir.Node { +func getDictionary(gf *types.Sym, targs []*types.Type) ir.Node { if len(targs) == 0 { - base.Fatalf("%s should have type arguments", name) + base.Fatalf("%s should have type arguments", gf.Name) } - // The dictionary for this instantiation is named after the function - // and concrete types it is instantiated with. - // TODO: decouple this naming from the instantiation naming. The instantiation - // naming will be based on GC shapes, this naming must be fully stenciled. - if !strings.HasPrefix(name, ".inst.") { - base.Fatalf("%s should start in .inst.", name) - } - name = ".dict." + name[6:] - - // Get a symbol representing the dictionary. - sym := typecheck.Lookup(name) + sym := typecheck.MakeDictName(gf, targs, true) // Initialize the dictionary, if we haven't yet already. if lsym := sym.Linksym(); len(lsym.P) == 0 { - base.Fatalf("Dictionary should have alredy been generated: %v", sym) + base.Fatalf("Dictionary should have already been generated: %s.%s", sym.Pkg.Path, sym.Name) } // Make a node referencing the dictionary symbol. diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index fb6d660db52..db1faaf6f73 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -888,19 +888,10 @@ func TypesOf(x []ir.Node) []*types.Type { return r } -// MakeInstName makes the unique name for a stenciled generic function or method, -// based on the name of the function fnsym and the targs. It replaces any -// existing bracket type list in the name. makeInstName asserts that fnsym has -// brackets in its name if and only if hasBrackets is true. -// -// Names of declared generic functions have no brackets originally, so hasBrackets -// should be false. Names of generic methods already have brackets, since the new -// type parameter is specified in the generic type of the receiver (e.g. func -// (func (v *value[T]).set(...) { ... } has the original name (*value[T]).set. -// -// The standard naming is something like: 'genFn[int,bool]' for functions and -// '(*genType[int,bool]).methodName' for methods -func MakeInstName(fnsym *types.Sym, targs []*types.Type, hasBrackets bool) *types.Sym { +// makeGenericName returns the name of the generic function instantiated +// with the given types. +// name is the name of the generic function or method. +func makeGenericName(name string, targs []*types.Type, hasBrackets bool) string { b := bytes.NewBufferString("") // Determine if the type args are concrete types or new typeparams. @@ -922,7 +913,6 @@ func MakeInstName(fnsym *types.Sym, targs []*types.Type, hasBrackets bool) *type b.WriteString(".inst.") } - name := fnsym.Name i := strings.Index(name, "[") assert(hasBrackets == (i >= 0)) if i >= 0 { @@ -952,7 +942,38 @@ func MakeInstName(fnsym *types.Sym, targs []*types.Type, hasBrackets bool) *type if strings.HasPrefix(b.String(), ".inst..inst.") { panic(fmt.Sprintf("multiple .inst. prefix in %s", b.String())) } - return fnsym.Pkg.Lookup(b.String()) + return b.String() +} + +// MakeInstName makes the unique name for a stenciled generic function or method, +// based on the name of the function fnsym and the targs. It replaces any +// existing bracket type list in the name. makeInstName asserts that fnsym has +// brackets in its name if and only if hasBrackets is true. +// +// Names of declared generic functions have no brackets originally, so hasBrackets +// should be false. Names of generic methods already have brackets, since the new +// type parameter is specified in the generic type of the receiver (e.g. func +// (func (v *value[T]).set(...) { ... } has the original name (*value[T]).set. +// +// The standard naming is something like: 'genFn[int,bool]' for functions and +// '(*genType[int,bool]).methodName' for methods +func MakeInstName(gf *types.Sym, targs []*types.Type, hasBrackets bool) *types.Sym { + return gf.Pkg.Lookup(makeGenericName(gf.Name, targs, hasBrackets)) +} + +func MakeDictName(gf *types.Sym, targs []*types.Type, hasBrackets bool) *types.Sym { + for _, targ := range targs { + if targ.HasTParam() { + fmt.Printf("FUNCTION %s\n", gf.Name) + for _, targ := range targs { + fmt.Printf(" PARAM %+v\n", targ) + } + panic("dictionary should always have concrete type args") + } + } + name := makeGenericName(gf.Name, targs, hasBrackets) + name = ".dict." + name[6:] + return gf.Pkg.Lookup(name) } func assert(p bool) { From 6a5f7e8498b7cd53bb5461fbf777aa83aea067a8 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 8 Jun 2021 15:58:16 -0700 Subject: [PATCH 579/940] [dev.typeparams] cmd/compile: use dictionary entries for more conversion cases This CL handles I(x) where I is an interface type and x has typeparam type. Change-Id: Ib99de2b741d588947f5e0164255f6365e98acd8a Reviewed-on: https://go-review.googlesource.com/c/go/+/326189 Trust: Keith Randall Trust: Dan Scales Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/noder/stencil.go | 79 ++++++++++++++++------- test/typeparam/ifaceconv.go | 9 ++- 2 files changed, 62 insertions(+), 26 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 49781ddc074..29ee863a71f 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -838,7 +838,15 @@ func (subst *subster) node(n ir.Node) ir.Node { case ir.OTYPE: // Transform the conversion, now that we know the // type argument. - m = transformConvCall(m.(*ir.CallExpr)) + m = transformConvCall(call) + if m.Op() == ir.OCONVIFACE { + if srcType := x.(*ir.CallExpr).Args[0].Type(); srcType.IsTypeParam() { // TODO: or derived type + // Note: srcType uses x.Args[0], not m.X or call.Args[0], because + // we need the type before the type parameter -> type argument substitution. + c := m.(*ir.ConvExpr) + m = subst.convertUsingDictionary(c.Pos(), c.X, c.Type(), srcType) + } + } case ir.OMETHVALUE: // Redo the transformation of OXDOT, now that we @@ -919,30 +927,10 @@ func (subst *subster) node(n ir.Node) ir.Node { case ir.OCONVIFACE: x := x.(*ir.ConvExpr) - // TODO: handle converting from derived types. For now, just from naked - // type parameters. - if x.X.Type().IsTypeParam() { - // Load the actual runtime._type of the type parameter from the dictionary. - rt := subst.getDictionaryType(m.Pos(), x.X.Type()) - - // At this point, m is an interface type with a data word we want. - // But the type word represents a gcshape type, which we don't want. - // Replace with the instantiated type loaded from the dictionary. - m = ir.NewUnaryExpr(m.Pos(), ir.OIDATA, m) - typed(types.Types[types.TUNSAFEPTR], m) - m = ir.NewBinaryExpr(m.Pos(), ir.OEFACE, rt, m) - if !x.Type().IsEmptyInterface() { - // We just built an empty interface{}. Type it as such, - // then assert it to the required non-empty interface. - typed(types.NewInterface(types.LocalPkg, nil), m) - m = ir.NewTypeAssertExpr(m.Pos(), m, nil) - } - typed(x.Type(), m) - // TODO: we're throwing away the type word of the original version - // of m here (it would be OITAB(m)), which probably took some - // work to generate. Can we avoid generating it at all? - // (The linker will throw them away if not needed, so it would just - // save toolchain work, not binary size.) + // Note: x's argument is still typed as a type parameter. + // m's argument now has an instantiated type. + if t := x.X.Type(); t.IsTypeParam() { + m = subst.convertUsingDictionary(x.Pos(), m.(*ir.ConvExpr).X, m.Type(), t) } } return m @@ -951,6 +939,47 @@ func (subst *subster) node(n ir.Node) ir.Node { return edit(n) } +// convertUsingDictionary converts value v from generic type src to an interface type dst. +func (subst *subster) convertUsingDictionary(pos src.XPos, v ir.Node, dst, src *types.Type) ir.Node { + // TODO: handle converting from derived types. For now, just from naked + // type parameters. + if !src.IsTypeParam() { + base.Fatalf("source must be a type parameter %+v", src) + } + if !dst.IsInterface() { + base.Fatalf("can only convert type parameters to interfaces %+v -> %+v", src, dst) + } + // Load the actual runtime._type of the type parameter from the dictionary. + rt := subst.getDictionaryType(pos, src) + + // Convert value to an interface type, so the data field is what we want. + if !v.Type().IsInterface() { + v = ir.NewConvExpr(v.Pos(), ir.OCONVIFACE, nil, v) + typed(types.NewInterface(types.LocalPkg, nil), v) + } + + // At this point, v is an interface type with a data word we want. + // But the type word represents a gcshape type, which we don't want. + // Replace with the instantiated type loaded from the dictionary. + data := ir.NewUnaryExpr(pos, ir.OIDATA, v) + typed(types.Types[types.TUNSAFEPTR], data) + var i ir.Node = ir.NewBinaryExpr(pos, ir.OEFACE, rt, data) + if !dst.IsEmptyInterface() { + // We just built an empty interface{}. Type it as such, + // then assert it to the required non-empty interface. + typed(types.NewInterface(types.LocalPkg, nil), i) + i = ir.NewTypeAssertExpr(pos, i, nil) + } + typed(dst, i) + // TODO: we're throwing away the type word of the original version + // of m here (it would be OITAB(m)), which probably took some + // work to generate. Can we avoid generating it at all? + // (The linker will throw them away if not needed, so it would just + // save toolchain work, not binary size.) + return i + +} + func (subst *subster) namelist(l []*ir.Name) []*ir.Name { s := make([]*ir.Name, len(l)) for i, n := range l { diff --git a/test/typeparam/ifaceconv.go b/test/typeparam/ifaceconv.go index 0b0776815c9..32c2dbe7c28 100644 --- a/test/typeparam/ifaceconv.go +++ b/test/typeparam/ifaceconv.go @@ -38,10 +38,14 @@ func h[T C](x T) interface{foo() int} { return i } func i[T C](x T) C { - var i C = x + var i C = x // conversion in assignment return i } +func j[T C](t T) C { + return C(t) // explicit conversion +} + func main() { if got, want := f[int](7), 7; got != want { panic(fmt.Sprintf("got %d want %d", got, want)) @@ -55,4 +59,7 @@ func main() { if got, want := i[myInt](7).foo(), 8; got != want { panic(fmt.Sprintf("got %d want %d", got, want)) } + if got, want := j[myInt](7).foo(), 8; got != want { + panic(fmt.Sprintf("got %d want %d", got, want)) + } } From f9d50953b94c15936a72a39a205b3d72ea6dee41 Mon Sep 17 00:00:00 2001 From: Xiangdong Ji Date: Mon, 28 Jun 2021 20:27:30 +0800 Subject: [PATCH 580/940] net: fix failure of TestCVE202133195 TestCVE202133195 fails in testing LookupSRV if /etc/resolv.conf sets the option 'ndots' larger than the number of dots in the domain name under query. Fix the issue by making the input domain name in test codes 'rooted' to skip search list qualifying. Fixes #46955 Change-Id: I1909fa7e54e9c9af57623e57cafc905729ff99fa Reviewed-on: https://go-review.googlesource.com/c/go/+/330842 Reviewed-by: Damien Neil Run-TryBot: Damien Neil TryBot-Result: Go Bot Trust: Dmitri Shuralyov --- src/net/dnsclient_unix_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go index a59be7fea0d..d69107a2f23 100644 --- a/src/net/dnsclient_unix_test.go +++ b/src/net/dnsclient_unix_test.go @@ -1921,12 +1921,12 @@ func TestCVE202133195(t *testing.T) { t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected) } - _, _, err = r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org") - if expected := "lookup golang.org: SRV header name is invalid"; err == nil || err.Error() != expected { + _, _, err = r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org.") + if expected := "lookup golang.org.: SRV header name is invalid"; err == nil || err.Error() != expected { t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err, expected) } - _, _, err = LookupSRV("hdr", "tcp", "golang.org") - if expected := "lookup golang.org: SRV header name is invalid"; err == nil || err.Error() != expected { + _, _, err = LookupSRV("hdr", "tcp", "golang.org.") + if expected := "lookup golang.org.: SRV header name is invalid"; err == nil || err.Error() != expected { t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected) } From c45e800e0cb237fcedc9a3e4fd243e3a7f47334c Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Tue, 29 Jun 2021 09:20:04 -0700 Subject: [PATCH 581/940] crypto/x509: don't fail on optional auth key id fields If a certificate contains an AuthorityKeyIdentifier extension that lacks the keyIdentifier field, but contains the authorityCertIssuer and/or the authorityCertSerialNumber fields, don't return an error and continue parsing. Fixes #46854 Change-Id: I82739b415441f639a722755cc1f449d73078adfc Reviewed-on: https://go-review.googlesource.com/c/go/+/331689 Trust: Roland Shoemaker Run-TryBot: Roland Shoemaker TryBot-Result: Go Bot Reviewed-by: Filippo Valsorda --- src/crypto/x509/parser.go | 8 ++++--- src/crypto/x509/x509_test.go | 42 ++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/src/crypto/x509/parser.go b/src/crypto/x509/parser.go index 3d51ddd7f57..f085162a4e8 100644 --- a/src/crypto/x509/parser.go +++ b/src/crypto/x509/parser.go @@ -734,10 +734,12 @@ func processExtensions(out *Certificate) error { if !val.ReadASN1(&akid, cryptobyte_asn1.SEQUENCE) { return errors.New("x509: invalid authority key identifier") } - if !akid.ReadASN1(&akid, cryptobyte_asn1.Tag(0).ContextSpecific()) { - return errors.New("x509: invalid authority key identifier") + if akid.PeekASN1Tag(cryptobyte_asn1.Tag(0).ContextSpecific()) { + if !akid.ReadASN1(&akid, cryptobyte_asn1.Tag(0).ContextSpecific()) { + return errors.New("x509: invalid authority key identifier") + } + out.AuthorityKeyId = akid } - out.AuthorityKeyId = akid case 37: out.ExtKeyUsage, out.UnknownExtKeyUsage, err = parseExtKeyUsageExtension(e.Value) if err != nil { diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go index 802bce0f9af..a4053abf41d 100644 --- a/src/crypto/x509/x509_test.go +++ b/src/crypto/x509/x509_test.go @@ -3174,3 +3174,45 @@ func TestSigAlgMismatch(t *testing.T) { } } } + +const optionalAuthKeyIDPEM = `-----BEGIN CERTIFICATE----- +MIIFEjCCBHugAwIBAgICAQwwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1Zh +bGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu +Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24g +QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAe +BgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTA0MDYyOTE3MzkxNloX +DTI0MDYyOTE3MzkxNlowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVs +ZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAy +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0A +MIIBCAKCAQEAtzLI/ulxpgSFrQwRZN/OTe/IAxiHP6Gr+zymn/DDodrU2G4rU5D7 +JKQ+hPCe6F/s5SdE9SimP3ve4CrwyK9TL57KBQGTHo9mHDmnTfpatnMEJWbrd3/n +WcZKmSUUVOsmx/N/GdUwcI+vsEYq/63rKe3Xn6oEh6PU+YmlNF/bQ5GCNtlmPLG4 +uYL9nDo+EMg77wZlZnqbGRg9/3FRPDAuX749d3OyXQZswyNWmiuFJpIcpwKz5D8N +rwh5grg2Peqc0zWzvGnK9cyd6P1kjReAM25eSl2ZyR6HtJ0awNVuEzUjXt+bXz3v +1vd2wuo+u3gNHEJnawTY+Nbab4vyRKABqwIBA6OCAfMwggHvMB0GA1UdDgQWBBS/ +X7fRzt0fhvRbVazc1xDCDqmI5zCB0gYDVR0jBIHKMIHHoYHBpIG+MIG7MSQwIgYD +VQQHExtWYWxpQ2VydCBWYWxpZGF0aW9uIE5ldHdvcmsxFzAVBgNVBAoTDlZhbGlD +ZXJ0LCBJbmMuMTUwMwYDVQQLEyxWYWxpQ2VydCBDbGFzcyAyIFBvbGljeSBWYWxp +ZGF0aW9uIEF1dGhvcml0eTEhMB8GA1UEAxMYaHR0cDovL3d3dy52YWxpY2VydC5j +b20vMSAwHgYJKoZIhvcNAQkBFhFpbmZvQHZhbGljZXJ0LmNvbYIBATAPBgNVHRMB +Af8EBTADAQH/MDkGCCsGAQUFBwEBBC0wKzApBggrBgEFBQcwAYYdaHR0cDovL29j +c3Auc3RhcmZpZWxkdGVjaC5jb20wSgYDVR0fBEMwQTA/oD2gO4Y5aHR0cDovL2Nl +cnRpZmljYXRlcy5zdGFyZmllbGR0ZWNoLmNvbS9yZXBvc2l0b3J5L3Jvb3QuY3Js +MFEGA1UdIARKMEgwRgYEVR0gADA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY2VydGlm +aWNhdGVzLnN0YXJmaWVsZHRlY2guY29tL3JlcG9zaXRvcnkwDgYDVR0PAQH/BAQD +AgEGMA0GCSqGSIb3DQEBBQUAA4GBAKVi8afCXSWlcD284ipxs33kDTcdVWptobCr +mADkhWBKIMuh8D1195TaQ39oXCUIuNJ9MxB73HZn8bjhU3zhxoNbKXuNSm8uf0So +GkVrMgfHeMpkksK0hAzc3S1fTbvdiuo43NlmouxBulVtWmQ9twPMHOKRUJ7jCUSV +FxdzPcwl +-----END CERTIFICATE-----` + +func TestAuthKeyIdOptional(t *testing.T) { + b, _ := pem.Decode([]byte(optionalAuthKeyIDPEM)) + if b == nil { + t.Fatalf("couldn't decode test certificate") + } + _, err := ParseCertificate(b.Bytes) + if err != nil { + t.Fatalf("ParseCertificate to failed to parse certificate with optional authority key identifier fields: %s", err) + } +} From d19a53338fa6272b4fe9c39d66812a79e1464cd2 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Tue, 29 Jun 2021 16:53:44 +1000 Subject: [PATCH 582/940] image: add Uniform.RGBA64At and Rectangle.RGBA64At These types already implemented the Image interface. They should also implement the RGBA64Image interface (new in Go 1.17) Updates #44808 Change-Id: I9a2b13e305997088ae874efb95ad9e1648f94812 Reviewed-on: https://go-review.googlesource.com/c/go/+/331570 Trust: Nigel Tao Run-TryBot: Nigel Tao TryBot-Result: Go Bot Reviewed-by: Dmitri Shuralyov --- api/go1.17.txt | 2 ++ doc/go1.17.html | 4 ++-- src/image/geom.go | 8 ++++++++ src/image/image_test.go | 12 ++++++++++++ src/image/names.go | 5 +++++ 5 files changed, 29 insertions(+), 2 deletions(-) diff --git a/api/go1.17.txt b/api/go1.17.txt index c5eb381708c..8e4c0f5624b 100644 --- a/api/go1.17.txt +++ b/api/go1.17.txt @@ -47,7 +47,9 @@ pkg image, method (*Paletted) RGBA64At(int, int) color.RGBA64 pkg image, method (*Paletted) SetRGBA64(int, int, color.RGBA64) pkg image, method (*RGBA) RGBA64At(int, int) color.RGBA64 pkg image, method (*RGBA) SetRGBA64(int, int, color.RGBA64) +pkg image, method (*Uniform) RGBA64At(int, int) color.RGBA64 pkg image, method (*YCbCr) RGBA64At(int, int) color.RGBA64 +pkg image, method (Rectangle) RGBA64At(int, int) color.RGBA64 pkg image, type RGBA64Image interface { At, Bounds, ColorModel, RGBA64At } pkg image, type RGBA64Image interface, At(int, int) color.Color pkg image, type RGBA64Image interface, Bounds() Rectangle diff --git a/doc/go1.17.html b/doc/go1.17.html index 3551ba46c8c..b72752d77d8 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -811,8 +811,8 @@ func Foo() bool {

The concrete image types (RGBA, Gray16 and so on) now implement a new RGBA64Image - interface. Those concrete types, other than the chroma-subsampling - related YCbCr and NYCbCrA, also now implement + interface. The concrete types that previously implemented + draw.Image now also implement draw.RGBA64Image, a new interface in the image/draw package.

diff --git a/src/image/geom.go b/src/image/geom.go index 78e9e49d4f6..e71aa611872 100644 --- a/src/image/geom.go +++ b/src/image/geom.go @@ -246,6 +246,14 @@ func (r Rectangle) At(x, y int) color.Color { return color.Transparent } +// RGBA64At implements the RGBA64Image interface. +func (r Rectangle) RGBA64At(x, y int) color.RGBA64 { + if (Point{x, y}).In(r) { + return color.RGBA64{0xffff, 0xffff, 0xffff, 0xffff} + } + return color.RGBA64{} +} + // Bounds implements the Image interface. func (r Rectangle) Bounds() Rectangle { return r diff --git a/src/image/image_test.go b/src/image/image_test.go index c64b6107b74..7f41bcb6c70 100644 --- a/src/image/image_test.go +++ b/src/image/image_test.go @@ -213,7 +213,9 @@ func TestRGBA64Image(t *testing.T) { NewPaletted(r, palette.Plan9), NewRGBA(r), NewRGBA64(r), + NewUniform(color.RGBA64{}), NewYCbCr(r, YCbCrSubsampleRatio444), + r, } for _, tc := range testCases { switch tc := tc.(type) { @@ -226,6 +228,9 @@ func TestRGBA64Image(t *testing.T) { // means that setting one pixel can modify neighboring pixels. They // don't have Set or SetRGBA64 methods because that side effect could // be surprising. Here, we just memset the channel buffers instead. + // + // The Uniform and Rectangle types are also special-cased, as they + // don't have a Set or SetRGBA64 method. case interface { SetRGBA64(x, y int, c color.RGBA64) }: @@ -237,11 +242,18 @@ func TestRGBA64Image(t *testing.T) { memset(tc.YCbCr.Cr, 0x99) memset(tc.A, 0xAA) + case *Uniform: + tc.C = color.RGBA64{0x7FFF, 0x3FFF, 0x0000, 0x7FFF} + case *YCbCr: memset(tc.Y, 0x77) memset(tc.Cb, 0x88) memset(tc.Cr, 0x99) + case Rectangle: + // No-op. Rectangle pixels' colors are immutable. They're always + // color.Opaque. + default: t.Errorf("could not initialize pixels for %T", tc) continue diff --git a/src/image/names.go b/src/image/names.go index 8595a35014d..17b06588ac5 100644 --- a/src/image/names.go +++ b/src/image/names.go @@ -41,6 +41,11 @@ func (c *Uniform) Bounds() Rectangle { return Rectangle{Point{-1e9, -1e9}, Point func (c *Uniform) At(x, y int) color.Color { return c.C } +func (c *Uniform) RGBA64At(x, y int) color.RGBA64 { + r, g, b, a := c.C.RGBA() + return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)} +} + // Opaque scans the entire image and reports whether it is fully opaque. func (c *Uniform) Opaque() bool { _, _, _, a := c.C.RGBA() From f503740ccf6302ed13c7722ea50c6880a17703fb Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 28 Jun 2021 22:41:50 -0700 Subject: [PATCH 583/940] [dev.typeparams] cmd/compile: add derived-type dictionaries to unified IR This CL updates the unified IR export data serialization to explicitly and separately record the derived types used by a declaration. The readers currently just use this data to construct types/IR the same as before, but eventually we can use it for emitting GC-shape dictionaries. Change-Id: I7d67ad9b3f1fbe69664bf19e056bc94f73507220 Reviewed-on: https://go-review.googlesource.com/c/go/+/331829 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le Trust: Cuong Manh Le Trust: Matthew Dempsky --- src/cmd/compile/internal/noder/linker.go | 32 ++- src/cmd/compile/internal/noder/reader.go | 184 +++++++++-------- src/cmd/compile/internal/noder/reader2.go | 146 ++++++++----- src/cmd/compile/internal/noder/reloc.go | 1 + src/cmd/compile/internal/noder/unified.go | 2 +- src/cmd/compile/internal/noder/writer.go | 239 ++++++++++++++-------- 6 files changed, 381 insertions(+), 223 deletions(-) diff --git a/src/cmd/compile/internal/noder/linker.go b/src/cmd/compile/internal/noder/linker.go index 23e9446759c..ed47a355d81 100644 --- a/src/cmd/compile/internal/noder/linker.go +++ b/src/cmd/compile/internal/noder/linker.go @@ -134,11 +134,15 @@ func (l *linker) relocObj(pr *pkgReader, idx int) int { } w := l.pw.newEncoderRaw(relocObj) - bside := l.pw.newEncoderRaw(relocObjExt) - assert(bside.idx == w.idx) + wext := l.pw.newEncoderRaw(relocObjExt) + wdict := l.pw.newEncoderRaw(relocObjDict) + l.decls[sym] = w.idx + assert(wext.idx == w.idx) + assert(wdict.idx == w.idx) l.relocCommon(pr, &w, relocObj, idx) + l.relocCommon(pr, &wdict, relocObjDict, idx) var obj *ir.Name if path == "" { @@ -153,18 +157,18 @@ func (l *linker) relocObj(pr *pkgReader, idx int) int { } if obj != nil { - bside.sync(syncObject1) + wext.sync(syncObject1) switch tag { case objFunc: - l.relocFuncExt(&bside, obj) + l.relocFuncExt(&wext, obj) case objType: - l.relocTypeExt(&bside, obj) + l.relocTypeExt(&wext, obj) case objVar: - l.relocVarExt(&bside, obj) + l.relocVarExt(&wext, obj) } - bside.flush() + wext.flush() } else { - l.relocCommon(pr, &bside, relocObjExt, idx) + l.relocCommon(pr, &wext, relocObjExt, idx) } return w.idx @@ -286,7 +290,17 @@ func (pr *pkgDecoder) peekObj(idx int) (string, string, codeObj, []int) { bounds := make([]int, r.len()) for i := range bounds { r.sync(syncType) - bounds[i] = r.reloc(relocType) + if r.bool() { + r.len() + } else { + r.reloc(relocType) + } + + // TODO(mdempsky): This result now needs to include the 'derived' + // bool too, but none of the callers currently depend on it + // anyway. Either fix it to be meaningful, or just get rid of it + // altogether. + bounds[i] = -1 } tag := codeObj(r.code(syncCodeObj)) diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 66c0e99d114..4b42ae1ec38 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -54,14 +54,14 @@ func newPkgReader(pr pkgDecoder) *pkgReader { } type pkgReaderIndex struct { - pr *pkgReader - idx int - implicits []*types.Type + pr *pkgReader + idx int + dict *readerDict } func (pri pkgReaderIndex) asReader(k reloc, marker syncMarker) *reader { r := pri.pr.newReader(k, pri.idx, marker) - r.implicits = pri.implicits + r.dict = pri.dict return r } @@ -77,29 +77,10 @@ type reader struct { p *pkgReader - // Implicit and explicit type arguments in use for reading the - // current object. For example: - // - // func F[T any]() { - // type X[U any] struct { t T; u U } - // var _ X[string] - // } - // - // var _ = F[int] - // - // While instantiating F[int], we need to in turn instantiate - // X[string]. [int] and [string] are explicit type arguments for F - // and X, respectively; but [int] is also the implicit type - // arguments for X. - // - // (As an analogy to function literals, explicits are the function - // literal's formal parameters, while implicits are variables - // captured by the function literal.) - implicits []*types.Type - explicits []*types.Type - ext *reader + dict *readerDict + // TODO(mdempsky): The state below is all specific to reading // function bodies. It probably makes sense to split it out // separately so that it doesn't take up space in every reader @@ -135,6 +116,35 @@ type reader struct { inlvars, retvars ir.Nodes } +type readerDict struct { + // targs holds the implicit and explicit type arguments in use for + // reading the current object. For example: + // + // func F[T any]() { + // type X[U any] struct { t T; u U } + // var _ X[string] + // } + // + // var _ = F[int] + // + // While instantiating F[int], we need to in turn instantiate + // X[string]. [int] and [string] are explicit type arguments for F + // and X, respectively; but [int] is also the implicit type + // arguments for X. + // + // (As an analogy to function literals, explicits are the function + // literal's formal parameters, while implicits are variables + // captured by the function literal.) + targs []*types.Type + + // implicits counts how many of types within targs are implicit type + // arguments; the rest are explicit. + implicits int + + derivedReloc []int // reloc index of the derived type's descriptor + derived []*types.Type // slice of previously computed derived types +} + func (r *reader) setType(n ir.Node, typ *types.Type) { n.SetType(typ) n.SetTypecheck(1) @@ -283,17 +293,28 @@ func (r *reader) doPkg() *types.Pkg { func (r *reader) typ() *types.Type { r.sync(syncType) - return r.p.typIdx(r.reloc(relocType), r.implicits, r.explicits) + if r.bool() { + return r.p.typIdx(r.len(), r.dict) + } + return r.p.typIdx(r.reloc(relocType), nil) } -func (pr *pkgReader) typIdx(idx int, implicits, explicits []*types.Type) *types.Type { - if typ := pr.typs[idx]; typ != nil { +func (pr *pkgReader) typIdx(idx int, dict *readerDict) *types.Type { + var where **types.Type + if dict != nil { + where = &dict.derived[idx] + idx = dict.derivedReloc[idx] + } else { + where = &pr.typs[idx] + } + + if typ := *where; typ != nil { return typ } r := pr.newReader(relocType, idx, syncTypeIdx) - r.implicits = implicits - r.explicits = explicits + r.dict = dict + typ := r.doTyp() assert(typ != nil) @@ -336,20 +357,12 @@ func (pr *pkgReader) typIdx(idx int, implicits, explicits []*types.Type) *types. // // The idx 1, corresponding with type I was resolved successfully // after r.doTyp() call. - if typ := pr.typs[idx]; typ != nil { - return typ + + if prev := *where; prev != nil { + return prev } - // If we have type parameters, the type might refer to them, and it - // wouldn't be safe to reuse those in other contexts. So we - // conservatively avoid caching them in that case. - // - // TODO(mdempsky): If we're clever, we should be able to still cache - // types by tracking which type parameters are used. However, in my - // attempts so far, I haven't yet succeeded in being clever enough. - if !r.hasTypeParams() { - pr.typs[idx] = typ - } + *where = typ if !typ.IsUntyped() { types.CheckSize(typ) @@ -372,11 +385,7 @@ func (r *reader) doTyp() *types.Type { return obj.Type() case typeTypeParam: - idx := r.len() - if idx < len(r.implicits) { - return r.implicits[idx] - } - return r.explicits[idx-len(r.implicits)] + return r.dict.targs[r.len()] case typeArray: len := int64(r.uint64()) @@ -490,7 +499,12 @@ func (r *reader) obj() ir.Node { explicits[i] = r.typ() } - return r.p.objIdx(idx, r.implicits, explicits) + var implicits []*types.Type + if r.dict != nil { + implicits = r.dict.targs + } + + return r.p.objIdx(idx, implicits, explicits) } func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node { @@ -499,14 +513,11 @@ func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node _, sym := r.qualifiedIdent() - // Middle dot indicates local defined type; see writer.sym. - // TODO(mdempsky): Come up with a better way to handle this. - if strings.Contains(sym.Name, "·") { - r.implicits = implicits - r.ext.implicits = implicits - } - r.explicits = explicits - r.ext.explicits = explicits + dict := &readerDict{} + r.dict = dict + r.ext.dict = dict + + r.typeParamBounds(sym, implicits, explicits) origSym := sym @@ -515,9 +526,17 @@ func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node return sym.Def.(ir.Node) } - r.typeParamBounds(origSym) tag := codeObj(r.code(syncCodeObj)) + { + rdict := pr.newReader(relocObjDict, idx, syncObject1) + r.dict.derivedReloc = make([]int, rdict.len()) + r.dict.derived = make([]*types.Type, len(r.dict.derivedReloc)) + for i := range r.dict.derived { + r.dict.derivedReloc[i] = rdict.reloc(relocType) + } + } + do := func(op ir.Op, hasTParams bool) *ir.Name { pos := r.pos() if hasTParams { @@ -542,7 +561,7 @@ func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node case objStub: if pri, ok := objReader[origSym]; ok { - return pri.pr.objIdx(pri.idx, pri.implicits, r.explicits) + return pri.pr.objIdx(pri.idx, nil, explicits) } if haveLegacyImports { assert(!r.hasTypeParams()) @@ -621,46 +640,50 @@ func (r *reader) mangle(sym *types.Sym) *types.Sym { var buf bytes.Buffer buf.WriteString(sym.Name) buf.WriteByte('[') - for i, targs := range [2][]*types.Type{r.implicits, r.explicits} { - if i > 0 && len(r.implicits) != 0 && len(r.explicits) != 0 { - buf.WriteByte(';') - } - for j, targ := range targs { - if j > 0 { + for i, targ := range r.dict.targs { + if i > 0 { + if i == r.dict.implicits { + buf.WriteByte(';') + } else { buf.WriteByte(',') } - // TODO(mdempsky): We need the linker to replace "" in the symbol - // names here. - buf.WriteString(targ.LinkString()) } + buf.WriteString(targ.LinkString()) } buf.WriteByte(']') return sym.Pkg.Lookup(buf.String()) } -func (r *reader) typeParamBounds(sym *types.Sym) { +func (r *reader) typeParamBounds(sym *types.Sym, implicits, explicits []*types.Type) { r.sync(syncTypeParamBounds) nimplicits := r.len() nexplicits := r.len() - if len(r.implicits) != nimplicits || len(r.explicits) != nexplicits { - base.Fatalf("%v has %v+%v params, but instantiated with %v+%v args", sym, nimplicits, nexplicits, len(r.implicits), len(r.explicits)) + if nimplicits > len(implicits) || nexplicits != len(explicits) { + base.Fatalf("%v has %v+%v params, but instantiated with %v+%v args", sym, nimplicits, nexplicits, len(implicits), len(explicits)) } + r.dict.targs = append(implicits[:nimplicits:nimplicits], explicits...) + r.dict.implicits = nimplicits + // For stenciling, we can just skip over the type parameters. - for range r.explicits { + for range r.dict.targs[r.dict.implicits:] { // Skip past bounds without actually evaluating them. r.sync(syncType) - r.reloc(relocType) + if r.bool() { + r.len() + } else { + r.reloc(relocType) + } } } func (r *reader) typeParamNames() { r.sync(syncTypeParamNames) - for range r.explicits { + for range r.dict.targs[r.dict.implicits:] { r.pos() r.localIdent() } @@ -729,7 +752,7 @@ func (r *reader) selector() (origPkg *types.Pkg, sym *types.Sym) { } func (r *reader) hasTypeParams() bool { - return len(r.implicits)+len(r.explicits) != 0 + return r.dict != nil && len(r.dict.targs) != 0 } // @@@ Compiler extensions @@ -776,10 +799,10 @@ func (r *reader) funcExt(name *ir.Name) { Cost: int32(r.len()), CanDelayResults: r.bool(), } - r.addBody(name.Func, r.explicits) + r.addBody(name.Func) } } else { - r.addBody(name.Func, r.explicits) + r.addBody(name.Func) } r.sync(syncEOF) } @@ -795,8 +818,7 @@ func (r *reader) typeExt(name *ir.Name) { // type descriptor is written out as DUPOK and method wrappers are // generated even for imported types. var targs []*types.Type - targs = append(targs, r.implicits...) - targs = append(targs, r.explicits...) + targs = append(targs, r.dict.targs...) typ.SetRParams(targs) } @@ -841,8 +863,8 @@ var bodyReader = map[*ir.Func]pkgReaderIndex{} // constructed. var todoBodies []*ir.Func -func (r *reader) addBody(fn *ir.Func, implicits []*types.Type) { - pri := pkgReaderIndex{r.p, r.reloc(relocBody), implicits} +func (r *reader) addBody(fn *ir.Func) { + pri := pkgReaderIndex{r.p, r.reloc(relocBody), r.dict} bodyReader[fn] = pri if r.curfn == nil { @@ -1565,7 +1587,7 @@ func (r *reader) funcLit() ir.Node { r.setType(cv, outer.Type()) } - r.addBody(fn, r.implicits) + r.addBody(fn) return fn.OClosure } diff --git a/src/cmd/compile/internal/noder/reader2.go b/src/cmd/compile/internal/noder/reader2.go index 174bd3f5bdb..89f224d389c 100644 --- a/src/cmd/compile/internal/noder/reader2.go +++ b/src/cmd/compile/internal/noder/reader2.go @@ -57,7 +57,21 @@ type reader2 struct { p *pkgReader2 - tparams []*types2.TypeName + dict *reader2Dict +} + +type reader2Dict struct { + bounds []reader2TypeBound + + tparams []*types2.TypeParam + + derivedReloc []int + derived []types2.Type +} + +type reader2TypeBound struct { + derived bool + boundIdx int } func (pr *pkgReader2) newReader(k reloc, idx int, marker syncMarker) *reader2 { @@ -163,28 +177,37 @@ func (r *reader2) doPkg() *types2.Package { func (r *reader2) typ() types2.Type { r.sync(syncType) - return r.p.typIdx(r.reloc(relocType), r.tparams) + if r.bool() { + return r.p.typIdx(r.len(), r.dict) + } + return r.p.typIdx(r.reloc(relocType), nil) } -func (pr *pkgReader2) typIdx(idx int, tparams []*types2.TypeName) types2.Type { - if typ := pr.typs[idx]; typ != nil { +func (pr *pkgReader2) typIdx(idx int, dict *reader2Dict) types2.Type { + var where *types2.Type + if dict != nil { + where = &dict.derived[idx] + idx = dict.derivedReloc[idx] + } else { + where = &pr.typs[idx] + } + + if typ := *where; typ != nil { return typ } r := pr.newReader(relocType, idx, syncTypeIdx) - r.tparams = tparams + r.dict = dict + typ := r.doTyp() assert(typ != nil) - if pr.typs[idx] != nil { - // See comment in pkgReader.typIdx. - return pr.typs[idx] - } - - if len(tparams) == 0 { - pr.typs[idx] = typ + // See comment in pkgReader.typIdx explaining how this happens. + if prev := *where; prev != nil { + return prev } + *where = typ return typ } @@ -206,8 +229,7 @@ func (r *reader2) doTyp() (res types2.Type) { return name.Type() case typeTypeParam: - idx := r.len() - return r.tparams[idx].Type().(*types2.TypeParam) + return r.dict.tparams[r.len()] case typeArray: len := int64(r.uint64()) @@ -330,10 +352,12 @@ func (r *reader2) obj() (types2.Object, []types2.Type) { func (pr *pkgReader2) objIdx(idx int) (*types2.Package, string) { r := pr.newReader(relocObj, idx, syncObject1) + r.dict = &reader2Dict{} + objPkg, objName := r.qualifiedIdent() assert(objName != "") - bounds := r.typeParamBounds() + r.typeParamBounds() tag := codeObj(r.code(syncCodeObj)) if tag == objStub { @@ -341,6 +365,15 @@ func (pr *pkgReader2) objIdx(idx int) (*types2.Package, string) { return objPkg, objName } + { + rdict := r.p.newReader(relocObjDict, idx, syncObject1) + r.dict.derivedReloc = make([]int, rdict.len()) + r.dict.derived = make([]types2.Type, len(r.dict.derivedReloc)) + for i := range r.dict.derived { + r.dict.derivedReloc[i] = rdict.reloc(relocType) + } + } + objPkg.Scope().InsertLazy(objName, func() types2.Object { switch tag { default: @@ -358,21 +391,16 @@ func (pr *pkgReader2) objIdx(idx int) (*types2.Package, string) { case objFunc: pos := r.pos() - r.typeParamNames(bounds) + tparams := r.typeParamNames() sig := r.signature(nil) - if len(r.tparams) != 0 { - sig.SetTParams(r.tparams) - } + sig.SetTParams(tparams) return types2.NewFunc(pos, objPkg, objName, sig) case objType: pos := r.pos() return types2.NewTypeNameLazy(pos, objPkg, objName, func(named *types2.Named) (tparams []*types2.TypeName, underlying types2.Type, methods []*types2.Func) { - r.typeParamNames(bounds) - if len(r.tparams) != 0 { - tparams = r.tparams - } + tparams = r.typeParamNames() // TODO(mdempsky): Rewrite receiver types to underlying is an // Interface? The go/types importer does this (I think because @@ -382,7 +410,7 @@ func (pr *pkgReader2) objIdx(idx int) (*types2.Package, string) { methods = make([]*types2.Func, r.len()) for i := range methods { - methods[i] = r.method(bounds) + methods[i] = r.method() } return @@ -403,51 +431,73 @@ func (r *reader2) value() (types2.Type, constant.Value) { return r.typ(), r.rawValue() } -func (r *reader2) typeParamBounds() []int { +func (r *reader2) typeParamBounds() { r.sync(syncTypeParamBounds) - // exported types never have implicit type parameters - // TODO(mdempsky): Hide this from public importer. - assert(r.len() == 0) - - bounds := make([]int, r.len()) - for i := range bounds { - r.sync(syncType) - bounds[i] = r.reloc(relocType) + if implicits := r.len(); implicits != 0 { + base.Fatalf("unexpected object with %v implicit type parameter(s)", implicits) + } + + r.dict.bounds = make([]reader2TypeBound, r.len()) + for i := range r.dict.bounds { + b := &r.dict.bounds[i] + r.sync(syncType) + b.derived = r.bool() + if b.derived { + b.boundIdx = r.len() + } else { + b.boundIdx = r.reloc(relocType) + } } - return bounds } -func (r *reader2) typeParamNames(bounds []int) { +func (r *reader2) typeParamNames() []*types2.TypeName { r.sync(syncTypeParamNames) - r.tparams = make([]*types2.TypeName, len(bounds)) + // Note: This code assumes it only processes objects without + // implement type parameters. This is currently fine, because + // reader2 is only used to read in exported declarations, which are + // always package scoped. - for i := range r.tparams { + if len(r.dict.bounds) == 0 { + return nil + } + + // Careful: Type parameter lists may have cycles. To allow for this, + // we construct the type parameter list in two passes: first we + // create all the TypeNames and TypeParams, then we construct and + // set the bound type. + + names := make([]*types2.TypeName, len(r.dict.bounds)) + r.dict.tparams = make([]*types2.TypeParam, len(r.dict.bounds)) + for i := range r.dict.bounds { pos := r.pos() pkg, name := r.localIdent() - obj := types2.NewTypeName(pos, pkg, name, nil) - r.p.check.NewTypeParam(obj, i, nil) - r.tparams[i] = obj + names[i] = types2.NewTypeName(pos, pkg, name, nil) + r.dict.tparams[i] = r.p.check.NewTypeParam(names[i], i, nil) } - for i, tparam := range r.tparams { - bound := r.p.typIdx(bounds[i], r.tparams) - tparam.Type().(*types2.TypeParam).SetBound(bound) + for i, bound := range r.dict.bounds { + var dict *reader2Dict + if bound.derived { + dict = r.dict + } + boundType := r.p.typIdx(bound.boundIdx, dict) + r.dict.tparams[i].SetBound(boundType) } + + return names } -func (r *reader2) method(bounds []int) *types2.Func { +func (r *reader2) method() *types2.Func { r.sync(syncMethod) pos := r.pos() pkg, name := r.selector() - r.typeParamNames(bounds) + rparams := r.typeParamNames() sig := r.signature(r.param()) - if len(r.tparams) != 0 { - sig.SetRParams(r.tparams) - } + sig.SetRParams(rparams) _ = r.pos() // TODO(mdempsky): Remove; this is a hacker for linker.go. return types2.NewFunc(pos, pkg, name, sig) diff --git a/src/cmd/compile/internal/noder/reloc.go b/src/cmd/compile/internal/noder/reloc.go index 961de494199..4eb6bcdb1c0 100644 --- a/src/cmd/compile/internal/noder/reloc.go +++ b/src/cmd/compile/internal/noder/reloc.go @@ -34,6 +34,7 @@ const ( relocType relocObj relocObjExt + relocObjDict relocBody numRelocs = iota diff --git a/src/cmd/compile/internal/noder/unified.go b/src/cmd/compile/internal/noder/unified.go index 292fd13c679..8397f14be83 100644 --- a/src/cmd/compile/internal/noder/unified.go +++ b/src/cmd/compile/internal/noder/unified.go @@ -122,7 +122,7 @@ func unified(noders []*noder) { // Instantiated generic function: add to Decls for typechecking // and compilation. - if len(pri.implicits) != 0 && fn.OClosure == nil { + if pri.dict != nil && len(pri.dict.targs) != 0 && fn.OClosure == nil { target.Decls = append(target.Decls, fn) } } diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go index 04969100f0c..6348a567414 100644 --- a/src/cmd/compile/internal/noder/writer.go +++ b/src/cmd/compile/internal/noder/writer.go @@ -87,20 +87,27 @@ type writer struct { // scope closes, and then maybe we can just use the same map for // storing the TypeParams too (as their TypeName instead). - // type parameters. explicitIdx has the type parameters declared on - // the current object, while implicitIdx has the type parameters - // declared on the enclosing object (if any). - // - // TODO(mdempsky): Merge these back together, now that I've got them - // working. - implicitIdx map[*types2.TypeParam]int - explicitIdx map[*types2.TypeParam]int - // variables declared within this function localsIdx map[*types2.Var]int closureVars []posObj closureVarsIdx map[*types2.Var]int + + dict *writerDict + derived bool +} + +// A writerDict tracks types and objects that are used by a declaration. +type writerDict struct { + implicits []*types2.TypeName + + // derived is a slice of type indices for computing derived types + // (i.e., types that depend on the declaration's type parameters). + derived []int + + // derivedIdx maps a Type to its corresponding index within the + // derived slice, if present. + derivedIdx map[types2.Type]int } func (pw *pkgWriter) newWriter(k reloc, marker syncMarker) *writer { @@ -193,30 +200,39 @@ func (pw *pkgWriter) pkgIdx(pkg *types2.Package) int { // @@@ Types func (w *writer) typ(typ types2.Type) { + idx, derived := w.p.typIdx(typ, w.dict) + w.sync(syncType) - - if quirksMode() { - typ = w.p.dups.orig(typ) + if w.bool(derived) { + w.len(idx) + w.derived = true + } else { + w.reloc(relocType, idx) } - - w.reloc(relocType, w.p.typIdx(typ, w.implicitIdx, w.explicitIdx)) } -func (pw *pkgWriter) typIdx(typ types2.Type, implicitIdx, explicitIdx map[*types2.TypeParam]int) int { +// typIdx returns the index where the export data description of type +// can be read back in. If no such index exists yet, it's created. +// +// typIdx also reports whether typ is a derived type; that is, whether +// its identity depends on type parameters. +func (pw *pkgWriter) typIdx(typ types2.Type, dict *writerDict) (int, bool) { + if quirksMode() { + typ = pw.dups.orig(typ) + } + if idx, ok := pw.typsIdx[typ]; ok { - return idx + return idx, false + } + if dict != nil { + if idx, ok := dict.derivedIdx[typ]; ok { + return idx, true + } } w := pw.newWriter(relocType, syncTypeIdx) - w.implicitIdx = implicitIdx - w.explicitIdx = explicitIdx + w.dict = dict - pw.typsIdx[typ] = w.idx // handle cycles - w.doTyp(typ) - return w.flush() -} - -func (w *writer) doTyp(typ types2.Type) { switch typ := typ.(type) { default: base.Fatalf("unexpected type: %v (%T)", typ, typ) @@ -251,14 +267,19 @@ func (w *writer) doTyp(typ types2.Type) { w.obj(orig.Obj(), typ.TArgs()) case *types2.TypeParam: + index := func() int { + for idx, name := range w.dict.implicits { + if name.Type().(*types2.TypeParam) == typ { + return idx + } + } + + return len(w.dict.implicits) + typ.Index() + }() + + w.derived = true w.code(typeTypeParam) - if idx, ok := w.implicitIdx[typ]; ok { - w.len(idx) - } else if idx, ok := w.explicitIdx[typ]; ok { - w.len(len(w.implicitIdx) + idx) - } else { - w.p.fatalf(typ.Obj(), "%v not in %v or %v", typ, w.implicitIdx, w.explicitIdx) - } + w.len(index) case *types2.Array: w.code(typeArray) @@ -300,6 +321,16 @@ func (w *writer) doTyp(typ types2.Type) { w.code(typeUnion) w.unionType(typ) } + + if w.derived { + idx := len(dict.derived) + dict.derived = append(dict.derived, w.flush()) + dict.derivedIdx[typ] = idx + return idx, true + } + + pw.typsIdx[typ] = w.idx + return w.flush(), false } func (w *writer) structType(typ *types2.Struct) { @@ -367,13 +398,16 @@ func (w *writer) param(param *types2.Var) { // @@@ Objects func (w *writer) obj(obj types2.Object, explicits []types2.Type) { - w.sync(syncObject) - - var implicitIdx map[*types2.TypeParam]int - if isDefinedType(obj) && !isGlobal(obj) { - implicitIdx = w.implicitIdx + if isDefinedType(obj) && obj.Pkg() == w.p.curpkg { + decl, ok := w.p.typDecls[obj.(*types2.TypeName)] + assert(ok) + if len(decl.implicits) != 0 { + w.derived = true + } } - w.reloc(relocObj, w.p.objIdx(obj, implicitIdx)) + + w.sync(syncObject) + w.reloc(relocObj, w.p.objIdx(obj)) w.len(len(explicits)) for _, explicit := range explicits { @@ -381,37 +415,61 @@ func (w *writer) obj(obj types2.Object, explicits []types2.Type) { } } -func (pw *pkgWriter) objIdx(obj types2.Object, implicitIdx map[*types2.TypeParam]int) int { +func (pw *pkgWriter) objIdx(obj types2.Object) int { if idx, ok := pw.globalsIdx[obj]; ok { return idx } + dict := &writerDict{ + derivedIdx: make(map[types2.Type]int), + } + + if isDefinedType(obj) && obj.Pkg() == pw.curpkg { + decl, ok := pw.typDecls[obj.(*types2.TypeName)] + assert(ok) + dict.implicits = decl.implicits + } + w := pw.newWriter(relocObj, syncObject1) w.ext = pw.newWriter(relocObjExt, syncObject1) + wdict := pw.newWriter(relocObjDict, syncObject1) + + pw.globalsIdx[obj] = w.idx // break cycles assert(w.ext.idx == w.idx) + assert(wdict.idx == w.idx) - pw.globalsIdx[obj] = w.idx + w.dict = dict + w.ext.dict = dict - w.implicitIdx = implicitIdx - w.ext.implicitIdx = implicitIdx + // Ident goes first so importer can avoid unnecessary work if + // they've already resolved this object. + w.qualifiedIdent(obj) + + w.typeParamBounds(objTypeParams(obj)) w.doObj(obj) w.flush() w.ext.flush() + // Done writing out the object description; write out the list of + // derived types that we found along the way. + // + // TODO(mdempsky): Record details about how derived types are + // actually used so reader can optimize its runtime dictionaries. + // + // TODO(mdempsky): Record details about which instantiated functions + // are used too. + wdict.len(len(dict.derived)) + for _, typ := range dict.derived { + wdict.reloc(relocType, typ) + } + wdict.flush() + return w.idx } func (w *writer) doObj(obj types2.Object) { - // Ident goes first so importer can avoid unnecessary work if - // they've already resolved this object. - w.qualifiedIdent(obj) - - tparams := objTypeParams(obj) - w.setTypeParams(tparams) - w.typeParamBounds(tparams) - if obj.Pkg() != w.p.curpkg { w.code(objStub) return @@ -504,29 +562,12 @@ func (w *writer) value(typ types2.Type, val constant.Value) { w.rawValue(val) } -func (w *writer) setTypeParams(tparams []*types2.TypeName) { - if len(tparams) == 0 { - return - } - - explicitIdx := make(map[*types2.TypeParam]int) - for _, tparam := range tparams { - explicitIdx[tparam.Type().(*types2.TypeParam)] = len(explicitIdx) - } - - w.explicitIdx = explicitIdx - w.ext.explicitIdx = explicitIdx -} - func (w *writer) typeParamBounds(tparams []*types2.TypeName) { w.sync(syncTypeParamBounds) - // TODO(mdempsky): Remove. It's useful for debugging at the moment, - // but it doesn't belong here. - w.len(len(w.implicitIdx)) - w.len(len(w.explicitIdx)) - assert(len(w.explicitIdx) == len(tparams)) + w.len(len(w.dict.implicits)) + w.len(len(tparams)) for _, tparam := range tparams { w.typ(tparam.Type().(*types2.TypeParam).Bound()) } @@ -546,9 +587,6 @@ func (w *writer) method(meth *types2.Func) { assert(ok) sig := meth.Type().(*types2.Signature) - assert(len(w.explicitIdx) == len(sig.RParams())) - w.setTypeParams(sig.RParams()) - w.sync(syncMethod) w.pos(meth) w.selector(meth) @@ -566,11 +604,14 @@ func (w *writer) qualifiedIdent(obj types2.Object) { w.sync(syncSym) name := obj.Name() - if isDefinedType(obj) && !isGlobal(obj) { - // TODO(mdempsky): Find a better solution, this is terrible. + if isDefinedType(obj) && obj.Pkg() == w.p.curpkg { decl, ok := w.p.typDecls[obj.(*types2.TypeName)] assert(ok) - name = fmt.Sprintf("%s·%v", name, decl.gen) + if decl.gen != 0 { + // TODO(mdempsky): Find a better solution than embedding middle + // dot in the symbol name; this is terrible. + name = fmt.Sprintf("%s·%v", name, decl.gen) + } } w.pkg(obj.Pkg()) @@ -630,7 +671,7 @@ func (w *writer) funcExt(obj *types2.Func) { } sig, block := obj.Type().(*types2.Signature), decl.Body - body, closureVars := w.p.bodyIdx(w.p.curpkg, sig, block, w.explicitIdx) + body, closureVars := w.p.bodyIdx(w.p.curpkg, sig, block, w.dict) assert(len(closureVars) == 0) w.sync(syncFuncExt) @@ -672,9 +713,9 @@ func (w *writer) pragmaFlag(p ir.PragmaFlag) { // @@@ Function bodies -func (pw *pkgWriter) bodyIdx(pkg *types2.Package, sig *types2.Signature, block *syntax.BlockStmt, implicitIdx map[*types2.TypeParam]int) (idx int, closureVars []posObj) { +func (pw *pkgWriter) bodyIdx(pkg *types2.Package, sig *types2.Signature, block *syntax.BlockStmt, dict *writerDict) (idx int, closureVars []posObj) { w := pw.newWriter(relocBody, syncFuncBody) - w.implicitIdx = implicitIdx + w.dict = dict w.funcargs(sig) if w.bool(block != nil) { @@ -1238,14 +1279,13 @@ func (w *writer) funcLit(expr *syntax.FuncLit) { assert(ok) sig := tv.Type.(*types2.Signature) + body, closureVars := w.p.bodyIdx(w.p.curpkg, sig, expr.Body, w.dict) + w.sync(syncFuncLit) w.pos(expr) w.pos(expr.Type) // for QuirksMode w.signature(sig) - block := expr.Body - body, closureVars := w.p.bodyIdx(w.p.curpkg, sig, block, w.implicitIdx) - w.len(len(closureVars)) for _, cv := range closureVars { w.pos(cv.pos) @@ -1297,6 +1337,9 @@ func (w *writer) op(op ir.Op) { type typeDeclGen struct { *syntax.TypeDecl gen int + + // Implicit type parameters in scope at this type declaration. + implicits []*types2.TypeName } type fileImports struct { @@ -1308,6 +1351,19 @@ type declCollector struct { typegen *int file *fileImports withinFunc bool + implicits []*types2.TypeName +} + +func (c *declCollector) withTParams(obj types2.Object) *declCollector { + tparams := objTypeParams(obj) + if len(tparams) == 0 { + return c + } + + copy := *c + copy.implicits = copy.implicits[:len(copy.implicits):len(copy.implicits)] + copy.implicits = append(copy.implicits, objTypeParams(obj)...) + return © } func (c *declCollector) Visit(n syntax.Node) syntax.Visitor { @@ -1336,9 +1392,11 @@ func (c *declCollector) Visit(n syntax.Node) syntax.Visitor { obj := pw.info.Defs[n.Name].(*types2.Func) pw.funDecls[obj] = n + return c.withTParams(obj) + case *syntax.TypeDecl: obj := pw.info.Defs[n.Name].(*types2.TypeName) - d := typeDeclGen{TypeDecl: n} + d := typeDeclGen{TypeDecl: n, implicits: c.implicits} if n.Alias { pw.checkPragmas(n.Pragma, 0, false) @@ -1346,7 +1404,7 @@ func (c *declCollector) Visit(n syntax.Node) syntax.Visitor { pw.checkPragmas(n.Pragma, typePragmas, false) // Assign a unique ID to function-scoped defined types. - if !isGlobal(obj) { + if c.withinFunc { *c.typegen++ d.gen = *c.typegen } @@ -1354,6 +1412,12 @@ func (c *declCollector) Visit(n syntax.Node) syntax.Visitor { pw.typDecls[obj] = d + // TODO(mdempsky): Omit? Not strictly necessary; only matters for + // type declarations within function literals within parameterized + // type declarations, but types2 the function literals will be + // constant folded away. + return c.withTParams(obj) + case *syntax.VarDecl: pw.checkPragmas(n.Pragma, 0, true) @@ -1510,8 +1574,11 @@ func (w *writer) pkgDecl(decl syntax.Decl) { break // skip generic type decls } - name := w.p.info.Defs[decl.Name].(*types2.TypeName) + if decl.Name.Value == "_" { + break // skip blank type decls + } + name := w.p.info.Defs[decl.Name].(*types2.TypeName) // Skip type declarations for interfaces that are only usable as // type parameter bounds. if iface, ok := name.Type().Underlying().(*types2.Interface); ok && iface.IsConstraint() { @@ -1671,7 +1738,11 @@ func fieldIndex(info *types2.Info, str *types2.Struct, key *syntax.Name) int { func objTypeParams(obj types2.Object) []*types2.TypeName { switch obj := obj.(type) { case *types2.Func: - return obj.Type().(*types2.Signature).TParams() + sig := obj.Type().(*types2.Signature) + if sig.Recv() != nil { + return sig.RParams() + } + return sig.TParams() case *types2.TypeName: if !obj.IsAlias() { return obj.Type().(*types2.Named).TParams() From 0fa3265fe14c775668fc8272f47adf4fbaa60bac Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Tue, 29 Jun 2021 16:31:18 -0700 Subject: [PATCH 584/940] os: change example to avoid deprecated function The IsNotExist function is deprecated; change package example to avoid it and use the recommended way instead. Fixes #46976 Change-Id: I3c301d0a89b6bda42184df314ba8418062ca39ee Reviewed-on: https://go-review.googlesource.com/c/go/+/331692 Trust: Dmitri Shuralyov Reviewed-by: Ian Lance Taylor Reviewed-by: Robert Griesemer --- src/os/example_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/os/example_test.go b/src/os/example_test.go index 3adce517848..e8554b0b122 100644 --- a/src/os/example_test.go +++ b/src/os/example_test.go @@ -5,6 +5,7 @@ package os_test import ( + "errors" "fmt" "io/fs" "log" @@ -71,9 +72,9 @@ func ExampleFileMode() { } } -func ExampleIsNotExist() { +func ExampleErrNotExist() { filename := "a-nonexistent-file" - if _, err := os.Stat(filename); os.IsNotExist(err) { + if _, err := os.Stat(filename); errors.Is(err, fs.ErrNotExist) { fmt.Println("file does not exist") } // Output: From 7d0e9e6e74b45cf658257363151a79baf030033f Mon Sep 17 00:00:00 2001 From: uji Date: Wed, 30 Jun 2021 00:06:23 +0900 Subject: [PATCH 585/940] image/gif: fix typo in the comment (io.ReadByte -> io.ByteReader) Fixes #46967 Change-Id: I66e69c70b74e904623e8ca854562d255692b2143 Reviewed-on: https://go-review.googlesource.com/c/go/+/331649 Reviewed-by: Ian Lance Taylor Trust: Carlos Amedee --- src/image/gif/reader.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/image/gif/reader.go b/src/image/gif/reader.go index e580ab049e6..9e8268c86f3 100644 --- a/src/image/gif/reader.go +++ b/src/image/gif/reader.go @@ -116,7 +116,7 @@ type decoder struct { // consumed when checking that the blockReader is exhausted. // // To avoid the allocation of a bufio.Reader for the lzw Reader, blockReader -// implements io.ReadByte and buffers blocks into the decoder's "tmp" buffer. +// implements io.ByteReader and buffers blocks into the decoder's "tmp" buffer. type blockReader struct { d *decoder i, j uint8 // d.tmp[i:j] contains the buffered bytes From c080d0323bce56e25622a51dffecf756758c95a1 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 30 Jun 2021 10:19:02 -0700 Subject: [PATCH 586/940] cmd/dist: pass -Wno-unknown-warning-option in swig_callback_lto For #46557 Fixes #46991 Change-Id: Ic88ebaa13d3edf904657dc19ada4fd4ff7f44a8f Reviewed-on: https://go-review.googlesource.com/c/go/+/332010 Trust: Ian Lance Taylor Trust: Josh Bleecher Snyder Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Josh Bleecher Snyder --- src/cmd/dist/test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index f2c4cf0b430..4acd357974c 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -737,9 +737,9 @@ func (t *tester) registerTests() { fn: func(dt *distTest) error { cmd := t.addCmd(dt, "misc/swig/callback", t.goTest()) cmd.Env = append(os.Environ(), - "CGO_CFLAGS=-flto -Wno-lto-type-mismatch", - "CGO_CXXFLAGS=-flto -Wno-lto-type-mismatch", - "CGO_LDFLAGS=-flto -Wno-lto-type-mismatch", + "CGO_CFLAGS=-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option", + "CGO_CXXFLAGS=-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option", + "CGO_LDFLAGS=-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option", ) return nil }, From 4b5fdb0b7a362cb6fa6ad551757104e490483121 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 17 Jun 2021 17:49:15 -0700 Subject: [PATCH 587/940] [dev.typeparams] cmd/compile/internal/types2: introduce type set abstraction for interfaces With this change, interfaces are "completed" on-demand, when needed, and the respective information (set of all methods, type constraints) is recorded in a new typeSet data structure. As a consequence, interfaces don't need to be explicitly completed anymore and (internal) uses of interfaces have become much simpler. This change also introduces a new field Interface.complete to indicate that all methods and embedded elements have been set up. This prevent the computation and recording (!) of a partial type set for erroneous programs (if we compute the partial type set and store it, subsequent type set accesses use the wrong type set which may lead to follow-on errors). Change-Id: I1ffc907f7d0fb93b3e987fe5ff9c6fa5cae00d7f Reviewed-on: https://go-review.googlesource.com/c/go/+/329309 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/builtins.go | 2 +- src/cmd/compile/internal/types2/call.go | 1 - src/cmd/compile/internal/types2/expr.go | 1 - src/cmd/compile/internal/types2/infer.go | 27 ++-- src/cmd/compile/internal/types2/interface.go | 64 +++++----- src/cmd/compile/internal/types2/lookup.go | 17 +-- src/cmd/compile/internal/types2/predicates.go | 12 +- src/cmd/compile/internal/types2/sanitize.go | 8 +- .../compile/internal/types2/sizeof_test.go | 3 +- src/cmd/compile/internal/types2/subst.go | 15 ++- .../types2/testdata/check/cycles4.src | 15 ++- src/cmd/compile/internal/types2/type.go | 119 ++++++------------ src/cmd/compile/internal/types2/typeset.go | 70 +++++++++++ src/cmd/compile/internal/types2/typestring.go | 13 +- src/cmd/compile/internal/types2/typexpr.go | 8 +- src/cmd/compile/internal/types2/unify.go | 12 +- src/cmd/compile/internal/types2/universe.go | 4 +- 17 files changed, 205 insertions(+), 186 deletions(-) create mode 100644 src/cmd/compile/internal/types2/typeset.go diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index 8f2d849ef52..ffe872e7ab4 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -783,7 +783,7 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { tpar := NewTypeName(nopos, check.pkg, "", nil) ptyp := check.NewTypeParam(tpar, 0, &emptyInterface) // assigns type to tpar as a side-effect tsum := newUnion(rtypes, tildes) - ptyp.bound = &Interface{allMethods: markComplete, allTypes: tsum} + ptyp.bound = &Interface{complete: true, tset: &TypeSet{types: tsum}} return ptyp } diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index 8c717cd1e58..8c17a2f8080 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -99,7 +99,6 @@ func (check *Checker) callExpr(x *operand, call *syntax.CallExpr) exprKind { check.expr(x, call.ArgList[0]) if x.mode != invalid { if t := asInterface(T); t != nil { - check.completeInterface(nopos, t) if t.IsConstraint() { check.errorf(call, "cannot use interface %s in conversion (contains type list or is comparable)", T) break diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go index d1cb27de160..7fba179e444 100644 --- a/src/cmd/compile/internal/types2/expr.go +++ b/src/cmd/compile/internal/types2/expr.go @@ -735,7 +735,6 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const // Update operand types to the default type rather than the target // (interface) type: values must have concrete dynamic types. // Untyped nil was handled upfront. - check.completeInterface(nopos, t) if !t.Empty() { return nil, nil, _InvalidUntypedConversion // cannot assign untyped values to non-empty interfaces } diff --git a/src/cmd/compile/internal/types2/infer.go b/src/cmd/compile/internal/types2/infer.go index 63cd63aacc6..791e25e9f0c 100644 --- a/src/cmd/compile/internal/types2/infer.go +++ b/src/cmd/compile/internal/types2/infer.go @@ -321,24 +321,13 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { return w.isParameterized(t.params) || w.isParameterized(t.results) case *Interface: - if t.allMethods != nil { - // interface is complete - quick test - for _, m := range t.allMethods { - if w.isParameterized(m.typ) { - return true - } + tset := t.typeSet() + for _, m := range tset.methods { + if w.isParameterized(m.typ) { + return true } - return w.isParameterized(t.allTypes) } - - return t.iterate(func(t *Interface) bool { - for _, m := range t.methods { - if w.isParameterized(m.typ) { - return true - } - } - return w.isParameterizedList(t.embeddeds) - }, nil) + return w.isParameterized(tset.types) case *Map: return w.isParameterized(t.key) || w.isParameterized(t.elem) @@ -476,15 +465,15 @@ func (check *Checker) inferB(tparams []*TypeName, targs []Type, report bool) (ty // structuralType returns the structural type of a constraint, if any. func (check *Checker) structuralType(constraint Type) Type { if iface, _ := under(constraint).(*Interface); iface != nil { - check.completeInterface(nopos, iface) - if u, _ := iface.allTypes.(*Union); u != nil { + types := iface.typeSet().types + if u, _ := types.(*Union); u != nil { if u.NumTerms() == 1 { // TODO(gri) do we need to respect tilde? return u.types[0] } return nil } - return iface.allTypes + return types } return nil } diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go index c79026f00dd..4dee9234221 100644 --- a/src/cmd/compile/internal/types2/interface.go +++ b/src/cmd/compile/internal/types2/interface.go @@ -95,9 +95,13 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType check.posMap[ityp] = append(check.posMap[ityp], tlist[0].(*syntax.Operation).X.Pos()) } + // All methods and embedded elements for this interface are collected; + // i.e., this interface is may be used in a type set computation. + ityp.complete = true + if len(ityp.methods) == 0 && len(ityp.embeddeds) == 0 { // empty interface - ityp.allMethods = markComplete + ityp.tset = &topTypeSet return } @@ -105,7 +109,10 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType sortMethods(ityp.methods) sortTypes(ityp.embeddeds) - check.later(func() { check.completeInterface(iface.Pos(), ityp) }) + // Compute type set with a non-nil *Checker as soon as possible + // to report any errors. Subsequent uses of type sets should be + // using this computed type set and won't need to pass in a *Checker. + check.later(func() { newTypeSet(check, iface.Pos(), ityp) }) } func flattenUnion(list []syntax.Expr, x syntax.Expr) []syntax.Expr { @@ -116,26 +123,27 @@ func flattenUnion(list []syntax.Expr, x syntax.Expr) []syntax.Expr { return append(list, x) } -func (check *Checker) completeInterface(pos syntax.Pos, ityp *Interface) { - if ityp.allMethods != nil { - return +// newTypeSet may be called with check == nil. +// TODO(gri) move this function into typeset.go eventually +func newTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet { + if ityp.tset != nil { + return ityp.tset } - // completeInterface may be called via the LookupFieldOrMethod, - // MissingMethod, Identical, or IdenticalIgnoreTags external API - // in which case check will be nil. In this case, type-checking - // must be finished and all interfaces should have been completed. - if check == nil { - panic("internal error: incomplete interface") + // If the interface is not fully set up yet, the type set will + // not be complete, which may lead to errors when using the the + // type set (e.g. missing method). Don't compute a partial type + // set (and don't store it!), so that we still compute the full + // type set eventually. Instead, return the top type set and + // let any follow-on errors play out. + // + // TODO(gri) Consider recording when this happens and reporting + // it as an error (but only if there were no other errors so to + // to not have unnecessary follow-on errors). + if !ityp.complete { + return &topTypeSet } - completeInterface(check, pos, ityp) -} - -// completeInterface may be called with check == nil. -func completeInterface(check *Checker, pos syntax.Pos, ityp *Interface) { - assert(ityp.allMethods == nil) - if check != nil && check.conf.Trace { // Types don't generally have position information. // If we don't have a valid pos provided, try to use @@ -144,11 +152,11 @@ func completeInterface(check *Checker, pos syntax.Pos, ityp *Interface) { pos = ityp.methods[0].pos } - check.trace(pos, "complete %s", ityp) + check.trace(pos, "type set for %s", ityp) check.indent++ defer func() { check.indent-- - check.trace(pos, "=> %s (methods = %v, types = %v)", ityp, ityp.allMethods, ityp.allTypes) + check.trace(pos, "=> %s ", ityp.typeSet()) }() } @@ -157,7 +165,7 @@ func completeInterface(check *Checker, pos syntax.Pos, ityp *Interface) { // have valid interfaces. Mark the interface as complete to avoid // infinite recursion if the validType check occurs later for some // reason. - ityp.allMethods = markComplete + ityp.tset = new(TypeSet) // TODO(gri) is this sufficient? // Methods of embedded interfaces are collected unchanged; i.e., the identity // of a method I.m's Func Object of an interface I is the same as that of @@ -231,13 +239,11 @@ func completeInterface(check *Checker, pos syntax.Pos, ityp *Interface) { var types Type switch t := under(typ).(type) { case *Interface: - if t.allMethods == nil { - completeInterface(check, pos, t) - } - for _, m := range t.allMethods { + tset := newTypeSet(check, pos, t) + for _, m := range tset.methods { addMethod(pos, m, false) // use embedding position pos rather than m.pos } - types = t.allTypes + types = tset.types case *Union: // TODO(gri) combine with default case once we have // converted all tests to new notation and we @@ -274,9 +280,11 @@ func completeInterface(check *Checker, pos syntax.Pos, ityp *Interface) { if methods != nil { sortMethods(methods) - ityp.allMethods = methods + ityp.tset.methods = methods } - ityp.allTypes = allTypes + ityp.tset.types = allTypes + + return ityp.tset } func sortTypes(list []Type) { diff --git a/src/cmd/compile/internal/types2/lookup.go b/src/cmd/compile/internal/types2/lookup.go index 93ed620449e..9fcec44d534 100644 --- a/src/cmd/compile/internal/types2/lookup.go +++ b/src/cmd/compile/internal/types2/lookup.go @@ -182,9 +182,7 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack case *Interface: // look for a matching method - // TODO(gri) t.allMethods is sorted - use binary search - check.completeInterface(nopos, t) - if i, m := lookupMethod(t.allMethods, pkg, name); m != nil { + if i, m := t.typeSet().LookupMethod(pkg, name); m != nil { assert(m.typ != nil) index = concat(e.index, i) if obj != nil || e.multiples { @@ -195,7 +193,7 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack } case *TypeParam: - if i, m := lookupMethod(t.Bound().allMethods, pkg, name); m != nil { + if i, m := t.Bound().typeSet().LookupMethod(pkg, name); m != nil { assert(m.typ != nil) index = concat(e.index, i) if obj != nil || e.multiples { @@ -307,18 +305,15 @@ func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType b // To improve error messages, also report the wrong signature // when the method exists on *V instead of V. func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, wrongType *Func) { - check.completeInterface(nopos, T) - // fast path for common case if T.Empty() { return } if ityp := asInterface(V); ityp != nil { - check.completeInterface(nopos, ityp) - // TODO(gri) allMethods is sorted - can do this more efficiently - for _, m := range T.allMethods { - _, f := lookupMethod(ityp.allMethods, m.pkg, m.name) + // TODO(gri) the methods are sorted - could do this more efficiently + for _, m := range T.typeSet().methods { + _, f := ityp.typeSet().LookupMethod(m.pkg, m.name) if f == nil { // if m is the magic method == we're ok (interfaces are comparable) @@ -356,7 +351,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // A concrete type implements T if it implements all methods of T. Vd, _ := deref(V) Vn := asNamed(Vd) - for _, m := range T.allMethods { + for _, m := range T.typeSet().methods { // TODO(gri) should this be calling lookupFieldOrMethod instead (and why not)? obj, _, _ := check.rawLookupFieldOrMethod(V, false, m.pkg, m.name) diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go index 66de2490440..73af1271886 100644 --- a/src/cmd/compile/internal/types2/predicates.go +++ b/src/cmd/compile/internal/types2/predicates.go @@ -287,16 +287,8 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { // the same names and identical function types. Lower-case method names from // different packages are always different. The order of the methods is irrelevant. if y, ok := y.(*Interface); ok { - // If identical0 is called (indirectly) via an external API entry point - // (such as Identical, IdenticalIgnoreTags, etc.), check is nil. But in - // that case, interfaces are expected to be complete and lazy completion - // here is not needed. - if check != nil { - check.completeInterface(nopos, x) - check.completeInterface(nopos, y) - } - a := x.allMethods - b := y.allMethods + a := x.typeSet().methods + b := y.typeSet().methods if len(a) == len(b) { // Interface types are the only types where cycles can occur // that are not "terminated" via named types; and such cycles diff --git a/src/cmd/compile/internal/types2/sanitize.go b/src/cmd/compile/internal/types2/sanitize.go index 406b46e574c..3d2323a0a29 100644 --- a/src/cmd/compile/internal/types2/sanitize.go +++ b/src/cmd/compile/internal/types2/sanitize.go @@ -112,9 +112,11 @@ func (s sanitizer) typ(typ Type) Type { case *Interface: s.funcList(t.methods) s.typeList(t.embeddeds) - s.funcList(t.allMethods) - if allTypes := s.typ(t.allTypes); allTypes != t.allTypes { - t.allTypes = allTypes + // TODO(gri) do we need to sanitize type sets? + tset := t.typeSet() + s.funcList(tset.methods) + if types := s.typ(tset.types); types != tset.types { + tset.types = types } case *Map: diff --git a/src/cmd/compile/internal/types2/sizeof_test.go b/src/cmd/compile/internal/types2/sizeof_test.go index 3cb162764c8..0b1f7dacad3 100644 --- a/src/cmd/compile/internal/types2/sizeof_test.go +++ b/src/cmd/compile/internal/types2/sizeof_test.go @@ -28,7 +28,7 @@ func TestSizeof(t *testing.T) { {Tuple{}, 12, 24}, {Signature{}, 44, 88}, {Union{}, 24, 48}, - {Interface{}, 52, 104}, + {Interface{}, 40, 80}, {Map{}, 16, 32}, {Chan{}, 12, 24}, {Named{}, 84, 160}, @@ -49,6 +49,7 @@ func TestSizeof(t *testing.T) { // Misc {Scope{}, 56, 96}, {Package{}, 40, 80}, + {TypeSet{}, 20, 40}, } for _, test := range tests { diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index 3ef65c2e923..38bd07b8a28 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -136,6 +136,7 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, poslis // satisfies reports whether the type argument targ satisfies the constraint of type parameter // parameter tpar (after any of its type parameters have been substituted through smap). // A suitable error is reported if the result is false. +// TODO(gri) This should be a method of interfaces or type sets. func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap *substMap) bool { iface := tpar.Bound() if iface.Empty() { @@ -150,8 +151,7 @@ func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap // targ must implement iface (methods) // - check only if we have methods - check.completeInterface(nopos, iface) - if len(iface.allMethods) > 0 { + if iface.NumMethods() > 0 { // If the type argument is a pointer to a type parameter, the type argument's // method set is empty. // TODO(gri) is this what we want? (spec question) @@ -182,7 +182,7 @@ func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap } // targ's underlying type must also be one of the interface types listed, if any - if iface.allTypes == nil { + if iface.typeSet().types == nil { return true // nothing to do } @@ -190,7 +190,7 @@ func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap // list of iface types (i.e., the targ type list must be a non-empty subset of the iface types). if targ := asTypeParam(targ); targ != nil { targBound := targ.Bound() - if targBound.allTypes == nil { + if targBound.typeSet().types == nil { check.softErrorf(pos, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ) return false } @@ -198,7 +198,7 @@ func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap // TODO(gri) incorporate tilde information! if !iface.isSatisfiedBy(typ) { // TODO(gri) match this error message with the one below (or vice versa) - check.softErrorf(pos, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, typ, iface.allTypes) + check.softErrorf(pos, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, typ, iface.typeSet().types) return false } return true @@ -207,7 +207,7 @@ func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap // Otherwise, targ's type or underlying type must also be one of the interface types listed, if any. if !iface.isSatisfiedBy(targ) { - check.softErrorf(pos, "%s does not satisfy %s (%s not found in %s)", targ, tpar.bound, targ, iface.allTypes) + check.softErrorf(pos, "%s does not satisfy %s (%s not found in %s)", targ, tpar.bound, targ, iface.typeSet().types) return false } @@ -312,12 +312,11 @@ func (subst *subster) typ(typ Type) Type { methods, mcopied := subst.funcList(t.methods) embeddeds, ecopied := subst.typeList(t.embeddeds) if mcopied || ecopied { - iface := &Interface{methods: methods, embeddeds: embeddeds} + iface := &Interface{methods: methods, embeddeds: embeddeds, complete: t.complete} if subst.check == nil { panic("internal error: cannot instantiate interfaces yet") } subst.check.posMap[iface] = subst.check.posMap[t] // satisfy completeInterface requirement - subst.check.completeInterface(nopos, iface) return iface } diff --git a/src/cmd/compile/internal/types2/testdata/check/cycles4.src b/src/cmd/compile/internal/types2/testdata/check/cycles4.src index 445babca68b..924aabf475f 100644 --- a/src/cmd/compile/internal/types2/testdata/check/cycles4.src +++ b/src/cmd/compile/internal/types2/testdata/check/cycles4.src @@ -4,6 +4,8 @@ package p +import "unsafe" + // Check that all methods of T are collected before // determining the result type of m (which embeds // all methods of T). @@ -13,7 +15,7 @@ type T interface { E } -var _ = T.m(nil).m().e() +var _ int = T.m(nil).m().e() type E interface { e() int @@ -22,7 +24,7 @@ type E interface { // Check that unresolved forward chains are followed // (see also comment in resolver.go, checker.typeDecl). -var _ = C.m(nil).m().e() +var _ int = C.m(nil).m().e() type A B @@ -108,3 +110,12 @@ type Element interface { type Event interface { Target() Element } + +// Check that accessing an interface method too early doesn't lead +// to follow-on errors due to an incorrectly computed type set. + +type T8 interface { + m() [unsafe.Sizeof(T8.m /* ERROR undefined */ )]int +} + +var _ = T8.m // no error expected here diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index 10cb651d0c2..122e408eade 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -264,18 +264,20 @@ func (s *Signature) Variadic() bool { return s.variadic } // An Interface represents an interface type. type Interface struct { + obj Object // type name object defining this interface; or nil (for better error messages) methods []*Func // ordered list of explicitly declared methods - embeddeds []Type // ordered list of explicitly embedded types + embeddeds []Type // ordered list of explicitly embedded elements + complete bool // indicates that obj, methods, and embeddeds are set and type set can be computed - allMethods []*Func // ordered list of methods declared with or embedded in this interface (TODO(gri): replace with mset) - allTypes Type // intersection of all embedded and locally declared types (TODO(gri) need better field name) - - obj Object // type declaration defining this interface; or nil (for better error messages) + tset *TypeSet // type set described by this interface, computed lazily } +// typeSet returns the type set for interface t. +func (t *Interface) typeSet() *TypeSet { return newTypeSet(nil, nopos, t) } + // is reports whether interface t represents types that all satisfy f. func (t *Interface) is(f func(Type, bool) bool) bool { - switch t := t.allTypes.(type) { + switch t := t.typeSet().types.(type) { case nil, *top: // TODO(gri) should settle on top or nil to represent this case return false // we must have at least one type! (was bug) @@ -286,21 +288,14 @@ func (t *Interface) is(f func(Type, bool) bool) bool { } } -// emptyInterface represents the empty (completed) interface -var emptyInterface = Interface{allMethods: markComplete} +// emptyInterface represents the empty interface +var emptyInterface = Interface{complete: true, tset: &topTypeSet} -// markComplete is used to mark an empty interface as completely -// set up by setting the allMethods field to a non-nil empty slice. -var markComplete = make([]*Func, 0) - -// NewInterface returns a new (incomplete) interface for the given methods and embedded types. -// Each embedded type must have an underlying type of interface type. -// NewInterface takes ownership of the provided methods and may modify their types by setting -// missing receivers. To compute the method set of the interface, Complete must be called. +// NewInterface returns a new interface for the given methods and embedded types. +// NewInterface takes ownership of the provided methods and may modify their types +// by setting missing receivers. // -// Deprecated: Use NewInterfaceType instead which allows any (even non-defined) interface types -// to be embedded. This is necessary for interfaces that embed alias type names referring to -// non-defined (literal) interface types. +// Deprecated: Use NewInterfaceType instead which allows arbitrary embedded types. func NewInterface(methods []*Func, embeddeds []*Named) *Interface { tnames := make([]Type, len(embeddeds)) for i, t := range embeddeds { @@ -309,9 +304,9 @@ func NewInterface(methods []*Func, embeddeds []*Named) *Interface { return NewInterfaceType(methods, tnames) } -// NewInterfaceType returns a new (incomplete) interface for the given methods and embedded types. -// NewInterfaceType takes ownership of the provided methods and may modify their types by setting -// missing receivers. To compute the method set of the interface, Complete must be called. +// NewInterfaceType returns a new interface for the given methods and embedded types. +// NewInterfaceType takes ownership of the provided methods and may modify their types +// by setting missing receivers. func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface { if len(methods) == 0 && len(embeddeds) == 0 { return &emptyInterface @@ -331,6 +326,8 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface { typ.methods = methods typ.embeddeds = embeddeds + typ.complete = true + return typ } @@ -354,72 +351,27 @@ func (t *Interface) Embedded(i int) *Named { tname, _ := t.embeddeds[i].(*Named) func (t *Interface) EmbeddedType(i int) Type { return t.embeddeds[i] } // NumMethods returns the total number of methods of interface t. -// The interface must have been completed. -func (t *Interface) NumMethods() int { t.Complete(); return len(t.allMethods) } +func (t *Interface) NumMethods() int { return t.typeSet().NumMethods() } // Method returns the i'th method of interface t for 0 <= i < t.NumMethods(). // The methods are ordered by their unique Id. -// The interface must have been completed. -func (t *Interface) Method(i int) *Func { t.Complete(); return t.allMethods[i] } +func (t *Interface) Method(i int) *Func { return t.typeSet().Method(i) } // Empty reports whether t is the empty interface. -func (t *Interface) Empty() bool { - t.Complete() - return len(t.allMethods) == 0 && t.allTypes == nil -} - -// HasTypeList reports whether interface t has a type list, possibly from an embedded type. -func (t *Interface) HasTypeList() bool { - t.Complete() - return t.allTypes != nil -} +func (t *Interface) Empty() bool { return t.typeSet().IsTop() } // IsComparable reports whether interface t is or embeds the predeclared interface "comparable". -func (t *Interface) IsComparable() bool { - t.Complete() - _, m := lookupMethod(t.allMethods, nil, "==") - return m != nil -} +func (t *Interface) IsComparable() bool { return t.typeSet().IsComparable() } -// IsConstraint reports t.HasTypeList() || t.IsComparable(). -func (t *Interface) IsConstraint() bool { - return t.HasTypeList() || t.IsComparable() -} - -// iterate calls f with t and then with any embedded interface of t, recursively, until f returns true. -// iterate reports whether any call to f returned true. -// TODO(gri) This is now only used by infer.go - see if we can eliminate it. -func (t *Interface) iterate(f func(*Interface) bool, seen map[*Interface]bool) bool { - if f(t) { - return true - } - for _, e := range t.embeddeds { - // e should be an interface but be careful (it may be invalid) - if e := asInterface(e); e != nil { - // Cyclic interfaces such as "type E interface { E }" are not permitted - // but they are still constructed and we need to detect such cycles. - if seen[e] { - continue - } - if seen == nil { - seen = make(map[*Interface]bool) - } - seen[e] = true - if e.iterate(f, seen) { - return true - } - } - } - return false -} +// IsConstraint reports whether interface t is not just a method set. +func (t *Interface) IsConstraint() bool { return !t.typeSet().IsMethodSet() } // isSatisfiedBy reports whether interface t's type list is satisfied by the type typ. // If the type list is empty (absent), typ trivially satisfies the interface. // TODO(gri) This is not a great name. Eventually, we should have a more comprehensive // "implements" predicate. func (t *Interface) isSatisfiedBy(typ Type) bool { - t.Complete() - switch t := t.allTypes.(type) { + switch t := t.typeSet().types.(type) { case nil: return true // no type restrictions case *Union: @@ -430,15 +382,22 @@ func (t *Interface) isSatisfiedBy(typ Type) bool { } } -// Complete computes the interface's method set. It must be called by users of +// Complete computes the interface's type set. It must be called by users of // NewInterfaceType and NewInterface after the interface's embedded types are // fully defined and before using the interface type in any way other than to // form other types. The interface must not contain duplicate methods or a // panic occurs. Complete returns the receiver. +// +// Deprecated: Type sets are now computed lazily, on demand; this function +// is only here for backward-compatibility. It does not have to +// be called explicitly anymore. func (t *Interface) Complete() *Interface { - if t.allMethods == nil { - completeInterface(nil, nopos, t) - } + // Some tests are still depending on the state change + // (string representation of an Interface not containing an + // /* incomplete */ marker) caused by the explicit Complete + // call, so we compute the type set eagerly here. + t.complete = true + t.typeSet() return t } @@ -674,7 +633,7 @@ func (t *TypeParam) Bound() *Interface { pos = n.obj.pos } // TODO(gri) switch this to an unexported method on Checker. - t.check.completeInterface(pos, iface) + newTypeSet(t.check, pos, iface) return iface } @@ -700,7 +659,7 @@ func optype(typ Type) Type { // for a type parameter list of the form: // (type T interface { type T }). // See also issue #39680. - if a := t.Bound().allTypes; a != nil { + if a := t.Bound().typeSet().types; a != nil { // If we have a union with a single entry, ignore // any tilde because under(~t) == under(t). if u, _ := a.(*Union); u != nil && u.NumTerms() == 1 { diff --git a/src/cmd/compile/internal/types2/typeset.go b/src/cmd/compile/internal/types2/typeset.go new file mode 100644 index 00000000000..44e59294133 --- /dev/null +++ b/src/cmd/compile/internal/types2/typeset.go @@ -0,0 +1,70 @@ +// Copyright 2021 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 types2 + +import ( + "bytes" +) + +// topTypeSet may be used as type set for the empty interface. +var topTypeSet TypeSet + +// A TypeSet represents the type set of an interface. +type TypeSet struct { + // TODO(gri) consider using a set for the methods for faster lookup + methods []*Func // all methods of the interface; sorted by unique ID + types Type // typically a *Union; nil means no type restrictions +} + +func (s *TypeSet) String() string { + if s.IsTop() { + return "⊤" + } + + var buf bytes.Buffer + buf.WriteByte('{') + for i, m := range s.methods { + if i > 0 { + buf.WriteByte(';') + } + buf.WriteByte(' ') + buf.WriteString(m.String()) + } + if len(s.methods) > 0 && s.types != nil { + buf.WriteByte(';') + } + if s.types != nil { + buf.WriteByte(' ') + writeType(&buf, s.types, nil, nil) + } + + buf.WriteString(" }") // there was a least one method or type + return buf.String() +} + +// IsTop reports whether type set s is the top type set (corresponding to the empty interface). +func (s *TypeSet) IsTop() bool { return len(s.methods) == 0 && s.types == nil } + +// IsMethodSet reports whether the type set s is described by a single set of methods. +func (s *TypeSet) IsMethodSet() bool { return s.types == nil && !s.IsComparable() } + +// IsComparable reports whether each type in the set is comparable. +func (s *TypeSet) IsComparable() bool { + _, m := s.LookupMethod(nil, "==") + return m != nil +} + +// NumMethods returns the number of methods available. +func (s *TypeSet) NumMethods() int { return len(s.methods) } + +// Method returns the i'th method of type set s for 0 <= i < s.NumMethods(). +// The methods are ordered by their unique ID. +func (s *TypeSet) Method(i int) *Func { return s.methods[i] } + +// LookupMethod returns the index of and method with matching package and name, or (-1, nil). +func (s *TypeSet) LookupMethod(pkg *Package, name string) (int, *Func) { + // TODO(gri) s.methods is sorted - consider binary search + return lookupMethod(s.methods, pkg, name) +} diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go index f08c41c2a35..4925252b394 100644 --- a/src/cmd/compile/internal/types2/typestring.go +++ b/src/cmd/compile/internal/types2/typestring.go @@ -189,7 +189,8 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { if gcCompatibilityMode { // print flattened interface // (useful to compare against gc-generated interfaces) - for i, m := range t.allMethods { + tset := t.typeSet() + for i, m := range tset.methods { if i > 0 { buf.WriteString("; ") } @@ -197,12 +198,12 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { writeSignature(buf, m.typ.(*Signature), qf, visited) empty = false } - if !empty && t.allTypes != nil { + if !empty && tset.types != nil { buf.WriteString("; ") } - if t.allTypes != nil { + if tset.types != nil { buf.WriteString("type ") - writeType(buf, t.allTypes, qf, visited) + writeType(buf, tset.types, qf, visited) } } else { // print explicit interface methods and embedded types @@ -225,7 +226,9 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { empty = false } } - if debug && (t.allMethods == nil || len(t.methods) > len(t.allMethods)) { + // print /* incomplete */ if needed to satisfy existing tests + // TODO(gri) get rid of this eventually + if debug && t.tset == nil { if !empty { buf.WriteByte(' ') } diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index 583bb464b20..fe676be2efd 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -141,12 +141,12 @@ func (check *Checker) ordinaryType(pos syntax.Pos, typ Type) { // interface methods. Delay this check to the end of type-checking. check.later(func() { if t := asInterface(typ); t != nil { - check.completeInterface(pos, t) // TODO(gri) is this the correct position? - if t.allTypes != nil { - check.softErrorf(pos, "interface contains type constraints (%s)", t.allTypes) + tset := newTypeSet(check, pos, t) // TODO(gri) is this the correct position? + if tset.types != nil { + check.softErrorf(pos, "interface contains type constraints (%s)", tset.types) return } - if t.IsComparable() { + if tset.IsComparable() { check.softErrorf(pos, "interface is (or embeds) comparable") } } diff --git a/src/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go index e5983dd40c6..9a51dcb6d47 100644 --- a/src/cmd/compile/internal/types2/unify.go +++ b/src/cmd/compile/internal/types2/unify.go @@ -361,16 +361,8 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool { // the same names and identical function types. Lower-case method names from // different packages are always different. The order of the methods is irrelevant. if y, ok := y.(*Interface); ok { - // If identical0 is called (indirectly) via an external API entry point - // (such as Identical, IdenticalIgnoreTags, etc.), check is nil. But in - // that case, interfaces are expected to be complete and lazy completion - // here is not needed. - if u.check != nil { - u.check.completeInterface(nopos, x) - u.check.completeInterface(nopos, y) - } - a := x.allMethods - b := y.allMethods + a := x.typeSet().methods + b := y.typeSet().methods if len(a) == len(b) { // Interface types are the only types where cycles can occur // that are not "terminated" via named types; and such cycles diff --git a/src/cmd/compile/internal/types2/universe.go b/src/cmd/compile/internal/types2/universe.go index 76d4e55e84b..2bcc49778ef 100644 --- a/src/cmd/compile/internal/types2/universe.go +++ b/src/cmd/compile/internal/types2/universe.go @@ -88,7 +88,7 @@ func defPredeclaredTypes() { res := NewVar(nopos, nil, "", Typ[String]) sig := &Signature{results: NewTuple(res)} err := NewFunc(nopos, nil, "Error", sig) - typ := &Named{underlying: NewInterfaceType([]*Func{err}, nil).Complete()} + typ := &Named{underlying: NewInterfaceType([]*Func{err}, nil)} sig.recv = NewVar(nopos, nil, "", typ) def(NewTypeName(nopos, nil, "error", typ)) } @@ -216,7 +216,7 @@ func defPredeclaredComparable() { // set up later to match the usual interface method assumptions. sig := new(Signature) eql := NewFunc(nopos, nil, "==", sig) - iface := NewInterfaceType([]*Func{eql}, nil).Complete() + iface := NewInterfaceType([]*Func{eql}, nil) // set up the defined type for the interface obj := NewTypeName(nopos, nil, "comparable", nil) From 1ff43d1b179eb96a34b9007e10d78e2278643f3f Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 28 Jun 2021 16:00:26 -0700 Subject: [PATCH 588/940] [dev.typeparams] cmd/compile/internal/types2: remove unused *Checker arguments (cleanup) Simplified names and unnecessary function indirections where possible. Change-Id: I1c7a386393d086fd7ad29f892e03f048781f3547 Reviewed-on: https://go-review.googlesource.com/c/go/+/331512 Trust: Robert Griesemer Run-TryBot: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/api.go | 4 +- src/cmd/compile/internal/types2/builtins.go | 6 +-- src/cmd/compile/internal/types2/call.go | 4 +- .../compile/internal/types2/conversions.go | 6 +-- src/cmd/compile/internal/types2/expr.go | 6 +-- src/cmd/compile/internal/types2/infer.go | 4 +- src/cmd/compile/internal/types2/interface.go | 2 +- src/cmd/compile/internal/types2/lookup.go | 45 ++++++++----------- src/cmd/compile/internal/types2/operand.go | 8 ++-- src/cmd/compile/internal/types2/predicates.go | 40 ++++++----------- src/cmd/compile/internal/types2/stmt.go | 4 +- src/cmd/compile/internal/types2/unify.go | 13 +++--- 12 files changed, 61 insertions(+), 81 deletions(-) diff --git a/src/cmd/compile/internal/types2/api.go b/src/cmd/compile/internal/types2/api.go index 4f7f35e61b2..ae4fb6ad109 100644 --- a/src/cmd/compile/internal/types2/api.go +++ b/src/cmd/compile/internal/types2/api.go @@ -430,11 +430,11 @@ func Implements(V Type, T *Interface) bool { // Identical reports whether x and y are identical types. // Receivers of Signature types are ignored. func Identical(x, y Type) bool { - return (*Checker)(nil).identical(x, y) + return identical(x, y, true, nil) } // IdenticalIgnoreTags reports whether x and y are identical types if tags are ignored. // Receivers of Signature types are ignored. func IdenticalIgnoreTags(x, y Type) bool { - return (*Checker)(nil).identicalIgnoreTags(x, y) + return identical(x, y, false, nil) } diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index ffe872e7ab4..7ba26509e8d 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -281,7 +281,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( } // both argument types must be identical - if !check.identical(x.typ, y.typ) { + if !Identical(x.typ, y.typ) { check.errorf(x, invalidOp+"%v (mismatched types %s and %s)", call, x.typ, y.typ) return } @@ -346,7 +346,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( return } - if !check.identical(dst, src) { + if !Identical(dst, src) { check.errorf(x, invalidArg+"arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src) return } @@ -635,7 +635,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( base := derefStructPtr(x.typ) sel := selx.Sel.Value - obj, index, indirect := check.lookupFieldOrMethod(base, false, check.pkg, sel) + obj, index, indirect := LookupFieldOrMethod(base, false, check.pkg, sel) switch obj.(type) { case nil: check.errorf(x, invalidArg+"%s has no single field %s", base, sel) diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index 8c17a2f8080..34dafce8bf7 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -467,7 +467,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) { check.instantiatedOperand(x) - obj, index, indirect = check.lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel) + obj, index, indirect = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel) if obj == nil { switch { case index != nil: @@ -497,7 +497,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) { } else { changeCase = string(unicode.ToUpper(r)) + sel[1:] } - if obj, _, _ = check.lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, changeCase); obj != nil { + if obj, _, _ = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, changeCase); obj != nil { why += ", but does have " + changeCase } } diff --git a/src/cmd/compile/internal/types2/conversions.go b/src/cmd/compile/internal/types2/conversions.go index 30201e2b7f4..6c26a4c4468 100644 --- a/src/cmd/compile/internal/types2/conversions.go +++ b/src/cmd/compile/internal/types2/conversions.go @@ -93,7 +93,7 @@ func (x *operand) convertibleTo(check *Checker, T Type) bool { V := x.typ Vu := under(V) Tu := under(T) - if check.identicalIgnoreTags(Vu, Tu) { + if IdenticalIgnoreTags(Vu, Tu) { return true } @@ -101,7 +101,7 @@ func (x *operand) convertibleTo(check *Checker, T Type) bool { // have identical underlying types if tags are ignored" if V, ok := V.(*Pointer); ok { if T, ok := T.(*Pointer); ok { - if check.identicalIgnoreTags(under(V.base), under(T.base)) { + if IdenticalIgnoreTags(under(V.base), under(T.base)) { return true } } @@ -142,7 +142,7 @@ func (x *operand) convertibleTo(check *Checker, T Type) bool { if s := asSlice(V); s != nil { if p := asPointer(T); p != nil { if a := asArray(p.Elem()); a != nil { - if check.identical(s.Elem(), a.Elem()) { + if Identical(s.Elem(), a.Elem()) { if check == nil || check.allowVersion(check.pkg, 1, 17) { return true } diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go index 7fba179e444..1cb0ad4752b 100644 --- a/src/cmd/compile/internal/types2/expr.go +++ b/src/cmd/compile/internal/types2/expr.go @@ -1000,7 +1000,7 @@ func (check *Checker) binary(x *operand, e syntax.Expr, lhs, rhs syntax.Expr, op return } - if !check.identical(x.typ, y.typ) { + if !Identical(x.typ, y.typ) { // only report an error if we have valid types // (otherwise we had an error reported elsewhere already) if x.typ != Typ[Invalid] && y.typ != Typ[Invalid] { @@ -1329,7 +1329,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin xkey := keyVal(x.val) if asInterface(utyp.key) != nil { for _, vtyp := range visited[xkey] { - if check.identical(vtyp, x.typ) { + if Identical(vtyp, x.typ) { duplicate = true break } @@ -1550,7 +1550,7 @@ func (check *Checker) typeAssertion(pos syntax.Pos, x *operand, xtyp *Interface, } var msg string if wrongType != nil { - if check.identical(method.typ, wrongType.typ) { + if Identical(method.typ, wrongType.typ) { msg = fmt.Sprintf("missing method %s (%s has pointer receiver)", method.name, method.name) } else { msg = fmt.Sprintf("wrong type for method %s (have %s, want %s)", method.name, wrongType.typ, method.typ) diff --git a/src/cmd/compile/internal/types2/infer.go b/src/cmd/compile/internal/types2/infer.go index 791e25e9f0c..e5d94e44d97 100644 --- a/src/cmd/compile/internal/types2/infer.go +++ b/src/cmd/compile/internal/types2/infer.go @@ -94,7 +94,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeName, targs []Type, p // Unify parameter and argument types for generic parameters with typed arguments // and collect the indices of generic parameters with untyped arguments. // Terminology: generic parameter = function parameter with a type-parameterized type - u := newUnifier(check, false) + u := newUnifier(false) u.x.init(tparams) // Set the type arguments which we know already. @@ -374,7 +374,7 @@ func (check *Checker) inferB(tparams []*TypeName, targs []Type, report bool) (ty // Setup bidirectional unification between those structural bounds // and the corresponding type arguments (which may be nil!). - u := newUnifier(check, false) + u := newUnifier(false) u.x.init(tparams) u.y = u.x // type parameters between LHS and RHS of unification are identical diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go index 4dee9234221..499b078dc01 100644 --- a/src/cmd/compile/internal/types2/interface.go +++ b/src/cmd/compile/internal/types2/interface.go @@ -211,7 +211,7 @@ func newTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet { } // check != nil check.later(func() { - if !check.allowVersion(m.pkg, 1, 14) || !check.identical(m.typ, other.Type()) { + if !check.allowVersion(m.pkg, 1, 14) || !Identical(m.typ, other.Type()) { var err error_ err.errorf(pos, "duplicate method %s", m.name) err.errorf(mpos[other.(*Func)], "other declaration of %s", m.name) diff --git a/src/cmd/compile/internal/types2/lookup.go b/src/cmd/compile/internal/types2/lookup.go index 9fcec44d534..d59a2f474c6 100644 --- a/src/cmd/compile/internal/types2/lookup.go +++ b/src/cmd/compile/internal/types2/lookup.go @@ -6,6 +6,11 @@ package types2 +// Internal use of LookupFieldOrMethod: If the obj result is a method +// associated with a concrete (non-interface) type, the method's signature +// may not be fully set up. Call Checker.objDecl(obj, nil) before accessing +// the method's type. + // LookupFieldOrMethod looks up a field or method with given package and name // in T and returns the corresponding *Var or *Func, an index sequence, and a // bool indicating if there were any pointer indirections on the path to the @@ -33,19 +38,6 @@ package types2 // the method's formal receiver base type, nor was the receiver addressable. // func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) { - return (*Checker)(nil).lookupFieldOrMethod(T, addressable, pkg, name) -} - -// Internal use of Checker.lookupFieldOrMethod: If the obj result is a method -// associated with a concrete (non-interface) type, the method's signature -// may not be fully set up. Call Checker.objDecl(obj, nil) before accessing -// the method's type. -// TODO(gri) Now that we provide the *Checker, we can probably remove this -// caveat by calling Checker.objDecl from lookupFieldOrMethod. Investigate. - -// lookupFieldOrMethod is like the external version but completes interfaces -// as necessary. -func (check *Checker) lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) { // Methods cannot be associated to a named pointer type // (spec: "The type denoted by T is called the receiver base type; // it must not be a pointer or interface type and it must be declared @@ -55,7 +47,7 @@ func (check *Checker) lookupFieldOrMethod(T Type, addressable bool, pkg *Package // not have found it for T (see also issue 8590). if t := asNamed(T); t != nil { if p, _ := t.Underlying().(*Pointer); p != nil { - obj, index, indirect = check.rawLookupFieldOrMethod(p, false, pkg, name) + obj, index, indirect = lookupFieldOrMethod(p, false, pkg, name) if _, ok := obj.(*Func); ok { return nil, nil, false } @@ -63,7 +55,7 @@ func (check *Checker) lookupFieldOrMethod(T Type, addressable bool, pkg *Package } } - return check.rawLookupFieldOrMethod(T, addressable, pkg, name) + return lookupFieldOrMethod(T, addressable, pkg, name) } // TODO(gri) The named type consolidation and seen maps below must be @@ -71,10 +63,9 @@ func (check *Checker) lookupFieldOrMethod(T Type, addressable bool, pkg *Package // types always have only one representation (even when imported // indirectly via different packages.) -// rawLookupFieldOrMethod should only be called by lookupFieldOrMethod and missingMethod. -func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) { +// lookupFieldOrMethod should only be called by LookupFieldOrMethod and missingMethod. +func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) { // WARNING: The code in this function is extremely subtle - do not modify casually! - // This function and NewMethodSet should be kept in sync. if name == "_" { return // blank fields/methods are never found @@ -228,7 +219,7 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack return } - current = check.consolidateMultiples(next) + current = consolidateMultiples(next) } return nil, nil, false // not found @@ -245,7 +236,7 @@ type embeddedType struct { // consolidateMultiples collects multiple list entries with the same type // into a single entry marked as containing multiples. The result is the // consolidated list. -func (check *Checker) consolidateMultiples(list []embeddedType) []embeddedType { +func consolidateMultiples(list []embeddedType) []embeddedType { if len(list) <= 1 { return list // at most one entry - nothing to do } @@ -253,7 +244,7 @@ func (check *Checker) consolidateMultiples(list []embeddedType) []embeddedType { n := 0 // number of entries w/ unique type prev := make(map[Type]int) // index at which type was previously seen for _, e := range list { - if i, found := check.lookupType(prev, e.typ); found { + if i, found := lookupType(prev, e.typ); found { list[i].multiples = true // ignore this entry } else { @@ -265,14 +256,14 @@ func (check *Checker) consolidateMultiples(list []embeddedType) []embeddedType { return list[:n] } -func (check *Checker) lookupType(m map[Type]int, typ Type) (int, bool) { +func lookupType(m map[Type]int, typ Type) (int, bool) { // fast path: maybe the types are equal if i, found := m[typ]; found { return i, true } for t, i := range m { - if check.identical(t, typ) { + if Identical(t, typ) { return i, true } } @@ -338,7 +329,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // to see if they can be made to match. // TODO(gri) is this always correct? what about type bounds? // (Alternative is to rename/subst type parameters and compare.) - u := newUnifier(check, true) + u := newUnifier(true) u.x.init(ftyp.tparams) if !u.unify(ftyp, mtyp) { return m, f @@ -353,12 +344,12 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, Vn := asNamed(Vd) for _, m := range T.typeSet().methods { // TODO(gri) should this be calling lookupFieldOrMethod instead (and why not)? - obj, _, _ := check.rawLookupFieldOrMethod(V, false, m.pkg, m.name) + obj, _, _ := lookupFieldOrMethod(V, false, m.pkg, m.name) // Check if *V implements this method of T. if obj == nil { ptr := NewPointer(V) - obj, _, _ = check.rawLookupFieldOrMethod(ptr, false, m.pkg, m.name) + obj, _, _ = lookupFieldOrMethod(ptr, false, m.pkg, m.name) if obj != nil { return m, obj.(*Func) } @@ -414,7 +405,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // to see if they can be made to match. // TODO(gri) is this always correct? what about type bounds? // (Alternative is to rename/subst type parameters and compare.) - u := newUnifier(check, true) + u := newUnifier(true) if len(ftyp.tparams) > 0 { // We reach here only if we accept method type parameters. // In this case, unification must consider any receiver diff --git a/src/cmd/compile/internal/types2/operand.go b/src/cmd/compile/internal/types2/operand.go index fdc6ec52aae..83cc239d931 100644 --- a/src/cmd/compile/internal/types2/operand.go +++ b/src/cmd/compile/internal/types2/operand.go @@ -255,7 +255,7 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er } // x's type is identical to T - if check.identical(V, T) { + if Identical(V, T) { return true, 0 } @@ -287,7 +287,7 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er // x's type V and T have identical underlying types // and at least one of V or T is not a named type - if check.identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) { + if Identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) { return true, 0 } @@ -296,7 +296,7 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er if m, wrongType := check.missingMethod(V, Ti, true); m != nil /* Implements(V, Ti) */ { if reason != nil { if wrongType != nil { - if check.identical(m.typ, wrongType.typ) { + if Identical(m.typ, wrongType.typ) { *reason = fmt.Sprintf("missing method %s (%s has pointer receiver)", m.name, m.name) } else { *reason = fmt.Sprintf("wrong type for method %s (have %s, want %s)", m.Name(), wrongType.typ, m.typ) @@ -315,7 +315,7 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er // type, x's type V and T have identical element types, // and at least one of V or T is not a named type if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv { - if Tc, ok := Tu.(*Chan); ok && check.identical(Vc.elem, Tc.elem) { + if Tc, ok := Tu.(*Chan); ok && Identical(Vc.elem, Tc.elem) { return !isNamed(V) || !isNamed(T), _InvalidChanAssign } } diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go index 73af1271886..5ff7840d6f9 100644 --- a/src/cmd/compile/internal/types2/predicates.go +++ b/src/cmd/compile/internal/types2/predicates.go @@ -147,18 +147,6 @@ func hasNil(typ Type) bool { return false } -// identical reports whether x and y are identical types. -// Receivers of Signature types are ignored. -func (check *Checker) identical(x, y Type) bool { - return check.identical0(x, y, true, nil) -} - -// identicalIgnoreTags reports whether x and y are identical types if tags are ignored. -// Receivers of Signature types are ignored. -func (check *Checker) identicalIgnoreTags(x, y Type) bool { - return check.identical0(x, y, false, nil) -} - // An ifacePair is a node in a stack of interface type pairs compared for identity. type ifacePair struct { x, y *Interface @@ -170,7 +158,7 @@ func (p *ifacePair) identical(q *ifacePair) bool { } // For changes to this code the corresponding changes should be made to unifier.nify. -func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { +func identical(x, y Type, cmpTags bool, p *ifacePair) bool { // types must be expanded for comparison x = expandf(x) y = expandf(y) @@ -194,13 +182,13 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { if y, ok := y.(*Array); ok { // If one or both array lengths are unknown (< 0) due to some error, // assume they are the same to avoid spurious follow-on errors. - return (x.len < 0 || y.len < 0 || x.len == y.len) && check.identical0(x.elem, y.elem, cmpTags, p) + return (x.len < 0 || y.len < 0 || x.len == y.len) && identical(x.elem, y.elem, cmpTags, p) } case *Slice: // Two slice types are identical if they have identical element types. if y, ok := y.(*Slice); ok { - return check.identical0(x.elem, y.elem, cmpTags, p) + return identical(x.elem, y.elem, cmpTags, p) } case *Struct: @@ -215,7 +203,7 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { if f.embedded != g.embedded || cmpTags && x.Tag(i) != y.Tag(i) || !f.sameId(g.pkg, g.name) || - !check.identical0(f.typ, g.typ, cmpTags, p) { + !identical(f.typ, g.typ, cmpTags, p) { return false } } @@ -226,7 +214,7 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { case *Pointer: // Two pointer types are identical if they have identical base types. if y, ok := y.(*Pointer); ok { - return check.identical0(x.base, y.base, cmpTags, p) + return identical(x.base, y.base, cmpTags, p) } case *Tuple: @@ -237,7 +225,7 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { if x != nil { for i, v := range x.vars { w := y.vars[i] - if !check.identical0(v.typ, w.typ, cmpTags, p) { + if !identical(v.typ, w.typ, cmpTags, p) { return false } } @@ -255,9 +243,9 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { // parameter names. if y, ok := y.(*Signature); ok { return x.variadic == y.variadic && - check.identicalTParams(x.tparams, y.tparams, cmpTags, p) && - check.identical0(x.params, y.params, cmpTags, p) && - check.identical0(x.results, y.results, cmpTags, p) + identicalTParams(x.tparams, y.tparams, cmpTags, p) && + identical(x.params, y.params, cmpTags, p) && + identical(x.results, y.results, cmpTags, p) } case *Union: @@ -325,7 +313,7 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { } for i, f := range a { g := b[i] - if f.Id() != g.Id() || !check.identical0(f.typ, g.typ, cmpTags, q) { + if f.Id() != g.Id() || !identical(f.typ, g.typ, cmpTags, q) { return false } } @@ -336,14 +324,14 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { case *Map: // Two map types are identical if they have identical key and value types. if y, ok := y.(*Map); ok { - return check.identical0(x.key, y.key, cmpTags, p) && check.identical0(x.elem, y.elem, cmpTags, p) + return identical(x.key, y.key, cmpTags, p) && identical(x.elem, y.elem, cmpTags, p) } case *Chan: // Two channel types are identical if they have identical value types // and the same direction. if y, ok := y.(*Chan); ok { - return x.dir == y.dir && check.identical0(x.elem, y.elem, cmpTags, p) + return x.dir == y.dir && identical(x.elem, y.elem, cmpTags, p) } case *Named: @@ -376,13 +364,13 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { return false } -func (check *Checker) identicalTParams(x, y []*TypeName, cmpTags bool, p *ifacePair) bool { +func identicalTParams(x, y []*TypeName, cmpTags bool, p *ifacePair) bool { if len(x) != len(y) { return false } for i, x := range x { y := y[i] - if !check.identical0(x.typ.(*TypeParam).bound, y.typ.(*TypeParam).bound, cmpTags, p) { + if !identical(x.typ.(*TypeParam).bound, y.typ.(*TypeParam).bound, cmpTags, p) { return false } } diff --git a/src/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go index ab664321264..b41b23fedbc 100644 --- a/src/cmd/compile/internal/types2/stmt.go +++ b/src/cmd/compile/internal/types2/stmt.go @@ -256,7 +256,7 @@ L: // look for duplicate types for a given value // (quadratic algorithm, but these lists tend to be very short) for _, vt := range seen[val] { - if check.identical(v.typ, vt.typ) { + if Identical(v.typ, vt.typ) { var err error_ err.errorf(&v, "duplicate case %s in expression switch", &v) err.errorf(vt.pos, "previous case") @@ -282,7 +282,7 @@ L: // look for duplicate types // (quadratic algorithm, but type switches tend to be reasonably small) for t, other := range seen { - if T == nil && t == nil || T != nil && t != nil && check.identical(T, t) { + if T == nil && t == nil || T != nil && t != nil && Identical(T, t) { // talk about "case" rather than "type" because of nil case Ts := "nil" if T != nil { diff --git a/src/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go index 9a51dcb6d47..4e1f8322030 100644 --- a/src/cmd/compile/internal/types2/unify.go +++ b/src/cmd/compile/internal/types2/unify.go @@ -6,7 +6,10 @@ package types2 -import "bytes" +import ( + "bytes" + "fmt" +) // The unifier maintains two separate sets of type parameters x and y // which are used to resolve type parameters in the x and y arguments @@ -34,7 +37,6 @@ import "bytes" // and the respective types inferred for each type parameter. // A unifier is created by calling newUnifier. type unifier struct { - check *Checker exact bool x, y tparamsList // x and y must initialized via tparamsList.init types []Type // inferred types, shared by x and y @@ -45,8 +47,8 @@ type unifier struct { // exactly. If exact is not set, a named type's underlying type // is considered if unification would fail otherwise, and the // direction of channels is ignored. -func newUnifier(check *Checker, exact bool) *unifier { - u := &unifier{check: check, exact: exact} +func newUnifier(exact bool) *unifier { + u := &unifier{exact: exact} u.x.unifier = u u.y.unifier = u return u @@ -453,8 +455,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool { // avoid a crash in case of nil type default: - u.check.dump("### u.nify(%s, %s), u.x.tparams = %s", x, y, u.x.tparams) - unreachable() + panic(fmt.Sprintf("### u.nify(%s, %s), u.x.tparams = %s", x, y, u.x.tparams)) } return false From f0206e3df2f134cb1a13402aefbb6caeec4fc126 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 28 Jun 2021 17:21:26 -0700 Subject: [PATCH 589/940] [dev.typeparams] cmd/compile/internal/types2: move embedding positions from Checker to Interface This change moves the position information to the place where it is actually used. It also simplifies getting rid of it after use. In the process, fixed a latent bug: Before this CL, embedded types were sorted, but the corresponding embedding positions were not. Removed the sorting altogether as it is not needed for type-checking. Change-Id: I48003f317196d814326424430336b6cb222fdee6 Reviewed-on: https://go-review.googlesource.com/c/go/+/331514 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/check.go | 12 ++--- src/cmd/compile/internal/types2/interface.go | 46 +++++++------------ .../compile/internal/types2/sizeof_test.go | 2 +- src/cmd/compile/internal/types2/subst.go | 1 - src/cmd/compile/internal/types2/type.go | 10 ++-- 5 files changed, 28 insertions(+), 43 deletions(-) diff --git a/src/cmd/compile/internal/types2/check.go b/src/cmd/compile/internal/types2/check.go index 5d3c2c8ad25..071afef0587 100644 --- a/src/cmd/compile/internal/types2/check.go +++ b/src/cmd/compile/internal/types2/check.go @@ -82,12 +82,11 @@ type Checker struct { conf *Config pkg *Package *Info - version version // accepted language version - nextID uint64 // unique Id for type parameters (first valid Id is 1) - objMap map[Object]*declInfo // maps package-level objects and (non-interface) methods to declaration info - impMap map[importKey]*Package // maps (import path, source directory) to (complete or fake) package - posMap map[*Interface][]syntax.Pos // maps interface types to lists of embedded interface positions - typMap map[string]*Named // maps an instantiated named type hash to a *Named type + version version // accepted language version + nextID uint64 // unique Id for type parameters (first valid Id is 1) + objMap map[Object]*declInfo // maps package-level objects and (non-interface) methods to declaration info + impMap map[importKey]*Package // maps (import path, source directory) to (complete or fake) package + typMap map[string]*Named // maps an instantiated named type hash to a *Named type // pkgPathMap maps package names to the set of distinct import paths we've // seen for that name, anywhere in the import graph. It is used for @@ -189,7 +188,6 @@ func NewChecker(conf *Config, pkg *Package, info *Info) *Checker { version: version, objMap: make(map[Object]*declInfo), impMap: make(map[importKey]*Package), - posMap: make(map[*Interface][]syntax.Pos), typMap: make(map[string]*Named), } } diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go index 499b078dc01..e667830db3b 100644 --- a/src/cmd/compile/internal/types2/interface.go +++ b/src/cmd/compile/internal/types2/interface.go @@ -14,11 +14,18 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType var tlist []syntax.Expr // types collected from all type lists var tname *syntax.Name // most recent "type" name + addEmbedded := func(pos syntax.Pos, typ Type) { + ityp.embeddeds = append(ityp.embeddeds, typ) + if ityp.embedPos == nil { + ityp.embedPos = new([]syntax.Pos) + } + *ityp.embedPos = append(*ityp.embedPos, pos) + } + for _, f := range iface.MethodList { if f.Name == nil { // We have an embedded type; possibly a union of types. - ityp.embeddeds = append(ityp.embeddeds, parseUnion(check, flattenUnion(nil, f.Type))) - check.posMap[ityp] = append(check.posMap[ityp], f.Type.Pos()) + addEmbedded(f.Type.Pos(), parseUnion(check, flattenUnion(nil, f.Type))) continue } // f.Name != nil @@ -89,10 +96,9 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType // If we saw a type list, add it like an embedded union. if tlist != nil { - ityp.embeddeds = append(ityp.embeddeds, parseUnion(check, tlist)) // Types T in a type list are added as ~T expressions but we don't // have the position of the '~'. Use the first type position instead. - check.posMap[ityp] = append(check.posMap[ityp], tlist[0].(*syntax.Operation).X.Pos()) + addEmbedded(tlist[0].(*syntax.Operation).X.Pos(), parseUnion(check, tlist)) } // All methods and embedded elements for this interface are collected; @@ -106,8 +112,8 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType } // sort for API stability + // (don't sort embeddeds: they must correspond to *embedPos entries) sortMethods(ityp.methods) - sortTypes(ityp.embeddeds) // Compute type set with a non-nil *Checker as soon as possible // to report any errors. Subsequent uses of type sets should be @@ -227,14 +233,13 @@ func newTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet { // collect embedded elements var allTypes Type - var posList []syntax.Pos - if check != nil { - posList = check.posMap[ityp] - } for i, typ := range ityp.embeddeds { + // The embedding position is nil for imported interfaces + // and also for interface copies after substitution (but + // in that case we don't need to report errors again). var pos syntax.Pos // embedding position - if posList != nil { - pos = posList[i] + if ityp.embedPos != nil { + pos = (*ityp.embedPos)[i] } var types Type switch t := under(typ).(type) { @@ -268,6 +273,7 @@ func newTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet { } allTypes = intersect(allTypes, types) } + ityp.embedPos = nil // not needed anymore (errors have been reported) // process todo's (this only happens if check == nil) for i := 0; i < len(todo); i += 2 { @@ -287,24 +293,6 @@ func newTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet { return ityp.tset } -func sortTypes(list []Type) { - sort.Stable(byUniqueTypeName(list)) -} - -// byUniqueTypeName named type lists can be sorted by their unique type names. -type byUniqueTypeName []Type - -func (a byUniqueTypeName) Len() int { return len(a) } -func (a byUniqueTypeName) Less(i, j int) bool { return sortObj(a[i]).less(sortObj(a[j])) } -func (a byUniqueTypeName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } - -func sortObj(t Type) *object { - if named := asNamed(t); named != nil { - return &named.obj.object - } - return nil -} - func sortMethods(list []*Func) { sort.Sort(byUniqueMethodName(list)) } diff --git a/src/cmd/compile/internal/types2/sizeof_test.go b/src/cmd/compile/internal/types2/sizeof_test.go index 0b1f7dacad3..82e1221b67e 100644 --- a/src/cmd/compile/internal/types2/sizeof_test.go +++ b/src/cmd/compile/internal/types2/sizeof_test.go @@ -28,7 +28,7 @@ func TestSizeof(t *testing.T) { {Tuple{}, 12, 24}, {Signature{}, 44, 88}, {Union{}, 24, 48}, - {Interface{}, 40, 80}, + {Interface{}, 44, 88}, {Map{}, 16, 32}, {Chan{}, 12, 24}, {Named{}, 84, 160}, diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index 38bd07b8a28..db01c36f7ad 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -316,7 +316,6 @@ func (subst *subster) typ(typ Type) Type { if subst.check == nil { panic("internal error: cannot instantiate interfaces yet") } - subst.check.posMap[iface] = subst.check.posMap[t] // satisfy completeInterface requirement return iface } diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index 122e408eade..2cfcabbdb55 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -264,10 +264,11 @@ func (s *Signature) Variadic() bool { return s.variadic } // An Interface represents an interface type. type Interface struct { - obj Object // type name object defining this interface; or nil (for better error messages) - methods []*Func // ordered list of explicitly declared methods - embeddeds []Type // ordered list of explicitly embedded elements - complete bool // indicates that obj, methods, and embeddeds are set and type set can be computed + obj Object // type name object defining this interface; or nil (for better error messages) + methods []*Func // ordered list of explicitly declared methods + embeddeds []Type // ordered list of explicitly embedded elements + embedPos *[]syntax.Pos // positions of embedded elements; or nil (for error messages) - use pointer to save space + complete bool // indicates that all fields (except for tset) are set up tset *TypeSet // type set described by this interface, computed lazily } @@ -322,7 +323,6 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface { // sort for API stability sortMethods(methods) - sortTypes(embeddeds) typ.methods = methods typ.embeddeds = embeddeds From b47cbc2ffec163f30690613b3a9c3f7f108cd512 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 28 Jun 2021 17:37:41 -0700 Subject: [PATCH 590/940] [dev.typeparams] cmd/compile/internal/types2: move newTypeSet function into typeset.go No functional changes except for import declaration and comment adjustments. Change-Id: I75fb5edba8b89a5aad7c9b4ddb427c201265def0 Reviewed-on: https://go-review.googlesource.com/c/go/+/331515 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/interface.go | 190 +-------------- src/cmd/compile/internal/types2/typeset.go | 230 +++++++++++++++++-- 2 files changed, 210 insertions(+), 210 deletions(-) diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go index e667830db3b..18dc573340b 100644 --- a/src/cmd/compile/internal/types2/interface.go +++ b/src/cmd/compile/internal/types2/interface.go @@ -4,11 +4,7 @@ package types2 -import ( - "cmd/compile/internal/syntax" - "fmt" - "sort" -) +import "cmd/compile/internal/syntax" func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType, def *Named) { var tlist []syntax.Expr // types collected from all type lists @@ -128,187 +124,3 @@ func flattenUnion(list []syntax.Expr, x syntax.Expr) []syntax.Expr { } return append(list, x) } - -// newTypeSet may be called with check == nil. -// TODO(gri) move this function into typeset.go eventually -func newTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet { - if ityp.tset != nil { - return ityp.tset - } - - // If the interface is not fully set up yet, the type set will - // not be complete, which may lead to errors when using the the - // type set (e.g. missing method). Don't compute a partial type - // set (and don't store it!), so that we still compute the full - // type set eventually. Instead, return the top type set and - // let any follow-on errors play out. - // - // TODO(gri) Consider recording when this happens and reporting - // it as an error (but only if there were no other errors so to - // to not have unnecessary follow-on errors). - if !ityp.complete { - return &topTypeSet - } - - if check != nil && check.conf.Trace { - // Types don't generally have position information. - // If we don't have a valid pos provided, try to use - // one close enough. - if !pos.IsKnown() && len(ityp.methods) > 0 { - pos = ityp.methods[0].pos - } - - check.trace(pos, "type set for %s", ityp) - check.indent++ - defer func() { - check.indent-- - check.trace(pos, "=> %s ", ityp.typeSet()) - }() - } - - // An infinitely expanding interface (due to a cycle) is detected - // elsewhere (Checker.validType), so here we simply assume we only - // have valid interfaces. Mark the interface as complete to avoid - // infinite recursion if the validType check occurs later for some - // reason. - ityp.tset = new(TypeSet) // TODO(gri) is this sufficient? - - // Methods of embedded interfaces are collected unchanged; i.e., the identity - // of a method I.m's Func Object of an interface I is the same as that of - // the method m in an interface that embeds interface I. On the other hand, - // if a method is embedded via multiple overlapping embedded interfaces, we - // don't provide a guarantee which "original m" got chosen for the embedding - // interface. See also issue #34421. - // - // If we don't care to provide this identity guarantee anymore, instead of - // reusing the original method in embeddings, we can clone the method's Func - // Object and give it the position of a corresponding embedded interface. Then - // we can get rid of the mpos map below and simply use the cloned method's - // position. - - var todo []*Func - var seen objset - var methods []*Func - mpos := make(map[*Func]syntax.Pos) // method specification or method embedding position, for good error messages - addMethod := func(pos syntax.Pos, m *Func, explicit bool) { - switch other := seen.insert(m); { - case other == nil: - methods = append(methods, m) - mpos[m] = pos - case explicit: - if check == nil { - panic(fmt.Sprintf("%s: duplicate method %s", m.pos, m.name)) - } - // check != nil - var err error_ - err.errorf(pos, "duplicate method %s", m.name) - err.errorf(mpos[other.(*Func)], "other declaration of %s", m.name) - check.report(&err) - default: - // We have a duplicate method name in an embedded (not explicitly declared) method. - // Check method signatures after all types are computed (issue #33656). - // If we're pre-go1.14 (overlapping embeddings are not permitted), report that - // error here as well (even though we could do it eagerly) because it's the same - // error message. - if check == nil { - // check method signatures after all locally embedded interfaces are computed - todo = append(todo, m, other.(*Func)) - break - } - // check != nil - check.later(func() { - if !check.allowVersion(m.pkg, 1, 14) || !Identical(m.typ, other.Type()) { - var err error_ - err.errorf(pos, "duplicate method %s", m.name) - err.errorf(mpos[other.(*Func)], "other declaration of %s", m.name) - check.report(&err) - } - }) - } - } - - for _, m := range ityp.methods { - addMethod(m.pos, m, true) - } - - // collect embedded elements - var allTypes Type - for i, typ := range ityp.embeddeds { - // The embedding position is nil for imported interfaces - // and also for interface copies after substitution (but - // in that case we don't need to report errors again). - var pos syntax.Pos // embedding position - if ityp.embedPos != nil { - pos = (*ityp.embedPos)[i] - } - var types Type - switch t := under(typ).(type) { - case *Interface: - tset := newTypeSet(check, pos, t) - for _, m := range tset.methods { - addMethod(pos, m, false) // use embedding position pos rather than m.pos - } - types = tset.types - case *Union: - // TODO(gri) combine with default case once we have - // converted all tests to new notation and we - // can report an error when we don't have an - // interface before go1.18. - types = typ - case *TypeParam: - if check != nil && !check.allowVersion(check.pkg, 1, 18) { - check.errorf(pos, "%s is a type parameter, not an interface", typ) - continue - } - types = typ - default: - if typ == Typ[Invalid] { - continue - } - if check != nil && !check.allowVersion(check.pkg, 1, 18) { - check.errorf(pos, "%s is not an interface", typ) - continue - } - types = typ - } - allTypes = intersect(allTypes, types) - } - ityp.embedPos = nil // not needed anymore (errors have been reported) - - // process todo's (this only happens if check == nil) - for i := 0; i < len(todo); i += 2 { - m := todo[i] - other := todo[i+1] - if !Identical(m.typ, other.typ) { - panic(fmt.Sprintf("%s: duplicate method %s", m.pos, m.name)) - } - } - - if methods != nil { - sortMethods(methods) - ityp.tset.methods = methods - } - ityp.tset.types = allTypes - - return ityp.tset -} - -func sortMethods(list []*Func) { - sort.Sort(byUniqueMethodName(list)) -} - -func assertSortedMethods(list []*Func) { - if !debug { - panic("internal error: assertSortedMethods called outside debug mode") - } - if !sort.IsSorted(byUniqueMethodName(list)) { - panic("internal error: methods not sorted") - } -} - -// byUniqueMethodName method lists can be sorted by their unique method names. -type byUniqueMethodName []*Func - -func (a byUniqueMethodName) Len() int { return len(a) } -func (a byUniqueMethodName) Less(i, j int) bool { return a[i].less(&a[j].object) } -func (a byUniqueMethodName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } diff --git a/src/cmd/compile/internal/types2/typeset.go b/src/cmd/compile/internal/types2/typeset.go index 44e59294133..ce4a776f8f0 100644 --- a/src/cmd/compile/internal/types2/typeset.go +++ b/src/cmd/compile/internal/types2/typeset.go @@ -6,10 +6,13 @@ package types2 import ( "bytes" + "cmd/compile/internal/syntax" + "fmt" + "sort" ) -// topTypeSet may be used as type set for the empty interface. -var topTypeSet TypeSet +// ---------------------------------------------------------------------------- +// API // A TypeSet represents the type set of an interface. type TypeSet struct { @@ -18,6 +21,31 @@ type TypeSet struct { types Type // typically a *Union; nil means no type restrictions } +// IsTop reports whether type set s is the top type set (corresponding to the empty interface). +func (s *TypeSet) IsTop() bool { return len(s.methods) == 0 && s.types == nil } + +// IsMethodSet reports whether the type set s is described by a single set of methods. +func (s *TypeSet) IsMethodSet() bool { return s.types == nil && !s.IsComparable() } + +// IsComparable reports whether each type in the set is comparable. +func (s *TypeSet) IsComparable() bool { + _, m := s.LookupMethod(nil, "==") + return m != nil +} + +// NumMethods returns the number of methods available. +func (s *TypeSet) NumMethods() int { return len(s.methods) } + +// Method returns the i'th method of type set s for 0 <= i < s.NumMethods(). +// The methods are ordered by their unique ID. +func (s *TypeSet) Method(i int) *Func { return s.methods[i] } + +// LookupMethod returns the index of and method with matching package and name, or (-1, nil). +func (s *TypeSet) LookupMethod(pkg *Package, name string) (int, *Func) { + // TODO(gri) s.methods is sorted - consider binary search + return lookupMethod(s.methods, pkg, name) +} + func (s *TypeSet) String() string { if s.IsTop() { return "⊤" @@ -44,27 +72,187 @@ func (s *TypeSet) String() string { return buf.String() } -// IsTop reports whether type set s is the top type set (corresponding to the empty interface). -func (s *TypeSet) IsTop() bool { return len(s.methods) == 0 && s.types == nil } +// ---------------------------------------------------------------------------- +// Implementation -// IsMethodSet reports whether the type set s is described by a single set of methods. -func (s *TypeSet) IsMethodSet() bool { return s.types == nil && !s.IsComparable() } +// topTypeSet may be used as type set for the empty interface. +var topTypeSet TypeSet -// IsComparable reports whether each type in the set is comparable. -func (s *TypeSet) IsComparable() bool { - _, m := s.LookupMethod(nil, "==") - return m != nil +// newTypeSet may be called with check == nil. +func newTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet { + if ityp.tset != nil { + return ityp.tset + } + + // If the interface is not fully set up yet, the type set will + // not be complete, which may lead to errors when using the the + // type set (e.g. missing method). Don't compute a partial type + // set (and don't store it!), so that we still compute the full + // type set eventually. Instead, return the top type set and + // let any follow-on errors play out. + if !ityp.complete { + return &topTypeSet + } + + if check != nil && check.conf.Trace { + // Types don't generally have position information. + // If we don't have a valid pos provided, try to use + // one close enough. + if !pos.IsKnown() && len(ityp.methods) > 0 { + pos = ityp.methods[0].pos + } + + check.trace(pos, "type set for %s", ityp) + check.indent++ + defer func() { + check.indent-- + check.trace(pos, "=> %s ", ityp.typeSet()) + }() + } + + // An infinitely expanding interface (due to a cycle) is detected + // elsewhere (Checker.validType), so here we simply assume we only + // have valid interfaces. Mark the interface as complete to avoid + // infinite recursion if the validType check occurs later for some + // reason. + ityp.tset = new(TypeSet) // TODO(gri) is this sufficient? + + // Methods of embedded interfaces are collected unchanged; i.e., the identity + // of a method I.m's Func Object of an interface I is the same as that of + // the method m in an interface that embeds interface I. On the other hand, + // if a method is embedded via multiple overlapping embedded interfaces, we + // don't provide a guarantee which "original m" got chosen for the embedding + // interface. See also issue #34421. + // + // If we don't care to provide this identity guarantee anymore, instead of + // reusing the original method in embeddings, we can clone the method's Func + // Object and give it the position of a corresponding embedded interface. Then + // we can get rid of the mpos map below and simply use the cloned method's + // position. + + var todo []*Func + var seen objset + var methods []*Func + mpos := make(map[*Func]syntax.Pos) // method specification or method embedding position, for good error messages + addMethod := func(pos syntax.Pos, m *Func, explicit bool) { + switch other := seen.insert(m); { + case other == nil: + methods = append(methods, m) + mpos[m] = pos + case explicit: + if check == nil { + panic(fmt.Sprintf("%s: duplicate method %s", m.pos, m.name)) + } + // check != nil + var err error_ + err.errorf(pos, "duplicate method %s", m.name) + err.errorf(mpos[other.(*Func)], "other declaration of %s", m.name) + check.report(&err) + default: + // We have a duplicate method name in an embedded (not explicitly declared) method. + // Check method signatures after all types are computed (issue #33656). + // If we're pre-go1.14 (overlapping embeddings are not permitted), report that + // error here as well (even though we could do it eagerly) because it's the same + // error message. + if check == nil { + // check method signatures after all locally embedded interfaces are computed + todo = append(todo, m, other.(*Func)) + break + } + // check != nil + check.later(func() { + if !check.allowVersion(m.pkg, 1, 14) || !Identical(m.typ, other.Type()) { + var err error_ + err.errorf(pos, "duplicate method %s", m.name) + err.errorf(mpos[other.(*Func)], "other declaration of %s", m.name) + check.report(&err) + } + }) + } + } + + for _, m := range ityp.methods { + addMethod(m.pos, m, true) + } + + // collect embedded elements + var allTypes Type + for i, typ := range ityp.embeddeds { + // The embedding position is nil for imported interfaces + // and also for interface copies after substitution (but + // in that case we don't need to report errors again). + var pos syntax.Pos // embedding position + if ityp.embedPos != nil { + pos = (*ityp.embedPos)[i] + } + var types Type + switch t := under(typ).(type) { + case *Interface: + tset := newTypeSet(check, pos, t) + for _, m := range tset.methods { + addMethod(pos, m, false) // use embedding position pos rather than m.pos + } + types = tset.types + case *Union: + // TODO(gri) combine with default case once we have + // converted all tests to new notation and we + // can report an error when we don't have an + // interface before go1.18. + types = typ + case *TypeParam: + if check != nil && !check.allowVersion(check.pkg, 1, 18) { + check.errorf(pos, "%s is a type parameter, not an interface", typ) + continue + } + types = typ + default: + if typ == Typ[Invalid] { + continue + } + if check != nil && !check.allowVersion(check.pkg, 1, 18) { + check.errorf(pos, "%s is not an interface", typ) + continue + } + types = typ + } + allTypes = intersect(allTypes, types) + } + ityp.embedPos = nil // not needed anymore (errors have been reported) + + // process todo's (this only happens if check == nil) + for i := 0; i < len(todo); i += 2 { + m := todo[i] + other := todo[i+1] + if !Identical(m.typ, other.typ) { + panic(fmt.Sprintf("%s: duplicate method %s", m.pos, m.name)) + } + } + + if methods != nil { + sortMethods(methods) + ityp.tset.methods = methods + } + ityp.tset.types = allTypes + + return ityp.tset } -// NumMethods returns the number of methods available. -func (s *TypeSet) NumMethods() int { return len(s.methods) } - -// Method returns the i'th method of type set s for 0 <= i < s.NumMethods(). -// The methods are ordered by their unique ID. -func (s *TypeSet) Method(i int) *Func { return s.methods[i] } - -// LookupMethod returns the index of and method with matching package and name, or (-1, nil). -func (s *TypeSet) LookupMethod(pkg *Package, name string) (int, *Func) { - // TODO(gri) s.methods is sorted - consider binary search - return lookupMethod(s.methods, pkg, name) +func sortMethods(list []*Func) { + sort.Sort(byUniqueMethodName(list)) } + +func assertSortedMethods(list []*Func) { + if !debug { + panic("internal error: assertSortedMethods called outside debug mode") + } + if !sort.IsSorted(byUniqueMethodName(list)) { + panic("internal error: methods not sorted") + } +} + +// byUniqueMethodName method lists can be sorted by their unique method names. +type byUniqueMethodName []*Func + +func (a byUniqueMethodName) Len() int { return len(a) } +func (a byUniqueMethodName) Less(i, j int) bool { return a[i].less(&a[j].object) } +func (a byUniqueMethodName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } From ed56ea73e8aa60269bbb3d33af9e7614e6b3babf Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Wed, 30 Jun 2021 09:44:30 -0700 Subject: [PATCH 591/940] path/filepath: deflake TestEvalSymlinksAboveRoot on darwin On darwin, under load, it appears that the system occasionally deletes the temp dir mid-test. Don't fail the test when that happens. It would be nice to fix this in a deeper way. See golang.org/cl/332009 for some discussion. In the meantime, this will at least stop the flakiness. Updates #37910 Change-Id: I6669e466fed9abda4a87ca88345c04cd7986b41e Reviewed-on: https://go-review.googlesource.com/c/go/+/332009 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills --- src/path/filepath/path_test.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go index cd107b6c85a..bc5509b49cf 100644 --- a/src/path/filepath/path_test.go +++ b/src/path/filepath/path_test.go @@ -1469,11 +1469,16 @@ func TestEvalSymlinksAboveRoot(t *testing.T) { // Try different numbers of "..". for _, i := range []int{c, c + 1, c + 2} { check := strings.Join([]string{evalTmpDir, strings.Join(dd[:i], string(os.PathSeparator)), evalTmpDir[len(vol)+1:], "b", "file"}, string(os.PathSeparator)) - if resolved, err := filepath.EvalSymlinks(check); err != nil { + resolved, err := filepath.EvalSymlinks(check) + switch { + case runtime.GOOS == "darwin" && errors.Is(err, fs.ErrNotExist): + // On darwin, the temp dir is sometimes cleaned up mid-test (issue 37910). + testenv.SkipFlaky(t, 37910) + case err != nil: t.Errorf("EvalSymlinks(%q) failed: %v", check, err) - } else if !strings.HasSuffix(resolved, wantSuffix) { + case !strings.HasSuffix(resolved, wantSuffix): t.Errorf("EvalSymlinks(%q) = %q does not end with %q", check, resolved, wantSuffix) - } else { + default: t.Logf("EvalSymlinks(%q) = %q", check, resolved) } } From 8767b87ab54acca33c487ee46e237049b663b1c4 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Mon, 21 Jun 2021 17:04:59 -0700 Subject: [PATCH 592/940] [dev.typeparams] cmd/compile: functions to create GC shape types/names for a concrete type Created functions to create GC shape type and names, based on a proposal from Keith. Kept unsigned and signed integer types as different, since they have different shift operations. Included adding in alignment fields where padding is required between fields, even though that seems like it will be fairly uncommon to use. Added some extra unusual struct typeparams (for testing the gcshape names/types) in index.go test. Change-Id: I8132bbd28098bd933435b8972ac5cc0b39f4c0df Reviewed-on: https://go-review.googlesource.com/c/go/+/329921 Trust: Dan Scales Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/noder/stencil.go | 198 ++++++++++++++++++++++ test/typeparam/index.go | 36 ++++ 2 files changed, 234 insertions(+) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 29ee863a71f..b228e402586 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -8,6 +8,7 @@ package noder import ( + "bytes" "cmd/compile/internal/base" "cmd/compile/internal/ir" "cmd/compile/internal/objw" @@ -18,6 +19,7 @@ import ( "cmd/internal/src" "fmt" "go/constant" + "strconv" ) func assert(p bool) { @@ -490,6 +492,195 @@ func (g *irgen) getInstantiationForNode(inst *ir.InstExpr) (*ir.Func, ir.Node) { } } +func addGcType(fl []*types.Field, t *types.Type) []*types.Field { + return append(fl, types.NewField(base.Pos, typecheck.Lookup("F"+strconv.Itoa(len(fl))), t)) +} + +const INTTYPE = types.TINT64 // XX fix for 32-bit arch +const UINTTYPE = types.TUINT64 // XX fix for 32-bit arch +const INTSTRING = "i8" // XX fix for 32-bit arch +const UINTSTRING = "u8" // XX fix for 32-bit arch + +// accumGcshape adds fields to fl resulting from the GCshape transformation of +// type t. The string associated with the GCshape transformation of t is added to +// buf. fieldSym is the sym of the field associated with type t, if it is in a +// struct. fieldSym could be used to have special naming for blank fields, etc. +func accumGcshape(fl []*types.Field, buf *bytes.Buffer, t *types.Type, fieldSym *types.Sym) []*types.Field { + + // t.Kind() is already the kind of the underlying type, so no need to + // reference t.Underlying() to reference the underlying type. + assert(t.Kind() == t.Underlying().Kind()) + + switch t.Kind() { + case types.TINT8: + fl = addGcType(fl, types.Types[types.TINT8]) + buf.WriteString("i1") + + case types.TUINT8: + fl = addGcType(fl, types.Types[types.TUINT8]) + buf.WriteString("u1") + + case types.TINT16: + fl = addGcType(fl, types.Types[types.TINT16]) + buf.WriteString("i2") + + case types.TUINT16: + fl = addGcType(fl, types.Types[types.TUINT16]) + buf.WriteString("u2") + + case types.TINT32: + fl = addGcType(fl, types.Types[types.TINT32]) + buf.WriteString("i4") + + case types.TUINT32: + fl = addGcType(fl, types.Types[types.TUINT32]) + buf.WriteString("u4") + + case types.TINT64: + fl = addGcType(fl, types.Types[types.TINT64]) + buf.WriteString("i8") + + case types.TUINT64: + fl = addGcType(fl, types.Types[types.TUINT64]) + buf.WriteString("u8") + + case types.TINT: + fl = addGcType(fl, types.Types[INTTYPE]) + buf.WriteString(INTSTRING) + + case types.TUINT, types.TUINTPTR: + fl = addGcType(fl, types.Types[UINTTYPE]) + buf.WriteString(UINTSTRING) + + case types.TCOMPLEX64: + fl = addGcType(fl, types.Types[types.TFLOAT32]) + fl = addGcType(fl, types.Types[types.TFLOAT32]) + buf.WriteString("f4") + buf.WriteString("f4") + + case types.TCOMPLEX128: + fl = addGcType(fl, types.Types[types.TFLOAT64]) + fl = addGcType(fl, types.Types[types.TFLOAT64]) + buf.WriteString("f8") + buf.WriteString("f8") + + case types.TFLOAT32: + fl = addGcType(fl, types.Types[types.TFLOAT32]) + buf.WriteString("f4") + + case types.TFLOAT64: + fl = addGcType(fl, types.Types[types.TFLOAT64]) + buf.WriteString("f8") + + case types.TBOOL: + fl = addGcType(fl, types.Types[types.TINT8]) + buf.WriteString("i1") + + case types.TPTR: + fl = addGcType(fl, types.Types[types.TUNSAFEPTR]) + buf.WriteString("p") + + case types.TFUNC: + fl = addGcType(fl, types.Types[types.TUNSAFEPTR]) + buf.WriteString("p") + + case types.TSLICE: + fl = addGcType(fl, types.Types[types.TUNSAFEPTR]) + fl = addGcType(fl, types.Types[INTTYPE]) + fl = addGcType(fl, types.Types[INTTYPE]) + buf.WriteString("p") + buf.WriteString(INTSTRING) + buf.WriteString(INTSTRING) + + case types.TARRAY: + n := t.NumElem() + if n == 1 { + fl = accumGcshape(fl, buf, t.Elem(), nil) + } else if n > 0 { + // Represent an array with more than one element as its + // unique type, since it must be treated differently for + // regabi. + fl = addGcType(fl, t) + buf.WriteByte('[') + buf.WriteString(strconv.Itoa(int(n))) + buf.WriteString("](") + var ignore []*types.Field + // But to determine its gcshape name, we must call + // accumGcShape() on t.Elem(). + accumGcshape(ignore, buf, t.Elem(), nil) + buf.WriteByte(')') + } + + case types.TSTRUCT: + nfields := t.NumFields() + for i, f := range t.Fields().Slice() { + fl = accumGcshape(fl, buf, f.Type, f.Sym) + + // Check if we need to add an alignment field. + var pad int64 + if i < nfields-1 { + pad = t.Field(i+1).Offset - f.Offset - f.Type.Width + } else { + pad = t.Width - f.Offset - f.Type.Width + } + if pad > 0 { + // There is padding between fields or at end of + // struct. Add an alignment field. + fl = addGcType(fl, types.NewArray(types.Types[types.TUINT8], pad)) + buf.WriteString("a") + buf.WriteString(strconv.Itoa(int(pad))) + } + } + + case types.TCHAN: + fl = addGcType(fl, types.Types[types.TUNSAFEPTR]) + buf.WriteString("p") + + case types.TMAP: + fl = addGcType(fl, types.Types[types.TUNSAFEPTR]) + buf.WriteString("p") + + case types.TINTER: + fl = addGcType(fl, types.Types[types.TUNSAFEPTR]) + fl = addGcType(fl, types.Types[types.TUNSAFEPTR]) + buf.WriteString("pp") + + case types.TFORW, types.TANY: + assert(false) + + case types.TSTRING: + fl = addGcType(fl, types.Types[types.TUNSAFEPTR]) + fl = addGcType(fl, types.Types[INTTYPE]) + buf.WriteString("p") + buf.WriteString(INTSTRING) + + case types.TUNSAFEPTR: + fl = addGcType(fl, types.Types[types.TUNSAFEPTR]) + buf.WriteString("p") + + default: // Everything TTYPEPARAM and below in list of Kinds + assert(false) + } + + return fl +} + +// gcshapeType returns the GCshape type and name corresponding to type t. +func gcshapeType(t *types.Type) (*types.Type, string) { + var fl []*types.Field + buf := bytes.NewBufferString("") + + // Call CallSize so type sizes and field offsets are available. + types.CalcSize(t) + fl = accumGcshape(fl, buf, t, nil) + // TODO: Should gcshapes be in a global package, so we don't have to + // duplicate in each package? Or at least in the specified source package + // of a function/method instantiation? + gcshape := types.NewStruct(types.LocalPkg, fl) + assert(gcshape.Size() == t.Size()) + return gcshape, buf.String() +} + // getInstantiation gets the instantiantion and dictionary of the function or method nameNode // with the type arguments targs. If the instantiated function is not already // cached, then it calls genericSubst to create the new instantiation. @@ -506,6 +697,13 @@ func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth sym := typecheck.MakeInstName(nameNode.Sym(), targs, isMeth) st := g.target.Stencils[sym] if st == nil { + if false { + // Testing out gcshapeType() and gcshapeName() + for i, t := range targs { + gct, gcs := gcshapeType(t) + fmt.Printf("targ %d: %v %v\n", i, gct, gcs) + } + } // If instantiation doesn't exist yet, create it and add // to the list of decls. st = g.genericSubst(sym, nameNode, targs, isMeth) diff --git a/test/typeparam/index.go b/test/typeparam/index.go index cb9b2613c33..80824efac37 100644 --- a/test/typeparam/index.go +++ b/test/typeparam/index.go @@ -26,6 +26,26 @@ type obj struct { x int } +type obj2 struct { + x int8 + y float64 +} + +type obj3 struct { + x int64 + y int8 +} + +type inner struct { + y int64 + z int32 +} + +type obj4 struct { + x int32 + s inner +} + func main() { want := 2 @@ -43,4 +63,20 @@ func main() { if got := Index(vec3, vec3[2]); got != want { panic(fmt.Sprintf("got %d, want %d", got, want)) } + + vec4 := []obj2{obj2{2, 3.0}, obj2{3, 4.0}, obj2{4, 5.0}} + if got := Index(vec4, vec4[2]); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + vec5 := []obj3{obj3{2, 3}, obj3{3, 4}, obj3{4, 5}} + if got := Index(vec5, vec5[2]); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + vec6 := []obj4{obj4{2, inner{3, 4}}, obj4{3, inner{4, 5}}, obj4{4, inner{5, 6}}} + if got := Index(vec6, vec6[2]); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } } + From 4711bf30e5fec4cf290964785871deba5955c29a Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Wed, 30 Jun 2021 11:54:46 -0400 Subject: [PATCH 593/940] doc/go1.17: linkify "language changes" in the runtime section Change-Id: I82bd3954bfc5da59c7952eba2a28ff0e3b41427f Reviewed-on: https://go-review.googlesource.com/c/go/+/331969 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Dmitri Shuralyov --- doc/go1.17.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index b72752d77d8..66b4f48b61e 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -993,7 +993,7 @@ func Foo() bool { is no longer sufficient to guarantee that a call to Value.Convert will not panic. It may panic when converting `[]T` to `*[N]T` if the slice's length is less than N. - See the language changes section above. + See the language changes section above.

From 9d65578b83f0d52f0d2f526212dd3b4ee1a5f031 Mon Sep 17 00:00:00 2001 From: fanzha02 Date: Wed, 30 Jun 2021 10:51:54 +0800 Subject: [PATCH 594/940] cmd/compile: fix typos in document Correct "a2Spill" to "a3Spill" Change-Id: I6ac4c45973dfaeb16d3a90d835589b6af1aefe1d Reviewed-on: https://go-review.googlesource.com/c/go/+/331850 Trust: fannie zhang Reviewed-by: Cherry Mui --- src/cmd/compile/abi-internal.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/compile/abi-internal.md b/src/cmd/compile/abi-internal.md index 1ae3c2538ff..2bb40550832 100644 --- a/src/cmd/compile/abi-internal.md +++ b/src/cmd/compile/abi-internal.md @@ -233,7 +233,7 @@ stack frame is laid out in the following sequence: r1.x uintptr r1.y [2]uintptr a1Spill uint8 - a2Spill uint8 + a3Spill uint8 _ [6]uint8 // alignment padding In the stack frame, only the `a2` field is initialized on entry; the From 372b31273539b988fe887d7b7cc2ed14439278e6 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 30 Jun 2021 19:20:28 -0700 Subject: [PATCH 595/940] [dev.typeparams] cmd/compile: refactor top-level typechecking in unified IR This CL is a first step towards incremental typechecking during IR construction within unified IR. Namely, all top-level declarations are now typechecked as they're constructed, except for assignments (which aren't really declarations anyway). Change-Id: I65763a7659bf2e0f5e89dfe9e709d60e0fa4c631 Reviewed-on: https://go-review.googlesource.com/c/go/+/332097 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/noder/reader.go | 24 +++++++++--- src/cmd/compile/internal/noder/unified.go | 47 ++++++++++++++++------- 2 files changed, 53 insertions(+), 18 deletions(-) diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 4b42ae1ec38..24977ed7f0e 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -784,6 +784,8 @@ func (r *reader) funcExt(name *ir.Name) { fn.Pragma = r.pragmaFlag() r.linkname(name) + typecheck.Func(fn) + if r.bool() { fn.ABI = obj.ABI(r.uint64()) @@ -2124,7 +2126,7 @@ func (r *reader) methodWrapper(derefs int, tbase *types.Type, method *types.Fiel // TODO(mdempsky): Use method.Pos instead? pos := base.AutogeneratedPos - fn := r.newWrapperFunc(pos, sym, wrapper, method, target) + fn := r.newWrapperFunc(pos, sym, wrapper, method) var recv ir.Node = fn.Nname.Type().Recv().Nname.(*ir.Name) @@ -2143,6 +2145,8 @@ func (r *reader) methodWrapper(derefs int, tbase *types.Type, method *types.Fiel } addTailCall(pos, fn, recv, method) + + r.finishWrapperFunc(fn, target) } func (r *reader) methodValueWrapper(tbase *types.Type, method *types.Field, target *ir.Package) { @@ -2167,7 +2171,7 @@ func (r *reader) methodValueWrapper(tbase *types.Type, method *types.Field, targ // TODO(mdempsky): Use method.Pos instead? pos := base.AutogeneratedPos - fn := r.newWrapperFunc(pos, sym, nil, method, target) + fn := r.newWrapperFunc(pos, sym, nil, method) fn.SetNeedctxt(true) sym.Def = fn @@ -2181,9 +2185,11 @@ func (r *reader) methodValueWrapper(tbase *types.Type, method *types.Field, targ fn.ClosureVars = append(fn.ClosureVars, recv) addTailCall(pos, fn, recv, method) + + r.finishWrapperFunc(fn, target) } -func (r *reader) newWrapperFunc(pos src.XPos, sym *types.Sym, wrapper *types.Type, method *types.Field, target *ir.Package) *ir.Func { +func (r *reader) newWrapperFunc(pos src.XPos, sym *types.Sym, wrapper *types.Type, method *types.Field) *ir.Func { fn := ir.NewFunc(pos) fn.SetDupok(true) // TODO(mdempsky): Leave unset for local, non-generic wrappers? @@ -2214,11 +2220,19 @@ func (r *reader) newWrapperFunc(pos src.XPos, sym *types.Sym, wrapper *types.Typ defParams(ir.PPARAM, sig.Params()) defParams(ir.PPARAMOUT, sig.Results()) - target.Decls = append(target.Decls, fn) - return fn } +func (r *reader) finishWrapperFunc(fn *ir.Func, target *ir.Package) { + typecheck.Func(fn) + + ir.WithFunc(fn, func() { + typecheck.Stmts(fn.Body) + }) + + target.Decls = append(target.Decls, fn) +} + // newWrapperType returns a copy of the given signature type, but with // the receiver parameter type substituted with recvType. // If recvType is nil, newWrapperType returns a signature diff --git a/src/cmd/compile/internal/noder/unified.go b/src/cmd/compile/internal/noder/unified.go index 8397f14be83..03bcb2755b2 100644 --- a/src/cmd/compile/internal/noder/unified.go +++ b/src/cmd/compile/internal/noder/unified.go @@ -109,6 +109,16 @@ func unified(noders []*noder) { r.ext = r r.pkgInit(types.LocalPkg, target) + // Type-check any top-level assignments. We ignore non-assignments + // here because other declarations are typechecked as they're + // constructed. + for i, ndecls := 0, len(target.Decls); i < ndecls; i++ { + switch n := target.Decls[i]; n.Op() { + case ir.OAS, ir.OAS2: + target.Decls[i] = typecheck.Stmt(n) + } + } + // Don't use range--bodyIdx can add closures to todoBodies. for len(todoBodies) > 0 { // The order we expand bodies doesn't matter, so pop from the end @@ -122,22 +132,12 @@ func unified(noders []*noder) { // Instantiated generic function: add to Decls for typechecking // and compilation. - if pri.dict != nil && len(pri.dict.targs) != 0 && fn.OClosure == nil { + if fn.OClosure == nil && len(pri.dict.targs) != 0 { target.Decls = append(target.Decls, fn) } } todoBodies = nil - if !quirksMode() { - // TODO(mdempsky): Investigate generating wrappers in quirks mode too. - r.wrapTypes(target) - } - - // Don't use range--typecheck can add closures to Target.Decls. - for i := 0; i < len(target.Decls); i++ { - target.Decls[i] = typecheck.Stmt(target.Decls[i]) - } - // Don't use range--typecheck can add closures to Target.Decls. for i := 0; i < len(target.Decls); i++ { if fn, ok := target.Decls[i].(*ir.Func); ok { @@ -145,8 +145,9 @@ func unified(noders []*noder) { s := fmt.Sprintf("\nbefore typecheck %v", fn) ir.Dump(s, fn) } - ir.CurFunc = fn - typecheck.Stmts(fn.Body) + ir.WithFunc(fn, func() { + typecheck.Stmts(fn.Body) + }) if base.Flag.W > 1 { s := fmt.Sprintf("\nafter typecheck %v", fn) ir.Dump(s, fn) @@ -154,6 +155,26 @@ func unified(noders []*noder) { } } + if !quirksMode() { + // TODO(mdempsky): Investigate generating wrappers in quirks mode too. + r.wrapTypes(target) + } + + // Check that nothing snuck past typechecking. + for _, n := range target.Decls { + if n.Typecheck() == 0 { + base.FatalfAt(n.Pos(), "missed typecheck: %v", n) + } + + // For functions, check that at least their first statement (if + // any) was typechecked too. + if fn, ok := n.(*ir.Func); ok && len(fn.Body) != 0 { + if stmt := fn.Body[0]; stmt.Typecheck() == 0 { + base.FatalfAt(stmt.Pos(), "missed typecheck: %v", stmt) + } + } + } + base.ExitIfErrors() // just in case } From 706c580ee1db800353752629882209ef6509a0b4 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 1 Jul 2021 00:28:05 -0700 Subject: [PATCH 596/940] [dev.typeparams] cmd/compile: simplify autotmpname Rather than manually formatting a byte-string and then using a map lookup to convert it to string, we can just use a slice. This avoids both the overhead of formatting the byte slice and the map lookup. Change-Id: Ia7b883632ea990ce9ee848dd4b4e4cdfbd611212 Reviewed-on: https://go-review.googlesource.com/c/go/+/332191 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/typecheck/dcl.go | 31 +++++++++++++++++------ 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/cmd/compile/internal/typecheck/dcl.go b/src/cmd/compile/internal/typecheck/dcl.go index 5f8b8b3d417..f3ccbb4ac09 100644 --- a/src/cmd/compile/internal/typecheck/dcl.go +++ b/src/cmd/compile/internal/typecheck/dcl.go @@ -6,7 +6,7 @@ package typecheck import ( "fmt" - "strconv" + "sync" "cmd/compile/internal/base" "cmd/compile/internal/ir" @@ -430,15 +430,30 @@ func TempAt(pos src.XPos, curfn *ir.Func, t *types.Type) *ir.Name { return n } +var ( + autotmpnamesmu sync.Mutex + autotmpnames []string +) + // autotmpname returns the name for an autotmp variable numbered n. func autotmpname(n int) string { - // Give each tmp a different name so that they can be registerized. - // Add a preceding . to avoid clashing with legal names. - const prefix = ".autotmp_" - // Start with a buffer big enough to hold a large n. - b := []byte(prefix + " ")[:len(prefix)] - b = strconv.AppendInt(b, int64(n), 10) - return types.InternString(b) + autotmpnamesmu.Lock() + defer autotmpnamesmu.Unlock() + + // Grow autotmpnames, if needed. + if n >= len(autotmpnames) { + autotmpnames = append(autotmpnames, make([]string, n+1-len(autotmpnames))...) + autotmpnames = autotmpnames[:cap(autotmpnames)] + } + + s := autotmpnames[n] + if s == "" { + // Give each tmp a different name so that they can be registerized. + // Add a preceding . to avoid clashing with legal names. + s = fmt.Sprintf(".autotmp_%d", n) + autotmpnames[n] = s + } + return s } // f is method type, with receiver. From 1cd505c353e4656ba28fd8de8708e8c8e6c21cbf Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 28 Jun 2021 19:41:29 -0700 Subject: [PATCH 597/940] [dev.typeparams] cmd/compile/internal/types2: "comparable" must not be visible before Go 1.18 While at it, clean up the setup of comparable in universe.go. Fixes #46090 Change-Id: I9655b3e137a03763d677d9a2a730c5570ccff6dc Reviewed-on: https://go-review.googlesource.com/c/go/+/331517 Trust: Robert Griesemer Reviewed-by: Robert Findley --- .../types2/testdata/fixedbugs/issue46090.go2 | 9 +++ src/cmd/compile/internal/types2/typexpr.go | 2 +- src/cmd/compile/internal/types2/universe.go | 61 +++++++------------ 3 files changed, 32 insertions(+), 40 deletions(-) create mode 100644 src/cmd/compile/internal/types2/testdata/fixedbugs/issue46090.go2 diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue46090.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue46090.go2 new file mode 100644 index 00000000000..81b31974c8d --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue46090.go2 @@ -0,0 +1,9 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The predeclared type comparable is not visible before Go 1.18. + +package go1_17 + +type _ comparable // ERROR undeclared diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index fe676be2efd..5626fed7568 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -25,7 +25,7 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *Named, wantType boo // Note that we cannot use check.lookup here because the returned scope // may be different from obj.Parent(). See also Scope.LookupParent doc. scope, obj := check.scope.LookupParent(e.Value, check.pos) - if obj == nil { + if obj == nil || obj == universeComparable && !check.allowVersion(check.pkg, 1, 18) { if e.Value == "_" { check.error(e, "cannot use _ as value or type") } else { diff --git a/src/cmd/compile/internal/types2/universe.go b/src/cmd/compile/internal/types2/universe.go index 2bcc49778ef..c9b53bac921 100644 --- a/src/cmd/compile/internal/types2/universe.go +++ b/src/cmd/compile/internal/types2/universe.go @@ -20,11 +20,12 @@ var Universe *Scope var Unsafe *Package var ( - universeIota *Const - universeByte *Basic // uint8 alias, but has name "byte" - universeRune *Basic // int32 alias, but has name "rune" - universeAny *Interface - universeError *Named + universeIota *Const + universeByte *Basic // uint8 alias, but has name "byte" + universeRune *Basic // int32 alias, but has name "rune" + universeAny *Interface + universeError *Named + universeComparable Object ) // Typ contains the predeclared *Basic types indexed by their @@ -77,21 +78,30 @@ func defPredeclaredTypes() { def(NewTypeName(nopos, nil, t.name, t)) } - // any - // (Predeclared and entered into universe scope so we do all the - // usual checks; but removed again from scope later since it's - // only visible as constraint in a type parameter list.) + // type any = interface{} + // Entered into universe scope so we do all the usual checks; + // but removed again from scope later since it's only visible + // as constraint in a type parameter list. def(NewTypeName(nopos, nil, "any", &emptyInterface)) - // Error has a nil package in its qualified name since it is in no package + // type error interface{ Error() string } { res := NewVar(nopos, nil, "", Typ[String]) - sig := &Signature{results: NewTuple(res)} + sig := NewSignature(nil, nil, NewTuple(res), false) err := NewFunc(nopos, nil, "Error", sig) typ := &Named{underlying: NewInterfaceType([]*Func{err}, nil)} sig.recv = NewVar(nopos, nil, "", typ) def(NewTypeName(nopos, nil, "error", typ)) } + + // type comparable interface{ ==() } + { + sig := NewSignature(nil, nil, nil, false) + eql := NewFunc(nopos, nil, "==", sig) + typ := &Named{underlying: NewInterfaceType([]*Func{eql}, nil)} + sig.recv = NewVar(nopos, nil, "", typ) + def(NewTypeName(nopos, nil, "comparable", typ)) + } } var predeclaredConsts = [...]struct { @@ -200,33 +210,6 @@ func DefPredeclaredTestFuncs() { def(newBuiltin(_Trace)) } -func defPredeclaredComparable() { - // The "comparable" interface can be imagined as defined like - // - // type comparable interface { - // == () untyped bool - // != () untyped bool - // } - // - // == and != cannot be user-declared but we can declare - // a magic method == and check for its presence when needed. - - // Define interface { == () }. We don't care about the signature - // for == so leave it empty except for the receiver, which is - // set up later to match the usual interface method assumptions. - sig := new(Signature) - eql := NewFunc(nopos, nil, "==", sig) - iface := NewInterfaceType([]*Func{eql}, nil) - - // set up the defined type for the interface - obj := NewTypeName(nopos, nil, "comparable", nil) - named := NewNamed(obj, iface, nil) - obj.color_ = black - sig.recv = NewVar(nopos, nil, "", named) // complete == signature - - def(obj) -} - func init() { Universe = NewScope(nil, nopos, nopos, "universe") Unsafe = NewPackage("unsafe", "unsafe") @@ -236,13 +219,13 @@ func init() { defPredeclaredConsts() defPredeclaredNil() defPredeclaredFuncs() - defPredeclaredComparable() universeIota = Universe.Lookup("iota").(*Const) universeByte = Universe.Lookup("byte").(*TypeName).typ.(*Basic) universeRune = Universe.Lookup("rune").(*TypeName).typ.(*Basic) universeAny = Universe.Lookup("any").(*TypeName).typ.(*Interface) universeError = Universe.Lookup("error").(*TypeName).typ.(*Named) + universeComparable = Universe.Lookup("comparable") // "any" is only visible as constraint in a type parameter list delete(Universe.elems, "any") From 9cb1b0f50b5852b24e1a7b66f09faa1a521ae108 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 29 Jun 2021 12:22:21 -0700 Subject: [PATCH 598/940] [dev.typeparams] cmd/compile/internal/types2: delay interface check for type bounds While at it, clean up code for collecting/declaring type parameters. For #40789. Change-Id: I0855137d5ee85c0ae2fa60d33b28c24a33132fbc Reviewed-on: https://go-review.googlesource.com/c/go/+/331690 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/decl.go | 97 +++++++------------ src/cmd/compile/internal/types2/signature.go | 7 +- .../types2/testdata/fixedbugs/issue40789.go2 | 37 +++++++ src/cmd/compile/internal/types2/type.go | 6 +- 4 files changed, 82 insertions(+), 65 deletions(-) create mode 100644 src/cmd/compile/internal/types2/testdata/fixedbugs/issue40789.go2 diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go index 00b4ef70107..d36da06f421 100644 --- a/src/cmd/compile/internal/types2/decl.go +++ b/src/cmd/compile/internal/types2/decl.go @@ -674,77 +674,54 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named } -func (check *Checker) collectTypeParams(list []*syntax.Field) (tparams []*TypeName) { - // Type parameter lists should not be empty. The parser will - // complain but we still may get an incorrect AST: ignore it. - if len(list) == 0 { - return - } +func (check *Checker) collectTypeParams(list []*syntax.Field) []*TypeName { + tparams := make([]*TypeName, len(list)) - // Declare type parameters up-front, with empty interface as type bound. + // Declare type parameters up-front. // The scope of type parameters starts at the beginning of the type parameter - // list (so we can have mutually recursive parameterized interfaces). - for _, f := range list { - tparams = check.declareTypeParam(tparams, f.Name) + // list (so we can have mutually recursive parameterized type bounds). + for i, f := range list { + tparams[i] = check.declareTypeParam(i, f.Name) } var bound Type - for i, j := 0, 0; i < len(list); i = j { - f := list[i] - - // determine the range of type parameters list[i:j] with identical type bound - // (declared as in (type a, b, c B)) - j = i + 1 - for j < len(list) && list[j].Type == f.Type { - j++ + for i, f := range list { + // Optimization: Re-use the previous type bound if it hasn't changed. + // This also preserves the grouped output of type parameter lists + // when printing type strings. + if i == 0 || f.Type != list[i-1].Type { + bound = check.boundType(f.Type) } - - // this should never be the case, but be careful - if f.Type == nil { - continue - } - - // The predeclared identifier "any" is visible only as a constraint - // in a type parameter list. Look for it before general constraint - // resolution. - if tident, _ := unparen(f.Type).(*syntax.Name); tident != nil && tident.Value == "any" && check.lookup("any") == nil { - bound = universeAny - } else { - bound = check.typ(f.Type) - } - - // type bound must be an interface - // TODO(gri) We should delay the interface check because - // we may not have a complete interface yet: - // type C(type T C) interface {} - // (issue #39724). - if _, ok := under(bound).(*Interface); ok { - // set the type bounds - for i < j { - tparams[i].typ.(*TypeParam).bound = bound - i++ - } - } else if bound != Typ[Invalid] { - check.errorf(f.Type, "%s is not an interface", bound) - } - } - - return -} - -func (check *Checker) declareTypeParam(tparams []*TypeName, name *syntax.Name) []*TypeName { - tpar := NewTypeName(name.Pos(), check.pkg, name.Value, nil) - check.NewTypeParam(tpar, len(tparams), &emptyInterface) // assigns type to tpar as a side-effect - check.declare(check.scope, name, tpar, check.scope.pos) // TODO(gri) check scope position - tparams = append(tparams, tpar) - - if check.conf.Trace { - check.trace(name.Pos(), "type param = %v", tparams[len(tparams)-1]) + tparams[i].typ.(*TypeParam).bound = bound } return tparams } +func (check *Checker) declareTypeParam(index int, name *syntax.Name) *TypeName { + tpar := NewTypeName(name.Pos(), check.pkg, name.Value, nil) + check.NewTypeParam(tpar, index, nil) // assigns type to tpar as a side-effect + check.declare(check.scope, name, tpar, check.scope.pos) // TODO(gri) check scope position + return tpar +} + +// boundType type-checks the type expression e and returns its type, or Typ[Invalid]. +// The type must be an interface, including the predeclared type "any". +func (check *Checker) boundType(e syntax.Expr) Type { + // The predeclared identifier "any" is visible only as a type bound in a type parameter list. + if name, _ := unparen(e).(*syntax.Name); name != nil && name.Value == "any" && check.lookup("any") == nil { + return universeAny + } + + bound := check.typ(e) + check.later(func() { + if _, ok := under(bound).(*Interface); !ok && bound != Typ[Invalid] { + check.errorf(e, "%s is not an interface", bound) + } + }) + return bound +} + func (check *Checker) collectMethods(obj *TypeName) { // get associated methods // (Checker.collectObjects only collects methods with non-blank names; diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go index a7edc5ac03d..01158187ba7 100644 --- a/src/cmd/compile/internal/types2/signature.go +++ b/src/cmd/compile/internal/types2/signature.go @@ -48,10 +48,9 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams [] // blank identifiers were found => use rewritten receiver type recvTyp = isubst(recvPar.Type, smap) } - // TODO(gri) rework declareTypeParams - sig.rparams = nil - for _, rparam := range rparams { - sig.rparams = check.declareTypeParam(sig.rparams, rparam) + sig.rparams = make([]*TypeName, len(rparams)) + for i, rparam := range rparams { + sig.rparams[i] = check.declareTypeParam(i, rparam) } // determine receiver type to get its type parameters // and the respective type parameter bounds diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40789.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40789.go2 new file mode 100644 index 00000000000..9eea4ad60a6 --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40789.go2 @@ -0,0 +1,37 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "fmt" + +func main() { + m := map[string]int{ + "a": 6, + "b": 7, + } + fmt.Println(copyMap[map[string]int, string, int](m)) +} + +type Map[K comparable, V any] interface { + map[K] V +} + +func copyMap[M Map[K, V], K comparable, V any](m M) M { + m1 := make(M) + for k, v := range m { + m1[k] = v + } + return m1 +} + +// simpler test case from the same issue + +type A[X comparable] interface { + []X +} + +func f[B A[X], X comparable]() B { + return nil +} diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index 2cfcabbdb55..05e6d77d224 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -626,7 +626,11 @@ func (t *TypeParam) SetId(id uint64) { } func (t *TypeParam) Bound() *Interface { - iface := asInterface(t.bound) + // we may not have an interface (error reported elsewhere) + iface, _ := under(t.bound).(*Interface) + if iface == nil { + return &emptyInterface + } // use the type bound position if we have one pos := nopos if n, _ := t.bound.(*Named); n != nil { From 1eb756689c413c84bb2bf91396b54028671bc541 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 30 Jun 2021 11:21:32 -0700 Subject: [PATCH 599/940] [dev.typeparams] cmd/compile/internal/types2: make Interface.obj a *TypeName We know the exact type, so make it that. This saves some code and a word of space with each Interface. Follow-up on a comment in https://golang.org/cl/329309. Change-Id: I827e39d17aae159a52ac563544c5e6d017bc05ec Reviewed-on: https://go-review.googlesource.com/c/go/+/332011 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/call.go | 7 +++---- src/cmd/compile/internal/types2/sizeof_test.go | 2 +- src/cmd/compile/internal/types2/type.go | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index 34dafce8bf7..3377270ef80 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -479,11 +479,10 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) { var why string if tpar := asTypeParam(x.typ); tpar != nil { // Type parameter bounds don't specify fields, so don't mention "field". - switch obj := tpar.Bound().obj.(type) { - case nil: + if tname := tpar.Bound().obj; tname != nil { + why = check.sprintf("interface %s has no method %s", tname.name, sel) + } else { why = check.sprintf("type bound for %s has no method %s", x.typ, sel) - case *TypeName: - why = check.sprintf("interface %s has no method %s", obj.name, sel) } } else { why = check.sprintf("type %s has no field or method %s", x.typ, sel) diff --git a/src/cmd/compile/internal/types2/sizeof_test.go b/src/cmd/compile/internal/types2/sizeof_test.go index 82e1221b67e..0b1f7dacad3 100644 --- a/src/cmd/compile/internal/types2/sizeof_test.go +++ b/src/cmd/compile/internal/types2/sizeof_test.go @@ -28,7 +28,7 @@ func TestSizeof(t *testing.T) { {Tuple{}, 12, 24}, {Signature{}, 44, 88}, {Union{}, 24, 48}, - {Interface{}, 44, 88}, + {Interface{}, 40, 80}, {Map{}, 16, 32}, {Chan{}, 12, 24}, {Named{}, 84, 160}, diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index 05e6d77d224..f8aa453d5ca 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -264,7 +264,7 @@ func (s *Signature) Variadic() bool { return s.variadic } // An Interface represents an interface type. type Interface struct { - obj Object // type name object defining this interface; or nil (for better error messages) + obj *TypeName // corresponding declared object; or nil (for better error messages) methods []*Func // ordered list of explicitly declared methods embeddeds []Type // ordered list of explicitly embedded elements embedPos *[]syntax.Pos // positions of embedded elements; or nil (for error messages) - use pointer to save space From fac21803ce513b3d8cab1629f37fd0a9ea2fbe07 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 30 Jun 2021 12:45:51 -0700 Subject: [PATCH 600/940] [dev.typeparams] cmd/compile/internal/types2: rename newTypeSet -> computeTypeSet Follow-up on comment in https://golang.org/cl/329309. Change-Id: I31f746180237b916c1825fa1688641849478ba41 Reviewed-on: https://go-review.googlesource.com/c/go/+/332089 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/interface.go | 2 +- src/cmd/compile/internal/types2/type.go | 4 ++-- src/cmd/compile/internal/types2/typeset.go | 6 +++--- src/cmd/compile/internal/types2/typexpr.go | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go index 18dc573340b..1f4e80951a2 100644 --- a/src/cmd/compile/internal/types2/interface.go +++ b/src/cmd/compile/internal/types2/interface.go @@ -114,7 +114,7 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType // Compute type set with a non-nil *Checker as soon as possible // to report any errors. Subsequent uses of type sets should be // using this computed type set and won't need to pass in a *Checker. - check.later(func() { newTypeSet(check, iface.Pos(), ityp) }) + check.later(func() { computeTypeSet(check, iface.Pos(), ityp) }) } func flattenUnion(list []syntax.Expr, x syntax.Expr) []syntax.Expr { diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index f8aa453d5ca..b41dceea700 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -274,7 +274,7 @@ type Interface struct { } // typeSet returns the type set for interface t. -func (t *Interface) typeSet() *TypeSet { return newTypeSet(nil, nopos, t) } +func (t *Interface) typeSet() *TypeSet { return computeTypeSet(nil, nopos, t) } // is reports whether interface t represents types that all satisfy f. func (t *Interface) is(f func(Type, bool) bool) bool { @@ -637,7 +637,7 @@ func (t *TypeParam) Bound() *Interface { pos = n.obj.pos } // TODO(gri) switch this to an unexported method on Checker. - newTypeSet(t.check, pos, iface) + computeTypeSet(t.check, pos, iface) return iface } diff --git a/src/cmd/compile/internal/types2/typeset.go b/src/cmd/compile/internal/types2/typeset.go index ce4a776f8f0..265221501f2 100644 --- a/src/cmd/compile/internal/types2/typeset.go +++ b/src/cmd/compile/internal/types2/typeset.go @@ -78,8 +78,8 @@ func (s *TypeSet) String() string { // topTypeSet may be used as type set for the empty interface. var topTypeSet TypeSet -// newTypeSet may be called with check == nil. -func newTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet { +// computeTypeSet may be called with check == nil. +func computeTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet { if ityp.tset != nil { return ityp.tset } @@ -188,7 +188,7 @@ func newTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet { var types Type switch t := under(typ).(type) { case *Interface: - tset := newTypeSet(check, pos, t) + tset := computeTypeSet(check, pos, t) for _, m := range tset.methods { addMethod(pos, m, false) // use embedding position pos rather than m.pos } diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index 5626fed7568..e861f7e7848 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -141,7 +141,7 @@ func (check *Checker) ordinaryType(pos syntax.Pos, typ Type) { // interface methods. Delay this check to the end of type-checking. check.later(func() { if t := asInterface(typ); t != nil { - tset := newTypeSet(check, pos, t) // TODO(gri) is this the correct position? + tset := computeTypeSet(check, pos, t) // TODO(gri) is this the correct position? if tset.types != nil { check.softErrorf(pos, "interface contains type constraints (%s)", tset.types) return From 1aadb18f83bd9e0e2faf2ccc9bce301108aa1221 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 30 Jun 2021 12:56:50 -0700 Subject: [PATCH 601/940] [dev.typeparams] cmd/compile/internal/types2: move Struct type decl into struct.go (cleanup) Change-Id: I074550236785091d2f79dd5de73c3462614c5c0e Reviewed-on: https://go-review.googlesource.com/c/go/+/332090 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/struct.go | 46 +++++++++++++++++++++++ src/cmd/compile/internal/types2/type.go | 39 ------------------- 2 files changed, 46 insertions(+), 39 deletions(-) diff --git a/src/cmd/compile/internal/types2/struct.go b/src/cmd/compile/internal/types2/struct.go index 302b9886f40..f1d82fb50c0 100644 --- a/src/cmd/compile/internal/types2/struct.go +++ b/src/cmd/compile/internal/types2/struct.go @@ -9,6 +9,52 @@ import ( "strconv" ) +// ---------------------------------------------------------------------------- +// API + +// A Struct represents a struct type. +type Struct struct { + fields []*Var + tags []string // field tags; nil if there are no tags +} + +// NewStruct returns a new struct with the given fields and corresponding field tags. +// If a field with index i has a tag, tags[i] must be that tag, but len(tags) may be +// only as long as required to hold the tag with the largest index i. Consequently, +// if no field has a tag, tags may be nil. +func NewStruct(fields []*Var, tags []string) *Struct { + var fset objset + for _, f := range fields { + if f.name != "_" && fset.insert(f) != nil { + panic("multiple fields with the same name") + } + } + if len(tags) > len(fields) { + panic("more tags than fields") + } + return &Struct{fields: fields, tags: tags} +} + +// NumFields returns the number of fields in the struct (including blank and embedded fields). +func (s *Struct) NumFields() int { return len(s.fields) } + +// Field returns the i'th field for 0 <= i < NumFields(). +func (s *Struct) Field(i int) *Var { return s.fields[i] } + +// Tag returns the i'th field tag for 0 <= i < NumFields(). +func (s *Struct) Tag(i int) string { + if i < len(s.tags) { + return s.tags[i] + } + return "" +} + +func (s *Struct) Underlying() Type { return s } +func (s *Struct) String() string { return TypeString(s, nil) } + +// ---------------------------------------------------------------------------- +// Implementation + func (check *Checker) structType(styp *Struct, e *syntax.StructType) { if e.FieldList == nil { return diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index b41dceea700..aff97f9a983 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -124,43 +124,6 @@ func NewSlice(elem Type) *Slice { return &Slice{elem: elem} } // Elem returns the element type of slice s. func (s *Slice) Elem() Type { return s.elem } -// A Struct represents a struct type. -type Struct struct { - fields []*Var - tags []string // field tags; nil if there are no tags -} - -// NewStruct returns a new struct with the given fields and corresponding field tags. -// If a field with index i has a tag, tags[i] must be that tag, but len(tags) may be -// only as long as required to hold the tag with the largest index i. Consequently, -// if no field has a tag, tags may be nil. -func NewStruct(fields []*Var, tags []string) *Struct { - var fset objset - for _, f := range fields { - if f.name != "_" && fset.insert(f) != nil { - panic("multiple fields with the same name") - } - } - if len(tags) > len(fields) { - panic("more tags than fields") - } - return &Struct{fields: fields, tags: tags} -} - -// NumFields returns the number of fields in the struct (including blank and embedded fields). -func (s *Struct) NumFields() int { return len(s.fields) } - -// Field returns the i'th field for 0 <= i < NumFields(). -func (s *Struct) Field(i int) *Var { return s.fields[i] } - -// Tag returns the i'th field tag for 0 <= i < NumFields(). -func (s *Struct) Tag(i int) string { - if i < len(s.tags) { - return s.tags[i] - } - return "" -} - // A Pointer represents a pointer type. type Pointer struct { base Type // element type @@ -741,7 +704,6 @@ var theTop = &top{} func (t *Basic) Underlying() Type { return t } func (t *Array) Underlying() Type { return t } func (t *Slice) Underlying() Type { return t } -func (t *Struct) Underlying() Type { return t } func (t *Pointer) Underlying() Type { return t } func (t *Tuple) Underlying() Type { return t } func (t *Signature) Underlying() Type { return t } @@ -757,7 +719,6 @@ func (t *top) Underlying() Type { return t } func (t *Basic) String() string { return TypeString(t, nil) } func (t *Array) String() string { return TypeString(t, nil) } func (t *Slice) String() string { return TypeString(t, nil) } -func (t *Struct) String() string { return TypeString(t, nil) } func (t *Pointer) String() string { return TypeString(t, nil) } func (t *Tuple) String() string { return TypeString(t, nil) } func (t *Signature) String() string { return TypeString(t, nil) } From 0e0b80cb56ba3bd2128417d9368b4e74b1e45d95 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 30 Jun 2021 13:00:14 -0700 Subject: [PATCH 602/940] [dev.typeparams] cmd/compile/internal/types2: move Signature type decl into signature.go (cleanup) Change-Id: I68c9da6a87cdc15bde8bffa8cb86fb8705eb1f8e Reviewed-on: https://go-review.googlesource.com/c/go/+/332091 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/signature.go | 71 ++++++++++++++++++++ src/cmd/compile/internal/types2/type.go | 64 ------------------ 2 files changed, 71 insertions(+), 64 deletions(-) diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go index 01158187ba7..ab9a1c487eb 100644 --- a/src/cmd/compile/internal/types2/signature.go +++ b/src/cmd/compile/internal/types2/signature.go @@ -9,6 +9,77 @@ import ( "fmt" ) +// ---------------------------------------------------------------------------- +// API + +// A Signature represents a (non-builtin) function or method type. +// The receiver is ignored when comparing signatures for identity. +type Signature struct { + // We need to keep the scope in Signature (rather than passing it around + // and store it in the Func Object) because when type-checking a function + // literal we call the general type checker which returns a general Type. + // We then unpack the *Signature and use the scope for the literal body. + rparams []*TypeName // receiver type parameters from left to right; or nil + tparams []*TypeName // type parameters from left to right; or nil + scope *Scope // function scope, present for package-local signatures + recv *Var // nil if not a method + params *Tuple // (incoming) parameters from left to right; or nil + results *Tuple // (outgoing) results from left to right; or nil + variadic bool // true if the last parameter's type is of the form ...T (or string, for append built-in only) +} + +// NewSignature returns a new function type for the given receiver, parameters, +// and results, either of which may be nil. If variadic is set, the function +// is variadic, it must have at least one parameter, and the last parameter +// must be of unnamed slice type. +func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature { + if variadic { + n := params.Len() + if n == 0 { + panic("types2.NewSignature: variadic function must have at least one parameter") + } + if _, ok := params.At(n - 1).typ.(*Slice); !ok { + panic("types2.NewSignature: variadic parameter must be of unnamed slice type") + } + } + return &Signature{recv: recv, params: params, results: results, variadic: variadic} +} + +// Recv returns the receiver of signature s (if a method), or nil if a +// function. It is ignored when comparing signatures for identity. +// +// For an abstract method, Recv returns the enclosing interface either +// as a *Named or an *Interface. Due to embedding, an interface may +// contain methods whose receiver type is a different interface. +func (s *Signature) Recv() *Var { return s.recv } + +// TParams returns the type parameters of signature s, or nil. +func (s *Signature) TParams() []*TypeName { return s.tparams } + +// RParams returns the receiver type params of signature s, or nil. +func (s *Signature) RParams() []*TypeName { return s.rparams } + +// SetTParams sets the type parameters of signature s. +func (s *Signature) SetTParams(tparams []*TypeName) { s.tparams = tparams } + +// SetRParams sets the receiver type params of signature s. +func (s *Signature) SetRParams(rparams []*TypeName) { s.rparams = rparams } + +// Params returns the parameters of signature s, or nil. +func (s *Signature) Params() *Tuple { return s.params } + +// Results returns the results of signature s, or nil. +func (s *Signature) Results() *Tuple { return s.results } + +// Variadic reports whether the signature s is variadic. +func (s *Signature) Variadic() bool { return s.variadic } + +func (s *Signature) Underlying() Type { return s } +func (s *Signature) String() string { return TypeString(s, nil) } + +// ---------------------------------------------------------------------------- +// Implementation + // Disabled by default, but enabled when running tests (via types_test.go). var acceptMethodTypeParams bool diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index aff97f9a983..3a9511de48b 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -163,68 +163,6 @@ func (t *Tuple) Len() int { // At returns the i'th variable of tuple t. func (t *Tuple) At(i int) *Var { return t.vars[i] } -// A Signature represents a (non-builtin) function or method type. -// The receiver is ignored when comparing signatures for identity. -type Signature struct { - // We need to keep the scope in Signature (rather than passing it around - // and store it in the Func Object) because when type-checking a function - // literal we call the general type checker which returns a general Type. - // We then unpack the *Signature and use the scope for the literal body. - rparams []*TypeName // receiver type parameters from left to right; or nil - tparams []*TypeName // type parameters from left to right; or nil - scope *Scope // function scope, present for package-local signatures - recv *Var // nil if not a method - params *Tuple // (incoming) parameters from left to right; or nil - results *Tuple // (outgoing) results from left to right; or nil - variadic bool // true if the last parameter's type is of the form ...T (or string, for append built-in only) -} - -// NewSignature returns a new function type for the given receiver, parameters, -// and results, either of which may be nil. If variadic is set, the function -// is variadic, it must have at least one parameter, and the last parameter -// must be of unnamed slice type. -func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature { - if variadic { - n := params.Len() - if n == 0 { - panic("types2.NewSignature: variadic function must have at least one parameter") - } - if _, ok := params.At(n - 1).typ.(*Slice); !ok { - panic("types2.NewSignature: variadic parameter must be of unnamed slice type") - } - } - return &Signature{recv: recv, params: params, results: results, variadic: variadic} -} - -// Recv returns the receiver of signature s (if a method), or nil if a -// function. It is ignored when comparing signatures for identity. -// -// For an abstract method, Recv returns the enclosing interface either -// as a *Named or an *Interface. Due to embedding, an interface may -// contain methods whose receiver type is a different interface. -func (s *Signature) Recv() *Var { return s.recv } - -// TParams returns the type parameters of signature s, or nil. -func (s *Signature) TParams() []*TypeName { return s.tparams } - -// RParams returns the receiver type params of signature s, or nil. -func (s *Signature) RParams() []*TypeName { return s.rparams } - -// SetTParams sets the type parameters of signature s. -func (s *Signature) SetTParams(tparams []*TypeName) { s.tparams = tparams } - -// SetRParams sets the receiver type params of signature s. -func (s *Signature) SetRParams(rparams []*TypeName) { s.rparams = rparams } - -// Params returns the parameters of signature s, or nil. -func (s *Signature) Params() *Tuple { return s.params } - -// Results returns the results of signature s, or nil. -func (s *Signature) Results() *Tuple { return s.results } - -// Variadic reports whether the signature s is variadic. -func (s *Signature) Variadic() bool { return s.variadic } - // An Interface represents an interface type. type Interface struct { obj *TypeName // corresponding declared object; or nil (for better error messages) @@ -706,7 +644,6 @@ func (t *Array) Underlying() Type { return t } func (t *Slice) Underlying() Type { return t } func (t *Pointer) Underlying() Type { return t } func (t *Tuple) Underlying() Type { return t } -func (t *Signature) Underlying() Type { return t } func (t *Interface) Underlying() Type { return t } func (t *Map) Underlying() Type { return t } func (t *Chan) Underlying() Type { return t } @@ -721,7 +658,6 @@ func (t *Array) String() string { return TypeString(t, nil) } func (t *Slice) String() string { return TypeString(t, nil) } func (t *Pointer) String() string { return TypeString(t, nil) } func (t *Tuple) String() string { return TypeString(t, nil) } -func (t *Signature) String() string { return TypeString(t, nil) } func (t *Interface) String() string { return TypeString(t, nil) } func (t *Map) String() string { return TypeString(t, nil) } func (t *Chan) String() string { return TypeString(t, nil) } From eb437ba92cbb08a86ae064cbd7376c4a8e80485b Mon Sep 17 00:00:00 2001 From: go101 Date: Thu, 1 Jul 2021 14:25:45 +0000 Subject: [PATCH 603/940] cmd/compile: make stack value size threshold comparisons consistent Consistency is beautiful. Change-Id: Ib110dcff0ce2fa87b5576c79cd79c83aab385a7c GitHub-Last-Rev: b8758f8ae02cb025267aa87ebc5c2f9b4c32e742 GitHub-Pull-Request: golang/go#47011 Reviewed-on: https://go-review.googlesource.com/c/go/+/332230 Reviewed-by: Keith Randall Reviewed-by: Robert Griesemer Run-TryBot: Keith Randall TryBot-Result: Go Bot --- src/cmd/compile/internal/escape/escape.go | 8 ++++---- src/cmd/compile/internal/walk/builtin.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cmd/compile/internal/escape/escape.go b/src/cmd/compile/internal/escape/escape.go index 3ac7ff1ebe1..cd56f07b614 100644 --- a/src/cmd/compile/internal/escape/escape.go +++ b/src/cmd/compile/internal/escape/escape.go @@ -2013,14 +2013,14 @@ func HeapAllocReason(n ir.Node) string { return "too large for stack" } - if (n.Op() == ir.ONEW || n.Op() == ir.OPTRLIT) && n.Type().Elem().Width >= ir.MaxImplicitStackVarSize { + if (n.Op() == ir.ONEW || n.Op() == ir.OPTRLIT) && n.Type().Elem().Width > ir.MaxImplicitStackVarSize { return "too large for stack" } - if n.Op() == ir.OCLOSURE && typecheck.ClosureType(n.(*ir.ClosureExpr)).Size() >= ir.MaxImplicitStackVarSize { + if n.Op() == ir.OCLOSURE && typecheck.ClosureType(n.(*ir.ClosureExpr)).Size() > ir.MaxImplicitStackVarSize { return "too large for stack" } - if n.Op() == ir.OCALLPART && typecheck.PartialCallType(n.(*ir.SelectorExpr)).Size() >= ir.MaxImplicitStackVarSize { + if n.Op() == ir.OCALLPART && typecheck.PartialCallType(n.(*ir.SelectorExpr)).Size() > ir.MaxImplicitStackVarSize { return "too large for stack" } @@ -2033,7 +2033,7 @@ func HeapAllocReason(n ir.Node) string { if !ir.IsSmallIntConst(r) { return "non-constant size" } - if t := n.Type(); t.Elem().Width != 0 && ir.Int64Val(r) >= ir.MaxImplicitStackVarSize/t.Elem().Width { + if t := n.Type(); t.Elem().Width != 0 && ir.Int64Val(r) > ir.MaxImplicitStackVarSize/t.Elem().Width { return "too large for stack" } } diff --git a/src/cmd/compile/internal/walk/builtin.go b/src/cmd/compile/internal/walk/builtin.go index 1f08e4d3128..14efc05e327 100644 --- a/src/cmd/compile/internal/walk/builtin.go +++ b/src/cmd/compile/internal/walk/builtin.go @@ -489,7 +489,7 @@ func walkNew(n *ir.UnaryExpr, init *ir.Nodes) ir.Node { base.Errorf("%v can't be allocated in Go; it is incomplete (or unallocatable)", n.Type().Elem()) } if n.Esc() == ir.EscNone { - if t.Size() >= ir.MaxImplicitStackVarSize { + if t.Size() > ir.MaxImplicitStackVarSize { base.Fatalf("large ONEW with EscNone: %v", n) } return stackTempAddr(init, t) From 835d86a17ebf32a3cb081f66119c74363dbd8825 Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Wed, 23 Jun 2021 01:02:33 +0900 Subject: [PATCH 604/940] cmd/go: use path.Dir instead of filepath.Dir for package paths in 'go mod vendor' copyMetadata walk-up to parent directory until the pkg become modPath. But pkg should be slash-separated paths. It have to use path.Dir instead of filepath.Dir. Fixes #46867 Change-Id: I44cf1429fe52379a7415b94cc30ae3275cc430e8 Reviewed-on: https://go-review.googlesource.com/c/go/+/330149 Reviewed-by: Bryan C. Mills Trust: Bryan C. Mills Trust: Alexander Rakoczy Trust: Carlos Amedee Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot --- src/cmd/go/internal/modcmd/vendor.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cmd/go/internal/modcmd/vendor.go b/src/cmd/go/internal/modcmd/vendor.go index 8e1c0432f72..713d5f9f3fa 100644 --- a/src/cmd/go/internal/modcmd/vendor.go +++ b/src/cmd/go/internal/modcmd/vendor.go @@ -13,6 +13,7 @@ import ( "io" "io/fs" "os" + "path" "path/filepath" "sort" "strings" @@ -299,7 +300,7 @@ func copyMetadata(modPath, pkg, dst, src string, copiedFiles map[string]bool) { if modPath == pkg { break } - pkg = filepath.Dir(pkg) + pkg = path.Dir(pkg) dst = filepath.Dir(dst) src = filepath.Dir(src) } From 770899f7e11e32ee8500fc033a0aad369a6a5f7b Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Thu, 1 Jul 2021 12:32:05 -0400 Subject: [PATCH 605/940] cmd/go: add a regression test for 'go mod vendor' path traversal For #46867 Change-Id: I1547ebf7b91e9ddd7b67fd2f20e91391d79fa35d Reviewed-on: https://go-review.googlesource.com/c/go/+/332250 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Jay Conrod --- .../testdata/script/mod_vendor_issue46867.txt | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/cmd/go/testdata/script/mod_vendor_issue46867.txt diff --git a/src/cmd/go/testdata/script/mod_vendor_issue46867.txt b/src/cmd/go/testdata/script/mod_vendor_issue46867.txt new file mode 100644 index 00000000000..38ae87b44a9 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor_issue46867.txt @@ -0,0 +1,31 @@ +# Regression test for golang.org/issue/46867: +# 'go mod vendor' on Windows attempted to open and copy +# files from directories outside of the module. + +cd subdir +go mod vendor +! exists vendor/example.net/NOTICE +exists vendor/example.net/m/NOTICE + +-- subdir/go.mod -- +module golang.org/issue46867 + +go 1.17 + +replace example.net/m v0.1.0 => ./m + +require example.net/m v0.1.0 +-- subdir/issue.go -- +package issue + +import _ "example.net/m/n" +-- subdir/m/go.mod -- +module example.net/m + +go 1.17 +-- subdir/m/n/n.go -- +package n +-- subdir/m/NOTICE -- +This notice is in module m and SHOULD be vendored. +-- subdir/NOTICE -- +This notice is outside of module m and SHOULD NOT be vendored. From 9ba294e15bf09636ce3069ad577d8411c9730504 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Wed, 30 Jun 2021 15:38:56 -0700 Subject: [PATCH 606/940] [dev.typeparams] cmd/compile: fix getDictionarySym for methods references, write out sub-dictionaries For method references (only), selectorExpr() now computes n.Selection, which is the generic method that is selected. This allows us to compute as needed the proper sub-dictionary for method reference. Also cleans up some code for distinguishing method references from references to a field that has a function value (especially in the presence of embedded fields). Change-Id: I9c5b789c15537ff48c70ca7a6444aa0420178a3a Reviewed-on: https://go-review.googlesource.com/c/go/+/332095 Trust: Dan Scales Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/noder/expr.go | 29 +++++++++++++++++--- src/cmd/compile/internal/noder/stencil.go | 33 ++++++++++------------- src/cmd/compile/internal/noder/types.go | 14 ++++++---- 3 files changed, 48 insertions(+), 28 deletions(-) diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go index 017e98986fb..d974b291d08 100644 --- a/src/cmd/compile/internal/noder/expr.go +++ b/src/cmd/compile/internal/noder/expr.go @@ -206,6 +206,30 @@ func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.Selecto // only be fully transformed once it has an instantiated type. n := ir.NewSelectorExpr(pos, ir.OXDOT, x, typecheck.Lookup(expr.Sel.Value)) typed(g.typ(typ), n) + + // Fill in n.Selection for a generic method reference, even though we + // won't use it directly, since it is useful for analysis. + // Specifically do not fill in for fields or interfaces methods, so + // n.Selection being non-nil means a method reference, rather than an + // interface reference or reference to a field with a function value. + obj2 := g.info.Selections[expr].Obj() + sig := types2.AsSignature(obj2.Type()) + if sig == nil || sig.Recv() == nil { + return n + } + // recvType is the type of the last embedded field. Because of the + // way methods are imported, g.obj(obj2) doesn't work across + // packages, so we have to lookup the method via the receiver type. + recvType := deref2(sig.Recv().Type()) + if types2.AsInterface(recvType.Underlying()) != nil { + return n + } + + index := g.info.Selections[expr].Index() + last := index[len(index)-1] + recvObj := types2.AsNamed(recvType).Obj() + recv := g.pkg(recvObj.Pkg()).Lookup(recvObj.Name()).Def + n.Selection = recv.Type().Methods().Index(last) return n } @@ -308,10 +332,7 @@ func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.Selecto // getTargs gets the targs associated with the receiver of a selected method func getTargs(selinfo *types2.Selection) []types2.Type { - r := selinfo.Recv() - if p := types2.AsPointer(r); p != nil { - r = p.Elem() - } + r := deref2(selinfo.Recv()) n := types2.AsNamed(r) if n == nil { base.Fatalf("Incorrect type for selinfo %v", selinfo) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index b228e402586..c04300a1654 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -1282,14 +1282,15 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) if n.Op() == ir.OCALL { call := n.(*ir.CallExpr) if call.X.Op() == ir.OXDOT { - subtargs := deref(n.(*ir.CallExpr).X.(*ir.SelectorExpr).X.Type()).RParams() + subtargs := deref(call.X.(*ir.SelectorExpr).X.Type()).RParams() s2targs := make([]*types.Type, len(subtargs)) for i, t := range subtargs { s2targs[i] = subst.Typ(t) } - sym = typecheck.MakeDictName(ir.MethodSym(call.X.(*ir.SelectorExpr).X.Type(), call.X.(*ir.SelectorExpr).Sel), s2targs, true) + nameNode := call.X.(*ir.SelectorExpr).Selection.Nname.(*ir.Name) + sym = g.getDictionarySym(nameNode, s2targs, true) } else { - inst := n.(*ir.CallExpr).X.(*ir.InstExpr) + inst := call.X.(*ir.InstExpr) var nameNode *ir.Name var meth *ir.SelectorExpr var isMeth bool @@ -1325,14 +1326,12 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) for i, t := range subtargs { s2targs[i] = subst.Typ(t) } - sym = typecheck.MakeDictName(ir.MethodSym(selExpr.X.Type(), selExpr.Sel), s2targs, true) + nameNode := selExpr.Selection.Nname.(*ir.Name) + sym = g.getDictionarySym(nameNode, s2targs, true) } // TODO: handle closure cases that need sub-dictionaries, get rid of conditional if sym != nil { - // TODO: uncomment once we're sure all the - // subdictionaries are created correctly. - // Methods above aren't yet generating dictionaries recursively yet. - //off = objw.SymPtr(lsym, off, sym.Linksym(), 0) + off = objw.SymPtr(lsym, off, sym.Linksym(), 0) infoPrint(" - Subdict %v\n", sym.Name) } } @@ -1403,18 +1402,14 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo { infoPrint(" Closure&subdictionary required at generic function value %v\n", n.(*ir.InstExpr).X) info.subDictCalls = append(info.subDictCalls, n) } else if n.Op() == ir.OXDOT && !n.(*ir.SelectorExpr).Implicit() && - !n.(*ir.SelectorExpr).X.Type().IsInterface() && + n.(*ir.SelectorExpr).Selection != nil && len(n.(*ir.SelectorExpr).X.Type().RParams()) > 0 { - // Fix this - doesn't account for embedded fields, etc. - field := typecheck.Lookdot1(n.(*ir.SelectorExpr), n.(*ir.SelectorExpr).Sel, n.(*ir.SelectorExpr).X.Type(), n.(*ir.SelectorExpr).X.Type().Fields(), 0) - if field == nil { - if n.(*ir.SelectorExpr).X.Op() == ir.OTYPE { - infoPrint(" Closure&subdictionary required at generic meth expr %v\n", n) - } else { - infoPrint(" Closure&subdictionary required at generic meth value %v\n", n) - } - info.subDictCalls = append(info.subDictCalls, n) + if n.(*ir.SelectorExpr).X.Op() == ir.OTYPE { + infoPrint(" Closure&subdictionary required at generic meth expr %v\n", n) + } else { + infoPrint(" Closure&subdictionary required at generic meth value %v\n", n) } + info.subDictCalls = append(info.subDictCalls, n) } if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OFUNCINST { infoPrint(" Subdictionary at generic function call: %v - %v\n", n.(*ir.CallExpr).X.(*ir.InstExpr).X, n) @@ -1422,7 +1417,7 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo { info.subDictCalls = append(info.subDictCalls, n) } if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OXDOT && - !n.(*ir.CallExpr).X.(*ir.SelectorExpr).X.Type().IsInterface() && + n.(*ir.CallExpr).X.(*ir.SelectorExpr).Selection != nil && len(deref(n.(*ir.CallExpr).X.(*ir.SelectorExpr).X.Type()).RParams()) > 0 { infoPrint(" Subdictionary at generic method call: %v\n", n) n.(*ir.CallExpr).X.(*ir.SelectorExpr).SetImplicit(true) diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go index b37793b2d08..a0b7fea7cb1 100644 --- a/src/cmd/compile/internal/noder/types.go +++ b/src/cmd/compile/internal/noder/types.go @@ -278,11 +278,7 @@ func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) { methods := make([]*types.Field, typ.NumMethods()) for i := range methods { m := typ.Method(i) - recvType := types2.AsSignature(m.Type()).Recv().Type() - ptr := types2.AsPointer(recvType) - if ptr != nil { - recvType = ptr.Elem() - } + recvType := deref2(types2.AsSignature(m.Type()).Recv().Type()) var meth *ir.Name if m.Pkg() != g.self { // Imported methods cannot be loaded by name (what @@ -471,3 +467,11 @@ var dirs = [...]types.ChanDir{ types2.SendOnly: types.Csend, types2.RecvOnly: types.Crecv, } + +// deref2 does a single deref of types2 type t, if it is a pointer type. +func deref2(t types2.Type) types2.Type { + if ptr := types2.AsPointer(t); ptr != nil { + t = ptr.Elem() + } + return t +} From ef8ae82b37657ab788f490bd757ad1b5592b952f Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Thu, 1 Jul 2021 11:22:02 -0400 Subject: [PATCH 607/940] cmd/compile: fix bug in dwarf-gen var location generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes a bug in the SSA back end's DWARF generation code that determines variable locations / lifetimes. The code in question was written to handle sequences of initial pseudo-ops (zero width instructions such as OpPhi, OpArg, etc) in a basic block, detecting these ops at the start of a block and then treating the values specially when emitting ranges for the variables in those values. The logic in this code wasn't quite correct, meaning that a flag variable wasn't being set properly to record the presence of a block of zero-width value-bearing ops, leading to incorrect or missing DWARF locations for register params. Also in this patch is a tweak to some sanity-checking code intended to catch scheduling problems with OpArg/OpPhi etc. The checks need to allow for the possibility of an Arg op scheduled after a spill of an incoming register param inserted by the register allocator. Example: b1: v13 = ArgIntReg {p1+16} [2] : CX v14 = ArgIntReg {p2+16} [5] : R8 v38 = ArgIntReg {p3+16} [8] : R11 v35 = ArgIntReg {p1+0} [0] : AX v15 = StoreReg v35 : .autotmp_4[int] v40 = Arg {p4} [16] : p4+16[int] v1 = InitMem v3 = SB : SB v18 = CMPQ v14 v13 NE v18 → b3 b2 (unlikely) (18) Here the register allocator has decided to spill v35, meaning that the OpArg v40 is no longer going to be positioned prior to all other non-zero-width ops; this is a valid scenario and needs to be handled properly by the debug code. Fixes #46425. Change-Id: I239b3ad56a9c1b8ebf68af42e1f57308293ed7e6 Reviewed-on: https://go-review.googlesource.com/c/go/+/332269 Trust: Than McIntosh Reviewed-by: Cherry Mui Run-TryBot: Than McIntosh TryBot-Result: Go Bot --- src/cmd/compile/internal/ssa/debug.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/cmd/compile/internal/ssa/debug.go b/src/cmd/compile/internal/ssa/debug.go index eaa94975ec2..8e2872363b6 100644 --- a/src/cmd/compile/internal/ssa/debug.go +++ b/src/cmd/compile/internal/ssa/debug.go @@ -1115,8 +1115,14 @@ func (state *debugState) buildLocationLists(blockLocs []*BlockDebug) { continue } + mustBeFirst := func(v *Value) bool { + return v.Op == OpPhi || v.Op.isLoweredGetClosurePtr() || + v.Op == OpArgIntReg || v.Op == OpArgFloatReg + } + zeroWidthPending := false - apcChangedSize := 0 // size of changedVars for leading Args, Phi, ClosurePtr + blockPrologComplete := false // set to true at first non-zero-width op + apcChangedSize := 0 // size of changedVars for leading Args, Phi, ClosurePtr // expect to see values in pattern (apc)* (zerowidth|real)* for _, v := range b.Values { slots := state.valueNames[v.ID] @@ -1125,16 +1131,16 @@ func (state *debugState) buildLocationLists(blockLocs []*BlockDebug) { if opcodeTable[v.Op].zeroWidth { if changed { - if hasAnyArgOp(v) || v.Op == OpPhi || v.Op.isLoweredGetClosurePtr() { + if mustBeFirst(v) || v.Op == OpArg { // These ranges begin at true beginning of block, not after first instruction - if zeroWidthPending { - panic(fmt.Errorf("Unexpected op '%s' mixed with OpArg/OpPhi/OpLoweredGetClosurePtr at beginning of block %s in %s\n%s", v.LongString(), b, b.Func.Name, b.Func)) + if blockPrologComplete && mustBeFirst(v) { + panic(fmt.Errorf("Unexpected placement of op '%s' appearing after non-pseudo-op at beginning of block %s in %s\n%s", v.LongString(), b, b.Func.Name, b.Func)) } apcChangedSize = len(state.changedVars.contents()) + // Other zero-width ops must wait on a "real" op. + zeroWidthPending = true continue } - // Other zero-width ops must wait on a "real" op. - zeroWidthPending = true } continue } @@ -1145,6 +1151,7 @@ func (state *debugState) buildLocationLists(blockLocs []*BlockDebug) { // Not zero-width; i.e., a "real" instruction. zeroWidthPending = false + blockPrologComplete = true for i, varID := range state.changedVars.contents() { if i < apcChangedSize { // buffered true start-of-block changes state.updateVar(VarID(varID), v.Block, BlockStart) From 877688c838c35c48f8c658891ead6c381e21f6fa Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 10 Jun 2021 15:17:17 -0400 Subject: [PATCH 608/940] testing: add TB.Setenv For #41260 and #46688. Change-Id: I6f42742cc3234a90003136ae8798a6b0e1291788 Reviewed-on: https://go-review.googlesource.com/c/go/+/326790 Trust: Russ Cox Run-TryBot: Russ Cox TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- api/go1.17.txt | 1 + src/testing/testing.go | 1 + 2 files changed, 2 insertions(+) diff --git a/api/go1.17.txt b/api/go1.17.txt index 8e4c0f5624b..3d0a464fec5 100644 --- a/api/go1.17.txt +++ b/api/go1.17.txt @@ -181,6 +181,7 @@ pkg syscall (windows-amd64), type SysProcAttr struct, AdditionalInheritedHandles pkg syscall (windows-amd64), type SysProcAttr struct, ParentProcess Handle pkg testing, method (*B) Setenv(string, string) pkg testing, method (*T) Setenv(string, string) +pkg testing, type TB interface, Setenv(string, string) pkg text/template/parse, const SkipFuncCheck = 2 pkg text/template/parse, const SkipFuncCheck Mode pkg time, const Layout = "01/02 03:04:05PM '06 -0700" diff --git a/src/testing/testing.go b/src/testing/testing.go index fdf57a39535..eeee0aac172 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -644,6 +644,7 @@ type TB interface { Log(args ...interface{}) Logf(format string, args ...interface{}) Name() string + Setenv(key, value string) Skip(args ...interface{}) SkipNow() Skipf(format string, args ...interface{}) From 03761ede028d811dd7d7cf8a2690d4bfa2771d85 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Wed, 30 Jun 2021 14:28:18 -0700 Subject: [PATCH 609/940] net: don't reject null mx records Bypass hostname validity checking when a null mx record is returned as, defined in RFC 7505. Updates #46979 Change-Id: Ibe683bd6b47333a8ff30909fb2680ec8e10696ef Reviewed-on: https://go-review.googlesource.com/c/go/+/332094 Trust: Roland Shoemaker Trust: Katie Hockman Run-TryBot: Roland Shoemaker TryBot-Result: Go Bot Reviewed-by: Katie Hockman --- src/net/dnsclient_unix_test.go | 40 ++++++++++++++++++++++++++++++++++ src/net/lookup.go | 4 +++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go index d69107a2f23..59cdd2bf3e2 100644 --- a/src/net/dnsclient_unix_test.go +++ b/src/net/dnsclient_unix_test.go @@ -1957,3 +1957,43 @@ func TestCVE202133195(t *testing.T) { t.Errorf("LookupAddr returned unexpected error, got %q, want %q", err, expected) } } + +func TestNullMX(t *testing.T) { + fake := fakeDNSServer{ + rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) { + r := dnsmessage.Message{ + Header: dnsmessage.Header{ + ID: q.Header.ID, + Response: true, + RCode: dnsmessage.RCodeSuccess, + }, + Questions: q.Questions, + Answers: []dnsmessage.Resource{ + { + Header: dnsmessage.ResourceHeader{ + Name: q.Questions[0].Name, + Type: dnsmessage.TypeMX, + Class: dnsmessage.ClassINET, + }, + Body: &dnsmessage.MXResource{ + MX: dnsmessage.MustNewName("."), + }, + }, + }, + } + return r, nil + }, + } + r := Resolver{PreferGo: true, Dial: fake.DialContext} + rrset, err := r.LookupMX(context.Background(), "golang.org") + if err != nil { + t.Fatalf("LookupMX: %v", err) + } + if want := []*MX{&MX{Host: "."}}; !reflect.DeepEqual(rrset, want) { + records := []string{} + for _, rr := range rrset { + records = append(records, fmt.Sprintf("%v", rr)) + } + t.Errorf("records = [%v]; want [%v]", strings.Join(records, " "), want[0]) + } +} diff --git a/src/net/lookup.go b/src/net/lookup.go index 02a4cdcd1ee..b5af3a0f867 100644 --- a/src/net/lookup.go +++ b/src/net/lookup.go @@ -500,7 +500,9 @@ func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) { if mx == nil { continue } - if !isDomainName(mx.Host) { + // Bypass the hostname validity check for targets which contain only a dot, + // as this is used to represent a 'Null' MX record. + if mx.Host != "." && !isDomainName(mx.Host) { return nil, &DNSError{Err: "MX target is invalid", Name: name} } } From 838079beef0f4bfd1dfc3077ed469fced5cb32ae Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 1 Jul 2021 11:44:43 -0700 Subject: [PATCH 610/940] [dev.typeparams] cmd/internal/dwarf: remove putInlinedFunc's callersym param This parameter is only used for debugging, and all of putInlinedFunc's callers were actually passing the callee symbol instead. Change-Id: I964825a514cc42a1b0bcbce4ef11a1a47084d882 Reviewed-on: https://go-review.googlesource.com/c/go/+/332370 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- src/cmd/internal/dwarf/dwarf.go | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/cmd/internal/dwarf/dwarf.go b/src/cmd/internal/dwarf/dwarf.go index ec441c2bcb6..860c7d6c0d9 100644 --- a/src/cmd/internal/dwarf/dwarf.go +++ b/src/cmd/internal/dwarf/dwarf.go @@ -1266,7 +1266,7 @@ func PutAbstractFunc(ctxt Context, s *FnState) error { // its corresponding 'abstract' DIE (containing location-independent // attributes such as name, type, etc). Inlined subroutine DIEs can // have other inlined subroutine DIEs as children. -func putInlinedFunc(ctxt Context, s *FnState, callersym Sym, callIdx int) error { +func putInlinedFunc(ctxt Context, s *FnState, callIdx int) error { ic := s.InlCalls.Calls[callIdx] callee := ic.AbsFunSym @@ -1277,7 +1277,7 @@ func putInlinedFunc(ctxt Context, s *FnState, callersym Sym, callIdx int) error Uleb128put(ctxt, s.Info, int64(abbrev)) if logDwarf { - ctxt.Logf("putInlinedFunc(caller=%v,callee=%v,abbrev=%d)\n", callersym, callee, abbrev) + ctxt.Logf("putInlinedFunc(callee=%v,abbrev=%d)\n", callee, abbrev) } // Abstract origin. @@ -1312,8 +1312,7 @@ func putInlinedFunc(ctxt Context, s *FnState, callersym Sym, callIdx int) error // Children of this inline. for _, sib := range inlChildren(callIdx, &s.InlCalls) { - absfn := s.InlCalls.Calls[sib].AbsFunSym - err := putInlinedFunc(ctxt, s, absfn, sib) + err := putInlinedFunc(ctxt, s, sib) if err != nil { return err } @@ -1354,8 +1353,7 @@ func PutConcreteFunc(ctxt Context, s *FnState) error { // Inlined subroutines. for _, sib := range inlChildren(-1, &s.InlCalls) { - absfn := s.InlCalls.Calls[sib].AbsFunSym - err := putInlinedFunc(ctxt, s, absfn, sib) + err := putInlinedFunc(ctxt, s, sib) if err != nil { return err } @@ -1402,8 +1400,7 @@ func PutDefaultFunc(ctxt Context, s *FnState) error { // Inlined subroutines. for _, sib := range inlChildren(-1, &s.InlCalls) { - absfn := s.InlCalls.Calls[sib].AbsFunSym - err := putInlinedFunc(ctxt, s, absfn, sib) + err := putInlinedFunc(ctxt, s, sib) if err != nil { return err } From 9c1e7d9eff564df532c31114e2b833752519f0a2 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 30 Jun 2021 13:03:57 -0700 Subject: [PATCH 611/940] [dev.typeparams] cmd/compile/internal/types2: move Interface type decl into interface.go (cleanup) Change-Id: Ie1ba50c82afb7409f9495a19b8629c61c6a8d4dc Reviewed-on: https://go-review.googlesource.com/c/go/+/332092 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/interface.go | 148 +++++++++++++++++++ src/cmd/compile/internal/types2/type.go | 141 ------------------ 2 files changed, 148 insertions(+), 141 deletions(-) diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go index 1f4e80951a2..c344f8ed019 100644 --- a/src/cmd/compile/internal/types2/interface.go +++ b/src/cmd/compile/internal/types2/interface.go @@ -6,6 +6,154 @@ package types2 import "cmd/compile/internal/syntax" +// ---------------------------------------------------------------------------- +// API + +// An Interface represents an interface type. +type Interface struct { + obj *TypeName // corresponding declared object; or nil (for better error messages) + methods []*Func // ordered list of explicitly declared methods + embeddeds []Type // ordered list of explicitly embedded elements + embedPos *[]syntax.Pos // positions of embedded elements; or nil (for error messages) - use pointer to save space + complete bool // indicates that all fields (except for tset) are set up + + tset *TypeSet // type set described by this interface, computed lazily +} + +// typeSet returns the type set for interface t. +func (t *Interface) typeSet() *TypeSet { return computeTypeSet(nil, nopos, t) } + +// is reports whether interface t represents types that all satisfy f. +func (t *Interface) is(f func(Type, bool) bool) bool { + switch t := t.typeSet().types.(type) { + case nil, *top: + // TODO(gri) should settle on top or nil to represent this case + return false // we must have at least one type! (was bug) + case *Union: + return t.is(func(typ Type, tilde bool) bool { return f(typ, tilde) }) + default: + return f(t, false) + } +} + +// emptyInterface represents the empty interface +var emptyInterface = Interface{complete: true, tset: &topTypeSet} + +// NewInterface returns a new interface for the given methods and embedded types. +// NewInterface takes ownership of the provided methods and may modify their types +// by setting missing receivers. +// +// Deprecated: Use NewInterfaceType instead which allows arbitrary embedded types. +func NewInterface(methods []*Func, embeddeds []*Named) *Interface { + tnames := make([]Type, len(embeddeds)) + for i, t := range embeddeds { + tnames[i] = t + } + return NewInterfaceType(methods, tnames) +} + +// NewInterfaceType returns a new interface for the given methods and embedded types. +// NewInterfaceType takes ownership of the provided methods and may modify their types +// by setting missing receivers. +func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface { + if len(methods) == 0 && len(embeddeds) == 0 { + return &emptyInterface + } + + // set method receivers if necessary + typ := new(Interface) + for _, m := range methods { + if sig := m.typ.(*Signature); sig.recv == nil { + sig.recv = NewVar(m.pos, m.pkg, "", typ) + } + } + + // sort for API stability + sortMethods(methods) + + typ.methods = methods + typ.embeddeds = embeddeds + typ.complete = true + + return typ +} + +// NumExplicitMethods returns the number of explicitly declared methods of interface t. +func (t *Interface) NumExplicitMethods() int { return len(t.methods) } + +// ExplicitMethod returns the i'th explicitly declared method of interface t for 0 <= i < t.NumExplicitMethods(). +// The methods are ordered by their unique Id. +func (t *Interface) ExplicitMethod(i int) *Func { return t.methods[i] } + +// NumEmbeddeds returns the number of embedded types in interface t. +func (t *Interface) NumEmbeddeds() int { return len(t.embeddeds) } + +// Embedded returns the i'th embedded defined (*Named) type of interface t for 0 <= i < t.NumEmbeddeds(). +// The result is nil if the i'th embedded type is not a defined type. +// +// Deprecated: Use EmbeddedType which is not restricted to defined (*Named) types. +func (t *Interface) Embedded(i int) *Named { tname, _ := t.embeddeds[i].(*Named); return tname } + +// EmbeddedType returns the i'th embedded type of interface t for 0 <= i < t.NumEmbeddeds(). +func (t *Interface) EmbeddedType(i int) Type { return t.embeddeds[i] } + +// NumMethods returns the total number of methods of interface t. +func (t *Interface) NumMethods() int { return t.typeSet().NumMethods() } + +// Method returns the i'th method of interface t for 0 <= i < t.NumMethods(). +// The methods are ordered by their unique Id. +func (t *Interface) Method(i int) *Func { return t.typeSet().Method(i) } + +// Empty reports whether t is the empty interface. +func (t *Interface) Empty() bool { return t.typeSet().IsTop() } + +// IsComparable reports whether interface t is or embeds the predeclared interface "comparable". +func (t *Interface) IsComparable() bool { return t.typeSet().IsComparable() } + +// IsConstraint reports whether interface t is not just a method set. +func (t *Interface) IsConstraint() bool { return !t.typeSet().IsMethodSet() } + +// isSatisfiedBy reports whether interface t's type list is satisfied by the type typ. +// If the type list is empty (absent), typ trivially satisfies the interface. +// TODO(gri) This is not a great name. Eventually, we should have a more comprehensive +// "implements" predicate. +func (t *Interface) isSatisfiedBy(typ Type) bool { + switch t := t.typeSet().types.(type) { + case nil: + return true // no type restrictions + case *Union: + r, _ := t.intersect(typ, false) + return r != nil + default: + return Identical(t, typ) + } +} + +// Complete computes the interface's type set. It must be called by users of +// NewInterfaceType and NewInterface after the interface's embedded types are +// fully defined and before using the interface type in any way other than to +// form other types. The interface must not contain duplicate methods or a +// panic occurs. Complete returns the receiver. +// +// Deprecated: Type sets are now computed lazily, on demand; this function +// is only here for backward-compatibility. It does not have to +// be called explicitly anymore. +func (t *Interface) Complete() *Interface { + // Some tests are still depending on the state change + // (string representation of an Interface not containing an + // /* incomplete */ marker) caused by the explicit Complete + // call, so we compute the type set eagerly here. + t.complete = true + t.typeSet() + return t +} + +func (t *Interface) Underlying() Type { return t } +func (t *Interface) String() string { return TypeString(t, nil) } + +// ---------------------------------------------------------------------------- +// Implementation + func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType, def *Named) { var tlist []syntax.Expr // types collected from all type lists var tname *syntax.Name // most recent "type" name diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index 3a9511de48b..e2e10d21aec 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -163,145 +163,6 @@ func (t *Tuple) Len() int { // At returns the i'th variable of tuple t. func (t *Tuple) At(i int) *Var { return t.vars[i] } -// An Interface represents an interface type. -type Interface struct { - obj *TypeName // corresponding declared object; or nil (for better error messages) - methods []*Func // ordered list of explicitly declared methods - embeddeds []Type // ordered list of explicitly embedded elements - embedPos *[]syntax.Pos // positions of embedded elements; or nil (for error messages) - use pointer to save space - complete bool // indicates that all fields (except for tset) are set up - - tset *TypeSet // type set described by this interface, computed lazily -} - -// typeSet returns the type set for interface t. -func (t *Interface) typeSet() *TypeSet { return computeTypeSet(nil, nopos, t) } - -// is reports whether interface t represents types that all satisfy f. -func (t *Interface) is(f func(Type, bool) bool) bool { - switch t := t.typeSet().types.(type) { - case nil, *top: - // TODO(gri) should settle on top or nil to represent this case - return false // we must have at least one type! (was bug) - case *Union: - return t.is(func(typ Type, tilde bool) bool { return f(typ, tilde) }) - default: - return f(t, false) - } -} - -// emptyInterface represents the empty interface -var emptyInterface = Interface{complete: true, tset: &topTypeSet} - -// NewInterface returns a new interface for the given methods and embedded types. -// NewInterface takes ownership of the provided methods and may modify their types -// by setting missing receivers. -// -// Deprecated: Use NewInterfaceType instead which allows arbitrary embedded types. -func NewInterface(methods []*Func, embeddeds []*Named) *Interface { - tnames := make([]Type, len(embeddeds)) - for i, t := range embeddeds { - tnames[i] = t - } - return NewInterfaceType(methods, tnames) -} - -// NewInterfaceType returns a new interface for the given methods and embedded types. -// NewInterfaceType takes ownership of the provided methods and may modify their types -// by setting missing receivers. -func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface { - if len(methods) == 0 && len(embeddeds) == 0 { - return &emptyInterface - } - - // set method receivers if necessary - typ := new(Interface) - for _, m := range methods { - if sig := m.typ.(*Signature); sig.recv == nil { - sig.recv = NewVar(m.pos, m.pkg, "", typ) - } - } - - // sort for API stability - sortMethods(methods) - - typ.methods = methods - typ.embeddeds = embeddeds - typ.complete = true - - return typ -} - -// NumExplicitMethods returns the number of explicitly declared methods of interface t. -func (t *Interface) NumExplicitMethods() int { return len(t.methods) } - -// ExplicitMethod returns the i'th explicitly declared method of interface t for 0 <= i < t.NumExplicitMethods(). -// The methods are ordered by their unique Id. -func (t *Interface) ExplicitMethod(i int) *Func { return t.methods[i] } - -// NumEmbeddeds returns the number of embedded types in interface t. -func (t *Interface) NumEmbeddeds() int { return len(t.embeddeds) } - -// Embedded returns the i'th embedded defined (*Named) type of interface t for 0 <= i < t.NumEmbeddeds(). -// The result is nil if the i'th embedded type is not a defined type. -// -// Deprecated: Use EmbeddedType which is not restricted to defined (*Named) types. -func (t *Interface) Embedded(i int) *Named { tname, _ := t.embeddeds[i].(*Named); return tname } - -// EmbeddedType returns the i'th embedded type of interface t for 0 <= i < t.NumEmbeddeds(). -func (t *Interface) EmbeddedType(i int) Type { return t.embeddeds[i] } - -// NumMethods returns the total number of methods of interface t. -func (t *Interface) NumMethods() int { return t.typeSet().NumMethods() } - -// Method returns the i'th method of interface t for 0 <= i < t.NumMethods(). -// The methods are ordered by their unique Id. -func (t *Interface) Method(i int) *Func { return t.typeSet().Method(i) } - -// Empty reports whether t is the empty interface. -func (t *Interface) Empty() bool { return t.typeSet().IsTop() } - -// IsComparable reports whether interface t is or embeds the predeclared interface "comparable". -func (t *Interface) IsComparable() bool { return t.typeSet().IsComparable() } - -// IsConstraint reports whether interface t is not just a method set. -func (t *Interface) IsConstraint() bool { return !t.typeSet().IsMethodSet() } - -// isSatisfiedBy reports whether interface t's type list is satisfied by the type typ. -// If the type list is empty (absent), typ trivially satisfies the interface. -// TODO(gri) This is not a great name. Eventually, we should have a more comprehensive -// "implements" predicate. -func (t *Interface) isSatisfiedBy(typ Type) bool { - switch t := t.typeSet().types.(type) { - case nil: - return true // no type restrictions - case *Union: - r, _ := t.intersect(typ, false) - return r != nil - default: - return Identical(t, typ) - } -} - -// Complete computes the interface's type set. It must be called by users of -// NewInterfaceType and NewInterface after the interface's embedded types are -// fully defined and before using the interface type in any way other than to -// form other types. The interface must not contain duplicate methods or a -// panic occurs. Complete returns the receiver. -// -// Deprecated: Type sets are now computed lazily, on demand; this function -// is only here for backward-compatibility. It does not have to -// be called explicitly anymore. -func (t *Interface) Complete() *Interface { - // Some tests are still depending on the state change - // (string representation of an Interface not containing an - // /* incomplete */ marker) caused by the explicit Complete - // call, so we compute the type set eagerly here. - t.complete = true - t.typeSet() - return t -} - // A Map represents a map type. type Map struct { key, elem Type @@ -644,7 +505,6 @@ func (t *Array) Underlying() Type { return t } func (t *Slice) Underlying() Type { return t } func (t *Pointer) Underlying() Type { return t } func (t *Tuple) Underlying() Type { return t } -func (t *Interface) Underlying() Type { return t } func (t *Map) Underlying() Type { return t } func (t *Chan) Underlying() Type { return t } func (t *Named) Underlying() Type { return t.expand().underlying } @@ -658,7 +518,6 @@ func (t *Array) String() string { return TypeString(t, nil) } func (t *Slice) String() string { return TypeString(t, nil) } func (t *Pointer) String() string { return TypeString(t, nil) } func (t *Tuple) String() string { return TypeString(t, nil) } -func (t *Interface) String() string { return TypeString(t, nil) } func (t *Map) String() string { return TypeString(t, nil) } func (t *Chan) String() string { return TypeString(t, nil) } func (t *Named) String() string { return TypeString(t, nil) } From 30e5f266ed202740cfe0b7a9fde6117d6e1d6064 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 30 Jun 2021 13:26:11 -0700 Subject: [PATCH 612/940] [dev.typeparams] cmd/compile/internal/types2: move (remaining) type decls into their own files (cleanup) This change moves the type declarations and associated methods for each of the remaining Type types into their respective files. Except for import and comment adjustments, and receiver name adjustments for the Underlying and String methods, no functional changes are made. Change-Id: I3b9ccab3c85abea4852bacd28c2e47cec05c0bac Reviewed-on: https://go-review.googlesource.com/c/go/+/332093 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/array.go | 25 + src/cmd/compile/internal/types2/basic.go | 82 +++ src/cmd/compile/internal/types2/chan.go | 35 ++ src/cmd/compile/internal/types2/instance.go | 58 +++ src/cmd/compile/internal/types2/map.go | 24 + src/cmd/compile/internal/types2/named.go | 144 ++++++ src/cmd/compile/internal/types2/pointer.go | 19 + src/cmd/compile/internal/types2/slice.go | 19 + src/cmd/compile/internal/types2/tuple.go | 36 ++ src/cmd/compile/internal/types2/type.go | 501 +------------------ src/cmd/compile/internal/types2/typeparam.go | 80 +++ 11 files changed, 540 insertions(+), 483 deletions(-) create mode 100644 src/cmd/compile/internal/types2/array.go create mode 100644 src/cmd/compile/internal/types2/basic.go create mode 100644 src/cmd/compile/internal/types2/chan.go create mode 100644 src/cmd/compile/internal/types2/instance.go create mode 100644 src/cmd/compile/internal/types2/map.go create mode 100644 src/cmd/compile/internal/types2/named.go create mode 100644 src/cmd/compile/internal/types2/pointer.go create mode 100644 src/cmd/compile/internal/types2/slice.go create mode 100644 src/cmd/compile/internal/types2/tuple.go create mode 100644 src/cmd/compile/internal/types2/typeparam.go diff --git a/src/cmd/compile/internal/types2/array.go b/src/cmd/compile/internal/types2/array.go new file mode 100644 index 00000000000..502d49bc257 --- /dev/null +++ b/src/cmd/compile/internal/types2/array.go @@ -0,0 +1,25 @@ +// Copyright 2011 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 types2 + +// An Array represents an array type. +type Array struct { + len int64 + elem Type +} + +// NewArray returns a new array type for the given element type and length. +// A negative length indicates an unknown length. +func NewArray(elem Type, len int64) *Array { return &Array{len: len, elem: elem} } + +// Len returns the length of array a. +// A negative result indicates an unknown length. +func (a *Array) Len() int64 { return a.len } + +// Elem returns element type of array a. +func (a *Array) Elem() Type { return a.elem } + +func (a *Array) Underlying() Type { return a } +func (a *Array) String() string { return TypeString(a, nil) } diff --git a/src/cmd/compile/internal/types2/basic.go b/src/cmd/compile/internal/types2/basic.go new file mode 100644 index 00000000000..2fd973cafbc --- /dev/null +++ b/src/cmd/compile/internal/types2/basic.go @@ -0,0 +1,82 @@ +// Copyright 2011 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 types2 + +// BasicKind describes the kind of basic type. +type BasicKind int + +const ( + Invalid BasicKind = iota // type is invalid + + // predeclared types + Bool + Int + Int8 + Int16 + Int32 + Int64 + Uint + Uint8 + Uint16 + Uint32 + Uint64 + Uintptr + Float32 + Float64 + Complex64 + Complex128 + String + UnsafePointer + + // types for untyped values + UntypedBool + UntypedInt + UntypedRune + UntypedFloat + UntypedComplex + UntypedString + UntypedNil + + // aliases + Byte = Uint8 + Rune = Int32 +) + +// BasicInfo is a set of flags describing properties of a basic type. +type BasicInfo int + +// Properties of basic types. +const ( + IsBoolean BasicInfo = 1 << iota + IsInteger + IsUnsigned + IsFloat + IsComplex + IsString + IsUntyped + + IsOrdered = IsInteger | IsFloat | IsString + IsNumeric = IsInteger | IsFloat | IsComplex + IsConstType = IsBoolean | IsNumeric | IsString +) + +// A Basic represents a basic type. +type Basic struct { + kind BasicKind + info BasicInfo + name string +} + +// Kind returns the kind of basic type b. +func (b *Basic) Kind() BasicKind { return b.kind } + +// Info returns information about properties of basic type b. +func (b *Basic) Info() BasicInfo { return b.info } + +// Name returns the name of basic type b. +func (b *Basic) Name() string { return b.name } + +func (b *Basic) Underlying() Type { return b } +func (b *Basic) String() string { return TypeString(b, nil) } diff --git a/src/cmd/compile/internal/types2/chan.go b/src/cmd/compile/internal/types2/chan.go new file mode 100644 index 00000000000..77650dfb09d --- /dev/null +++ b/src/cmd/compile/internal/types2/chan.go @@ -0,0 +1,35 @@ +// Copyright 2011 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 types2 + +// A Chan represents a channel type. +type Chan struct { + dir ChanDir + elem Type +} + +// A ChanDir value indicates a channel direction. +type ChanDir int + +// The direction of a channel is indicated by one of these constants. +const ( + SendRecv ChanDir = iota + SendOnly + RecvOnly +) + +// NewChan returns a new channel type for the given direction and element type. +func NewChan(dir ChanDir, elem Type) *Chan { + return &Chan{dir: dir, elem: elem} +} + +// Dir returns the direction of channel c. +func (c *Chan) Dir() ChanDir { return c.dir } + +// Elem returns the element type of channel c. +func (c *Chan) Elem() Type { return c.elem } + +func (c *Chan) Underlying() Type { return c } +func (c *Chan) String() string { return TypeString(c, nil) } diff --git a/src/cmd/compile/internal/types2/instance.go b/src/cmd/compile/internal/types2/instance.go new file mode 100644 index 00000000000..9d6097e8742 --- /dev/null +++ b/src/cmd/compile/internal/types2/instance.go @@ -0,0 +1,58 @@ +// Copyright 2011 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 types2 + +import "cmd/compile/internal/syntax" + +// An instance represents an instantiated generic type syntactically +// (without expanding the instantiation). Type instances appear only +// during type-checking and are replaced by their fully instantiated +// (expanded) types before the end of type-checking. +type instance struct { + check *Checker // for lazy instantiation + pos syntax.Pos // position of type instantiation; for error reporting only + base *Named // parameterized type to be instantiated + targs []Type // type arguments + poslist []syntax.Pos // position of each targ; for error reporting only + value Type // base(targs...) after instantiation or Typ[Invalid]; nil if not yet set +} + +// expand returns the instantiated (= expanded) type of t. +// The result is either an instantiated *Named type, or +// Typ[Invalid] if there was an error. +func (t *instance) expand() Type { + v := t.value + if v == nil { + v = t.check.instantiate(t.pos, t.base, t.targs, t.poslist) + if v == nil { + v = Typ[Invalid] + } + t.value = v + } + // After instantiation we must have an invalid or a *Named type. + if debug && v != Typ[Invalid] { + _ = v.(*Named) + } + return v +} + +// expand expands a type instance into its instantiated +// type and leaves all other types alone. expand does +// not recurse. +func expand(typ Type) Type { + if t, _ := typ.(*instance); t != nil { + return t.expand() + } + return typ +} + +// expandf is set to expand. +// Call expandf when calling expand causes compile-time cycle error. +var expandf func(Type) Type + +func init() { expandf = expand } + +func (t *instance) Underlying() Type { return t } +func (t *instance) String() string { return TypeString(t, nil) } diff --git a/src/cmd/compile/internal/types2/map.go b/src/cmd/compile/internal/types2/map.go new file mode 100644 index 00000000000..0d3464caae7 --- /dev/null +++ b/src/cmd/compile/internal/types2/map.go @@ -0,0 +1,24 @@ +// Copyright 2011 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 types2 + +// A Map represents a map type. +type Map struct { + key, elem Type +} + +// NewMap returns a new map for the given key and element types. +func NewMap(key, elem Type) *Map { + return &Map{key: key, elem: elem} +} + +// Key returns the key type of map m. +func (m *Map) Key() Type { return m.key } + +// Elem returns the element type of map m. +func (m *Map) Elem() Type { return m.elem } + +func (t *Map) Underlying() Type { return t } +func (t *Map) String() string { return TypeString(t, nil) } diff --git a/src/cmd/compile/internal/types2/named.go b/src/cmd/compile/internal/types2/named.go new file mode 100644 index 00000000000..2005dfbd84a --- /dev/null +++ b/src/cmd/compile/internal/types2/named.go @@ -0,0 +1,144 @@ +// Copyright 2011 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 types2 + +import "sync" + +// TODO(gri) Clean up Named struct below; specifically the fromRHS field (can we use underlying?). + +// A Named represents a named (defined) type. +type Named struct { + check *Checker // for Named.under implementation; nilled once under has been called + info typeInfo // for cycle detection + obj *TypeName // corresponding declared object + orig *Named // original, uninstantiated type + fromRHS Type // type (on RHS of declaration) this *Named type is derived from (for cycle reporting) + underlying Type // possibly a *Named during setup; never a *Named once set up completely + tparams []*TypeName // type parameters, or nil + targs []Type // type arguments (after instantiation), or nil + methods []*Func // methods declared for this type (not the method set of this type); signatures are type-checked lazily + + resolve func(*Named) ([]*TypeName, Type, []*Func) + once sync.Once +} + +// NewNamed returns a new named type for the given type name, underlying type, and associated methods. +// If the given type name obj doesn't have a type yet, its type is set to the returned named type. +// The underlying type must not be a *Named. +func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named { + if _, ok := underlying.(*Named); ok { + panic("types2.NewNamed: underlying type must not be *Named") + } + return (*Checker)(nil).newNamed(obj, nil, underlying, nil, methods) +} + +func (t *Named) expand() *Named { + if t.resolve == nil { + return t + } + + t.once.Do(func() { + // TODO(mdempsky): Since we're passing t to resolve anyway + // (necessary because types2 expects the receiver type for methods + // on defined interface types to be the Named rather than the + // underlying Interface), maybe it should just handle calling + // SetTParams, SetUnderlying, and AddMethod instead? Those + // methods would need to support reentrant calls though. It would + // also make the API more future-proof towards further extensions + // (like SetTParams). + + tparams, underlying, methods := t.resolve(t) + + switch underlying.(type) { + case nil, *Named: + panic("invalid underlying type") + } + + t.tparams = tparams + t.underlying = underlying + t.methods = methods + }) + return t +} + +// newNamed is like NewNamed but with a *Checker receiver and additional orig argument. +func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams []*TypeName, methods []*Func) *Named { + typ := &Named{check: check, obj: obj, orig: orig, fromRHS: underlying, underlying: underlying, tparams: tparams, methods: methods} + if typ.orig == nil { + typ.orig = typ + } + if obj.typ == nil { + obj.typ = typ + } + // Ensure that typ is always expanded, at which point the check field can be + // nilled out. + // + // Note that currently we cannot nil out check inside typ.under(), because + // it's possible that typ is expanded multiple times. + // + // TODO(gri): clean this up so that under is the only function mutating + // named types. + if check != nil { + check.later(func() { + switch typ.under().(type) { + case *Named, *instance: + panic("internal error: unexpanded underlying type") + } + typ.check = nil + }) + } + return typ +} + +// Obj returns the type name for the named type t. +func (t *Named) Obj() *TypeName { return t.obj } + +// Orig returns the original generic type an instantiated type is derived from. +// If t is not an instantiated type, the result is t. +func (t *Named) Orig() *Named { return t.orig } + +// TODO(gri) Come up with a better representation and API to distinguish +// between parameterized instantiated and non-instantiated types. + +// TParams returns the type parameters of the named type t, or nil. +// The result is non-nil for an (originally) parameterized type even if it is instantiated. +func (t *Named) TParams() []*TypeName { return t.expand().tparams } + +// SetTParams sets the type parameters of the named type t. +func (t *Named) SetTParams(tparams []*TypeName) { t.expand().tparams = tparams } + +// TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated. +func (t *Named) TArgs() []Type { return t.targs } + +// SetTArgs sets the type arguments of the named type t. +func (t *Named) SetTArgs(args []Type) { t.targs = args } + +// NumMethods returns the number of explicit methods whose receiver is named type t. +func (t *Named) NumMethods() int { return len(t.expand().methods) } + +// Method returns the i'th method of named type t for 0 <= i < t.NumMethods(). +func (t *Named) Method(i int) *Func { return t.expand().methods[i] } + +// SetUnderlying sets the underlying type and marks t as complete. +func (t *Named) SetUnderlying(underlying Type) { + if underlying == nil { + panic("types2.Named.SetUnderlying: underlying type must not be nil") + } + if _, ok := underlying.(*Named); ok { + panic("types2.Named.SetUnderlying: underlying type must not be *Named") + } + t.expand().underlying = underlying +} + +// AddMethod adds method m unless it is already in the method list. +func (t *Named) AddMethod(m *Func) { + t.expand() + if i, _ := lookupMethod(t.methods, m.pkg, m.name); i < 0 { + t.methods = append(t.methods, m) + } +} + +func (t *Named) Underlying() Type { return t.expand().underlying } +func (t *Named) String() string { return TypeString(t, nil) } diff --git a/src/cmd/compile/internal/types2/pointer.go b/src/cmd/compile/internal/types2/pointer.go new file mode 100644 index 00000000000..63055fc6b05 --- /dev/null +++ b/src/cmd/compile/internal/types2/pointer.go @@ -0,0 +1,19 @@ +// Copyright 2011 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 types2 + +// A Pointer represents a pointer type. +type Pointer struct { + base Type // element type +} + +// NewPointer returns a new pointer type for the given element (base) type. +func NewPointer(elem Type) *Pointer { return &Pointer{base: elem} } + +// Elem returns the element type for the given pointer p. +func (p *Pointer) Elem() Type { return p.base } + +func (p *Pointer) Underlying() Type { return p } +func (p *Pointer) String() string { return TypeString(p, nil) } diff --git a/src/cmd/compile/internal/types2/slice.go b/src/cmd/compile/internal/types2/slice.go new file mode 100644 index 00000000000..9c22a6fb1b6 --- /dev/null +++ b/src/cmd/compile/internal/types2/slice.go @@ -0,0 +1,19 @@ +// Copyright 2011 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 types2 + +// A Slice represents a slice type. +type Slice struct { + elem Type +} + +// NewSlice returns a new slice type for the given element type. +func NewSlice(elem Type) *Slice { return &Slice{elem: elem} } + +// Elem returns the element type of slice s. +func (s *Slice) Elem() Type { return s.elem } + +func (s *Slice) Underlying() Type { return s } +func (s *Slice) String() string { return TypeString(s, nil) } diff --git a/src/cmd/compile/internal/types2/tuple.go b/src/cmd/compile/internal/types2/tuple.go new file mode 100644 index 00000000000..a3946beab57 --- /dev/null +++ b/src/cmd/compile/internal/types2/tuple.go @@ -0,0 +1,36 @@ +// Copyright 2011 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 types2 + +// A Tuple represents an ordered list of variables; a nil *Tuple is a valid (empty) tuple. +// Tuples are used as components of signatures and to represent the type of multiple +// assignments; they are not first class types of Go. +type Tuple struct { + vars []*Var +} + +// NewTuple returns a new tuple for the given variables. +func NewTuple(x ...*Var) *Tuple { + if len(x) > 0 { + return &Tuple{vars: x} + } + // TODO(gri) Don't represent empty tuples with a (*Tuple)(nil) pointer; + // it's too subtle and causes problems. + return nil +} + +// Len returns the number variables of tuple t. +func (t *Tuple) Len() int { + if t != nil { + return len(t.vars) + } + return 0 +} + +// At returns the i'th variable of tuple t. +func (t *Tuple) At(i int) *Var { return t.vars[i] } + +func (t *Tuple) Underlying() Type { return t } +func (t *Tuple) String() string { return TypeString(t, nil) } diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index e2e10d21aec..e3f63f63b55 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -4,12 +4,6 @@ package types2 -import ( - "cmd/compile/internal/syntax" - "sync" - "sync/atomic" -) - // A Type represents a type of Go. // All types implement the Type interface. type Type interface { @@ -22,394 +16,31 @@ type Type interface { String() string } -// BasicKind describes the kind of basic type. -type BasicKind int +// top represents the top of the type lattice. +// It is the underlying type of a type parameter that +// can be satisfied by any type (ignoring methods), +// because its type constraint contains no restrictions +// besides methods. +type top struct{} -const ( - Invalid BasicKind = iota // type is invalid +// theTop is the singleton top type. +var theTop = &top{} - // predeclared types - Bool - Int - Int8 - Int16 - Int32 - Int64 - Uint - Uint8 - Uint16 - Uint32 - Uint64 - Uintptr - Float32 - Float64 - Complex64 - Complex128 - String - UnsafePointer +func (t *top) Underlying() Type { return t } +func (t *top) String() string { return TypeString(t, nil) } - // types for untyped values - UntypedBool - UntypedInt - UntypedRune - UntypedFloat - UntypedComplex - UntypedString - UntypedNil - - // aliases - Byte = Uint8 - Rune = Int32 -) - -// BasicInfo is a set of flags describing properties of a basic type. -type BasicInfo int - -// Properties of basic types. -const ( - IsBoolean BasicInfo = 1 << iota - IsInteger - IsUnsigned - IsFloat - IsComplex - IsString - IsUntyped - - IsOrdered = IsInteger | IsFloat | IsString - IsNumeric = IsInteger | IsFloat | IsComplex - IsConstType = IsBoolean | IsNumeric | IsString -) - -// A Basic represents a basic type. -type Basic struct { - kind BasicKind - info BasicInfo - name string -} - -// Kind returns the kind of basic type b. -func (b *Basic) Kind() BasicKind { return b.kind } - -// Info returns information about properties of basic type b. -func (b *Basic) Info() BasicInfo { return b.info } - -// Name returns the name of basic type b. -func (b *Basic) Name() string { return b.name } - -// An Array represents an array type. -type Array struct { - len int64 - elem Type -} - -// NewArray returns a new array type for the given element type and length. -// A negative length indicates an unknown length. -func NewArray(elem Type, len int64) *Array { return &Array{len: len, elem: elem} } - -// Len returns the length of array a. -// A negative result indicates an unknown length. -func (a *Array) Len() int64 { return a.len } - -// Elem returns element type of array a. -func (a *Array) Elem() Type { return a.elem } - -// A Slice represents a slice type. -type Slice struct { - elem Type -} - -// NewSlice returns a new slice type for the given element type. -func NewSlice(elem Type) *Slice { return &Slice{elem: elem} } - -// Elem returns the element type of slice s. -func (s *Slice) Elem() Type { return s.elem } - -// A Pointer represents a pointer type. -type Pointer struct { - base Type // element type -} - -// NewPointer returns a new pointer type for the given element (base) type. -func NewPointer(elem Type) *Pointer { return &Pointer{base: elem} } - -// Elem returns the element type for the given pointer p. -func (p *Pointer) Elem() Type { return p.base } - -// A Tuple represents an ordered list of variables; a nil *Tuple is a valid (empty) tuple. -// Tuples are used as components of signatures and to represent the type of multiple -// assignments; they are not first class types of Go. -type Tuple struct { - vars []*Var -} - -// NewTuple returns a new tuple for the given variables. -func NewTuple(x ...*Var) *Tuple { - if len(x) > 0 { - return &Tuple{vars: x} +// under returns the true expanded underlying type. +// If it doesn't exist, the result is Typ[Invalid]. +// under must only be called when a type is known +// to be fully set up. +func under(t Type) Type { + // TODO(gri) is this correct for *Union? + if n := asNamed(t); n != nil { + return n.under() } - // TODO(gri) Don't represent empty tuples with a (*Tuple)(nil) pointer; - // it's too subtle and causes problems. - return nil -} - -// Len returns the number variables of tuple t. -func (t *Tuple) Len() int { - if t != nil { - return len(t.vars) - } - return 0 -} - -// At returns the i'th variable of tuple t. -func (t *Tuple) At(i int) *Var { return t.vars[i] } - -// A Map represents a map type. -type Map struct { - key, elem Type -} - -// NewMap returns a new map for the given key and element types. -func NewMap(key, elem Type) *Map { - return &Map{key: key, elem: elem} -} - -// Key returns the key type of map m. -func (m *Map) Key() Type { return m.key } - -// Elem returns the element type of map m. -func (m *Map) Elem() Type { return m.elem } - -// A Chan represents a channel type. -type Chan struct { - dir ChanDir - elem Type -} - -// A ChanDir value indicates a channel direction. -type ChanDir int - -// The direction of a channel is indicated by one of these constants. -const ( - SendRecv ChanDir = iota - SendOnly - RecvOnly -) - -// NewChan returns a new channel type for the given direction and element type. -func NewChan(dir ChanDir, elem Type) *Chan { - return &Chan{dir: dir, elem: elem} -} - -// Dir returns the direction of channel c. -func (c *Chan) Dir() ChanDir { return c.dir } - -// Elem returns the element type of channel c. -func (c *Chan) Elem() Type { return c.elem } - -// TODO(gri) Clean up Named struct below; specifically the fromRHS field (can we use underlying?). - -// A Named represents a named (defined) type. -type Named struct { - check *Checker // for Named.under implementation; nilled once under has been called - info typeInfo // for cycle detection - obj *TypeName // corresponding declared object - orig *Named // original, uninstantiated type - fromRHS Type // type (on RHS of declaration) this *Named type is derived from (for cycle reporting) - underlying Type // possibly a *Named during setup; never a *Named once set up completely - tparams []*TypeName // type parameters, or nil - targs []Type // type arguments (after instantiation), or nil - methods []*Func // methods declared for this type (not the method set of this type); signatures are type-checked lazily - - resolve func(*Named) ([]*TypeName, Type, []*Func) - once sync.Once -} - -// NewNamed returns a new named type for the given type name, underlying type, and associated methods. -// If the given type name obj doesn't have a type yet, its type is set to the returned named type. -// The underlying type must not be a *Named. -func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named { - if _, ok := underlying.(*Named); ok { - panic("types2.NewNamed: underlying type must not be *Named") - } - return (*Checker)(nil).newNamed(obj, nil, underlying, nil, methods) -} - -func (t *Named) expand() *Named { - if t.resolve == nil { - return t - } - - t.once.Do(func() { - // TODO(mdempsky): Since we're passing t to resolve anyway - // (necessary because types2 expects the receiver type for methods - // on defined interface types to be the Named rather than the - // underlying Interface), maybe it should just handle calling - // SetTParams, SetUnderlying, and AddMethod instead? Those - // methods would need to support reentrant calls though. It would - // also make the API more future-proof towards further extensions - // (like SetTParams). - - tparams, underlying, methods := t.resolve(t) - - switch underlying.(type) { - case nil, *Named: - panic("invalid underlying type") - } - - t.tparams = tparams - t.underlying = underlying - t.methods = methods - }) return t } -// newNamed is like NewNamed but with a *Checker receiver and additional orig argument. -func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams []*TypeName, methods []*Func) *Named { - typ := &Named{check: check, obj: obj, orig: orig, fromRHS: underlying, underlying: underlying, tparams: tparams, methods: methods} - if typ.orig == nil { - typ.orig = typ - } - if obj.typ == nil { - obj.typ = typ - } - // Ensure that typ is always expanded, at which point the check field can be - // nilled out. - // - // Note that currently we cannot nil out check inside typ.under(), because - // it's possible that typ is expanded multiple times. - // - // TODO(gri): clean this up so that under is the only function mutating - // named types. - if check != nil { - check.later(func() { - switch typ.under().(type) { - case *Named, *instance: - panic("internal error: unexpanded underlying type") - } - typ.check = nil - }) - } - return typ -} - -// Obj returns the type name for the named type t. -func (t *Named) Obj() *TypeName { return t.obj } - -// Orig returns the original generic type an instantiated type is derived from. -// If t is not an instantiated type, the result is t. -func (t *Named) Orig() *Named { return t.orig } - -// TODO(gri) Come up with a better representation and API to distinguish -// between parameterized instantiated and non-instantiated types. - -// TParams returns the type parameters of the named type t, or nil. -// The result is non-nil for an (originally) parameterized type even if it is instantiated. -func (t *Named) TParams() []*TypeName { return t.expand().tparams } - -// SetTParams sets the type parameters of the named type t. -func (t *Named) SetTParams(tparams []*TypeName) { t.expand().tparams = tparams } - -// TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated. -func (t *Named) TArgs() []Type { return t.targs } - -// SetTArgs sets the type arguments of the named type t. -func (t *Named) SetTArgs(args []Type) { t.targs = args } - -// NumMethods returns the number of explicit methods whose receiver is named type t. -func (t *Named) NumMethods() int { return len(t.expand().methods) } - -// Method returns the i'th method of named type t for 0 <= i < t.NumMethods(). -func (t *Named) Method(i int) *Func { return t.expand().methods[i] } - -// SetUnderlying sets the underlying type and marks t as complete. -func (t *Named) SetUnderlying(underlying Type) { - if underlying == nil { - panic("types2.Named.SetUnderlying: underlying type must not be nil") - } - if _, ok := underlying.(*Named); ok { - panic("types2.Named.SetUnderlying: underlying type must not be *Named") - } - t.expand().underlying = underlying -} - -// AddMethod adds method m unless it is already in the method list. -func (t *Named) AddMethod(m *Func) { - t.expand() - if i, _ := lookupMethod(t.methods, m.pkg, m.name); i < 0 { - t.methods = append(t.methods, m) - } -} - -// Note: This is a uint32 rather than a uint64 because the -// respective 64 bit atomic instructions are not available -// on all platforms. -var lastID uint32 - -// nextID returns a value increasing monotonically by 1 with -// each call, starting with 1. It may be called concurrently. -func nextID() uint64 { return uint64(atomic.AddUint32(&lastID, 1)) } - -// A TypeParam represents a type parameter type. -type TypeParam struct { - check *Checker // for lazy type bound completion - id uint64 // unique id, for debugging only - obj *TypeName // corresponding type name - index int // type parameter index in source order, starting at 0 - bound Type // *Named or *Interface; underlying type is always *Interface -} - -// Obj returns the type name for the type parameter t. -func (t *TypeParam) Obj() *TypeName { return t.obj } - -// NewTypeParam returns a new TypeParam. bound can be nil (and set later). -func (check *Checker) NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam { - // Always increment lastID, even if it is not used. - id := nextID() - if check != nil { - check.nextID++ - id = check.nextID - } - typ := &TypeParam{check: check, id: id, obj: obj, index: index, bound: bound} - if obj.typ == nil { - obj.typ = typ - } - return typ -} - -// Index returns the index of the type param within its param list. -func (t *TypeParam) Index() int { - return t.index -} - -// SetId sets the unique id of a type param. Should only be used for type params -// in imported generic types. -func (t *TypeParam) SetId(id uint64) { - t.id = id -} - -func (t *TypeParam) Bound() *Interface { - // we may not have an interface (error reported elsewhere) - iface, _ := under(t.bound).(*Interface) - if iface == nil { - return &emptyInterface - } - // use the type bound position if we have one - pos := nopos - if n, _ := t.bound.(*Named); n != nil { - pos = n.obj.pos - } - // TODO(gri) switch this to an unexported method on Checker. - computeTypeSet(t.check, pos, iface) - return iface -} - -func (t *TypeParam) SetBound(bound Type) { - if bound == nil { - panic("types2.TypeParam.SetBound: bound must not be nil") - } - t.bound = bound -} - // optype returns a type's operational type. Except for // type parameters, the operational type is the same // as the underlying type (as returned by under). For @@ -441,102 +72,6 @@ func optype(typ Type) Type { return under(typ) } -// An instance represents an instantiated generic type syntactically -// (without expanding the instantiation). Type instances appear only -// during type-checking and are replaced by their fully instantiated -// (expanded) types before the end of type-checking. -type instance struct { - check *Checker // for lazy instantiation - pos syntax.Pos // position of type instantiation; for error reporting only - base *Named // parameterized type to be instantiated - targs []Type // type arguments - poslist []syntax.Pos // position of each targ; for error reporting only - value Type // base(targs...) after instantiation or Typ[Invalid]; nil if not yet set -} - -// expand returns the instantiated (= expanded) type of t. -// The result is either an instantiated *Named type, or -// Typ[Invalid] if there was an error. -func (t *instance) expand() Type { - v := t.value - if v == nil { - v = t.check.instantiate(t.pos, t.base, t.targs, t.poslist) - if v == nil { - v = Typ[Invalid] - } - t.value = v - } - // After instantiation we must have an invalid or a *Named type. - if debug && v != Typ[Invalid] { - _ = v.(*Named) - } - return v -} - -// expand expands a type instance into its instantiated -// type and leaves all other types alone. expand does -// not recurse. -func expand(typ Type) Type { - if t, _ := typ.(*instance); t != nil { - return t.expand() - } - return typ -} - -// expandf is set to expand. -// Call expandf when calling expand causes compile-time cycle error. -var expandf func(Type) Type - -func init() { expandf = expand } - -// top represents the top of the type lattice. -// It is the underlying type of a type parameter that -// can be satisfied by any type (ignoring methods), -// because its type constraint contains no restrictions -// besides methods. -type top struct{} - -// theTop is the singleton top type. -var theTop = &top{} - -// Type-specific implementations of Underlying. -func (t *Basic) Underlying() Type { return t } -func (t *Array) Underlying() Type { return t } -func (t *Slice) Underlying() Type { return t } -func (t *Pointer) Underlying() Type { return t } -func (t *Tuple) Underlying() Type { return t } -func (t *Map) Underlying() Type { return t } -func (t *Chan) Underlying() Type { return t } -func (t *Named) Underlying() Type { return t.expand().underlying } -func (t *TypeParam) Underlying() Type { return t } -func (t *instance) Underlying() Type { return t } -func (t *top) Underlying() Type { return t } - -// Type-specific implementations of String. -func (t *Basic) String() string { return TypeString(t, nil) } -func (t *Array) String() string { return TypeString(t, nil) } -func (t *Slice) String() string { return TypeString(t, nil) } -func (t *Pointer) String() string { return TypeString(t, nil) } -func (t *Tuple) String() string { return TypeString(t, nil) } -func (t *Map) String() string { return TypeString(t, nil) } -func (t *Chan) String() string { return TypeString(t, nil) } -func (t *Named) String() string { return TypeString(t, nil) } -func (t *TypeParam) String() string { return TypeString(t, nil) } -func (t *instance) String() string { return TypeString(t, nil) } -func (t *top) String() string { return TypeString(t, nil) } - -// under returns the true expanded underlying type. -// If it doesn't exist, the result is Typ[Invalid]. -// under must only be called when a type is known -// to be fully set up. -func under(t Type) Type { - // TODO(gri) is this correct for *Union? - if n := asNamed(t); n != nil { - return n.under() - } - return t -} - // Converters // // A converter must only be called when a type is diff --git a/src/cmd/compile/internal/types2/typeparam.go b/src/cmd/compile/internal/types2/typeparam.go new file mode 100644 index 00000000000..5c744059124 --- /dev/null +++ b/src/cmd/compile/internal/types2/typeparam.go @@ -0,0 +1,80 @@ +// Copyright 2011 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 types2 + +import "sync/atomic" + +// Note: This is a uint32 rather than a uint64 because the +// respective 64 bit atomic instructions are not available +// on all platforms. +var lastID uint32 + +// nextID returns a value increasing monotonically by 1 with +// each call, starting with 1. It may be called concurrently. +func nextID() uint64 { return uint64(atomic.AddUint32(&lastID, 1)) } + +// A TypeParam represents a type parameter type. +type TypeParam struct { + check *Checker // for lazy type bound completion + id uint64 // unique id, for debugging only + obj *TypeName // corresponding type name + index int // type parameter index in source order, starting at 0 + bound Type // *Named or *Interface; underlying type is always *Interface +} + +// Obj returns the type name for the type parameter t. +func (t *TypeParam) Obj() *TypeName { return t.obj } + +// NewTypeParam returns a new TypeParam. bound can be nil (and set later). +func (check *Checker) NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam { + // Always increment lastID, even if it is not used. + id := nextID() + if check != nil { + check.nextID++ + id = check.nextID + } + typ := &TypeParam{check: check, id: id, obj: obj, index: index, bound: bound} + if obj.typ == nil { + obj.typ = typ + } + return typ +} + +// Index returns the index of the type param within its param list. +func (t *TypeParam) Index() int { + return t.index +} + +// SetId sets the unique id of a type param. Should only be used for type params +// in imported generic types. +func (t *TypeParam) SetId(id uint64) { + t.id = id +} + +func (t *TypeParam) Bound() *Interface { + // we may not have an interface (error reported elsewhere) + iface, _ := under(t.bound).(*Interface) + if iface == nil { + return &emptyInterface + } + // use the type bound position if we have one + pos := nopos + if n, _ := t.bound.(*Named); n != nil { + pos = n.obj.pos + } + // TODO(gri) switch this to an unexported method on Checker. + computeTypeSet(t.check, pos, iface) + return iface +} + +func (t *TypeParam) SetBound(bound Type) { + if bound == nil { + panic("types2.TypeParam.SetBound: bound must not be nil") + } + t.bound = bound +} + +func (t *TypeParam) Underlying() Type { return t } +func (t *TypeParam) String() string { return TypeString(t, nil) } From 2aea44204ef8e3467bd2d21865e3d2b8045f3d12 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 1 Jul 2021 12:47:58 -0700 Subject: [PATCH 613/940] [dev.typeparams] cmd/compile: enable generics syntax with -lang=go1.18 We already use -lang=go1.18 to control the types2 type checker behavior. This CL does the same for the parser. Also, disable an assertion in the unified IR linker that depended on the -G flag. This assertion was more useful during initial bootstrapping of that code, but it's less critical now. With these two changes, "GOEXPERIMENT=unified ./make.bash" is enough to get a fully functional generics-enabled toolchain. There's no need to continue specifying custom compiler flags later on. Change-Id: I7766381926f3bb17eee2e5fcc182a38a39e937e1 Reviewed-on: https://go-review.googlesource.com/c/go/+/332373 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Trust: Matthew Dempsky Trust: Robert Griesemer Reviewed-by: Robert Griesemer Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/noder/linker.go | 6 ++++-- src/cmd/compile/internal/noder/noder.go | 6 +++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/cmd/compile/internal/noder/linker.go b/src/cmd/compile/internal/noder/linker.go index ed47a355d81..eefb5083e50 100644 --- a/src/cmd/compile/internal/noder/linker.go +++ b/src/cmd/compile/internal/noder/linker.go @@ -149,9 +149,11 @@ func (l *linker) relocObj(pr *pkgReader, idx int) int { var ok bool obj, ok = sym.Def.(*ir.Name) - // Generic types and functions won't have definitions. + // Generic types and functions and declared constraint types won't + // have definitions. // For now, just generically copy their extension data. - if !ok && base.Flag.G == 0 { + // TODO(mdempsky): Restore assertion. + if !ok && false { base.Fatalf("missing definition for %v", sym) } } diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go index 3d83129aea6..6a2aacd3fea 100644 --- a/src/cmd/compile/internal/noder/noder.go +++ b/src/cmd/compile/internal/noder/noder.go @@ -9,6 +9,7 @@ import ( "fmt" "go/constant" "go/token" + "internal/buildcfg" "os" "path/filepath" "runtime" @@ -30,8 +31,11 @@ import ( func LoadPackage(filenames []string) { base.Timer.Start("fe", "parse") + // -G=3 and unified expect generics syntax, but -G=0 does not. + supportsGenerics := base.Flag.G != 0 || buildcfg.Experiment.Unified + mode := syntax.CheckBranches - if base.Flag.G != 0 { + if supportsGenerics && types.AllowsGoVersion(types.LocalPkg, 1, 18) { mode |= syntax.AllowGenerics } From a18726a648df48917e0ed1404cf6cdbc81acd495 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 1 Jul 2021 15:23:41 -0700 Subject: [PATCH 614/940] [dev.typeparams] cmd/compile: incremental typecheck during unified IR This CL changes unified IR to incrementally typecheck the IR as it's constructed. This is significant, because it means reader can now use typecheck.Expr to typecheck sub-expressions when it's needed. This should be helpful for construction and insertion of dictionaries. This CL does introduce two quirks outside of unified IR itself, which simplify preserving binary output: 1. Top-level declarations are sorted after they're constructed, to avoid worrying about the order that closures are added. 2. Zero-padding autotmp_N variable names. Interleaving typechecking means autotmp variables are sometimes named differently (since their naming depends on the number of variables declared so far), and this ensures that code that sorts variables by names doesn't suddenly sort autotmp_8/autotmp_9 differently than it would have sorted autotmp_9/autotmp_10. While at it, this CL also updated reader to use ir.WithFunc instead of manually setting and restoring ir.CurFunc. There's now only one remaining direct use of ir.CurFunc. Change-Id: I6233b4c059596e471c53166f94750917d710462f Reviewed-on: https://go-review.googlesource.com/c/go/+/332469 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/gc/main.go | 15 +++ src/cmd/compile/internal/noder/reader.go | 100 ++++++++++++------ src/cmd/compile/internal/noder/unified.go | 17 --- .../compile/internal/noder/unified_test.go | 2 +- src/cmd/compile/internal/typecheck/dcl.go | 11 +- 5 files changed, 92 insertions(+), 53 deletions(-) diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index c94f19fd47c..68017516dfd 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -32,6 +32,7 @@ import ( "log" "os" "runtime" + "sort" ) func hidePanic() { @@ -202,6 +203,20 @@ func Main(archInit func(*ssagen.ArchInfo)) { typecheck.Export(initTask) } + // Stability quirk: sort top-level declarations, so we're not + // sensitive to the order that functions are added. In particular, + // the order that noder+typecheck add function closures is very + // subtle, and not important to reproduce. + // + // Note: This needs to happen after pkginit.Task, otherwise it risks + // changing the order in which top-level variables are initialized. + if base.Debug.UnifiedQuirks != 0 { + s := typecheck.Target.Decls + sort.SliceStable(s, func(i, j int) bool { + return s[i].Pos().Before(s[j].Pos()) + }) + } + // Eliminate some obviously dead code. // Must happen after typechecking. for _, n := range typecheck.Target.Decls { diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 24977ed7f0e..275baead04b 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -886,27 +886,25 @@ func (r *reader) funcBody(fn *ir.Func) { r.curfn = fn r.closureVars = fn.ClosureVars - // TODO(mdempsky): Get rid of uses of typecheck.NodAddrAt so we - // don't have to set ir.CurFunc. - outerCurFunc := ir.CurFunc - ir.CurFunc = fn + ir.WithFunc(fn, func() { + r.funcargs(fn) - r.funcargs(fn) + if !r.bool() { + return + } - if r.bool() { body := r.stmts() if body == nil { pos := src.NoXPos if quirksMode() { pos = funcParamsEndPos(fn) } - body = []ir.Node{ir.NewBlockStmt(pos, nil)} + body = []ir.Node{typecheck.Stmt(ir.NewBlockStmt(pos, nil))} } fn.Body = body fn.Endlineno = r.pos() - } + }) - ir.CurFunc = outerCurFunc r.marker.WriteTo(fn) } @@ -1045,7 +1043,42 @@ func (r *reader) closeAnotherScope() { scopeVars := r.scopeVars[len(r.scopeVars)-1] r.scopeVars = r.scopeVars[:len(r.scopeVars)-1] - if scopeVars == len(r.curfn.Dcl) { + // Quirkish: noder decides which scopes to keep before + // typechecking, whereas incremental typechecking during IR + // construction can result in new autotemps being allocated. To + // produce identical output, we ignore autotemps here for the + // purpose of deciding whether to retract the scope. + // + // This is important for net/http/fcgi, because it contains: + // + // var body io.ReadCloser + // if len(content) > 0 { + // body, req.pw = io.Pipe() + // } else { … } + // + // Notably, io.Pipe is inlinable, and inlining it introduces a ~R0 + // variable at the call site. + // + // Noder does not preserve the scope where the io.Pipe() call + // resides, because it doesn't contain any declared variables in + // source. So the ~R0 variable ends up being assigned to the + // enclosing scope instead. + // + // However, typechecking this assignment also introduces + // autotemps, because io.Pipe's results need conversion before + // they can be assigned to their respective destination variables. + // + // TODO(mdempsky): We should probably just keep all scopes, and + // let dwarfgen take care of pruning them instead. + retract := true + for _, n := range r.curfn.Dcl[scopeVars:] { + if !n.AutoTemp() { + retract = false + break + } + } + + if retract { // no variables were declared in this scope, so we can retract it. r.marker.Unpush() } else { @@ -1068,6 +1101,7 @@ func (r *reader) stmt() ir.Node { } func (r *reader) stmts() []ir.Node { + assert(ir.CurFunc == r.curfn) var res ir.Nodes r.sync(syncStmts) @@ -1079,7 +1113,7 @@ func (r *reader) stmts() []ir.Node { } if n := r.stmt1(tag, &res); n != nil { - res.Append(n) + res.Append(typecheck.Stmt(n)) } } } @@ -1108,7 +1142,7 @@ func (r *reader) stmt1(tag codeStmt, out *ir.Nodes) ir.Node { for _, name := range names { as := ir.NewAssignStmt(pos, name, nil) as.PtrInit().Append(ir.NewDecl(pos, ir.ODCL, name)) - out.Append(as) + out.Append(typecheck.Stmt(as)) } return nil } @@ -1488,6 +1522,9 @@ func (r *reader) expr() ir.Node { case exprCall: fun := r.expr() + if clo, ok := fun.(*ir.ClosureExpr); ok { + clo.Func.SetClosureCalled(true) + } pos := r.pos() args := r.exprs() dots := r.bool() @@ -1574,11 +1611,15 @@ func (r *reader) funcLit() ir.Node { } fn := ir.NewClosureFunc(opos, r.curfn != nil) + clo := fn.OClosure + ir.NameClosure(clo, r.curfn) r.setType(fn.Nname, xtype2) if quirksMode() { fn.Nname.Ntype = ir.TypeNodeAt(typPos, xtype2) } + typecheck.Func(fn) + r.setType(clo, fn.Type()) fn.ClosureVars = make([]*ir.Name, 0, r.len()) for len(fn.ClosureVars) < cap(fn.ClosureVars) { @@ -1591,7 +1632,8 @@ func (r *reader) funcLit() ir.Node { r.addBody(fn) - return fn.OClosure + // TODO(mdempsky): Remove hard-coding of typecheck.Target. + return ir.UseClosure(clo, typecheck.Target) } func (r *reader) exprList() []ir.Node { @@ -1788,7 +1830,7 @@ func InlineCall(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExp r.setType(tmpfn.Nname, fn.Type()) r.curfn = tmpfn - r.inlCaller = ir.CurFunc + r.inlCaller = callerfn r.inlCall = call r.inlFunc = fn r.inlTreeIndex = inlIndex @@ -1872,17 +1914,13 @@ func InlineCall(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExp nparams := len(r.curfn.Dcl) - oldcurfn := ir.CurFunc - ir.CurFunc = r.curfn + ir.WithFunc(r.curfn, func() { + r.curfn.Body = r.stmts() + r.curfn.Endlineno = r.pos() - r.curfn.Body = r.stmts() - r.curfn.Endlineno = r.pos() + deadcode.Func(r.curfn) - typecheck.Stmts(r.curfn.Body) - deadcode.Func(r.curfn) - - // Replace any "return" statements within the function body. - { + // Replace any "return" statements within the function body. var edit func(ir.Node) ir.Node edit = func(n ir.Node) ir.Node { if ret, ok := n.(*ir.ReturnStmt); ok { @@ -1892,9 +1930,7 @@ func InlineCall(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExp return n } edit(r.curfn) - } - - ir.CurFunc = oldcurfn + }) body := ir.Nodes(r.curfn.Body) @@ -1998,16 +2034,12 @@ func expandInline(fn *ir.Func, pri pkgReaderIndex) { r.funarghack = true r.funcBody(tmpfn) + + ir.WithFunc(tmpfn, func() { + deadcode.Func(tmpfn) + }) } - oldcurfn := ir.CurFunc - ir.CurFunc = tmpfn - - typecheck.Stmts(tmpfn.Body) - deadcode.Func(tmpfn) - - ir.CurFunc = oldcurfn - used := usedLocals(tmpfn.Body) for _, name := range tmpfn.Dcl { diff --git a/src/cmd/compile/internal/noder/unified.go b/src/cmd/compile/internal/noder/unified.go index 03bcb2755b2..39989778f80 100644 --- a/src/cmd/compile/internal/noder/unified.go +++ b/src/cmd/compile/internal/noder/unified.go @@ -138,23 +138,6 @@ func unified(noders []*noder) { } todoBodies = nil - // Don't use range--typecheck can add closures to Target.Decls. - for i := 0; i < len(target.Decls); i++ { - if fn, ok := target.Decls[i].(*ir.Func); ok { - if base.Flag.W > 1 { - s := fmt.Sprintf("\nbefore typecheck %v", fn) - ir.Dump(s, fn) - } - ir.WithFunc(fn, func() { - typecheck.Stmts(fn.Body) - }) - if base.Flag.W > 1 { - s := fmt.Sprintf("\nafter typecheck %v", fn) - ir.Dump(s, fn) - } - } - } - if !quirksMode() { // TODO(mdempsky): Investigate generating wrappers in quirks mode too. r.wrapTypes(target) diff --git a/src/cmd/compile/internal/noder/unified_test.go b/src/cmd/compile/internal/noder/unified_test.go index ca91b49fbbe..26173682fbd 100644 --- a/src/cmd/compile/internal/noder/unified_test.go +++ b/src/cmd/compile/internal/noder/unified_test.go @@ -54,7 +54,7 @@ func TestUnifiedCompare(t *testing.T) { t.Parallel() } - pkgs1 := loadPackages(t, goos, goarch, "-d=unified=0 -d=inlfuncswithclosures=0") + pkgs1 := loadPackages(t, goos, goarch, "-d=unified=0 -d=inlfuncswithclosures=0 -d=unifiedquirks=1") pkgs2 := loadPackages(t, goos, goarch, "-d=unified=1 -d=inlfuncswithclosures=0 -d=unifiedquirks=1") if len(pkgs1) != len(pkgs2) { diff --git a/src/cmd/compile/internal/typecheck/dcl.go b/src/cmd/compile/internal/typecheck/dcl.go index f3ccbb4ac09..66d755089a0 100644 --- a/src/cmd/compile/internal/typecheck/dcl.go +++ b/src/cmd/compile/internal/typecheck/dcl.go @@ -450,7 +450,16 @@ func autotmpname(n int) string { if s == "" { // Give each tmp a different name so that they can be registerized. // Add a preceding . to avoid clashing with legal names. - s = fmt.Sprintf(".autotmp_%d", n) + prefix := ".autotmp_%d" + + // In quirks mode, pad out the number to stabilize variable + // sorting. This ensures autotmps 8 and 9 sort the same way even + // if they get renumbered to 9 and 10, respectively. + if base.Debug.UnifiedQuirks != 0 { + prefix = ".autotmp_%06d" + } + + s = fmt.Sprintf(prefix, n) autotmpnames[n] = s } return s From 6125d0c4265067cdb67af1340bf689975dd128f4 Mon Sep 17 00:00:00 2001 From: komisan19 Date: Fri, 2 Jul 2021 05:41:10 +0000 Subject: [PATCH 615/940] cmd/dist: correct comment: SysProcAttri -> SysProcAttr Fixes #46982 Change-Id: I07a18507b7aad828714b187f296fa7268f32b1c4 GitHub-Last-Rev: f498febffdae0bc93ae1794d1ee62b2ef3ecf1bb GitHub-Pull-Request: golang/go#46983 Reviewed-on: https://go-review.googlesource.com/c/go/+/331869 Reviewed-by: Tobias Klauser Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot --- src/cmd/dist/test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 4acd357974c..f40fa926dfd 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -781,7 +781,7 @@ func (t *tester) registerTests() { t.registerTest("testasan", "../misc/cgo/testasan", "go", "run", ".") } if goos == "linux" && goarch != "ppc64le" { - // because syscall.SysProcAttri struct used in misc/cgo/testsanitizers is only built on linux. + // because syscall.SysProcAttr struct used in misc/cgo/testsanitizers is only built on linux. // Some inconsistent failures happen on ppc64le so disable for now. t.registerHostTest("testsanitizers", "../misc/cgo/testsanitizers", "misc/cgo/testsanitizers", ".") } From 6dec18cc75021bfbfac267941a567b257721208b Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Mon, 28 Jun 2021 18:04:58 -0700 Subject: [PATCH 616/940] [dev.typeparams] cmd/compile: start using sub-dictionary entries where needed Added new struct instInfo for information about an instantiation (of a generic function/method with gcshapes or concrete types). We use this to remember the dictionary param node, the nodes where sub-dictionaries need to be used, etc. The instInfo map replaces the Stencil map in Package. Added code to access sub-dictionary entries at the appropriate call sites. We are currently still calculating the corresponding main dictionary, even when we really only need a sub-dictionary. I'll clean that up in a follow-up CL. Added code to deal with "generic" closures (closures that reference some generic variables/types). We decided that closures will share the same dictionary as the containing function (accessing the dictionary via a closure variable). So, the getGfInfo function now traverses all the nodes of each closure in a function that it is analyzing, so that a function's dictionary has all the entries needed for all its closures as well. Also, the instInfo of a closure is largely shared with its containing function. A good test for generic closures already exists with orderedmap.go. Other improvements: - Only create sub-dictionary entries when the function/method call/value or closure actually has type params in it. Added new test file subdict.go with an example where a generic method has an instantiated method call that does not depend not have type params. Change-Id: I691b9dc024a89d2305fcf1d8ba8540e53c9d103f Reviewed-on: https://go-review.googlesource.com/c/go/+/331516 Trust: Dan Scales Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/ir/package.go | 3 - src/cmd/compile/internal/noder/irgen.go | 32 +- src/cmd/compile/internal/noder/stencil.go | 344 +++++++++++++++------- test/typeparam/subdict.go | 42 +++ 4 files changed, 309 insertions(+), 112 deletions(-) create mode 100644 test/typeparam/subdict.go diff --git a/src/cmd/compile/internal/ir/package.go b/src/cmd/compile/internal/ir/package.go index e4b93d113ed..3896e2b91b1 100644 --- a/src/cmd/compile/internal/ir/package.go +++ b/src/cmd/compile/internal/ir/package.go @@ -32,7 +32,4 @@ type Package struct { // Exported (or re-exported) symbols. Exports []*Name - - // Map from function names of stencils to already-created stencils. - Stencils map[*types.Sym]*Func } diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go index 8f390612506..299d468a15f 100644 --- a/src/cmd/compile/internal/noder/irgen.go +++ b/src/cmd/compile/internal/noder/irgen.go @@ -100,11 +100,34 @@ func check2(noders []*noder) { type gfInfo struct { tparams []*types.Type derivedTypes []*types.Type - // Node in generic function that requires a subdictionary. Some of these - // are not function/method values (not strictly calls). + // Nodes in generic function that requires a subdictionary. Includes + // method and function calls (OCALL), function values (OFUNCINST), method + // values/expressions (OXDOT). subDictCalls []ir.Node } +// instInfo is information gathered on an gcshape (or fully concrete) +// instantiation of a function. +type instInfo struct { + fun *ir.Func // The instantiated function (with body) + dictParam *ir.Name // The node inside fun that refers to the dictionary param + // Addr of static dictionary associated with this instantiation. This is the + // dictionary you should pass if all the type args are concreate. Soon to be + // removed, when creating static dictionary and instantiated function are + // separated. + dictAddr ir.Node + + gf *ir.Name // The associated generic function + gfInfo *gfInfo + + startSubDict int // Start of dict entries for subdictionaries + dictLen int // Total number of entries in dictionary + + // Map from nodes in instantiated fun (OCALL, OCALLMETHOD, OFUNCINST, and + // OMETHEXPR) to the associated dictionary entry for a sub-dictionary + dictEntryMap map[ir.Node]int +} + type irgen struct { target *ir.Package self *types2.Package @@ -123,6 +146,11 @@ type irgen struct { // Map from generic function to information about its type params, derived // types, and subdictionaries. gfInfoMap map[*types.Sym]*gfInfo + + // Map from a name of function that been instantiated to information about + // its instantiated function, associated generic function/method, and the + // mapping from IR nodes to dictionary entries. + instInfoMap map[*types.Sym]*instInfo } func (g *irgen) generate(noders []*noder) { diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index c04300a1654..9d70e0e299e 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -44,7 +44,7 @@ func infoPrint(format string, a ...interface{}) { // encountered already or new ones that are encountered during the stenciling // process. func (g *irgen) stencil() { - g.target.Stencils = make(map[*types.Sym]*ir.Func) + g.instInfoMap = make(map[*types.Sym]*instInfo) g.gfInfoMap = make(map[*types.Sym]*gfInfo) // Instantiate the methods of instantiated generic types that we have seen so far. @@ -86,6 +86,9 @@ func (g *irgen) stencil() { // to calling that function directly. modified := false closureRequired := false + // declInfo will be non-nil exactly if we are scanning an instantiated function + declInfo := g.instInfoMap[decl.Sym()] + ir.Visit(decl, func(n ir.Node) { if n.Op() == ir.OFUNCINST { // generic F, not immediately called @@ -103,11 +106,24 @@ func (g *irgen) stencil() { call := n.(*ir.CallExpr) inst := call.X.(*ir.InstExpr) st, dict := g.getInstantiationForNode(inst) - if infoPrintMode && g.target.Stencils[decl.Sym()] == nil { + dictkind := "Main dictionary" + if declInfo != nil { + // Get the dictionary arg via sub-dictionary reference + entry, ok := declInfo.dictEntryMap[n] + // If the entry is not found, it must be that + // this node was did not have any type args + // that depend on type params, so we need a + // main dictionary, not a sub-dictionary. + if ok { + dict = getDictionaryEntry(n.Pos(), declInfo.dictParam, entry, declInfo.dictLen) + dictkind = "Sub-dictionary" + } + } + if infoPrintMode { if inst.X.Op() == ir.OMETHVALUE { - fmt.Printf("Main dictionary in %v at generic method call: %v - %v\n", decl, inst.X, call) + fmt.Printf("%s in %v at generic method call: %v - %v\n", dictkind, decl, inst.X, call) } else { - fmt.Printf("Main dictionary in %v at generic function call: %v - %v\n", decl, inst.X, call) + fmt.Printf("%s in %v at generic function call: %v - %v\n", dictkind, decl, inst.X, call) } } // Replace the OFUNCINST with a direct reference to the @@ -147,6 +163,17 @@ func (g *irgen) stencil() { } st, dict := g.getInstantiation(gf, targs, true) + entry, ok := declInfo.dictEntryMap[n] + // TODO: Not creating sub-dictionary entry for + // absDifference in absdiff.go yet. Unusual case, + // where there are different generic method + // implementations of Abs in absDifference. + if ok { + if infoPrintMode { + fmt.Printf("Sub-dictionary in %v at generic method call: %v\n", decl, call) + } + dict = getDictionaryEntry(n.Pos(), declInfo.dictParam, entry, declInfo.dictLen) + } call.SetOp(ir.OCALL) call.X = st.Nname call.Args.Prepend(dict, meth.X) @@ -175,8 +202,6 @@ func (g *irgen) stencil() { ir.EditChildren(x, edit) switch { case x.Op() == ir.OFUNCINST: - // TODO: only set outer!=nil if this instantiation uses - // a type parameter from outer. See comment in buildClosure. return g.buildClosure(outer, x) case x.Op() == ir.OMETHEXPR && len(deref(x.(*ir.SelectorExpr).X.Type()).RParams()) > 0 && !types.IsInterfaceMethod(x.(*ir.SelectorExpr).Selection.Type): // TODO: test for ptr-to-method case @@ -208,6 +233,11 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { var dictValue ir.Node // dictionary to use var rcvrValue ir.Node // receiver, if a method value typ := x.Type() // type of the closure + var outerInfo *instInfo + if outer != nil { + outerInfo = g.instInfoMap[outer.Sym()] + } + usingSubdict := false if x.Op() == ir.OFUNCINST { inst := x.(*ir.InstExpr) @@ -234,11 +264,20 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { // as its first two arguments. // dictValue is the value to use for the dictionary argument. target, dictValue = g.getInstantiation(gf, targs, rcvrValue != nil) - if infoPrintMode && (outer == nil || g.target.Stencils[outer.Sym()] == nil) { + dictkind := "Main dictionary" + if outerInfo != nil { + entry, ok := outerInfo.dictEntryMap[x] + if ok { + dictValue = getDictionaryEntry(x.Pos(), outerInfo.dictParam, entry, outerInfo.dictLen) + dictkind = "Sub-dictionary" + usingSubdict = true + } + } + if infoPrintMode { if rcvrValue == nil { - fmt.Printf("Main dictionary in %v for function value %v\n", outer, inst.X) + fmt.Printf("%s in %v for generic function value %v\n", dictkind, outer, inst.X) } else { - fmt.Printf("Main dictionary in %v for method value %v\n", outer, inst.X) + fmt.Printf("%s in %v for generic method value %v\n", dictkind, outer, inst.X) } } } else { // ir.OMETHEXPR @@ -270,8 +309,17 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { } } target, dictValue = g.getInstantiation(gf, targs, true) - if infoPrintMode && (outer == nil || g.target.Stencils[outer.Sym()] == nil) { - fmt.Printf("Main dictionary in %v for method expression %v\n", outer, x) + dictkind := "Main dictionary" + if outerInfo != nil { + entry, ok := outerInfo.dictEntryMap[x] + if ok { + dictValue = getDictionaryEntry(x.Pos(), outerInfo.dictParam, entry, outerInfo.dictLen) + dictkind = "Sub-dictionary" + usingSubdict = true + } + } + if infoPrintMode { + fmt.Printf("%s in %v for method expression %v\n", dictkind, outer, x) } } @@ -386,14 +434,12 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { // First, figure out the dictionary argument. var dict2Var ir.Node - if outer != nil { - // If there's an outer function, the dictionary value will be read from - // the dictionary of the outer function. - // TODO: only use a subdictionary if any of the instantiating types - // depend on the type params of the outer function. + if usingSubdict { + // Capture sub-dictionary calculated in the outer function dict2Var = ir.CaptureName(pos, fn, dictVar) + typed(types.Types[types.TUINTPTR], dict2Var) } else { - // No outer function, instantiating types are known concrete types. + // Static dictionary, so can be used directly in the closure dict2Var = dictValue } // Also capture the receiver variable. @@ -695,8 +741,8 @@ func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth nameNode.Func.Dcl = nameNode.Func.Inl.Dcl } sym := typecheck.MakeInstName(nameNode.Sym(), targs, isMeth) - st := g.target.Stencils[sym] - if st == nil { + info := g.instInfoMap[sym] + if info == nil { if false { // Testing out gcshapeType() and gcshapeName() for i, t := range targs { @@ -706,27 +752,38 @@ func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth } // If instantiation doesn't exist yet, create it and add // to the list of decls. - st = g.genericSubst(sym, nameNode, targs, isMeth) + gfInfo := g.getGfInfo(nameNode) + info = &instInfo{ + gf: nameNode, + gfInfo: gfInfo, + startSubDict: len(targs) + len(gfInfo.derivedTypes), + dictLen: len(targs) + len(gfInfo.derivedTypes) + len(gfInfo.subDictCalls), + dictEntryMap: make(map[ir.Node]int), + } + // genericSubst fills in info.dictParam and info.dictEntryMap. + st := g.genericSubst(sym, nameNode, targs, isMeth, info) + info.fun = st + info.dictAddr = g.getDictionaryValue(nameNode, targs, isMeth) + g.instInfoMap[sym] = info // This ensures that the linker drops duplicates of this instantiation. // All just works! st.SetDupok(true) - g.target.Stencils[sym] = st g.target.Decls = append(g.target.Decls, st) if base.Flag.W > 1 { ir.Dump(fmt.Sprintf("\nstenciled %v", st), st) } } - return st, g.getDictionaryValue(nameNode, targs, isMeth) + return info.fun, info.dictAddr } // Struct containing info needed for doing the substitution as we create the // instantiation of a generic function with specified type arguments. type subster struct { - g *irgen - isMethod bool // If a method is being instantiated - newf *ir.Func // Func node for the new stenciled function - ts typecheck.Tsubster - dictionary *ir.Name // Name of dictionary variable + g *irgen + isMethod bool // If a method is being instantiated + newf *ir.Func // Func node for the new stenciled function + ts typecheck.Tsubster + info *instInfo // Place to put extra info in the instantiation } // genericSubst returns a new function with name newsym. The function is an @@ -734,8 +791,8 @@ type subster struct { // args targs. For a method with a generic receiver, it returns an instantiated // function type where the receiver becomes the first parameter. Otherwise the // instantiated method would still need to be transformed by later compiler -// phases. -func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*types.Type, isMethod bool) *ir.Func { +// phases. genericSubst fills in info.dictParam and info.dictEntryMap. +func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*types.Type, isMethod bool, info *instInfo) *ir.Func { var tparams []*types.Type if isMethod { // Get the type params from the method receiver (after skipping @@ -769,6 +826,7 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*type g: g, isMethod: isMethod, newf: newf, + info: info, ts: typecheck.Tsubster{ Tparams: tparams, Targs: targs, @@ -778,13 +836,7 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*type newf.Dcl = make([]*ir.Name, 0, len(gf.Dcl)+1) - // Replace the types in the function signature. - // Ugly: also, we have to insert the Name nodes of the parameters/results into - // the function type. The current function type has no Nname fields set, - // because it came via conversion from the types2 type. - oldt := nameNode.Type() - // We also transform a generic method type to the corresponding - // instantiated function type where the dictionary is the first parameter. + // Create the needed dictionary param dictionarySym := newsym.Pkg.Lookup(".dict") dictionaryType := types.Types[types.TUINTPTR] dictionaryName := ir.NewNameAt(gf.Pos(), dictionarySym) @@ -800,11 +852,21 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*type } dictionaryArg := types.NewField(gf.Pos(), dictionarySym, dictionaryType) dictionaryArg.Nname = dictionaryName - subst.dictionary = dictionaryName + info.dictParam = dictionaryName + + // We add the dictionary as the first parameter in the function signature. + // We also transform a method type to the corresponding function type + // (make the receiver be the next parameter after the dictionary). + oldt := nameNode.Type() var args []*types.Field args = append(args, dictionaryArg) args = append(args, oldt.Recvs().FieldSlice()...) args = append(args, oldt.Params().FieldSlice()...) + + // Replace the types in the function signature via subst.fields. + // Ugly: also, we have to insert the Name nodes of the parameters/results into + // the function type. The current function type has no Nname fields set, + // because it came via conversion from the types2 type. newt := types.NewSignature(oldt.Pkg(), nil, nil, subst.fields(ir.PPARAM, args, newf.Dcl), subst.fields(ir.PPARAMOUT, oldt.Results().FieldSlice(), newf.Dcl)) @@ -884,6 +946,26 @@ func (g *irgen) checkDictionary(name *ir.Name, targs []*types.Type) (code []ir.N return } +// getDictionaryEntry gets the i'th entry in the dictionary dict. +func getDictionaryEntry(pos src.XPos, dict *ir.Name, i int, size int) ir.Node { + // Convert dictionary to *[N]uintptr + // All entries in the dictionary are pointers. They all point to static data, though, so we + // treat them as uintptrs so the GC doesn't need to keep track of them. + d := ir.NewConvExpr(pos, ir.OCONVNOP, types.Types[types.TUNSAFEPTR], dict) + d.SetTypecheck(1) + d = ir.NewConvExpr(pos, ir.OCONVNOP, types.NewArray(types.Types[types.TUINTPTR], int64(size)).PtrTo(), d) + d.SetTypecheck(1) + + // Load entry i out of the dictionary. + deref := ir.NewStarExpr(pos, d) + typed(d.Type().Elem(), deref) + idx := ir.NewConstExpr(constant.MakeUint64(uint64(i)), dict) // TODO: what to set orig to? + typed(types.Types[types.TUINTPTR], idx) + r := ir.NewIndexExpr(pos, deref, idx) + typed(types.Types[types.TUINTPTR], r) + return r +} + // getDictionaryType returns a *runtime._type from the dictionary corresponding to the input type. // The input type must be a type parameter (TODO: or a local derived type). func (subst *subster) getDictionaryType(pos src.XPos, t *types.Type) ir.Node { @@ -898,21 +980,10 @@ func (subst *subster) getDictionaryType(pos src.XPos, t *types.Type) ir.Node { base.Fatalf(fmt.Sprintf("couldn't find type param %+v", t)) } - // Convert dictionary to *[N]uintptr - // All entries in the dictionary are pointers. They all point to static data, though, so we - // treat them as uintptrs so the GC doesn't need to keep track of them. - d := ir.NewConvExpr(pos, ir.OCONVNOP, types.Types[types.TUNSAFEPTR], subst.dictionary) - d.SetTypecheck(1) - d = ir.NewConvExpr(pos, ir.OCONVNOP, types.NewArray(types.Types[types.TUINTPTR], int64(len(tparams))).PtrTo(), d) - d.SetTypecheck(1) - - // Load entry i out of the dictionary. - deref := ir.NewStarExpr(pos, d) - typed(d.Type().Elem(), deref) - idx := ir.NewConstExpr(constant.MakeUint64(uint64(i)), subst.dictionary) // TODO: what to set orig to? - typed(types.Types[types.TUINTPTR], idx) - r := ir.NewIndexExpr(pos, deref, idx) - typed(types.Types[types.TUINT8].PtrTo(), r) // standard typing of a *runtime._type in the compiler is *byte + r := getDictionaryEntry(pos, subst.info.dictParam, i, len(tparams)) + // change type of retrieved dictionary entry to *byte, which is the + // standard typing of a *runtime._type in the compiler + typed(types.Types[types.TUINT8].PtrTo(), r) return r } @@ -957,6 +1028,18 @@ func (subst *subster) node(n ir.Node) ir.Node { m.SetType(subst.ts.Typ(x.Type())) } } + + for i, de := range subst.info.gfInfo.subDictCalls { + if de == x { + // Remember the dictionary entry associated with this + // node in the instantiated function + // TODO: make sure this remains correct with respect to the + // transformations below. + subst.info.dictEntryMap[m] = subst.info.startSubDict + i + break + } + } + ir.EditChildren(m, edit) m.SetTypecheck(1) @@ -1109,7 +1192,26 @@ func (subst *subster) node(n ir.Node) ir.Node { ir.CurFunc = newfn subst.newf = newfn newfn.Dcl = subst.namelist(oldfn.Dcl) - newfn.ClosureVars = subst.namelist(oldfn.ClosureVars) + + // Make a closure variable for the dictionary of the + // containing function. + cdict := ir.CaptureName(oldfn.Pos(), newfn, subst.info.dictParam) + typed(types.Types[types.TUINTPTR], cdict) + ir.FinishCaptureNames(oldfn.Pos(), saveNewf, newfn) + newfn.ClosureVars = append(newfn.ClosureVars, subst.namelist(oldfn.ClosureVars)...) + + // Create inst info for the instantiated closure. The dict + // param is the closure variable for the dictionary of the + // outer function. Since the dictionary is shared, use the + // same entries for startSubDict, dictLen, dictEntryMap. + cinfo := &instInfo{ + fun: newfn, + dictParam: cdict, + startSubDict: subst.info.startSubDict, + dictLen: subst.info.dictLen, + dictEntryMap: subst.info.dictEntryMap, + } + subst.g.instInfoMap[newfn.Nname.Sym()] = cinfo typed(subst.ts.Typ(oldfn.Nname.Type()), newfn.Nname) typed(newfn.Nname.Type(), newfn.OClosure) @@ -1257,7 +1359,7 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) // Initialize the dictionary, if we haven't yet already. if lsym := sym.Linksym(); len(lsym.P) == 0 { - infoPrint("Creating dictionary %v\n", sym.Name) + infoPrint("=== Creating dictionary %v\n", sym.Name) off := 0 // Emit an entry for each targ (concrete type or gcshape). for _, t := range targs { @@ -1279,7 +1381,8 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) // Emit an entry for each subdictionary (after substituting targs) for _, n := range info.subDictCalls { var sym *types.Sym - if n.Op() == ir.OCALL { + switch n.Op() { + case ir.OCALL: call := n.(*ir.CallExpr) if call.X.Op() == ir.OXDOT { subtargs := deref(call.X.(*ir.SelectorExpr).X.Type()).RParams() @@ -1304,11 +1407,9 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) subtargs[i] = subst.Typ(t) } sym = g.getDictionarySym(nameNode, subtargs, isMeth) - // TODO: This can actually be a static - // main dictionary, if all of the subtargs - // are concrete types (!HasTParam) } - } else if n.Op() == ir.OFUNCINST { + + case ir.OFUNCINST: inst := n.(*ir.InstExpr) nameNode := inst.X.(*ir.Name) subtargs := typecheck.TypesOf(inst.Targs) @@ -1316,10 +1417,8 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) subtargs[i] = subst.Typ(t) } sym = g.getDictionarySym(nameNode, subtargs, false) - // TODO: This can actually be a static - // main dictionary, if all of the subtargs - // are concrete types (!HasTParam) - } else if n.Op() == ir.OXDOT { + + case ir.OXDOT: selExpr := n.(*ir.SelectorExpr) subtargs := selExpr.X.Type().RParams() s2targs := make([]*types.Type, len(subtargs)) @@ -1328,14 +1427,16 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) } nameNode := selExpr.Selection.Nname.(*ir.Name) sym = g.getDictionarySym(nameNode, s2targs, true) + + default: + assert(false) } - // TODO: handle closure cases that need sub-dictionaries, get rid of conditional - if sym != nil { - off = objw.SymPtr(lsym, off, sym.Linksym(), 0) - infoPrint(" - Subdict %v\n", sym.Name) - } + + off = objw.SymPtr(lsym, off, sym.Linksym(), 0) + infoPrint(" - Subdict %v\n", sym.Name) } objw.Global(lsym, int32(off), obj.DUPOK|obj.RODATA) + infoPrint("=== Done dictionary\n") // Add any new, fully instantiated types seen during the substitution to g.instTypeList. g.instTypeList = append(g.instTypeList, subst.InstTypeList...) @@ -1363,6 +1464,26 @@ func (g *irgen) getDictionaryValue(gf *ir.Name, targs []*types.Type, isMeth bool return np } +// hasTParamNodes returns true if the type of any node in targs has a typeparam. +func hasTParamNodes(targs []ir.Node) bool { + for _, n := range targs { + if n.Type().HasTParam() { + return true + } + } + return false +} + +// hasTParamNodes returns true if any type in targs has a typeparam. +func hasTParamTypes(targs []*types.Type) bool { + for _, t := range targs { + if t.HasTParam() { + return true + } + } + return false +} + // getGfInfo get information for a generic function - type params, derived generic // types, and subdictionaries. func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo { @@ -1377,8 +1498,9 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo { if recv != nil { info.tparams = deref(recv.Type).RParams() } else { - info.tparams = make([]*types.Type, len(gn.Type().TParams().FieldSlice())) - for i, f := range gn.Type().TParams().FieldSlice() { + tparams := gn.Type().TParams().FieldSlice() + info.tparams = make([]*types.Type, len(tparams)) + for i, f := range tparams { info.tparams[i] = f.Type } } @@ -1387,23 +1509,28 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo { } if infoPrintMode { - fmt.Printf(">>> Info for %v\n", gn) + fmt.Printf(">>> GfInfo for %v\n", gn) for _, t := range info.tparams { fmt.Printf(" Typeparam %v\n", t) } - for _, t := range info.derivedTypes { - fmt.Printf(" Derived type %v\n", t) - } } - for _, stmt := range gf.Body { - ir.Visit(stmt, func(n ir.Node) { - if n.Op() == ir.OFUNCINST && !n.(*ir.InstExpr).Implicit() { + var visitFunc func(ir.Node) + visitFunc = func(n ir.Node) { + if n.Op() == ir.OFUNCINST && !n.(*ir.InstExpr).Implicit() { + if hasTParamNodes(n.(*ir.InstExpr).Targs) { infoPrint(" Closure&subdictionary required at generic function value %v\n", n.(*ir.InstExpr).X) info.subDictCalls = append(info.subDictCalls, n) - } else if n.Op() == ir.OXDOT && !n.(*ir.SelectorExpr).Implicit() && - n.(*ir.SelectorExpr).Selection != nil && - len(n.(*ir.SelectorExpr).X.Type().RParams()) > 0 { + } + } else if n.Op() == ir.OXDOT && !n.(*ir.SelectorExpr).Implicit() && + n.(*ir.SelectorExpr).Selection != nil && + len(n.(*ir.SelectorExpr).X.Type().RParams()) > 0 { + if n.(*ir.SelectorExpr).X.Op() == ir.OTYPE { + infoPrint(" Closure&subdictionary required at generic meth expr %v\n", n) + } else { + infoPrint(" Closure&subdictionary required at generic meth value %v\n", n) + } + if hasTParamTypes(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) { if n.(*ir.SelectorExpr).X.Op() == ir.OTYPE { infoPrint(" Closure&subdictionary required at generic meth expr %v\n", n) } else { @@ -1411,40 +1538,43 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo { } info.subDictCalls = append(info.subDictCalls, n) } - if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OFUNCINST { - infoPrint(" Subdictionary at generic function call: %v - %v\n", n.(*ir.CallExpr).X.(*ir.InstExpr).X, n) - n.(*ir.CallExpr).X.(*ir.InstExpr).SetImplicit(true) + } + if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OFUNCINST { + n.(*ir.CallExpr).X.(*ir.InstExpr).SetImplicit(true) + if hasTParamNodes(n.(*ir.CallExpr).X.(*ir.InstExpr).Targs) { + infoPrint(" Subdictionary at generic function/method call: %v - %v\n", n.(*ir.CallExpr).X.(*ir.InstExpr).X, n) info.subDictCalls = append(info.subDictCalls, n) } - if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OXDOT && - n.(*ir.CallExpr).X.(*ir.SelectorExpr).Selection != nil && - len(deref(n.(*ir.CallExpr).X.(*ir.SelectorExpr).X.Type()).RParams()) > 0 { + } + if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OXDOT && + n.(*ir.CallExpr).X.(*ir.SelectorExpr).Selection != nil && + len(deref(n.(*ir.CallExpr).X.(*ir.SelectorExpr).X.Type()).RParams()) > 0 { + n.(*ir.CallExpr).X.(*ir.SelectorExpr).SetImplicit(true) + if hasTParamTypes(deref(n.(*ir.CallExpr).X.(*ir.SelectorExpr).X.Type()).RParams()) { infoPrint(" Subdictionary at generic method call: %v\n", n) - n.(*ir.CallExpr).X.(*ir.SelectorExpr).SetImplicit(true) info.subDictCalls = append(info.subDictCalls, n) } - if n.Op() == ir.OCLOSURE { - oldfn := n.(*ir.ClosureExpr).Func - needDict := false - if oldfn.Nname.Type().HasTParam() { - needDict = true - infoPrint(" Subdictionary for closure that has generic params: %v\n", oldfn) - } else { - for _, cv := range oldfn.ClosureVars { - if cv.Type().HasTParam() { - needDict = true - infoPrint(" Subdictionary for closure that has generic capture: %v\n", oldfn) - break - } - } - } - if needDict { - info.subDictCalls = append(info.subDictCalls, n) - } + } + if n.Op() == ir.OCLOSURE { + // Visit the closure body and add all relevant entries to the + // dictionary of the outer function (closure will just use + // the dictionary of the outer function). + for _, n1 := range n.(*ir.ClosureExpr).Func.Body { + ir.Visit(n1, visitFunc) } + } - addType(&info, n, n.Type()) - }) + addType(&info, n, n.Type()) + } + + for _, stmt := range gf.Body { + ir.Visit(stmt, visitFunc) + } + if infoPrintMode { + for _, t := range info.derivedTypes { + fmt.Printf(" Derived type %v\n", t) + } + fmt.Printf(">>> Done Gfinfo\n") } g.gfInfoMap[gn.Sym()] = &info return &info diff --git a/test/typeparam/subdict.go b/test/typeparam/subdict.go new file mode 100644 index 00000000000..c899af6d0d6 --- /dev/null +++ b/test/typeparam/subdict.go @@ -0,0 +1,42 @@ +// run -gcflags=-G=3 + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test cases where a main dictionary is needed inside a generic function/method, because +// we are calling a method on a fully-instantiated type or a fully-instantiated function. +// (probably not common situations, of course) + +package main + +import ( + "fmt" +) + +type value[T comparable] struct { + val T +} + +func (v *value[T]) test(def T) bool { + return (v.val == def) +} + +func (v *value[T]) get(def T) T { + var c value[int] + if c.test(32) { + return def + } else if v.test(def) { + return def + } else { + return v.val + } +} + + +func main() { + var s value[string] + if got, want := s.get("ab"), ""; got != want { + panic(fmt.Sprintf("get() == %d, want %d", got, want)) + } +} From 743f03eeb0bdcb596b46fae51d23c0fcf0db0474 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 1 Jul 2021 16:52:59 -0700 Subject: [PATCH 617/940] spec, unsafe: clarify unsafe.Slice docs For #19367 Change-Id: If0ff8ddba3b6b48e2e198cf3653e73284c7572a3 Reviewed-on: https://go-review.googlesource.com/c/go/+/332409 Trust: Ian Lance Taylor Reviewed-by: Matthew Dempsky Reviewed-by: Robert Griesemer Reviewed-by: Keith Randall --- doc/go_spec.html | 8 +++++--- src/unsafe/unsafe.go | 6 ++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index e0602418e80..ad21ffb1b88 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -6782,7 +6782,8 @@ The rules for valid uses of Pointer The function Slice returns a slice whose underlying array starts at ptr -and whose length and capacity are len: +and whose length and capacity are len. +Slice(ptr, len) is equivalent to

@@ -6790,7 +6791,8 @@ and whose length and capacity are len:
 

-As a special case, if ptr is nil and len is zero, +except that, as a special case, if ptr +is nil and len is zero, Slice returns nil.

diff --git a/src/unsafe/unsafe.go b/src/unsafe/unsafe.go index eaf72c96181..16e3890d0be 100644 --- a/src/unsafe/unsafe.go +++ b/src/unsafe/unsafe.go @@ -217,11 +217,13 @@ func Alignof(x ArbitraryType) uintptr func Add(ptr Pointer, len IntegerType) Pointer // The function Slice returns a slice whose underlying array starts at ptr -// and whose length and capacity are len: +// and whose length and capacity are len. +// Slice(ptr, len) is equivalent to // // (*[len]ArbitraryType)(unsafe.Pointer(ptr))[:] // -// As a special case, if ptr is nil and len is zero, Slice returns nil. +// except that, as a special case, if ptr is nil and len is zero, +// Slice returns nil. // // The len argument must be of integer type or an untyped constant. // A constant len argument must be non-negative and representable by a value of type int; From 287c5e8066396e953254d7980a80ec082edf11bd Mon Sep 17 00:00:00 2001 From: go101 Date: Fri, 2 Jul 2021 08:01:20 +0000 Subject: [PATCH 618/940] cmd/compile: fix stack growing algorithm The current stack growing implementation looks not right. Specially, the line runtime/stack.go#L1068 never gets executed, which causes many unnecessary copystack calls. This PR is trying to correct the implementation. As I'm not familiar with the code, the fix is just a guess. Change-Id: I0bea1148175fad34f74f19d455c240c94d3cb78b GitHub-Last-Rev: 57205f91fe6f7cecbf0b7aad0d90d2f81270b1e8 GitHub-Pull-Request: golang/go#47010 Reviewed-on: https://go-review.googlesource.com/c/go/+/332229 Reviewed-by: Keith Randall Run-TryBot: Keith Randall TryBot-Result: Go Bot Trust: Dmitri Shuralyov --- src/runtime/stack.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/runtime/stack.go b/src/runtime/stack.go index b21c9c95182..6e0d157630b 100644 --- a/src/runtime/stack.go +++ b/src/runtime/stack.go @@ -1064,7 +1064,9 @@ func newstack() { // recheck the bounds on return.) if f := findfunc(gp.sched.pc); f.valid() { max := uintptr(funcMaxSPDelta(f)) - for newsize-gp.sched.sp < max+_StackGuard { + needed := max + _StackGuard + used := gp.stack.hi - gp.sched.sp + for newsize-used < needed { newsize *= 2 } } From 912f0750472dd4f674b69ca1616bfaf377af1805 Mon Sep 17 00:00:00 2001 From: Sean Liao Date: Tue, 8 Jun 2021 20:13:23 +0200 Subject: [PATCH 619/940] net/http: mention socks5 support in proxy Change-Id: I55b6d5c77221569eeafea625379affd476a65772 Reviewed-on: https://go-review.googlesource.com/c/go/+/326011 Reviewed-by: Damien Neil Trust: Dmitri Shuralyov --- src/net/http/transport.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/net/http/transport.go b/src/net/http/transport.go index 47cb992a502..309194e8e52 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -427,6 +427,7 @@ func (t *Transport) onceSetNextProtoDefaults() { // // The environment values may be either a complete URL or a // "host[:port]", in which case the "http" scheme is assumed. +// The schemes "http", "https", and "socks5" are supported. // An error is returned if the value is a different form. // // A nil URL and nil error are returned if no proxy is defined in the From b994cc69e05d7821a08f75619f356ecfe5ca9b43 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Fri, 2 Jul 2021 12:32:38 -0700 Subject: [PATCH 620/940] [dev.typeparams] cmd/compile: separate out creating instantiations from creating dictionaries We often need to create a function/method instantiation, but not a dictionary, because the call to the instantiation will be using a sub-dictionary. Also, main dictionaries are only need for concrete, non-gcshape types, whereas instantiations will be for gcshape types (or concrete types, for strict stenciling). Created a helper function getDictOrSubdict() to reduce duplicated code. Also, moved gfGetGfInfo() call in getDictionarySym() inside conditional where it is needed, to avoid extra work when dictionary has already been created. Change-Id: I06587cb2ddc77de2f991e9f9eaf462d2c5a5d45e Reviewed-on: https://go-review.googlesource.com/c/go/+/332550 Trust: Dan Scales Reviewed-by: Keith Randall --- src/cmd/compile/internal/noder/irgen.go | 5 - src/cmd/compile/internal/noder/stencil.go | 121 ++++++++++++---------- 2 files changed, 64 insertions(+), 62 deletions(-) diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go index 299d468a15f..64c29435b5e 100644 --- a/src/cmd/compile/internal/noder/irgen.go +++ b/src/cmd/compile/internal/noder/irgen.go @@ -111,11 +111,6 @@ type gfInfo struct { type instInfo struct { fun *ir.Func // The instantiated function (with body) dictParam *ir.Name // The node inside fun that refers to the dictionary param - // Addr of static dictionary associated with this instantiation. This is the - // dictionary you should pass if all the type args are concreate. Soon to be - // removed, when creating static dictionary and instantiated function are - // separated. - dictAddr ir.Node gf *ir.Name // The associated generic function gfInfo *gfInfo diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 9d70e0e299e..d35e036ae6d 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -105,21 +105,15 @@ func (g *irgen) stencil() { // instantiation. call := n.(*ir.CallExpr) inst := call.X.(*ir.InstExpr) - st, dict := g.getInstantiationForNode(inst) - dictkind := "Main dictionary" - if declInfo != nil { - // Get the dictionary arg via sub-dictionary reference - entry, ok := declInfo.dictEntryMap[n] - // If the entry is not found, it must be that - // this node was did not have any type args - // that depend on type params, so we need a - // main dictionary, not a sub-dictionary. - if ok { - dict = getDictionaryEntry(n.Pos(), declInfo.dictParam, entry, declInfo.dictLen) + nameNode, isMeth := g.getInstNameNode(inst) + targs := typecheck.TypesOf(inst.Targs) + st := g.getInstantiation(nameNode, targs, isMeth) + dictValue, usingSubdict := g.getDictOrSubdict(declInfo, n, nameNode, targs, isMeth) + if infoPrintMode { + dictkind := "Main dictionary" + if usingSubdict { dictkind = "Sub-dictionary" } - } - if infoPrintMode { if inst.X.Op() == ir.OMETHVALUE { fmt.Printf("%s in %v at generic method call: %v - %v\n", dictkind, decl, inst.X, call) } else { @@ -137,7 +131,7 @@ func (g *irgen) stencil() { call.Args.Prepend(inst.X.(*ir.SelectorExpr).X) } // Add dictionary to argument list. - call.Args.Prepend(dict) + call.Args.Prepend(dictValue) // Transform the Call now, which changes OCALL // to OCALLFUNC and does typecheckaste/assignconvfn. transformCall(call) @@ -162,21 +156,18 @@ func (g *irgen) stencil() { } } - st, dict := g.getInstantiation(gf, targs, true) - entry, ok := declInfo.dictEntryMap[n] - // TODO: Not creating sub-dictionary entry for + st := g.getInstantiation(gf, targs, true) + dictValue, usingSubdict := g.getDictOrSubdict(declInfo, n, gf, targs, true) + _ = usingSubdict + // TODO: We should do assert(usingSubdict) here, but + // not creating sub-dictionary entry for // absDifference in absdiff.go yet. Unusual case, // where there are different generic method // implementations of Abs in absDifference. - if ok { - if infoPrintMode { - fmt.Printf("Sub-dictionary in %v at generic method call: %v\n", decl, call) - } - dict = getDictionaryEntry(n.Pos(), declInfo.dictParam, entry, declInfo.dictLen) - } + call.SetOp(ir.OCALL) call.X = st.Nname - call.Args.Prepend(dict, meth.X) + call.Args.Prepend(dictValue, meth.X) // Transform the Call now, which changes OCALL // to OCALLFUNC and does typecheckaste/assignconvfn. transformCall(call) @@ -263,17 +254,13 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { // For method values, the target expects a dictionary and the receiver // as its first two arguments. // dictValue is the value to use for the dictionary argument. - target, dictValue = g.getInstantiation(gf, targs, rcvrValue != nil) - dictkind := "Main dictionary" - if outerInfo != nil { - entry, ok := outerInfo.dictEntryMap[x] - if ok { - dictValue = getDictionaryEntry(x.Pos(), outerInfo.dictParam, entry, outerInfo.dictLen) - dictkind = "Sub-dictionary" - usingSubdict = true - } - } + target = g.getInstantiation(gf, targs, rcvrValue != nil) + dictValue, usingSubdict = g.getDictOrSubdict(outerInfo, x, gf, targs, rcvrValue != nil) if infoPrintMode { + dictkind := "Main dictionary" + if usingSubdict { + dictkind = "Sub-dictionary" + } if rcvrValue == nil { fmt.Printf("%s in %v for generic function value %v\n", dictkind, outer, inst.X) } else { @@ -308,17 +295,13 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { break } } - target, dictValue = g.getInstantiation(gf, targs, true) - dictkind := "Main dictionary" - if outerInfo != nil { - entry, ok := outerInfo.dictEntryMap[x] - if ok { - dictValue = getDictionaryEntry(x.Pos(), outerInfo.dictParam, entry, outerInfo.dictLen) - dictkind = "Sub-dictionary" - usingSubdict = true - } - } + target = g.getInstantiation(gf, targs, true) + dictValue, usingSubdict = g.getDictOrSubdict(outerInfo, x, gf, targs, true) if infoPrintMode { + dictkind := "Main dictionary" + if usingSubdict { + dictkind = "Sub-dictionary" + } fmt.Printf("%s in %v for method expression %v\n", dictkind, outer, x) } } @@ -497,8 +480,8 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { return ir.InitExpr(init, c) } -// instantiateMethods instantiates all the methods of all fully-instantiated -// generic types that have been added to g.instTypeList. +// instantiateMethods instantiates all the methods (and associated dictionaries) of +// all fully-instantiated generic types that have been added to g.instTypeList. func (g *irgen) instantiateMethods() { for i := 0; i < len(g.instTypeList); i++ { typ := g.instTypeList[i] @@ -521,23 +504,48 @@ func (g *irgen) instantiateMethods() { // Direct method calls go directly to the instantiations, implemented above. // Indirect method calls use wrappers generated in reflectcall. Those wrappers // will use these instantiations if they are needed (for interface tables or reflection). - _, _ = g.getInstantiation(baseNname, typ.RParams(), true) + _ = g.getInstantiation(baseNname, typ.RParams(), true) + _ = g.getDictionarySym(baseNname, typ.RParams(), true) } } g.instTypeList = nil } -// getInstantiationForNode returns the function/method instantiation and -// dictionary value for a InstExpr node inst. -func (g *irgen) getInstantiationForNode(inst *ir.InstExpr) (*ir.Func, ir.Node) { +// getInstNameNode returns the name node for the method or function being instantiated, and a bool which is true if a method is being instantiated. +func (g *irgen) getInstNameNode(inst *ir.InstExpr) (*ir.Name, bool) { if meth, ok := inst.X.(*ir.SelectorExpr); ok { - return g.getInstantiation(meth.Selection.Nname.(*ir.Name), typecheck.TypesOf(inst.Targs), true) + return meth.Selection.Nname.(*ir.Name), true } else { - return g.getInstantiation(inst.X.(*ir.Name), typecheck.TypesOf(inst.Targs), false) + return inst.X.(*ir.Name), false } } +// getDictOrSubdict returns, for a method/function call or reference (node n) in an +// instantiation (described by instInfo), a node which is accessing a sub-dictionary +// or main/static dictionary, as needed, and also returns a boolean indicating if a +// sub-dictionary was accessed. nameNode is the particular function or method being +// called/referenced, and targs are the type arguments. +func (g *irgen) getDictOrSubdict(declInfo *instInfo, n ir.Node, nameNode *ir.Name, targs []*types.Type, isMeth bool) (ir.Node, bool) { + var dict ir.Node + usingSubdict := false + if declInfo != nil { + // Get the dictionary arg via sub-dictionary reference + entry, ok := declInfo.dictEntryMap[n] + // If the entry is not found, it may be that this node did not have + // any type args that depend on type params, so we need a main + // dictionary, not a sub-dictionary. + if ok { + dict = getDictionaryEntry(n.Pos(), declInfo.dictParam, entry, declInfo.dictLen) + usingSubdict = true + } + } + if !usingSubdict { + dict = g.getDictionaryValue(nameNode, targs, isMeth) + } + return dict, usingSubdict +} + func addGcType(fl []*types.Field, t *types.Type) []*types.Field { return append(fl, types.NewField(base.Pos, typecheck.Lookup("F"+strconv.Itoa(len(fl))), t)) } @@ -730,7 +738,7 @@ func gcshapeType(t *types.Type) (*types.Type, string) { // getInstantiation gets the instantiantion and dictionary of the function or method nameNode // with the type arguments targs. If the instantiated function is not already // cached, then it calls genericSubst to create the new instantiation. -func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth bool) (*ir.Func, ir.Node) { +func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth bool) *ir.Func { if nameNode.Func.Body == nil && nameNode.Func.Inl != nil { // If there is no body yet but Func.Inl exists, then we can can // import the whole generic body. @@ -763,7 +771,6 @@ func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth // genericSubst fills in info.dictParam and info.dictEntryMap. st := g.genericSubst(sym, nameNode, targs, isMeth, info) info.fun = st - info.dictAddr = g.getDictionaryValue(nameNode, targs, isMeth) g.instInfoMap[sym] = info // This ensures that the linker drops duplicates of this instantiation. // All just works! @@ -773,7 +780,7 @@ func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth ir.Dump(fmt.Sprintf("\nstenciled %v", st), st) } } - return info.fun, info.dictAddr + return info.fun } // Struct containing info needed for doing the substitution as we create the @@ -1352,13 +1359,13 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) base.Fatalf("%s should have type arguments", gf.Sym().Name) } - info := g.getGfInfo(gf) - // Get a symbol representing the dictionary. sym := typecheck.MakeDictName(gf.Sym(), targs, isMeth) // Initialize the dictionary, if we haven't yet already. if lsym := sym.Linksym(); len(lsym.P) == 0 { + info := g.getGfInfo(gf) + infoPrint("=== Creating dictionary %v\n", sym.Name) off := 0 // Emit an entry for each targ (concrete type or gcshape). From ef39edefe1c59c0d5dbe0c23e95a664a2ad46839 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 2 Jul 2021 16:39:49 -0700 Subject: [PATCH 621/940] [dev.typeparams] src,cmd: bump go.mod to 'go 1.18' Necessary for building/testing generics code within src/ or src/cmd/ since CL 332373, and we'll need to do this eventually anyway. Change-Id: Ia8c658c92d861fd3803fa18bfc80407c3381b411 Reviewed-on: https://go-review.googlesource.com/c/go/+/332554 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky Reviewed-by: Keith Randall TryBot-Result: Go Bot --- src/cmd/go.mod | 2 +- src/go.mod | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/go.mod b/src/cmd/go.mod index cd03968eedc..da304e292b5 100644 --- a/src/cmd/go.mod +++ b/src/cmd/go.mod @@ -1,6 +1,6 @@ module cmd -go 1.17 +go 1.18 require ( github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a diff --git a/src/go.mod b/src/go.mod index 379dcf504e5..1fb8cbfcbe0 100644 --- a/src/go.mod +++ b/src/go.mod @@ -1,6 +1,6 @@ module std -go 1.17 +go 1.18 require ( golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e From 5dac279fbdd8a4273253de98a4e44484b20bec5b Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 2 Jul 2021 16:29:42 -0700 Subject: [PATCH 622/940] [dev.typeparams] cmd/compile: formalize "hidden parameters" idea This CL formalizes the closure-var trick used for method-value wrappers to be reusable for defining other functions that take hidden parameters via the closure-context register. In particular, it: 1. Adds a new ir.NewHiddenParam function for creating hidden parameters. 2. Changes ir.NewClosureVar to copy Type/Typecheck from the closure variable, so that callers can needing to manually copy these. 3. Updates existing code accordingly (i.e., method-value wrappers to start using ir.NewHiddenParam, and closure builders to stop copying types). Longer term, I anticipate using this to pass dictionaries to stenciled functions within unified IR. Change-Id: I9da3ffdb2a26d15c6e89a21b4e080686d6dc872c Reviewed-on: https://go-review.googlesource.com/c/go/+/332612 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/escape/call.go | 4 +--- src/cmd/compile/internal/escape/escape.go | 10 ++++++-- src/cmd/compile/internal/escape/expr.go | 3 --- src/cmd/compile/internal/escape/graph.go | 8 +++++-- src/cmd/compile/internal/ir/name.go | 24 ++++++++++++++++++- src/cmd/compile/internal/noder/reader.go | 15 ++---------- src/cmd/compile/internal/typecheck/iimport.go | 9 ++----- src/cmd/compile/internal/walk/closure.go | 9 +------ 8 files changed, 43 insertions(+), 39 deletions(-) diff --git a/src/cmd/compile/internal/escape/call.go b/src/cmd/compile/internal/escape/call.go index 46bfe65aff1..5bd748027e9 100644 --- a/src/cmd/compile/internal/escape/call.go +++ b/src/cmd/compile/internal/escape/call.go @@ -343,9 +343,7 @@ func (e *escape) wrapExpr(pos src.XPos, exprp *ir.Node, init *ir.Nodes, call ir. e.oldLoc(tmp).captured = true - cv := ir.NewClosureVar(pos, wrapper, tmp) - cv.SetType(tmp.Type()) - tmp = typecheck.Expr(cv).(*ir.Name) + tmp = ir.NewClosureVar(pos, wrapper, tmp) } *exprp = tmp diff --git a/src/cmd/compile/internal/escape/escape.go b/src/cmd/compile/internal/escape/escape.go index 04d0c2356c1..61e0121a40a 100644 --- a/src/cmd/compile/internal/escape/escape.go +++ b/src/cmd/compile/internal/escape/escape.go @@ -183,8 +183,14 @@ func (b *batch) initFunc(fn *ir.Func) { // Allocate locations for local variables. for _, n := range fn.Dcl { - if n.Op() == ir.ONAME { - e.newLoc(n, false) + e.newLoc(n, false) + } + + // Also for hidden parameters (e.g., the ".this" parameter to a + // method value wrapper). + if fn.OClosure == nil { + for _, n := range fn.ClosureVars { + e.newLoc(n.Canonical(), false) } } diff --git a/src/cmd/compile/internal/escape/expr.go b/src/cmd/compile/internal/escape/expr.go index dfcd55734ab..c2a679d4749 100644 --- a/src/cmd/compile/internal/escape/expr.go +++ b/src/cmd/compile/internal/escape/expr.go @@ -46,9 +46,6 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) { if n.Class == ir.PFUNC || n.Class == ir.PEXTERN { return } - if n.IsClosureVar() && n.Defn == nil { - return // ".this" from method value wrapper - } e.flow(k, e.oldLoc(n)) case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT: diff --git a/src/cmd/compile/internal/escape/graph.go b/src/cmd/compile/internal/escape/graph.go index 6316435dfe4..d3ae1da693e 100644 --- a/src/cmd/compile/internal/escape/graph.go +++ b/src/cmd/compile/internal/escape/graph.go @@ -222,7 +222,9 @@ func (e *escape) newLoc(n ir.Node, transient bool) *location { } if n != nil && n.Op() == ir.ONAME { - n = n.(*ir.Name).Canonical() + if canon := n.(*ir.Name).Canonical(); n != canon { + base.Fatalf("newLoc on non-canonical %v (canonical is %v)", n, canon) + } } loc := &location{ n: n, @@ -234,7 +236,9 @@ func (e *escape) newLoc(n ir.Node, transient bool) *location { if n != nil { if n.Op() == ir.ONAME { n := n.(*ir.Name) - if n.Curfn != e.curfn { + if n.Class == ir.PPARAM && n.Curfn == nil { + // ok; hidden parameter + } else if n.Curfn != e.curfn { base.Fatalf("curfn mismatch: %v != %v for %v", n.Curfn, e.curfn, n) } diff --git a/src/cmd/compile/internal/ir/name.go b/src/cmd/compile/internal/ir/name.go index ff9784df1b1..a2eec05013e 100644 --- a/src/cmd/compile/internal/ir/name.go +++ b/src/cmd/compile/internal/ir/name.go @@ -358,7 +358,7 @@ func (n *Name) Byval() bool { return n.Canonical().flags&nameByval != 0 } -// NewClosureVar creates a new closure variable for fn to refer to +// NewClosureVar returns a new closure variable for fn to refer to // outer variable n. func NewClosureVar(pos src.XPos, fn *Func, n *Name) *Name { c := NewNameAt(pos, n.Sym()) @@ -368,11 +368,33 @@ func NewClosureVar(pos src.XPos, fn *Func, n *Name) *Name { c.Defn = n.Canonical() c.Outer = n + c.SetType(n.Type()) + c.SetTypecheck(n.Typecheck()) + fn.ClosureVars = append(fn.ClosureVars, c) return c } +// NewHiddenParam returns a new hidden parameter for fn with the given +// name and type. +func NewHiddenParam(pos src.XPos, fn *Func, sym *types.Sym, typ *types.Type) *Name { + if fn.OClosure != nil { + base.FatalfAt(fn.Pos(), "cannot add hidden parameters to closures") + } + + fn.SetNeedctxt(true) + + // Create a fake parameter, disassociated from any real function, to + // pretend to capture. + fake := NewNameAt(pos, sym) + fake.Class = PPARAM + fake.SetType(typ) + fake.SetByval(true) + + return NewClosureVar(pos, fn, fake) +} + // CaptureName returns a Name suitable for referring to n from within function // fn or from the package block if fn is nil. If n is a free variable declared // within a function that encloses fn, then CaptureName returns the closure diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 275baead04b..14d982a1af0 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -1623,11 +1623,7 @@ func (r *reader) funcLit() ir.Node { fn.ClosureVars = make([]*ir.Name, 0, r.len()) for len(fn.ClosureVars) < cap(fn.ClosureVars) { - pos := r.pos() - outer := r.useLocal() - - cv := ir.NewClosureVar(pos, fn, outer) - r.setType(cv, outer.Type()) + ir.NewClosureVar(r.pos(), fn, r.useLocal()) } r.addBody(fn) @@ -2204,17 +2200,10 @@ func (r *reader) methodValueWrapper(tbase *types.Type, method *types.Field, targ pos := base.AutogeneratedPos fn := r.newWrapperFunc(pos, sym, nil, method) - fn.SetNeedctxt(true) sym.Def = fn // Declare and initialize variable holding receiver. - recv := ir.NewNameAt(pos, typecheck.Lookup(".this")) - recv.Class = ir.PAUTOHEAP - recv.SetType(recvType) - recv.Curfn = fn - recv.SetIsClosureVar(true) - recv.SetByval(true) - fn.ClosureVars = append(fn.ClosureVars, recv) + recv := ir.NewHiddenParam(pos, fn, typecheck.Lookup(".this"), recvType) addTailCall(pos, fn, recv, method) diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 7b61260e798..a45bbfd1f82 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -1289,13 +1289,8 @@ func (r *importReader) node() ir.Node { cvars := make([]*ir.Name, r.int64()) for i := range cvars { cvars[i] = ir.CaptureName(r.pos(), fn, r.localName().Canonical()) - if go117ExportTypes { - if cvars[i].Type() != nil || cvars[i].Defn == nil { - base.Fatalf("bad import of closure variable") - } - // Closure variable should have Defn set, which is its captured - // variable, and it gets the same type as the captured variable. - cvars[i].SetType(cvars[i].Defn.Type()) + if go117ExportTypes && cvars[i].Defn == nil { + base.Fatalf("bad import of closure variable") } } fn.ClosureVars = cvars diff --git a/src/cmd/compile/internal/walk/closure.go b/src/cmd/compile/internal/walk/closure.go index a86ed2ab805..7f6ef473bf2 100644 --- a/src/cmd/compile/internal/walk/closure.go +++ b/src/cmd/compile/internal/walk/closure.go @@ -238,17 +238,10 @@ func methodValueWrapper(dot *ir.SelectorExpr) *ir.Func { fn := typecheck.DeclFunc(sym, tfn) fn.SetDupok(true) - fn.SetNeedctxt(true) fn.SetWrapper(true) // Declare and initialize variable holding receiver. - ptr := ir.NewNameAt(base.Pos, typecheck.Lookup(".this")) - ptr.Class = ir.PAUTOHEAP - ptr.SetType(rcvrtype) - ptr.Curfn = fn - ptr.SetIsClosureVar(true) - ptr.SetByval(true) - fn.ClosureVars = append(fn.ClosureVars, ptr) + ptr := ir.NewHiddenParam(base.Pos, fn, typecheck.Lookup(".this"), rcvrtype) call := ir.NewCallExpr(base.Pos, ir.OCALL, ir.NewSelectorExpr(base.Pos, ir.OXDOT, ptr, meth), nil) call.Args = ir.ParamNames(tfn.Type()) From ad2ba3ff518b9762e3f5497f0a8ce67c0e155aa8 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Sat, 3 Jul 2021 05:50:05 -0700 Subject: [PATCH 623/940] [dev.typeparams] src,cmd: run 'go mod tidy' Run 'go mod tidy' to satisfy the longtest builders. Change-Id: I5b31b63d0f273fca0833e44b826edfd726a1a958 Reviewed-on: https://go-review.googlesource.com/c/go/+/332669 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- src/cmd/go.sum | 23 ----------------------- src/go.sum | 7 ------- 2 files changed, 30 deletions(-) diff --git a/src/cmd/go.sum b/src/cmd/go.sum index d728acaec99..7f0d978ef0b 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -5,41 +5,18 @@ github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a h1:jmAp/2PZAScNd62lTD github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 h1:mV02weKRL81bEnm8A0HT1/CAelMQDBuQIfLw8n+d6xI= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e h1:pv3V0NlNSh5Q6AX/StwGLBjcLS7UN4m4Gq+V+uSecqM= golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI= golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a h1:e8qnjKz4EE6OjRki9wTadWSIogINvq10sMcuBRORxMY= golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 h1:yhBbb4IRs2HS9PPlAg6DMC6mUOKexJBNsLf4Z+6En1Q= golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.2-0.20210519160823-49064d2332f9 h1:2XlR/j4I4xz5GQZI7zBjqTfezYyRIE2jD5IMousB2rg= golang.org/x/tools v0.1.2-0.20210519160823-49064d2332f9/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/src/go.sum b/src/go.sum index 6e869b96f71..b3de6c526c9 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,15 +1,8 @@ golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI= golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I= golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 h1:yhBbb4IRs2HS9PPlAg6DMC6mUOKexJBNsLf4Z+6En1Q= golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f h1:yQJrRE0hDxDFmZLlRaw+3vusO4fwNHgHIjUOMO7bHYI= golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From c45d0eaadb77f11061cf9b18f521eb0b27e6bedb Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Sat, 3 Jul 2021 04:53:25 -0700 Subject: [PATCH 624/940] [dev.typeparams] cmd/compile: flatten OINLCALL in walk Inlining replaces inlined calls with OINLCALL nodes, and then somewhat clumsily tries to rewrite these in place without messing up order-of-evaluation rules. But handling these rules cleanly is much easier to do during order, and escape analysis is the only major pass between inlining and order. It's simpler to teach escape analysis how to analyze OINLCALL nodes than to try to hide them from escape analysis. Does not pass toolstash -cmp, but seems to just be line number changes. Change-Id: I1986cea39793e3e1ed5e887ba29d46364c6c532e Reviewed-on: https://go-review.googlesource.com/c/go/+/332649 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le Trust: Matthew Dempsky --- src/cmd/compile/internal/escape/call.go | 11 ++ src/cmd/compile/internal/escape/expr.go | 2 +- src/cmd/compile/internal/escape/stmt.go | 2 +- src/cmd/compile/internal/inline/inl.go | 110 +++++------------- src/cmd/compile/internal/ir/expr.go | 14 ++- src/cmd/compile/internal/ir/fmt.go | 9 ++ .../compile/internal/logopt/logopt_test.go | 2 +- src/cmd/compile/internal/noder/reader.go | 18 +-- src/cmd/compile/internal/typecheck/dcl.go | 1 + src/cmd/compile/internal/walk/order.go | 33 +++++- 10 files changed, 102 insertions(+), 100 deletions(-) diff --git a/src/cmd/compile/internal/escape/call.go b/src/cmd/compile/internal/escape/call.go index 5bd748027e9..6fcfb1b3b4a 100644 --- a/src/cmd/compile/internal/escape/call.go +++ b/src/cmd/compile/internal/escape/call.go @@ -110,6 +110,17 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir argumentFunc(fn, e.tagHole(ks, fn, param), &args[i]) } + case ir.OINLCALL: + call := call.(*ir.InlinedCallExpr) + e.stmts(call.Body) + for i, result := range call.ReturnVars { + k := e.discardHole() + if ks != nil { + k = ks[i] + } + e.expr(k, result) + } + case ir.OAPPEND: call := call.(*ir.CallExpr) args := call.Args diff --git a/src/cmd/compile/internal/escape/expr.go b/src/cmd/compile/internal/escape/expr.go index c2a679d4749..60b44fe0aa6 100644 --- a/src/cmd/compile/internal/escape/expr.go +++ b/src/cmd/compile/internal/escape/expr.go @@ -130,7 +130,7 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) { n := n.(*ir.UnaryExpr) e.discard(n.X) - case ir.OCALLMETH, ir.OCALLFUNC, ir.OCALLINTER, ir.OLEN, ir.OCAP, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCOPY, ir.ORECOVER, ir.OUNSAFEADD, ir.OUNSAFESLICE: + case ir.OCALLMETH, ir.OCALLFUNC, ir.OCALLINTER, ir.OINLCALL, ir.OLEN, ir.OCAP, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCOPY, ir.ORECOVER, ir.OUNSAFEADD, ir.OUNSAFESLICE: e.call([]hole{k}, n) case ir.ONEW: diff --git a/src/cmd/compile/internal/escape/stmt.go b/src/cmd/compile/internal/escape/stmt.go index 0bdb07b2784..c71848b8a1c 100644 --- a/src/cmd/compile/internal/escape/stmt.go +++ b/src/cmd/compile/internal/escape/stmt.go @@ -173,7 +173,7 @@ func (e *escape) stmt(n ir.Node) { dsts[i] = res.Nname.(*ir.Name) } e.assignList(dsts, n.Results, "return", n) - case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OCLOSE, ir.OCOPY, ir.ODELETE, ir.OPANIC, ir.OPRINT, ir.OPRINTN, ir.ORECOVER: + case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OINLCALL, ir.OCLOSE, ir.OCOPY, ir.ODELETE, ir.OPANIC, ir.OPRINT, ir.OPRINTN, ir.ORECOVER: e.call(nil, n) case ir.OGO, ir.ODEFER: n := n.(*ir.GoDeferStmt) diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go index a6961e4e4d1..f1e927d6432 100644 --- a/src/cmd/compile/internal/inline/inl.go +++ b/src/cmd/compile/internal/inline/inl.go @@ -515,37 +515,6 @@ func InlineCalls(fn *ir.Func) { ir.CurFunc = savefn } -// Turn an OINLCALL into a statement. -func inlconv2stmt(inlcall *ir.InlinedCallExpr) ir.Node { - n := ir.NewBlockStmt(inlcall.Pos(), nil) - n.List = inlcall.Init() - n.List.Append(inlcall.Body.Take()...) - return n -} - -// Turn an OINLCALL into a single valued expression. -// The result of inlconv2expr MUST be assigned back to n, e.g. -// n.Left = inlconv2expr(n.Left) -func inlconv2expr(n *ir.InlinedCallExpr) ir.Node { - r := n.ReturnVars[0] - return ir.InitExpr(append(n.Init(), n.Body...), r) -} - -// Turn the rlist (with the return values) of the OINLCALL in -// n into an expression list lumping the ninit and body -// containing the inlined statements on the first list element so -// order will be preserved. Used in return, oas2func and call -// statements. -func inlconv2list(n *ir.InlinedCallExpr) []ir.Node { - if n.Op() != ir.OINLCALL || len(n.ReturnVars) == 0 { - base.Fatalf("inlconv2list %+v\n", n) - } - - s := n.ReturnVars - s[0] = ir.InitExpr(append(n.Init(), n.Body...), s[0]) - return s -} - // inlnode recurses over the tree to find inlineable calls, which will // be turned into OINLCALLs by mkinlcall. When the recursion comes // back up will examine left, right, list, rlist, ninit, ntest, nincr, @@ -599,33 +568,18 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.No ir.EditChildren(n, edit) - if as := n; as.Op() == ir.OAS2FUNC { - as := as.(*ir.AssignListStmt) - if as.Rhs[0].Op() == ir.OINLCALL { - as.Rhs = inlconv2list(as.Rhs[0].(*ir.InlinedCallExpr)) - as.SetOp(ir.OAS2) - as.SetTypecheck(0) - n = typecheck.Stmt(as) - } - } - // with all the branches out of the way, it is now time to // transmogrify this node itself unless inhibited by the // switch at the top of this function. switch n.Op() { case ir.OCALLMETH: base.FatalfAt(n.Pos(), "OCALLMETH missed by typecheck") - case ir.OCALLFUNC: - n := n.(*ir.CallExpr) - if n.NoInline { - return n - } - } - var call *ir.CallExpr - switch n.Op() { case ir.OCALLFUNC: - call = n.(*ir.CallExpr) + call := n.(*ir.CallExpr) + if call.NoInline { + break + } if base.Flag.LowerM > 3 { fmt.Printf("%v:call to func %+v\n", ir.Line(n), call.X) } @@ -635,27 +589,10 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.No if fn := inlCallee(call.X); fn != nil && fn.Inl != nil { n = mkinlcall(call, fn, maxCost, inlMap, edit) } - case ir.OCALLMETH: - base.FatalfAt(n.Pos(), "OCALLMETH missed by typecheck") } base.Pos = lno - if n.Op() == ir.OINLCALL { - ic := n.(*ir.InlinedCallExpr) - switch call.Use { - default: - ir.Dump("call", call) - base.Fatalf("call missing use") - case ir.CallUseExpr: - n = inlconv2expr(ic) - case ir.CallUseStmt: - n = inlconv2stmt(ic) - case ir.CallUseList: - // leave for caller to convert - } - } - return n } @@ -811,6 +748,30 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b return res } +// CalleeEffects appends any side effects from evaluating callee to init. +func CalleeEffects(init *ir.Nodes, callee ir.Node) { + for { + switch callee.Op() { + case ir.ONAME, ir.OCLOSURE, ir.OMETHEXPR: + return // done + + case ir.OCONVNOP: + conv := callee.(*ir.ConvExpr) + init.Append(ir.TakeInit(conv)...) + callee = conv.X + + case ir.OINLCALL: + ic := callee.(*ir.InlinedCallExpr) + init.Append(ir.TakeInit(ic)...) + init.Append(ic.Body.Take()...) + callee = ic.SingleResult() + + default: + base.FatalfAt(callee.Pos(), "unexpected callee expression: %v", callee) + } + } +} + // oldInline creates an InlinedCallExpr to replace the given call // expression. fn is the callee function to be inlined. inlIndex is // the inlining tree position index, for use with src.NewInliningBase @@ -825,19 +786,10 @@ func oldInline(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExpr ninit := call.Init() // For normal function calls, the function callee expression - // may contain side effects (e.g., added by addinit during - // inlconv2expr or inlconv2list). Make sure to preserve these, + // may contain side effects. Make sure to preserve these, // if necessary (#42703). if call.Op() == ir.OCALLFUNC { - callee := call.X - for callee.Op() == ir.OCONVNOP { - conv := callee.(*ir.ConvExpr) - ninit.Append(ir.TakeInit(conv)...) - callee = conv.X - } - if callee.Op() != ir.ONAME && callee.Op() != ir.OCLOSURE && callee.Op() != ir.OMETHEXPR { - base.Fatalf("unexpected callee expression: %v", callee) - } + CalleeEffects(&ninit, call.X) } // Make temp names to use instead of the originals. @@ -979,6 +931,7 @@ func inlvar(var_ *ir.Name) *ir.Name { n := typecheck.NewName(var_.Sym()) n.SetType(var_.Type()) + n.SetTypecheck(1) n.Class = ir.PAUTO n.SetUsed(true) n.SetAutoTemp(var_.AutoTemp()) @@ -993,6 +946,7 @@ func inlvar(var_ *ir.Name) *ir.Name { func retvar(t *types.Field, i int) *ir.Name { n := typecheck.NewName(typecheck.LookupNum("~R", i)) n.SetType(t.Type) + n.SetTypecheck(1) n.Class = ir.PAUTO n.SetUsed(true) n.Curfn = ir.CurFunc // the calling function, not the called one diff --git a/src/cmd/compile/internal/ir/expr.go b/src/cmd/compile/internal/ir/expr.go index 919cb3362fe..4ff75e616d9 100644 --- a/src/cmd/compile/internal/ir/expr.go +++ b/src/cmd/compile/internal/ir/expr.go @@ -345,7 +345,7 @@ func (n *StructKeyExpr) Sym() *types.Sym { return n.Field.Sym } type InlinedCallExpr struct { miniExpr Body Nodes - ReturnVars Nodes + ReturnVars Nodes // must be side-effect free } func NewInlinedCallExpr(pos src.XPos, body, retvars []Node) *InlinedCallExpr { @@ -357,6 +357,13 @@ func NewInlinedCallExpr(pos src.XPos, body, retvars []Node) *InlinedCallExpr { return n } +func (n *InlinedCallExpr) SingleResult() Node { + if have := len(n.ReturnVars); have != 1 { + base.FatalfAt(n.Pos(), "inlined call has %v results, expected 1", have) + } + return n.ReturnVars[0] +} + // A LogicalExpr is a expression X Op Y where Op is && or ||. // It is separate from BinaryExpr to make room for statements // that must be executed before Y but after X. @@ -800,6 +807,11 @@ func StaticValue(n Node) Node { continue } + if n.Op() == OINLCALL { + n = n.(*InlinedCallExpr).SingleResult() + continue + } + n1 := staticValue1(n) if n1 == nil { return n diff --git a/src/cmd/compile/internal/ir/fmt.go b/src/cmd/compile/internal/ir/fmt.go index ae62d5f51b9..6f6e26dec42 100644 --- a/src/cmd/compile/internal/ir/fmt.go +++ b/src/cmd/compile/internal/ir/fmt.go @@ -859,6 +859,15 @@ func exprFmt(n Node, s fmt.State, prec int) { } fmt.Fprintf(s, "(%.v)", n.Args) + case OINLCALL: + n := n.(*InlinedCallExpr) + // TODO(mdempsky): Print Init and/or Body? + if len(n.ReturnVars) == 1 { + fmt.Fprintf(s, "%v", n.ReturnVars[0]) + return + } + fmt.Fprintf(s, "(.%v)", n.ReturnVars) + case OMAKEMAP, OMAKECHAN, OMAKESLICE: n := n.(*MakeExpr) if n.Cap != nil { diff --git a/src/cmd/compile/internal/logopt/logopt_test.go b/src/cmd/compile/internal/logopt/logopt_test.go index 41a11b0c701..902cbc8091f 100644 --- a/src/cmd/compile/internal/logopt/logopt_test.go +++ b/src/cmd/compile/internal/logopt/logopt_test.go @@ -221,7 +221,7 @@ func s15a8(x *[15]int64) [15]int64 { `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":9},"end":{"line":4,"character":9}}},"message":"inlineLoc"},`+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from ~R0 = \u0026y.b (assign-pair)"},`+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: flow: ~r0 = ~R0:"},`+ - `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: from return (*int)(~R0) (return)"}]}`) + `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: from return ~R0 (return)"}]}`) }) } diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 14d982a1af0..d938dca5d4a 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -15,6 +15,7 @@ import ( "cmd/compile/internal/base" "cmd/compile/internal/deadcode" "cmd/compile/internal/dwarfgen" + "cmd/compile/internal/inline" "cmd/compile/internal/ir" "cmd/compile/internal/reflectdata" "cmd/compile/internal/typecheck" @@ -1848,23 +1849,10 @@ func InlineCall(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExp init := ir.TakeInit(call) // For normal function calls, the function callee expression - // may contain side effects (e.g., added by addinit during - // inlconv2expr or inlconv2list). Make sure to preserve these, + // may contain side effects. Make sure to preserve these, // if necessary (#42703). if call.Op() == ir.OCALLFUNC { - callee := call.X - for callee.Op() == ir.OCONVNOP { - conv := callee.(*ir.ConvExpr) - init.Append(ir.TakeInit(conv)...) - callee = conv.X - } - - switch callee.Op() { - case ir.ONAME, ir.OCLOSURE, ir.OMETHEXPR: - // ok - default: - base.Fatalf("unexpected callee expression: %v", callee) - } + inline.CalleeEffects(&init, call.X) } var args ir.Nodes diff --git a/src/cmd/compile/internal/typecheck/dcl.go b/src/cmd/compile/internal/typecheck/dcl.go index 66d755089a0..90d3020fe0c 100644 --- a/src/cmd/compile/internal/typecheck/dcl.go +++ b/src/cmd/compile/internal/typecheck/dcl.go @@ -418,6 +418,7 @@ func TempAt(pos src.XPos, curfn *ir.Func, t *types.Type) *ir.Name { n := ir.NewNameAt(pos, s) s.Def = n n.SetType(t) + n.SetTypecheck(1) n.Class = ir.PAUTO n.SetEsc(ir.EscNever) n.Curfn = curfn diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go index 007af03d4bb..eec340261ef 100644 --- a/src/cmd/compile/internal/walk/order.go +++ b/src/cmd/compile/internal/walk/order.go @@ -655,9 +655,20 @@ func (o *orderState) stmt(n ir.Node) { n := n.(*ir.AssignListStmt) t := o.markTemp() o.exprList(n.Lhs) - o.init(n.Rhs[0]) - o.call(n.Rhs[0]) - o.as2func(n) + call := n.Rhs[0] + o.init(call) + if ic, ok := call.(*ir.InlinedCallExpr); ok { + o.stmtList(ic.Body) + + n.SetOp(ir.OAS2) + n.Rhs = ic.ReturnVars + + o.exprList(n.Rhs) + o.out = append(o.out, n) + } else { + o.call(call) + o.as2func(n) + } o.cleanTemp(t) // Special: use temporary variables to hold result, @@ -717,6 +728,17 @@ func (o *orderState) stmt(n ir.Node) { o.out = append(o.out, n) o.cleanTemp(t) + case ir.OINLCALL: + n := n.(*ir.InlinedCallExpr) + o.stmtList(n.Body) + + // discard results; double-check for no side effects + for _, result := range n.ReturnVars { + if staticinit.AnySideEffects(result) { + base.FatalfAt(result.Pos(), "inlined call result has side effects: %v", result) + } + } + case ir.OCHECKNIL, ir.OCLOSE, ir.OPANIC, ir.ORECV: n := n.(*ir.UnaryExpr) t := o.markTemp() @@ -1241,6 +1263,11 @@ func (o *orderState) expr1(n, lhs ir.Node) ir.Node { } return n + case ir.OINLCALL: + n := n.(*ir.InlinedCallExpr) + o.stmtList(n.Body) + return n.SingleResult() + case ir.OAPPEND: // Check for append(x, make([]T, y)...) . n := n.(*ir.CallExpr) From ea5369bac041e7a78e198f4412350cfd923215aa Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Sat, 3 Jul 2021 05:27:54 -0700 Subject: [PATCH 625/940] [dev.typeparams] cmd/compile: remove ir.CallUse Unneeded after the previous CL changed inlining to leave OINLCALL nodes in place. Change-Id: I9af09a86a21caa51a1117b3de17d7312dd702600 Reviewed-on: https://go-review.googlesource.com/c/go/+/332650 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le Trust: Matthew Dempsky --- src/cmd/compile/internal/ir/expr.go | 12 ------------ src/cmd/compile/internal/noder/helpers.go | 3 --- src/cmd/compile/internal/noder/stmt.go | 6 +----- src/cmd/compile/internal/noder/transform.go | 1 - src/cmd/compile/internal/typecheck/func.go | 4 ---- src/cmd/compile/internal/typecheck/iexport.go | 1 - src/cmd/compile/internal/typecheck/iimport.go | 1 - src/cmd/compile/internal/typecheck/stmt.go | 1 - 8 files changed, 1 insertion(+), 28 deletions(-) diff --git a/src/cmd/compile/internal/ir/expr.go b/src/cmd/compile/internal/ir/expr.go index 4ff75e616d9..9c800dcd1a7 100644 --- a/src/cmd/compile/internal/ir/expr.go +++ b/src/cmd/compile/internal/ir/expr.go @@ -142,17 +142,6 @@ func (n *BinaryExpr) SetOp(op Op) { } } -// A CallUse records how the result of the call is used: -type CallUse byte - -const ( - _ CallUse = iota - - CallUseExpr // single expression result is used - CallUseList // list of results are used - CallUseStmt // results not used - call is a statement -) - // A CallExpr is a function call X(Args). type CallExpr struct { miniExpr @@ -161,7 +150,6 @@ type CallExpr struct { Args Nodes KeepAlive []*Name // vars to be kept alive until call returns IsDDD bool - Use CallUse NoInline bool } diff --git a/src/cmd/compile/internal/noder/helpers.go b/src/cmd/compile/internal/noder/helpers.go index 6ab318318bb..08affe44119 100644 --- a/src/cmd/compile/internal/noder/helpers.go +++ b/src/cmd/compile/internal/noder/helpers.go @@ -113,9 +113,6 @@ func Binary(pos src.XPos, op ir.Op, typ *types.Type, x, y ir.Node) ir.Node { func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool) ir.Node { n := ir.NewCallExpr(pos, ir.OCALL, fun, args) n.IsDDD = dots - // n.Use will be changed to ir.CallUseStmt in g.stmt() if this call is - // just a statement (any return values are ignored). - n.Use = ir.CallUseExpr if fun.Op() == ir.OTYPE { // Actually a type conversion, not a function call. diff --git a/src/cmd/compile/internal/noder/stmt.go b/src/cmd/compile/internal/noder/stmt.go index 32a1483b4aa..672a732187e 100644 --- a/src/cmd/compile/internal/noder/stmt.go +++ b/src/cmd/compile/internal/noder/stmt.go @@ -35,11 +35,7 @@ func (g *irgen) stmt(stmt syntax.Stmt) ir.Node { case *syntax.BlockStmt: return ir.NewBlockStmt(g.pos(stmt), g.blockStmt(stmt)) case *syntax.ExprStmt: - x := g.expr(stmt.X) - if call, ok := x.(*ir.CallExpr); ok { - call.Use = ir.CallUseStmt - } - return x + return g.expr(stmt.X) case *syntax.SendStmt: n := ir.NewSendStmt(g.pos(stmt), g.expr(stmt.Chan), g.expr(stmt.Value)) if n.Chan.Type().HasTParam() || n.Value.Type().HasTParam() { diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go index 7a685c4b470..e02b7e758db 100644 --- a/src/cmd/compile/internal/noder/transform.go +++ b/src/cmd/compile/internal/noder/transform.go @@ -326,7 +326,6 @@ assignOK: stmt := stmt.(*ir.AssignListStmt) stmt.SetOp(ir.OAS2FUNC) r := rhs[0].(*ir.CallExpr) - r.Use = ir.CallUseList rtyp := r.Type() mismatched := false diff --git a/src/cmd/compile/internal/typecheck/func.go b/src/cmd/compile/internal/typecheck/func.go index d0aad5ac078..68f0c20e526 100644 --- a/src/cmd/compile/internal/typecheck/func.go +++ b/src/cmd/compile/internal/typecheck/func.go @@ -317,10 +317,6 @@ func tcFunc(n *ir.Func) { // tcCall typechecks an OCALL node. func tcCall(n *ir.CallExpr, top int) ir.Node { - n.Use = ir.CallUseExpr - if top == ctxStmt { - n.Use = ir.CallUseStmt - } Stmts(n.Init()) // imported rewritten f(g()) calls (#30907) n.X = typecheck(n.X, ctxExpr|ctxType|ctxCallee) if n.X.Diag() { diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index b17af815ec8..82bbda5228f 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -1922,7 +1922,6 @@ func (w *exportWriter) expr(n ir.Node) { w.bool(n.IsDDD) if go117ExportTypes { w.exoticType(n.Type()) - w.uint64(uint64(n.Use)) } case ir.OMAKEMAP, ir.OMAKECHAN, ir.OMAKESLICE: diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index a45bbfd1f82..17e60effd68 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -1465,7 +1465,6 @@ func (r *importReader) node() ir.Node { n.IsDDD = r.bool() if go117ExportTypes { n.SetType(r.exoticType()) - n.Use = ir.CallUse(r.uint64()) } return n diff --git a/src/cmd/compile/internal/typecheck/stmt.go b/src/cmd/compile/internal/typecheck/stmt.go index f1275f29c07..01434118222 100644 --- a/src/cmd/compile/internal/typecheck/stmt.go +++ b/src/cmd/compile/internal/typecheck/stmt.go @@ -201,7 +201,6 @@ assignOK: stmt := stmt.(*ir.AssignListStmt) stmt.SetOp(ir.OAS2FUNC) r := rhs[0].(*ir.CallExpr) - r.Use = ir.CallUseList rtyp := r.Type() mismatched := false From 899b158ee9e99642bdbea2008d7cc70382db6545 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Sat, 3 Jul 2021 11:22:26 -0700 Subject: [PATCH 626/940] [dev.typeparams] cmd/compile: set Func.ClosureCalled in escape analysis The Func.ClosureCalled flag is an optimization used by escape analysis to detect closures that were directly called, so we know we have visibility of the result flows. It's not needed by any other phases of the compiler, so we might as well calculate it within escape analysis too. This saves some trouble during IR construction and trying to maintain the ClosureCalled flag through inlining and copying. Passes toolstash -cmp. Change-Id: Ic53cecb7ac439745c0dfba2cd202b9cc40f1e47c Reviewed-on: https://go-review.googlesource.com/c/go/+/332691 Run-TryBot: Matthew Dempsky Trust: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/escape/call.go | 7 +++++++ src/cmd/compile/internal/inline/inl.go | 9 +-------- src/cmd/compile/internal/ir/func.go | 2 +- src/cmd/compile/internal/noder/helpers.go | 2 -- src/cmd/compile/internal/noder/reader.go | 3 --- src/cmd/compile/internal/noder/stencil.go | 2 -- src/cmd/compile/internal/typecheck/func.go | 2 -- 7 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/cmd/compile/internal/escape/call.go b/src/cmd/compile/internal/escape/call.go index 6fcfb1b3b4a..9e5abed5914 100644 --- a/src/cmd/compile/internal/escape/call.go +++ b/src/cmd/compile/internal/escape/call.go @@ -57,6 +57,13 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir var fn *ir.Name switch call.Op() { case ir.OCALLFUNC: + // If we have a direct call to a closure (not just one we were + // able to statically resolve with ir.StaticValue), mark it as + // such so batch.outlives can optimize the flow results. + if call.X.Op() == ir.OCLOSURE { + call.X.(*ir.ClosureExpr).Func.SetClosureCalled(true) + } + switch v := ir.StaticValue(call.X); v.Op() { case ir.ONAME: if v := v.(*ir.Name); v.Class == ir.PFUNC { diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go index f1e927d6432..45a533fcafc 100644 --- a/src/cmd/compile/internal/inline/inl.go +++ b/src/cmd/compile/internal/inline/inl.go @@ -470,9 +470,6 @@ func inlcopy(n ir.Node) ir.Node { // x.Func.Body for iexport and local inlining. oldfn := x.Func newfn := ir.NewFunc(oldfn.Pos()) - if oldfn.ClosureCalled() { - newfn.SetClosureCalled(true) - } m.(*ir.ClosureExpr).Func = newfn newfn.Nname = ir.NewNameAt(oldfn.Nname.Pos(), oldfn.Nname.Sym()) // XXX OK to share fn.Type() ?? @@ -1154,11 +1151,7 @@ func (subst *inlsubst) closure(n *ir.ClosureExpr) ir.Node { // the closure is inlined in a specific function. newclo := newfn.OClosure newclo.SetInit(subst.list(n.Init())) - if oldfn.ClosureCalled() { - return typecheck.Callee(newclo) - } else { - return typecheck.Expr(newclo) - } + return typecheck.Expr(newclo) } // node recursively copies a node from the saved pristine body of the diff --git a/src/cmd/compile/internal/ir/func.go b/src/cmd/compile/internal/ir/func.go index 3b9e36d4c59..269b6f14ec1 100644 --- a/src/cmd/compile/internal/ir/func.go +++ b/src/cmd/compile/internal/ir/func.go @@ -202,7 +202,7 @@ const ( funcExportInline // include inline body in export data funcInstrumentBody // add race/msan instrumentation during SSA construction funcOpenCodedDeferDisallowed // can't do open-coded defers - funcClosureCalled // closure is only immediately called + funcClosureCalled // closure is only immediately called; used by escape analysis ) type SymAndPos struct { diff --git a/src/cmd/compile/internal/noder/helpers.go b/src/cmd/compile/internal/noder/helpers.go index 08affe44119..b0fb913ee84 100644 --- a/src/cmd/compile/internal/noder/helpers.go +++ b/src/cmd/compile/internal/noder/helpers.go @@ -160,8 +160,6 @@ func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool) // Add information, now that we know that fun is actually being called. switch fun := fun.(type) { - case *ir.ClosureExpr: - fun.Func.SetClosureCalled(true) case *ir.SelectorExpr: if fun.Op() == ir.OMETHVALUE { op := ir.ODOTMETH diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index d938dca5d4a..05cfc614a27 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -1523,9 +1523,6 @@ func (r *reader) expr() ir.Node { case exprCall: fun := r.expr() - if clo, ok := fun.(*ir.ClosureExpr); ok { - clo.Func.SetClosureCalled(true) - } pos := r.pos() args := r.exprs() dots := r.bool() diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index d35e036ae6d..dbaebf76238 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -1193,8 +1193,6 @@ func (subst *subster) node(n ir.Node) ir.Node { newfn := ir.NewClosureFunc(oldfn.Pos(), subst.newf != nil) ir.NameClosure(newfn.OClosure, subst.newf) - newfn.SetClosureCalled(oldfn.ClosureCalled()) - saveNewf := subst.newf ir.CurFunc = newfn subst.newf = newfn diff --git a/src/cmd/compile/internal/typecheck/func.go b/src/cmd/compile/internal/typecheck/func.go index 68f0c20e526..847e9b9aead 100644 --- a/src/cmd/compile/internal/typecheck/func.go +++ b/src/cmd/compile/internal/typecheck/func.go @@ -242,8 +242,6 @@ func tcClosure(clo *ir.ClosureExpr, top int) ir.Node { fn.Iota = x } - fn.SetClosureCalled(top&ctxCallee != 0) - ir.NameClosure(clo, ir.CurFunc) Func(fn) From cd00499c6125692d704ac8a04b07825ee1648207 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Sat, 3 Jul 2021 11:55:31 -0700 Subject: [PATCH 627/940] [dev.typeparams] cmd/compile: better Call constructor Historically, it's been tedious to create and typecheck ir.OCALL nodes, except by handing them off entirely to typecheck. This is because typecheck needed context on whether the call is an expression or statement, and to set flags like Func.ClosureCalled and CallExpr.Use. However, those flags have now been removed entirely by recent CLs, so we can instead just provide a better typecheck.Call function for constructing and typechecking arbitrary call nodes. Notably, this simplifies things for unified IR, which can now incrementally typecheck call expressions as it goes without worrying about context. Change-Id: Icbdc55c3bd8be84a242323bc45006f9dec09fdcd Reviewed-on: https://go-review.googlesource.com/c/go/+/332692 Run-TryBot: Matthew Dempsky Trust: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/noder/reader.go | 8 +++----- src/cmd/compile/internal/reflectdata/alg.go | 6 ++---- src/cmd/compile/internal/typecheck/typecheck.go | 17 +++++------------ src/cmd/compile/internal/walk/walk.go | 3 +-- 4 files changed, 11 insertions(+), 23 deletions(-) diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 05cfc614a27..122bc70f24b 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -1526,9 +1526,7 @@ func (r *reader) expr() ir.Node { pos := r.pos() args := r.exprs() dots := r.bool() - n := ir.NewCallExpr(pos, ir.OCALL, fun, args) - n.IsDDD = dots - return n + return typecheck.Call(pos, fun, args, dots) case exprTypeSwitchGuard: pos := r.pos() @@ -2281,8 +2279,8 @@ func addTailCall(pos src.XPos, fn *ir.Func, recv ir.Node, method *types.Field) { fn.SetWrapper(true) // TODO(mdempsky): Leave unset for tail calls? - call := ir.NewCallExpr(pos, ir.OCALL, ir.NewSelectorExpr(pos, ir.OXDOT, recv, method.Sym), args) - call.IsDDD = method.Type.IsVariadic() + dot := ir.NewSelectorExpr(pos, ir.OXDOT, recv, method.Sym) + call := typecheck.Call(pos, dot, args, method.Type.IsVariadic()).(*ir.CallExpr) if method.Type.NumResults() == 0 { fn.Body.Append(call) diff --git a/src/cmd/compile/internal/reflectdata/alg.go b/src/cmd/compile/internal/reflectdata/alg.go index 0707e0b61ca..36ad389647f 100644 --- a/src/cmd/compile/internal/reflectdata/alg.go +++ b/src/cmd/compile/internal/reflectdata/alg.go @@ -679,8 +679,7 @@ func EqString(s, t ir.Node) (eqlen *ir.BinaryExpr, eqmem *ir.CallExpr) { fn := typecheck.LookupRuntime("memequal") fn = typecheck.SubstArgTypes(fn, types.Types[types.TUINT8], types.Types[types.TUINT8]) - call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, []ir.Node{sptr, tptr, ir.Copy(slen)}) - typecheck.Call(call) + call := typecheck.Call(base.Pos, fn, []ir.Node{sptr, tptr, ir.Copy(slen)}, false).(*ir.CallExpr) cmp := ir.NewBinaryExpr(base.Pos, ir.OEQ, slen, tlen) cmp = typecheck.Expr(cmp).(*ir.BinaryExpr) @@ -716,8 +715,7 @@ func EqInterface(s, t ir.Node) (eqtab *ir.BinaryExpr, eqdata *ir.CallExpr) { sdata.SetTypecheck(1) tdata.SetTypecheck(1) - call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, []ir.Node{stab, sdata, tdata}) - typecheck.Call(call) + call := typecheck.Call(base.Pos, fn, []ir.Node{stab, sdata, tdata}, false).(*ir.CallExpr) cmp := ir.NewBinaryExpr(base.Pos, ir.OEQ, stab, ttab) cmp = typecheck.Expr(cmp).(*ir.BinaryExpr) diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go index 21d3100f661..8f3d6cf4bb5 100644 --- a/src/cmd/compile/internal/typecheck/typecheck.go +++ b/src/cmd/compile/internal/typecheck/typecheck.go @@ -13,6 +13,7 @@ import ( "cmd/compile/internal/base" "cmd/compile/internal/ir" "cmd/compile/internal/types" + "cmd/internal/src" ) // Function collecting autotmps generated during typechecking, @@ -34,18 +35,10 @@ func Stmt(n ir.Node) ir.Node { return typecheck(n, ctxStmt) } func Exprs(exprs []ir.Node) { typecheckslice(exprs, ctxExpr) } func Stmts(stmts []ir.Node) { typecheckslice(stmts, ctxStmt) } -func Call(call *ir.CallExpr) { - t := call.X.Type() - if t == nil { - panic("misuse of Call") - } - ctx := ctxStmt - if t.NumResults() > 0 { - ctx = ctxExpr | ctxMultiOK - } - if typecheck(call, ctx) != call { - panic("bad typecheck") - } +func Call(pos src.XPos, callee ir.Node, args []ir.Node, dots bool) ir.Node { + call := ir.NewCallExpr(pos, ir.OCALL, callee, args) + call.IsDDD = dots + return typecheck(call, ctxStmt|ctxExpr) } func Callee(n ir.Node) ir.Node { diff --git a/src/cmd/compile/internal/walk/walk.go b/src/cmd/compile/internal/walk/walk.go index f687127fee3..6551fe7a645 100644 --- a/src/cmd/compile/internal/walk/walk.go +++ b/src/cmd/compile/internal/walk/walk.go @@ -113,8 +113,7 @@ func vmkcall(fn ir.Node, t *types.Type, init *ir.Nodes, va []ir.Node) *ir.CallEx base.Fatalf("vmkcall %v needs %v args got %v", fn, n, len(va)) } - call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, va) - typecheck.Call(call) + call := typecheck.Call(base.Pos, fn, va, false).(*ir.CallExpr) call.SetType(t) return walkExpr(call, init).(*ir.CallExpr) } From 49ade6b298c269e6d405d43a2e42dec218e97660 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 2 Jul 2021 13:18:03 -0700 Subject: [PATCH 628/940] [dev.typeparams] test: add expected failure mechanism This CL changes the existing excluded-test mechanism into a known-failure mechanism instead. That is, it runs the test regardless, but only reports if it failed (or succeeded) unexpectedly. It also splits the known failures list into fine-grain failure lists for types2, types2 w/ 32-bit target, -G=3, and unified. Updates #46704. Change-Id: I1213cbccf1bab6a92d9bfcf0d971a2554249bbff Reviewed-on: https://go-review.googlesource.com/c/go/+/332551 Trust: Matthew Dempsky Trust: Dan Scales Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Dan Scales Reviewed-by: Robert Griesemer --- test/run.go | 274 +++++++++++++++++++++++---------------- test/typeparam/nested.go | 2 +- 2 files changed, 164 insertions(+), 112 deletions(-) diff --git a/test/run.go b/test/run.go index d04f7d20ed8..ff8bf4b229e 100644 --- a/test/run.go +++ b/test/run.go @@ -42,7 +42,7 @@ var ( linkshared = flag.Bool("linkshared", false, "") updateErrors = flag.Bool("update_errors", false, "update error messages in test file based on compiler output") runoutputLimit = flag.Int("l", defaultRunOutputLimit(), "number of parallel runoutput tests to run") - force = flag.Bool("f", false, "run expected-failure generics tests rather than skipping them") + force = flag.Bool("f", false, "ignore expected-failure test lists") generics = flag.String("G", defaultGLevels, "a comma-separated list of -G compiler flags to test with") shard = flag.Int("shard", 0, "shard index to run. Only applicable if -shards is non-zero.") @@ -175,8 +175,15 @@ func main() { status = "FAIL" } if test.err != nil { - status = "FAIL" errStr = test.err.Error() + if test.expectFail { + errStr += " (expected)" + } else { + status = "FAIL" + } + } else if test.expectFail { + status = "FAIL" + errStr = "unexpected success" } if status == "FAIL" { failed = true @@ -321,11 +328,45 @@ type test struct { tempDir string err error + + // expectFail indicates whether the (overall) test recipe is + // expected to fail under the current test configuration (e.g., -G=3 + // or GOEXPERIMENT=unified). + expectFail bool } -// usesTypes2 reports whether the compiler uses types2 for this test -// configuration (irrespective of flags specified by the test itself). -func (t *test) usesTypes2() bool { return unifiedEnabled || t.glevel != 0 } +// initExpectFail initializes t.expectFail based on the build+test +// configuration. It should only be called for tests known to use +// types2. +func (t *test) initExpectFail() { + if *force { + return + } + + failureSets := []map[string]bool{types2Failures} + + // Note: gccgo supports more 32-bit architectures than this, but + // hopefully the 32-bit failures are fixed before this matters. + switch goarch { + case "386", "arm", "mips", "mipsle": + failureSets = append(failureSets, types2Failures32Bit) + } + + if unifiedEnabled { + failureSets = append(failureSets, unifiedFailures) + } else { + failureSets = append(failureSets, g3Failures) + } + + filename := strings.Replace(t.goFileName(), "\\", "/", -1) // goFileName() uses \ on Windows + + for _, set := range failureSets { + if set[filename] { + t.expectFail = true + return + } + } +} func startTests(dir, gofile string, glevels []int) []*test { tests := make([]*test, len(glevels)) @@ -556,17 +597,6 @@ func (t *test) run() { close(t.donec) }() - if t.usesTypes2() && !*force { - // Files excluded from types2 testing. - filename := strings.Replace(t.goFileName(), "\\", "/", -1) // goFileName() uses \ on Windows - if excludedFiles[filename] { - if *verbose { - fmt.Printf("excl\t%s\n", filename) - } - return - } - } - srcBytes, err := ioutil.ReadFile(t.goFileName()) if err != nil { t.err = err @@ -703,12 +733,6 @@ func (t *test) run() { // at the specified -G level. If so, it may update flags as // necessary to test with -G. validForGLevel := func(tool Tool) bool { - if !t.usesTypes2() { - // tests should always pass when run w/o types2 (i.e., using the - // legacy typechecker). - return true - } - hasGFlag := false for _, flag := range flags { if strings.Contains(flag, "-G") { @@ -724,6 +748,14 @@ func (t *test) run() { return false } + if t.glevel == 0 && !hasGFlag && !unifiedEnabled { + // tests should always pass when run w/o types2 (i.e., using the + // legacy typechecker). + return true + } + + t.initExpectFail() + switch tool { case Build, Run: // ok; handled in goGcflags @@ -2071,103 +2103,123 @@ func overlayDir(dstRoot, srcRoot string) error { // List of files that the compiler cannot errorcheck with the new typechecker (compiler -G option). // Temporary scaffolding until we pass all the tests at which point this map can be removed. -// -// TODO(mdempsky): Split exclude list to disambiguate whether the -// failure is within types2, -G=3, or unified. -var excludedFiles = map[string]bool{ - "directive.go": true, // misplaced compiler directive checks - "float_lit3.go": true, // types2 reports extra errors - "import1.go": true, // types2 reports extra errors - "import6.go": true, // issue #43109 - "initializerr.go": true, // types2 reports extra errors - "linkname2.go": true, // error reported by noder (not running for types2 errorcheck test) - "notinheap.go": true, // types2 doesn't report errors about conversions that are invalid due to //go:notinheap - "printbig.go": true, // large untyped int passed to print (32-bit) - "shift1.go": true, // issue #42989 - "typecheck.go": true, // invalid function is not causing errors when called - "writebarrier.go": true, // correct diagnostics, but different lines (probably irgen's fault) +var types2Failures = setOf( + "directive.go", // misplaced compiler directive checks + "float_lit3.go", // types2 reports extra errors + "import1.go", // types2 reports extra errors + "import6.go", // issue #43109 + "initializerr.go", // types2 reports extra errors + "linkname2.go", // error reported by noder (not running for types2 errorcheck test) + "notinheap.go", // types2 doesn't report errors about conversions that are invalid due to //go:notinheap + "shift1.go", // issue #42989 + "typecheck.go", // invalid function is not causing errors when called - "interface/private.go": true, // types2 phrases errors differently (doesn't use non-spec "private" term) + "interface/private.go", // types2 phrases errors differently (doesn't use non-spec "private" term) - "fixedbugs/bug114.go": true, // large untyped int passed to println (32-bit) - "fixedbugs/bug176.go": true, // types2 reports all errors (pref: types2) - "fixedbugs/bug195.go": true, // types2 reports slightly different (but correct) bugs - "fixedbugs/bug228.go": true, // types2 doesn't run when there are syntax errors - "fixedbugs/bug231.go": true, // types2 bug? (same error reported twice) - "fixedbugs/bug255.go": true, // types2 reports extra errors - "fixedbugs/bug374.go": true, // types2 reports extra errors - "fixedbugs/bug385_32.go": true, // types2 doesn't produce missing error "type .* too large" (32-bit specific) - "fixedbugs/bug388.go": true, // types2 not run due to syntax errors - "fixedbugs/bug412.go": true, // types2 produces a follow-on error + "fixedbugs/bug176.go", // types2 reports all errors (pref: types2) + "fixedbugs/bug195.go", // types2 reports slightly different (but correct) bugs + "fixedbugs/bug228.go", // types2 doesn't run when there are syntax errors + "fixedbugs/bug231.go", // types2 bug? (same error reported twice) + "fixedbugs/bug255.go", // types2 reports extra errors + "fixedbugs/bug374.go", // types2 reports extra errors + "fixedbugs/bug388.go", // types2 not run due to syntax errors + "fixedbugs/bug412.go", // types2 produces a follow-on error - "fixedbugs/issue10700.go": true, // types2 reports ok hint, but does not match regexp - "fixedbugs/issue11590.go": true, // types2 doesn't report a follow-on error (pref: types2) - "fixedbugs/issue11610.go": true, // types2 not run after syntax errors - "fixedbugs/issue11614.go": true, // types2 reports an extra error - "fixedbugs/issue14520.go": true, // missing import path error by types2 - "fixedbugs/issue16133.go": true, // types2 doesn't use package path for qualified identifiers when package name is ambiguous - "fixedbugs/issue16428.go": true, // types2 reports two instead of one error - "fixedbugs/issue17038.go": true, // types2 doesn't report a follow-on error (pref: types2) - "fixedbugs/issue17270.go": true, // ICE in irgen - "fixedbugs/issue17645.go": true, // multiple errors on same line - "fixedbugs/issue18331.go": true, // missing error about misuse of //go:noescape (irgen needs code from noder) - "fixedbugs/issue18419.go": true, // types2 reports - "fixedbugs/issue19012.go": true, // multiple errors on same line - "fixedbugs/issue20174.go": true, // ICE due to width not calculated (probably irgen's fault) - "fixedbugs/issue20233.go": true, // types2 reports two instead of one error (pref: compiler) - "fixedbugs/issue20245.go": true, // types2 reports two instead of one error (pref: compiler) - "fixedbugs/issue20250.go": true, // correct diagnostics, but different lines (probably irgen's fault) - "fixedbugs/issue21979.go": true, // types2 doesn't report a follow-on error (pref: types2) - "fixedbugs/issue23305.go": true, // large untyped int passed to println (32-bit) - "fixedbugs/issue23732.go": true, // types2 reports different (but ok) line numbers - "fixedbugs/issue25958.go": true, // types2 doesn't report a follow-on error (pref: types2) - "fixedbugs/issue28079b.go": true, // types2 reports follow-on errors - "fixedbugs/issue28268.go": true, // types2 reports follow-on errors - "fixedbugs/issue31053.go": true, // types2 reports "unknown field" instead of "cannot refer to unexported field" - "fixedbugs/issue33460.go": true, // types2 reports alternative positions in separate error - "fixedbugs/issue42058a.go": true, // types2 doesn't report "channel element type too large" - "fixedbugs/issue42058b.go": true, // types2 doesn't report "channel element type too large" - "fixedbugs/issue42284.go": true, // unified formats important constant expression differently in diagnostics - "fixedbugs/issue4232.go": true, // types2 reports (correct) extra errors - "fixedbugs/issue4452.go": true, // types2 reports (correct) extra errors - "fixedbugs/issue4510.go": true, // types2 reports different (but ok) line numbers - "fixedbugs/issue5609.go": true, // types2 needs a better error message - "fixedbugs/issue7525b.go": true, // types2 reports init cycle error on different line - ok otherwise - "fixedbugs/issue7525c.go": true, // types2 reports init cycle error on different line - ok otherwise - "fixedbugs/issue7525d.go": true, // types2 reports init cycle error on different line - ok otherwise - "fixedbugs/issue7525e.go": true, // types2 reports init cycle error on different line - ok otherwise - "fixedbugs/issue7525.go": true, // types2 reports init cycle error on different line - ok otherwise - "fixedbugs/issue9691.go": true, // "cannot assign to int(.autotmp_4)" (probably irgen's fault) + "fixedbugs/issue10700.go", // types2 reports ok hint, but does not match regexp + "fixedbugs/issue11590.go", // types2 doesn't report a follow-on error (pref: types2) + "fixedbugs/issue11610.go", // types2 not run after syntax errors + "fixedbugs/issue11614.go", // types2 reports an extra error + "fixedbugs/issue14520.go", // missing import path error by types2 + "fixedbugs/issue16133.go", // types2 doesn't use package path for qualified identifiers when package name is ambiguous + "fixedbugs/issue16428.go", // types2 reports two instead of one error + "fixedbugs/issue17038.go", // types2 doesn't report a follow-on error (pref: types2) + "fixedbugs/issue17645.go", // multiple errors on same line + "fixedbugs/issue18331.go", // missing error about misuse of //go:noescape (irgen needs code from noder) + "fixedbugs/issue18419.go", // types2 reports + "fixedbugs/issue19012.go", // multiple errors on same line + "fixedbugs/issue20233.go", // types2 reports two instead of one error (pref: compiler) + "fixedbugs/issue20245.go", // types2 reports two instead of one error (pref: compiler) + "fixedbugs/issue21979.go", // types2 doesn't report a follow-on error (pref: types2) + "fixedbugs/issue23732.go", // types2 reports different (but ok) line numbers + "fixedbugs/issue25958.go", // types2 doesn't report a follow-on error (pref: types2) + "fixedbugs/issue28079b.go", // types2 reports follow-on errors + "fixedbugs/issue28268.go", // types2 reports follow-on errors + "fixedbugs/issue31053.go", // types2 reports "unknown field" instead of "cannot refer to unexported field" + "fixedbugs/issue33460.go", // types2 reports alternative positions in separate error + "fixedbugs/issue42058a.go", // types2 doesn't report "channel element type too large" + "fixedbugs/issue42058b.go", // types2 doesn't report "channel element type too large" + "fixedbugs/issue4232.go", // types2 reports (correct) extra errors + "fixedbugs/issue4452.go", // types2 reports (correct) extra errors + "fixedbugs/issue4510.go", // types2 reports different (but ok) line numbers + "fixedbugs/issue5609.go", // types2 needs a better error message + "fixedbugs/issue7525b.go", // types2 reports init cycle error on different line - ok otherwise + "fixedbugs/issue7525c.go", // types2 reports init cycle error on different line - ok otherwise + "fixedbugs/issue7525d.go", // types2 reports init cycle error on different line - ok otherwise + "fixedbugs/issue7525e.go", // types2 reports init cycle error on different line - ok otherwise + "fixedbugs/issue7525.go", // types2 reports init cycle error on different line - ok otherwise +) - // tests that rely on -m diagnostics, which currently differ with -G=3 - // - // TODO(mdempsky): Triage, though most of the issues seem to fall into: +var types2Failures32Bit = setOf( + "printbig.go", // large untyped int passed to print (32-bit) + "fixedbugs/bug114.go", // large untyped int passed to println (32-bit) + "fixedbugs/issue23305.go", // large untyped int passed to println (32-bit) + "fixedbugs/bug385_32.go", // types2 doesn't produce missing error "type .* too large" (32-bit specific) +) + +var g3Failures = setOf( + // TODO: Triage tests without explicit failure explanations. From a + // cursory inspection, they mostly fall into: // - Anonymous result parameters given different names (e.g., ~r0 vs ~r1) // - Some escape analysis diagnostics being printed without position information // - Some expressions printed differently (e.g., "int(100)" instead // of "100" or "&composite literal" instead of "&[4]int{...}"). - "closure3.go": true, - "escape2.go": true, - "escape2n.go": true, - "escape4.go": true, - "escape_calls.go": true, - "escape_field.go": true, - "escape_iface.go": true, - "escape_indir.go": true, - "escape_level.go": true, - "escape_map.go": true, - "escape_param.go": true, - "escape_slice.go": true, - "escape_struct_param1.go": true, - "escape_struct_param2.go": true, - "fixedbugs/issue12006.go": true, - "fixedbugs/issue13799.go": true, - "fixedbugs/issue21709.go": true, - "fixedbugs/issue31573.go": true, - "fixedbugs/issue37837.go": true, - "fixedbugs/issue39292.go": true, - "fixedbugs/issue7921.go": true, - "inline.go": true, + + "closure3.go", // prints "s escapes to heap" without line number + "escape2.go", + "escape2n.go", + "escape4.go", // prints "1 escapes to heap" without line number + "escape_calls.go", + "escape_field.go", + "escape_iface.go", + "escape_indir.go", + "escape_level.go", + "escape_map.go", + "escape_param.go", + "escape_slice.go", + "escape_struct_param1.go", + "escape_struct_param2.go", + "writebarrier.go", // correct diagnostics, but different lines (probably irgen's fault) + + "fixedbugs/issue12006.go", + "fixedbugs/issue13799.go", + "fixedbugs/issue17270.go", // ICE in irgen + "fixedbugs/issue20174.go", // ICE due to width not calculated (probably irgen's fault) + "fixedbugs/issue20250.go", // correct diagnostics, but different lines (probably irgen's fault) + "fixedbugs/issue21709.go", + "fixedbugs/issue31573.go", + "fixedbugs/issue37837.go", + "fixedbugs/issue39292.go", + "fixedbugs/issue7921.go", // prints "composite literal does not escape" but test expects "[]byte{...} does not escape" + "fixedbugs/issue9691.go", // "cannot assign to int(.autotmp_4)" (probably irgen's fault) + + "typeparam/nested.go", // -G=3 doesn't support function-local types with generics +) + +var unifiedFailures = setOf( + "closure3.go", // unified IR numbers closures differently than -d=inlfuncswithclosures + "escape4.go", // unified IR can inline f5 and f6; test doesn't expect this + "inline.go", // unified IR reports function literal diagnostics on different lines than -d=inlfuncswithclosures + + "fixedbugs/issue42284.go", // prints "T(0) does not escape", but test expects "a.I(a.T(0)) does not escape" + "fixedbugs/issue7921.go", // prints "… escapes to heap", but test expects "string(…) escapes to heap" +) + +func setOf(keys ...string) map[string]bool { + m := make(map[string]bool, len(keys)) + for _, key := range keys { + m[key] = true + } + return m } // splitQuoted splits the string s around each instance of one or more consecutive diff --git a/test/typeparam/nested.go b/test/typeparam/nested.go index 6512b3fc8fe..c0037a3e6e4 100644 --- a/test/typeparam/nested.go +++ b/test/typeparam/nested.go @@ -1,4 +1,4 @@ -// run -gcflags=all="-d=unified -G" +// run -gcflags=-G=3 // Copyright 2021 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style From 5c42b6a953036b906626f5b25b7655641fbad060 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 8 Jun 2021 11:57:11 -0700 Subject: [PATCH 629/940] [dev.typeparams] test: add regress tests that fail(ed) with -G=3 This CL includes multiple test cases that exercise unique failures with -G=3 mode that did not affect unified IR mode. Most of these were found over a period of about 3 hours of manual experimentation. Thanks to Cuong Manh Le for test cases 11 and 12. Updates #46704. Change-Id: Ia2fa619536732b121b6c929329065c85b9384511 Reviewed-on: https://go-review.googlesource.com/c/go/+/326169 Trust: Matthew Dempsky Trust: Dan Scales Trust: Cuong Manh Le Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Dan Scales Reviewed-by: Robert Griesemer --- test/run.go | 15 +++++++++- test/typeparam/mdempsky/1.dir/a.go | 9 ++++++ test/typeparam/mdempsky/1.dir/b.go | 9 ++++++ test/typeparam/mdempsky/1.go | 7 +++++ test/typeparam/mdempsky/10.dir/a.go | 7 +++++ test/typeparam/mdempsky/10.dir/b.go | 17 ++++++++++++ test/typeparam/mdempsky/10.go | 7 +++++ test/typeparam/mdempsky/11.go | 16 +++++++++++ test/typeparam/mdempsky/12.dir/a.go | 11 ++++++++ test/typeparam/mdempsky/12.dir/main.go | 13 +++++++++ test/typeparam/mdempsky/12.go | 9 ++++++ test/typeparam/mdempsky/13.go | 38 ++++++++++++++++++++++++++ test/typeparam/mdempsky/14.go | 37 +++++++++++++++++++++++++ test/typeparam/mdempsky/2.go | 20 ++++++++++++++ test/typeparam/mdempsky/3.dir/a.go | 7 +++++ test/typeparam/mdempsky/3.dir/b.go | 9 ++++++ test/typeparam/mdempsky/3.go | 7 +++++ test/typeparam/mdempsky/4.dir/a.go | 12 ++++++++ test/typeparam/mdempsky/4.dir/b.go | 9 ++++++ test/typeparam/mdempsky/4.go | 7 +++++ test/typeparam/mdempsky/5.go | 15 ++++++++++ test/typeparam/mdempsky/6.go | 11 ++++++++ test/typeparam/mdempsky/7.dir/a.go | 9 ++++++ test/typeparam/mdempsky/7.dir/b.go | 9 ++++++ test/typeparam/mdempsky/7.go | 7 +++++ test/typeparam/mdempsky/8.dir/a.go | 7 +++++ test/typeparam/mdempsky/8.dir/b.go | 11 ++++++++ test/typeparam/mdempsky/8.go | 7 +++++ test/typeparam/mdempsky/9.go | 11 ++++++++ 29 files changed, 352 insertions(+), 1 deletion(-) create mode 100644 test/typeparam/mdempsky/1.dir/a.go create mode 100644 test/typeparam/mdempsky/1.dir/b.go create mode 100644 test/typeparam/mdempsky/1.go create mode 100644 test/typeparam/mdempsky/10.dir/a.go create mode 100644 test/typeparam/mdempsky/10.dir/b.go create mode 100644 test/typeparam/mdempsky/10.go create mode 100644 test/typeparam/mdempsky/11.go create mode 100644 test/typeparam/mdempsky/12.dir/a.go create mode 100644 test/typeparam/mdempsky/12.dir/main.go create mode 100644 test/typeparam/mdempsky/12.go create mode 100644 test/typeparam/mdempsky/13.go create mode 100644 test/typeparam/mdempsky/14.go create mode 100644 test/typeparam/mdempsky/2.go create mode 100644 test/typeparam/mdempsky/3.dir/a.go create mode 100644 test/typeparam/mdempsky/3.dir/b.go create mode 100644 test/typeparam/mdempsky/3.go create mode 100644 test/typeparam/mdempsky/4.dir/a.go create mode 100644 test/typeparam/mdempsky/4.dir/b.go create mode 100644 test/typeparam/mdempsky/4.go create mode 100644 test/typeparam/mdempsky/5.go create mode 100644 test/typeparam/mdempsky/6.go create mode 100644 test/typeparam/mdempsky/7.dir/a.go create mode 100644 test/typeparam/mdempsky/7.dir/b.go create mode 100644 test/typeparam/mdempsky/7.go create mode 100644 test/typeparam/mdempsky/8.dir/a.go create mode 100644 test/typeparam/mdempsky/8.dir/b.go create mode 100644 test/typeparam/mdempsky/8.go create mode 100644 test/typeparam/mdempsky/9.go diff --git a/test/run.go b/test/run.go index ff8bf4b229e..df3befbf21d 100644 --- a/test/run.go +++ b/test/run.go @@ -86,7 +86,7 @@ var ( // dirs are the directories to look for *.go files in. // TODO(bradfitz): just use all directories? - dirs = []string{".", "ken", "chan", "interface", "syntax", "dwarf", "fixedbugs", "codegen", "runtime", "abi", "typeparam"} + dirs = []string{".", "ken", "chan", "interface", "syntax", "dwarf", "fixedbugs", "codegen", "runtime", "abi", "typeparam", "typeparam/mdempsky"} // ratec controls the max number of tests running at a time. ratec chan bool @@ -2203,6 +2203,19 @@ var g3Failures = setOf( "fixedbugs/issue9691.go", // "cannot assign to int(.autotmp_4)" (probably irgen's fault) "typeparam/nested.go", // -G=3 doesn't support function-local types with generics + + "typeparam/mdempsky/1.go", + "typeparam/mdempsky/2.go", + "typeparam/mdempsky/3.go", + "typeparam/mdempsky/4.go", + "typeparam/mdempsky/5.go", + "typeparam/mdempsky/7.go", + "typeparam/mdempsky/8.go", + "typeparam/mdempsky/9.go", + "typeparam/mdempsky/11.go", + "typeparam/mdempsky/12.go", + "typeparam/mdempsky/13.go", + "typeparam/mdempsky/14.go", ) var unifiedFailures = setOf( diff --git a/test/typeparam/mdempsky/1.dir/a.go b/test/typeparam/mdempsky/1.dir/a.go new file mode 100644 index 00000000000..a668eb52dc9 --- /dev/null +++ b/test/typeparam/mdempsky/1.dir/a.go @@ -0,0 +1,9 @@ +// Copyright 2021 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 a + +type T[_ any] int + +func F() { _ = new(T[int]) } diff --git a/test/typeparam/mdempsky/1.dir/b.go b/test/typeparam/mdempsky/1.dir/b.go new file mode 100644 index 00000000000..af6fef3f6d8 --- /dev/null +++ b/test/typeparam/mdempsky/1.dir/b.go @@ -0,0 +1,9 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "./a" + +func main() { a.F() } diff --git a/test/typeparam/mdempsky/1.go b/test/typeparam/mdempsky/1.go new file mode 100644 index 00000000000..87b4ff46c1e --- /dev/null +++ b/test/typeparam/mdempsky/1.go @@ -0,0 +1,7 @@ +// compiledir -G=3 + +// Copyright 2021 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 ignored diff --git a/test/typeparam/mdempsky/10.dir/a.go b/test/typeparam/mdempsky/10.dir/a.go new file mode 100644 index 00000000000..95e111d3470 --- /dev/null +++ b/test/typeparam/mdempsky/10.dir/a.go @@ -0,0 +1,7 @@ +// Copyright 2021 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 a + +type I[T any] interface{ M() T } diff --git a/test/typeparam/mdempsky/10.dir/b.go b/test/typeparam/mdempsky/10.dir/b.go new file mode 100644 index 00000000000..0ef28fd02de --- /dev/null +++ b/test/typeparam/mdempsky/10.dir/b.go @@ -0,0 +1,17 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "./a" + +var m = a.I[int].M + +var never bool + +func main() { + if never { + m(nil) + } +} diff --git a/test/typeparam/mdempsky/10.go b/test/typeparam/mdempsky/10.go new file mode 100644 index 00000000000..76930e5e4f6 --- /dev/null +++ b/test/typeparam/mdempsky/10.go @@ -0,0 +1,7 @@ +// rundir -G=3 + +// Copyright 2021 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 ignored diff --git a/test/typeparam/mdempsky/11.go b/test/typeparam/mdempsky/11.go new file mode 100644 index 00000000000..e86c038a104 --- /dev/null +++ b/test/typeparam/mdempsky/11.go @@ -0,0 +1,16 @@ +// errorcheck + +// Copyright 2021 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. + +// Reported by Cuong Manh Le. + +package p + +type a struct{} + +//go:notinheap +type b a + +var _ = (*b)(new(a)) // ERROR "cannot convert" diff --git a/test/typeparam/mdempsky/12.dir/a.go b/test/typeparam/mdempsky/12.dir/a.go new file mode 100644 index 00000000000..ee8be939a8f --- /dev/null +++ b/test/typeparam/mdempsky/12.dir/a.go @@ -0,0 +1,11 @@ +// Copyright 2021 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 a + +type S[T any] struct { + F T +} + +var X = S[int]{} diff --git a/test/typeparam/mdempsky/12.dir/main.go b/test/typeparam/mdempsky/12.dir/main.go new file mode 100644 index 00000000000..2891322e298 --- /dev/null +++ b/test/typeparam/mdempsky/12.dir/main.go @@ -0,0 +1,13 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./a" +) + +func main() { + _ = a.X +} diff --git a/test/typeparam/mdempsky/12.go b/test/typeparam/mdempsky/12.go new file mode 100644 index 00000000000..a2dc4daaccc --- /dev/null +++ b/test/typeparam/mdempsky/12.go @@ -0,0 +1,9 @@ +// rundir -G=3 + +// Copyright 2021 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. + +// Reported by Cuong Manh Le. + +package ignored diff --git a/test/typeparam/mdempsky/13.go b/test/typeparam/mdempsky/13.go new file mode 100644 index 00000000000..dc1d29bce1c --- /dev/null +++ b/test/typeparam/mdempsky/13.go @@ -0,0 +1,38 @@ +// run -gcflags=-G=3 + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type Mer interface{ M() } + +func F[T Mer](expectPanic bool) { + defer func() { + err := recover() + if (err != nil) != expectPanic { + print("FAIL: (", err, " != nil) != ", expectPanic, "\n") + } + }() + + var t T + T.M(t) +} + +type MyMer int + +func (MyMer) M() {} + +func main() { + F[Mer](true) + F[struct{ Mer }](true) + F[*struct{ Mer }](true) + + F[MyMer](false) + F[*MyMer](true) + F[struct{ MyMer }](false) + F[struct{ *MyMer }](true) + F[*struct{ MyMer }](true) + F[*struct{ *MyMer }](true) +} diff --git a/test/typeparam/mdempsky/14.go b/test/typeparam/mdempsky/14.go new file mode 100644 index 00000000000..61f9436910c --- /dev/null +++ b/test/typeparam/mdempsky/14.go @@ -0,0 +1,37 @@ +// run -gcflags=-G=3 + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func Zero[T any]() (_ T) { return } + +type T[X any] int + +func (T[X]) M() { + var have interface{} = Zero[X]() + var want interface{} = Zero[MyInt]() + + if have != want { + println("FAIL") + } +} + +type I interface{ M() } + +type MyInt int +type U = T[MyInt] + +var x = U(0) +var i I = x + +func main() { + x.M() + U.M(x) + (*U).M(&x) + + i.M() + I.M(x) +} diff --git a/test/typeparam/mdempsky/2.go b/test/typeparam/mdempsky/2.go new file mode 100644 index 00000000000..f09730f9491 --- /dev/null +++ b/test/typeparam/mdempsky/2.go @@ -0,0 +1,20 @@ +// compile -G=3 + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type T[A, B, C any] int + +func (T[A, B, C]) m(x int) { + if x <= 0 { + return + } + T[B, C, A](0).m(x - 1) +} + +func main() { + T[int8, int16, int32](0).m(3) +} diff --git a/test/typeparam/mdempsky/3.dir/a.go b/test/typeparam/mdempsky/3.dir/a.go new file mode 100644 index 00000000000..cf456e8d48f --- /dev/null +++ b/test/typeparam/mdempsky/3.dir/a.go @@ -0,0 +1,7 @@ +// Copyright 2021 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 a + +func F[T interface{ chan int }](c T) {} diff --git a/test/typeparam/mdempsky/3.dir/b.go b/test/typeparam/mdempsky/3.dir/b.go new file mode 100644 index 00000000000..0cfd142f4c4 --- /dev/null +++ b/test/typeparam/mdempsky/3.dir/b.go @@ -0,0 +1,9 @@ +// Copyright 2021 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 b + +import "./a" + +func g() { a.F(make(chan int)) } diff --git a/test/typeparam/mdempsky/3.go b/test/typeparam/mdempsky/3.go new file mode 100644 index 00000000000..87b4ff46c1e --- /dev/null +++ b/test/typeparam/mdempsky/3.go @@ -0,0 +1,7 @@ +// compiledir -G=3 + +// Copyright 2021 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 ignored diff --git a/test/typeparam/mdempsky/4.dir/a.go b/test/typeparam/mdempsky/4.dir/a.go new file mode 100644 index 00000000000..cb672949eae --- /dev/null +++ b/test/typeparam/mdempsky/4.dir/a.go @@ -0,0 +1,12 @@ +// Copyright 2021 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 a + +func F[T any](T) { +Loop: + for { + break Loop + } +} diff --git a/test/typeparam/mdempsky/4.dir/b.go b/test/typeparam/mdempsky/4.dir/b.go new file mode 100644 index 00000000000..e1fb0e7c5ea --- /dev/null +++ b/test/typeparam/mdempsky/4.dir/b.go @@ -0,0 +1,9 @@ +// Copyright 2021 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 b + +import "./a" + +func f() { a.F(0) } diff --git a/test/typeparam/mdempsky/4.go b/test/typeparam/mdempsky/4.go new file mode 100644 index 00000000000..87b4ff46c1e --- /dev/null +++ b/test/typeparam/mdempsky/4.go @@ -0,0 +1,7 @@ +// compiledir -G=3 + +// Copyright 2021 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 ignored diff --git a/test/typeparam/mdempsky/5.go b/test/typeparam/mdempsky/5.go new file mode 100644 index 00000000000..0d1ad399462 --- /dev/null +++ b/test/typeparam/mdempsky/5.go @@ -0,0 +1,15 @@ +// compile -G=3 + +// Copyright 2021 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 a + +type X[T any] int + +func (X[T]) F(T) {} + +func x() { + X[interface{}](0).F(0) +} diff --git a/test/typeparam/mdempsky/6.go b/test/typeparam/mdempsky/6.go new file mode 100644 index 00000000000..a26ff62f6d4 --- /dev/null +++ b/test/typeparam/mdempsky/6.go @@ -0,0 +1,11 @@ +// compile -G=3 + +// Copyright 2021 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 a + +type I[T any] interface{ M() T } + +var _ = I[int].M diff --git a/test/typeparam/mdempsky/7.dir/a.go b/test/typeparam/mdempsky/7.dir/a.go new file mode 100644 index 00000000000..59c59956118 --- /dev/null +++ b/test/typeparam/mdempsky/7.dir/a.go @@ -0,0 +1,9 @@ +// Copyright 2021 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 a + +type I[T any] interface{ M() T } + +var X I[int] diff --git a/test/typeparam/mdempsky/7.dir/b.go b/test/typeparam/mdempsky/7.dir/b.go new file mode 100644 index 00000000000..9f705308114 --- /dev/null +++ b/test/typeparam/mdempsky/7.dir/b.go @@ -0,0 +1,9 @@ +// Copyright 2021 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 b + +import "./a" + +var _ = a.X diff --git a/test/typeparam/mdempsky/7.go b/test/typeparam/mdempsky/7.go new file mode 100644 index 00000000000..87b4ff46c1e --- /dev/null +++ b/test/typeparam/mdempsky/7.go @@ -0,0 +1,7 @@ +// compiledir -G=3 + +// Copyright 2021 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 ignored diff --git a/test/typeparam/mdempsky/8.dir/a.go b/test/typeparam/mdempsky/8.dir/a.go new file mode 100644 index 00000000000..607fe5e0af2 --- /dev/null +++ b/test/typeparam/mdempsky/8.dir/a.go @@ -0,0 +1,7 @@ +// Copyright 2021 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 a + +func F[T interface{ comparable }]() {} diff --git a/test/typeparam/mdempsky/8.dir/b.go b/test/typeparam/mdempsky/8.dir/b.go new file mode 100644 index 00000000000..ef2637b894f --- /dev/null +++ b/test/typeparam/mdempsky/8.dir/b.go @@ -0,0 +1,11 @@ +// Copyright 2021 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 b + +import "./a" + +func init() { + a.F[func()]() // ERROR "does not satisfy comparable" +} diff --git a/test/typeparam/mdempsky/8.go b/test/typeparam/mdempsky/8.go new file mode 100644 index 00000000000..32cf4b830d2 --- /dev/null +++ b/test/typeparam/mdempsky/8.go @@ -0,0 +1,7 @@ +// errorcheckdir -G=3 + +// Copyright 2021 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 ignored diff --git a/test/typeparam/mdempsky/9.go b/test/typeparam/mdempsky/9.go new file mode 100644 index 00000000000..b72516c4eab --- /dev/null +++ b/test/typeparam/mdempsky/9.go @@ -0,0 +1,11 @@ +// compile -G=3 + +// Copyright 2021 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 a + +func f[V any]() []V { return []V{0: *new(V)} } + +func g() { f[int]() } From 4676c3675e85a8a82a1513ef1f5e38aebc80ddc8 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Sun, 4 Jul 2021 12:06:39 +0700 Subject: [PATCH 630/940] [dev.typeparams] cmd/compile: rename PartialCallType -> MethodValueType CL 330837 rename OCALLPART to OMETHVALUE, so do the same thing for PartialCallType for consistency. Change-Id: Id40eb35bbcee7719acfb41fce0e2b968879f9fef Reviewed-on: https://go-review.googlesource.com/c/go/+/332769 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/escape/utils.go | 2 +- src/cmd/compile/internal/typecheck/func.go | 8 ++++---- src/cmd/compile/internal/walk/closure.go | 2 +- src/cmd/compile/internal/walk/order.go | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/cmd/compile/internal/escape/utils.go b/src/cmd/compile/internal/escape/utils.go index 6e2f9c424a8..5f462ef570f 100644 --- a/src/cmd/compile/internal/escape/utils.go +++ b/src/cmd/compile/internal/escape/utils.go @@ -193,7 +193,7 @@ func HeapAllocReason(n ir.Node) string { if n.Op() == ir.OCLOSURE && typecheck.ClosureType(n.(*ir.ClosureExpr)).Size() > ir.MaxImplicitStackVarSize { return "too large for stack" } - if n.Op() == ir.OMETHVALUE && typecheck.PartialCallType(n.(*ir.SelectorExpr)).Size() > ir.MaxImplicitStackVarSize { + if n.Op() == ir.OMETHVALUE && typecheck.MethodValueType(n.(*ir.SelectorExpr)).Size() > ir.MaxImplicitStackVarSize { return "too large for stack" } diff --git a/src/cmd/compile/internal/typecheck/func.go b/src/cmd/compile/internal/typecheck/func.go index 847e9b9aead..7dec65c1d68 100644 --- a/src/cmd/compile/internal/typecheck/func.go +++ b/src/cmd/compile/internal/typecheck/func.go @@ -125,10 +125,10 @@ func ClosureType(clo *ir.ClosureExpr) *types.Type { return typ } -// PartialCallType returns the struct type used to hold all the information -// needed in the closure for n (n must be a OMETHVALUE node). -// The address of a variable of the returned type can be cast to a func. -func PartialCallType(n *ir.SelectorExpr) *types.Type { +// MethodValueType returns the struct type used to hold all the information +// needed in the closure for a OMETHVALUE node. The address of a variable of +// the returned type can be cast to a func. +func MethodValueType(n *ir.SelectorExpr) *types.Type { t := types.NewStruct(types.NoPkg, []*types.Field{ types.NewField(base.Pos, Lookup("F"), types.Types[types.TUINTPTR]), types.NewField(base.Pos, Lookup("R"), n.X.Type()), diff --git a/src/cmd/compile/internal/walk/closure.go b/src/cmd/compile/internal/walk/closure.go index 7f6ef473bf2..2d0b2dcc0ee 100644 --- a/src/cmd/compile/internal/walk/closure.go +++ b/src/cmd/compile/internal/walk/closure.go @@ -175,7 +175,7 @@ func walkMethodValue(n *ir.SelectorExpr, init *ir.Nodes) ir.Node { init.Append(typecheck.Stmt(check)) } - typ := typecheck.PartialCallType(n) + typ := typecheck.MethodValueType(n) clos := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ), nil) clos.SetEsc(n.Esc()) diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go index eec340261ef..cd2bbcb73ba 100644 --- a/src/cmd/compile/internal/walk/order.go +++ b/src/cmd/compile/internal/walk/order.go @@ -1306,7 +1306,7 @@ func (o *orderState) expr1(n, lhs ir.Node) ir.Node { n := n.(*ir.SelectorExpr) n.X = o.expr(n.X, nil) if n.Transient() { - t := typecheck.PartialCallType(n) + t := typecheck.MethodValueType(n) n.Prealloc = o.newTemp(t, false) } return n From c96833e5badedb025761de6a74ed5f9c848059de Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Wed, 7 Jul 2021 14:58:36 +0000 Subject: [PATCH 631/940] doc: remove stale comment about arm64 port Fixes #47079. Change-Id: I8a671e3fdc13083e44e8d89064a5e7621e53bc4c Reviewed-on: https://go-review.googlesource.com/c/go/+/333075 Trust: Michael Knyszek Reviewed-by: Keith Randall Run-TryBot: Michael Knyszek TryBot-Result: Go Bot --- doc/asm.html | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/asm.html b/doc/asm.html index 7173d9bd514..d5788000861 100644 --- a/doc/asm.html +++ b/doc/asm.html @@ -827,10 +827,6 @@ The other codes are -> (arithmetic right shift),

ARM64

-

-The ARM64 port is in an experimental state. -

-

R18 is the "platform register", reserved on the Apple platform. To prevent accidental misuse, the register is named R18_PLATFORM. From b4844c9f54eb6a559d8dc9333cf5b1e66dab8167 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Tue, 6 Jul 2021 10:53:00 -0700 Subject: [PATCH 632/940] [dev.typeparams] cmd/compile: handle the (*T).M method expression with dictionaries The (*T).M method expression is where M is a value method, but the type (*T) is a pointer to the main type. In this case, after following any embedded fields, we need to add an extra star operator when using the receiver arg in the closure call. Thanks to Cuong for finding/pointing out an example for this case (typeparam/mdempsky/14.go) This example also shows that we now need the ability to export/import OEFACE and OIDATA, which I added. Change-Id: Ida0f81ce757fff78fec6276c60052ed71d207454 Reviewed-on: https://go-review.googlesource.com/c/go/+/333014 Run-TryBot: Dan Scales Reviewed-by: Keith Randall TryBot-Result: Go Bot Trust: Dan Scales --- src/cmd/compile/internal/noder/stencil.go | 30 +++++++++++-------- src/cmd/compile/internal/typecheck/iexport.go | 4 +-- src/cmd/compile/internal/typecheck/iimport.go | 4 +-- test/run.go | 1 - test/typeparam/dictionaryCapture.go | 12 ++++++++ 5 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index dbaebf76238..656cab84d17 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -94,7 +94,7 @@ func (g *irgen) stencil() { // generic F, not immediately called closureRequired = true } - if n.Op() == ir.OMETHEXPR && len(n.(*ir.SelectorExpr).X.Type().RParams()) > 0 && !types.IsInterfaceMethod(n.(*ir.SelectorExpr).Selection.Type) { + if n.Op() == ir.OMETHEXPR && len(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) > 0 && !types.IsInterfaceMethod(n.(*ir.SelectorExpr).Selection.Type) { // T.M, T a type which is generic, not immediately // called. Not necessary if the method selected is // actually for an embedded interface field. @@ -229,6 +229,7 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { outerInfo = g.instInfoMap[outer.Sym()] } usingSubdict := false + valueMethod := false if x.Op() == ir.OFUNCINST { inst := x.(*ir.InstExpr) @@ -269,16 +270,10 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { } } else { // ir.OMETHEXPR // Method expression T.M where T is a generic type. - // TODO: Is (*T).M right? se := x.(*ir.SelectorExpr) - targs := se.X.Type().RParams() + targs := deref(se.X.Type()).RParams() if len(targs) == 0 { - if se.X.Type().IsPtr() { - targs = se.X.Type().Elem().RParams() - if len(targs) == 0 { - panic("bad") - } - } + panic("bad") } // se.X.Type() is the top-level type of the method expression. To @@ -295,6 +290,10 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { break } } + if !gf.Type().Recv().Type.IsPtr() { + // Remember if value method, so we can detect (*T).M case. + valueMethod = true + } target = g.getInstantiation(gf, targs, true) dictValue, usingSubdict = g.getDictOrSubdict(outerInfo, x, gf, targs, true) if infoPrintMode { @@ -446,8 +445,15 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { // If we are doing a method expression, we need to // explicitly traverse any embedded fields in the receiver // argument in order to call the method instantiation. - dot := typecheck.AddImplicitDots(ir.NewSelectorExpr(base.Pos, ir.OXDOT, formalParams[0].Nname.(*ir.Name), x.(*ir.SelectorExpr).Sel)) - args = append(args, dot.X) + arg0 := formalParams[0].Nname.(ir.Node) + arg0 = typecheck.AddImplicitDots(ir.NewSelectorExpr(base.Pos, ir.OXDOT, arg0, x.(*ir.SelectorExpr).Sel)).X + if valueMethod && arg0.Type().IsPtr() { + // For handling the (*T).M case: if we have a pointer + // receiver after following all the embedded fields, + // but it's a value method, add a star operator. + arg0 = ir.NewStarExpr(arg0.Pos(), arg0) + } + args = append(args, arg0) } else { args = append(args, formalParams[i].Nname.(*ir.Name)) } @@ -1342,7 +1348,7 @@ func (subst *subster) fields(class ir.Class, oldfields []*types.Field, dcl []*ir return newfields } -// defer does a single defer of type t, if it is a pointer type. +// deref does a single deref of type t, if it is a pointer type. func deref(t *types.Type) *types.Type { if t.IsPtr() { return t.Elem() diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index 82bbda5228f..b717c373f5f 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -1957,7 +1957,7 @@ func (w *exportWriter) expr(n ir.Node) { w.typ(n.Type()) // unary expressions - case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.ORECV: + case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.ORECV, ir.OIDATA: n := n.(*ir.UnaryExpr) w.op(n.Op()) w.pos(n.Pos()) @@ -1993,7 +1993,7 @@ func (w *exportWriter) expr(n ir.Node) { // binary expressions case ir.OADD, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OEQ, ir.OGE, ir.OGT, ir.OLE, ir.OLT, - ir.OLSH, ir.OMOD, ir.OMUL, ir.ONE, ir.OOR, ir.ORSH, ir.OSUB, ir.OXOR: + ir.OLSH, ir.OMOD, ir.OMUL, ir.ONE, ir.OOR, ir.ORSH, ir.OSUB, ir.OXOR, ir.OEFACE: n := n.(*ir.BinaryExpr) w.op(n.Op()) w.pos(n.Pos()) diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 17e60effd68..f178869e285 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -1497,7 +1497,7 @@ func (r *importReader) node() ir.Node { return ir.NewLinksymOffsetExpr(pos, Lookup(name).Linksym(), int64(off), typ) // unary expressions - case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.ORECV: + case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.ORECV, ir.OIDATA: n := ir.NewUnaryExpr(r.pos(), op, r.expr()) if go117ExportTypes { n.SetType(r.typ()) @@ -1521,7 +1521,7 @@ func (r *importReader) node() ir.Node { // binary expressions case ir.OADD, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OEQ, ir.OGE, ir.OGT, ir.OLE, ir.OLT, - ir.OLSH, ir.OMOD, ir.OMUL, ir.ONE, ir.OOR, ir.ORSH, ir.OSUB, ir.OXOR: + ir.OLSH, ir.OMOD, ir.OMUL, ir.ONE, ir.OOR, ir.ORSH, ir.OSUB, ir.OXOR, ir.OEFACE: n := ir.NewBinaryExpr(r.pos(), op, r.expr(), r.expr()) if go117ExportTypes { n.SetType(r.typ()) diff --git a/test/run.go b/test/run.go index df3befbf21d..7afad0ec09c 100644 --- a/test/run.go +++ b/test/run.go @@ -2215,7 +2215,6 @@ var g3Failures = setOf( "typeparam/mdempsky/11.go", "typeparam/mdempsky/12.go", "typeparam/mdempsky/13.go", - "typeparam/mdempsky/14.go", ) var unifiedFailures = setOf( diff --git a/test/typeparam/dictionaryCapture.go b/test/typeparam/dictionaryCapture.go index af508859e1c..26af7a09b0b 100644 --- a/test/typeparam/dictionaryCapture.go +++ b/test/typeparam/dictionaryCapture.go @@ -73,20 +73,32 @@ func methodExpressions() { x := s[int]{a:7} f0 := s[int].g0 f0(x) + f0p := (*s[int]).g0 + f0p(&x) f1 := s[int].g1 is7(f1(x)) + f1p := (*s[int]).g1 + is7(f1p(&x)) f2 := s[int].g2 is77(f2(x)) + f2p := (*s[int]).g2 + is77(f2p(&x)) } func genMethodExpressions[T comparable](want T) { x := s[T]{a: want} f0 := s[T].g0 f0(x) + f0p := (*s[T]).g0 + f0p(&x) f1 := s[T].g1 if got := f1(x); got != want { panic(fmt.Sprintf("f1(x) == %d, want %d", got, want)) } + f1p := (*s[T]).g1 + if got := f1p(&x); got != want { + panic(fmt.Sprintf("f1p(&x) == %d, want %d", got, want)) + } f2 := s[T].g2 if got1, got2 := f2(x); got1 != want || got2 != want { panic(fmt.Sprintf("f2(x) == %d, %d, want %d, %d", got1, got2, want, want)) From b614c05a151ffc45b8eb5725c9df399aca20663d Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Mon, 5 Jul 2021 20:58:56 -0700 Subject: [PATCH 633/940] [dev.typeparams] cmd/compile: add built-in name/type "comparable". This allows exporting comparable type bounds, and importing back into types2 for typechecking. Fixes typeparam/mdempsky/8.go Change-Id: I3ee12433df2ed68ac6ef4cad24be9fcdfaaca4e3 Reviewed-on: https://go-review.googlesource.com/c/go/+/333129 Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Robert Griesemer Trust: Dan Scales --- src/cmd/compile/internal/importer/support.go | 2 ++ src/cmd/compile/internal/noder/types.go | 8 -------- src/cmd/compile/internal/typecheck/bexport.go | 2 ++ src/cmd/compile/internal/typecheck/universe.go | 15 +++++++++++++++ src/cmd/compile/internal/types/type.go | 2 ++ src/go/internal/gcimporter/support.go | 2 ++ test/run.go | 1 - 7 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/cmd/compile/internal/importer/support.go b/src/cmd/compile/internal/importer/support.go index 3d1f77afcd0..7eecae15a62 100644 --- a/src/cmd/compile/internal/importer/support.go +++ b/src/cmd/compile/internal/importer/support.go @@ -101,6 +101,8 @@ var predeclared = []types2.Type{ // error types2.Universe.Lookup("error").Type(), + // comparable + types2.Universe.Lookup("comparable").Type(), // untyped types types2.Typ[types2.UntypedBool], diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go index a0b7fea7cb1..d925f991c87 100644 --- a/src/cmd/compile/internal/noder/types.go +++ b/src/cmd/compile/internal/noder/types.go @@ -189,14 +189,6 @@ func (g *irgen) typ0(typ types2.Type) *types.Type { // With Go 1.18, an embedded element can be any type, not // just an interface. - if t := types2.AsInterface(e); t != nil { - if t.IsComparable() { - // Ignore predefined type 'comparable', since it - // doesn't resolve and it doesn't have any - // relevant methods. - continue - } - } embeddeds[j] = types.NewField(src.NoXPos, nil, g.typ1(e)) j++ } diff --git a/src/cmd/compile/internal/typecheck/bexport.go b/src/cmd/compile/internal/typecheck/bexport.go index 4a84bb13fa4..45d67f6ea23 100644 --- a/src/cmd/compile/internal/typecheck/bexport.go +++ b/src/cmd/compile/internal/typecheck/bexport.go @@ -78,6 +78,8 @@ func predeclared() []*types.Type { // error types.ErrorType, + // comparable + types.ComparableType, // untyped types types.UntypedBool, diff --git a/src/cmd/compile/internal/typecheck/universe.go b/src/cmd/compile/internal/typecheck/universe.go index de185ab9447..54f3c89c245 100644 --- a/src/cmd/compile/internal/typecheck/universe.go +++ b/src/cmd/compile/internal/typecheck/universe.go @@ -158,6 +158,15 @@ func InitUniverse() { s.Def = n types.CalcSize(types.ErrorType) + // comparable type (interface) + s = types.BuiltinPkg.Lookup("comparable") + n = ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, s) + types.ComparableType = types.NewNamed(n) + types.ComparableType.SetUnderlying(makeComparableInterface()) + n.SetType(types.ComparableType) + s.Def = n + types.CalcSize(types.ComparableType) + types.Types[types.TUNSAFEPTR] = defBasic(types.TUNSAFEPTR, ir.Pkgs.Unsafe, "Pointer") // simple aliases @@ -338,6 +347,12 @@ func makeErrorInterface() *types.Type { return types.NewInterface(types.NoPkg, []*types.Field{method}) } +func makeComparableInterface() *types.Type { + sig := types.NewSignature(types.NoPkg, fakeRecvField(), nil, nil, nil) + method := types.NewField(src.NoXPos, Lookup("=="), sig) + return types.NewInterface(types.NoPkg, []*types.Field{method}) +} + // DeclareUniverse makes the universe block visible within the current package. func DeclareUniverse() { // Operationally, this is similar to a dot import of builtinpkg, except diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index 7f750007972..28312111adb 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -123,6 +123,8 @@ var ( // Predeclared error interface type. ErrorType *Type + // Predeclared comparable interface type. + ComparableType *Type // Types to represent untyped string and boolean constants. UntypedString = New(TSTRING) diff --git a/src/go/internal/gcimporter/support.go b/src/go/internal/gcimporter/support.go index b8bb14dc490..bb2058172ac 100644 --- a/src/go/internal/gcimporter/support.go +++ b/src/go/internal/gcimporter/support.go @@ -104,6 +104,8 @@ var predeclared = []types.Type{ // error types.Universe.Lookup("error").Type(), + // comparable + types.Universe.Lookup("comparable").Type(), // untyped types types.Typ[types.UntypedBool], diff --git a/test/run.go b/test/run.go index 7afad0ec09c..713e2006dc0 100644 --- a/test/run.go +++ b/test/run.go @@ -2210,7 +2210,6 @@ var g3Failures = setOf( "typeparam/mdempsky/4.go", "typeparam/mdempsky/5.go", "typeparam/mdempsky/7.go", - "typeparam/mdempsky/8.go", "typeparam/mdempsky/9.go", "typeparam/mdempsky/11.go", "typeparam/mdempsky/12.go", From 501725032cb8e0fd5ef75b50f949dda09ce4b441 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Tue, 6 Jul 2021 09:38:58 -0700 Subject: [PATCH 634/940] [dev.typeparams] cmd/compile: handle derived types that are converted to interfaces Up to this point, we were only handling typeparams that were converted to empty or non-empty interfaces. But we have a dictionary entry for each derived type (i.e. type derived from typeparams) as well. So, when doing a conversion, look for the source type in both the type params and derived types of the generic info, and then use the appropriate dictionary entry. Added some cases to ifaceconv.go (e.g. converting []T to an empty interface). Change-Id: I7bbad0128bec20ccccd93ae1d65c1ffd44ca79a0 Reviewed-on: https://go-review.googlesource.com/c/go/+/333011 Trust: Dan Scales Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/noder/stencil.go | 60 +++++++++++++---------- test/typeparam/ifaceconv.go | 18 +++++++ 2 files changed, 52 insertions(+), 26 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 656cab84d17..ce9dc09bc3b 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -979,21 +979,14 @@ func getDictionaryEntry(pos src.XPos, dict *ir.Name, i int, size int) ir.Node { return r } -// getDictionaryType returns a *runtime._type from the dictionary corresponding to the input type. -// The input type must be a type parameter (TODO: or a local derived type). -func (subst *subster) getDictionaryType(pos src.XPos, t *types.Type) ir.Node { - tparams := subst.ts.Tparams - var i = 0 - for i = range tparams { - if t == tparams[i] { - break - } - } - if i == len(tparams) { - base.Fatalf(fmt.Sprintf("couldn't find type param %+v", t)) +// getDictionaryType returns a *runtime._type from the dictionary entry i +// (which refers to a type param or a derived type that uses type params). +func (subst *subster) getDictionaryType(pos src.XPos, i int) ir.Node { + if i < 0 || i >= subst.info.startSubDict { + base.Fatalf(fmt.Sprintf("bad dict index %d", i)) } - r := getDictionaryEntry(pos, subst.info.dictParam, i, len(tparams)) + r := getDictionaryEntry(pos, subst.info.dictParam, i, subst.info.startSubDict) // change type of retrieved dictionary entry to *byte, which is the // standard typing of a *runtime._type in the compiler typed(types.Types[types.TUINT8].PtrTo(), r) @@ -1134,11 +1127,12 @@ func (subst *subster) node(n ir.Node) ir.Node { // type argument. m = transformConvCall(call) if m.Op() == ir.OCONVIFACE { - if srcType := x.(*ir.CallExpr).Args[0].Type(); srcType.IsTypeParam() { // TODO: or derived type - // Note: srcType uses x.Args[0], not m.X or call.Args[0], because - // we need the type before the type parameter -> type argument substitution. + // Note: srcType uses x.Args[0], not m.X or call.Args[0], because + // we need the type before the type parameter -> type argument substitution. + srcType := x.(*ir.CallExpr).Args[0].Type() + if ix := subst.findDictType(srcType); ix >= 0 { c := m.(*ir.ConvExpr) - m = subst.convertUsingDictionary(c.Pos(), c.X, c.Type(), srcType) + m = subst.convertUsingDictionary(c.Pos(), c.X, c.Type(), srcType, ix) } } @@ -1240,8 +1234,9 @@ func (subst *subster) node(n ir.Node) ir.Node { x := x.(*ir.ConvExpr) // Note: x's argument is still typed as a type parameter. // m's argument now has an instantiated type. - if t := x.X.Type(); t.IsTypeParam() { - m = subst.convertUsingDictionary(x.Pos(), m.(*ir.ConvExpr).X, m.Type(), t) + t := x.X.Type() + if ix := subst.findDictType(t); ix >= 0 { + m = subst.convertUsingDictionary(x.Pos(), m.(*ir.ConvExpr).X, m.Type(), t, ix) } } return m @@ -1250,18 +1245,31 @@ func (subst *subster) node(n ir.Node) ir.Node { return edit(n) } -// convertUsingDictionary converts value v from generic type src to an interface type dst. -func (subst *subster) convertUsingDictionary(pos src.XPos, v ir.Node, dst, src *types.Type) ir.Node { - // TODO: handle converting from derived types. For now, just from naked - // type parameters. - if !src.IsTypeParam() { - base.Fatalf("source must be a type parameter %+v", src) +// findDictType looks for type t in the typeparams or derived types in the generic +// function info subst.info.gfInfo. This will indicate the dictionary entry with the +// correct concrete type for the associated instantiated function. +func (subst *subster) findDictType(t *types.Type) int { + for i, dt := range subst.info.gfInfo.tparams { + if dt == t { + return i + } } + for i, dt := range subst.info.gfInfo.derivedTypes { + if types.Identical(dt, t) { + return i + len(subst.info.gfInfo.tparams) + } + } + return -1 +} + +// convertUsingDictionary converts value v from instantiated type src (which is index +// 'ix' in the instantiation's dictionary) to an interface type dst. +func (subst *subster) convertUsingDictionary(pos src.XPos, v ir.Node, dst, src *types.Type, ix int) ir.Node { if !dst.IsInterface() { base.Fatalf("can only convert type parameters to interfaces %+v -> %+v", src, dst) } // Load the actual runtime._type of the type parameter from the dictionary. - rt := subst.getDictionaryType(pos, src) + rt := subst.getDictionaryType(pos, ix) // Convert value to an interface type, so the data field is what we want. if !v.Type().IsInterface() { diff --git a/test/typeparam/ifaceconv.go b/test/typeparam/ifaceconv.go index 32c2dbe7c28..f4023366b9e 100644 --- a/test/typeparam/ifaceconv.go +++ b/test/typeparam/ifaceconv.go @@ -18,6 +18,13 @@ func f[T any](x T) interface{} { var i interface{} = x return i } + +func fs[T any](x T) interface{} { + y := []T{x} + var i interface{} = y + return i +} + func g[T any](x T) E { var i E = x return i @@ -46,10 +53,18 @@ func j[T C](t T) C { return C(t) // explicit conversion } +func js[T any](x T) interface{} { + y := []T{x} + return interface{}(y) +} + func main() { if got, want := f[int](7), 7; got != want { panic(fmt.Sprintf("got %d want %d", got, want)) } + if got, want := fs[int](7), []int{7}; got.([]int)[0] != want[0] { + panic(fmt.Sprintf("got %d want %d", got, want)) + } if got, want := g[int](7), 7; got != want { panic(fmt.Sprintf("got %d want %d", got, want)) } @@ -62,4 +77,7 @@ func main() { if got, want := j[myInt](7).foo(), 8; got != want { panic(fmt.Sprintf("got %d want %d", got, want)) } + if got, want := js[int](7), []int{7}; got.([]int)[0] != want[0] { + panic(fmt.Sprintf("got %d want %d", got, want)) + } } From c65ca97a452f872516a7e9462cd27ac17d913747 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 7 Jul 2021 04:03:24 -0700 Subject: [PATCH 635/940] [dev.typeparams] cmd/compile: fix windows longtest builder CL 332469 broke the Windows longtest builders, because it changed the names assigned to autotmp variables that end up in export data. The naming of autotmps doesn't actually matter, so instead we can just hack iexport to write out "$autotmp" as a magic marker, and let the reader replace it with an appropriate unique name. This is a little hacky, but so is iexport's handling of autotmps already, and this should also go away eventually with unified IR. Change-Id: Ic17395337c745b66b9d63ee566299290214e6273 Reviewed-on: https://go-review.googlesource.com/c/go/+/333089 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky Reviewed-by: Cuong Manh Le TryBot-Result: Go Bot --- src/cmd/compile/internal/typecheck/iexport.go | 11 +++++++++-- src/cmd/compile/internal/typecheck/iimport.go | 12 ++++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index b717c373f5f..0a48078bd0f 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -2116,8 +2116,15 @@ func (w *exportWriter) localIdent(s *types.Sym) { return } - // TODO(mdempsky): Fix autotmp hack. - if i := strings.LastIndex(name, "."); i >= 0 && !strings.HasPrefix(name, ".autotmp_") && !strings.HasPrefix(name, ".dict") { // TODO: just use autotmp names for dictionaries? + // The name of autotmp variables isn't important; they just need to + // be unique. To stabilize the export data, simply write out "$" as + // a marker and let the importer generate its own unique name. + if strings.HasPrefix(name, ".autotmp_") { + w.string("$autotmp") + return + } + + if i := strings.LastIndex(name, "."); i >= 0 && !strings.HasPrefix(name, ".dict") { // TODO: just use autotmp names for dictionaries? base.Fatalf("unexpected dot in identifier: %v", name) } diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index f178869e285..7b7cd7f148d 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -265,6 +265,7 @@ type importReader struct { // Slice of all dcls for function, including any interior closures allDcls []*ir.Name allClosureVars []*ir.Name + autotmpgen int } func (p *iimporter) newReader(off uint64, pkg *types.Pkg) *importReader { @@ -516,8 +517,15 @@ func (r *importReader) ident(selector bool) *types.Sym { return nil } pkg := r.currPkg - if selector && types.IsExported(name) { - pkg = types.LocalPkg + if selector { + if types.IsExported(name) { + pkg = types.LocalPkg + } + } else { + if name == "$autotmp" { + name = autotmpname(r.autotmpgen) + r.autotmpgen++ + } } return pkg.Lookup(name) } From f264879f74efc8b9a9bcf4e04df0f8f5affa11a9 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Fri, 2 Jul 2021 14:00:49 -0400 Subject: [PATCH 636/940] cmd/go/internal/modload: fix an apparent typo in the AutoRoot comment Updates #40276 Change-Id: Ic192d51f9f0306e5c206c550ef02f6d4495d0851 Reviewed-on: https://go-review.googlesource.com/c/go/+/332569 Trust: Bryan C. Mills Reviewed-by: Jay Conrod --- src/cmd/go/internal/modload/init.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go index cbc7289afa5..09136b7de1a 100644 --- a/src/cmd/go/internal/modload/init.go +++ b/src/cmd/go/internal/modload/init.go @@ -71,7 +71,7 @@ type Root int const ( // AutoRoot is the default for most commands. modload.Init will look for // a go.mod file in the current directory or any parent. If none is found, - // modules may be disabled (GO111MODULE=on) or commands may run in a + // modules may be disabled (GO111MODULE=auto) or commands may run in a // limited module mode. AutoRoot Root = iota From 00c00558e1513d4f110f0b778242c965e7f6505a Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Fri, 2 Jul 2021 11:27:37 -0400 Subject: [PATCH 637/940] cmd/go/internal/modload: remove unused functions Also unexport functions that are not used outside the modload package. Change-Id: I0de187cbb673cadafce95a27f5ccff934ae21104 Reviewed-on: https://go-review.googlesource.com/c/go/+/332570 Trust: Bryan C. Mills Reviewed-by: Jay Conrod --- src/cmd/go/internal/modload/load.go | 37 ---------------------------- src/cmd/go/internal/modload/query.go | 4 +-- 2 files changed, 2 insertions(+), 39 deletions(-) diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go index a3a8021c049..771b142b73e 100644 --- a/src/cmd/go/internal/modload/load.go +++ b/src/cmd/go/internal/modload/load.go @@ -675,20 +675,6 @@ func DirImportPath(ctx context.Context, dir string) string { return "." } -// TargetPackages returns the list of packages in the target (top-level) module -// matching pattern, which may be relative to the working directory, under all -// build tag settings. -func TargetPackages(ctx context.Context, pattern string) *search.Match { - // TargetPackages is relative to the main module, so ensure that the main - // module is a thing that can contain packages. - LoadModFile(ctx) // Sets Target. - ModRoot() // Emits an error if Target cannot contain packages. - - m := search.NewMatch(pattern) - matchPackages(ctx, m, imports.AnyTags(), omitStd, []module.Version{Target}) - return m -} - // ImportMap returns the actual package import path // for an import path found in source code. // If the given import path does not appear in the source code @@ -720,29 +706,6 @@ func PackageModule(path string) module.Version { return pkg.mod } -// PackageImports returns the imports for the package named by the import path. -// Test imports will be returned as well if tests were loaded for the package -// (i.e., if "all" was loaded or if LoadTests was set and the path was matched -// by a command line argument). PackageImports will return nil for -// unknown package paths. -func PackageImports(path string) (imports, testImports []string) { - pkg, ok := loaded.pkgCache.Get(path).(*loadPkg) - if !ok { - return nil, nil - } - imports = make([]string, len(pkg.imports)) - for i, p := range pkg.imports { - imports[i] = p.path - } - if pkg.test != nil { - testImports = make([]string, len(pkg.test.imports)) - for i, p := range pkg.test.imports { - testImports[i] = p.path - } - } - return imports, testImports -} - // Lookup returns the source directory, import path, and any loading error for // the package at path as imported from the package in parentDir. // Lookup requires that one of the Load functions in this package has already diff --git a/src/cmd/go/internal/modload/query.go b/src/cmd/go/internal/modload/query.go index 6f6c6e8c98d..dda9004a9f4 100644 --- a/src/cmd/go/internal/modload/query.go +++ b/src/cmd/go/internal/modload/query.go @@ -920,8 +920,8 @@ func (e *PackageNotInModuleError) ImportPath() string { return "" } -// ModuleHasRootPackage returns whether module m contains a package m.Path. -func ModuleHasRootPackage(ctx context.Context, m module.Version) (bool, error) { +// moduleHasRootPackage returns whether module m contains a package m.Path. +func moduleHasRootPackage(ctx context.Context, m module.Version) (bool, error) { needSum := false root, isLocal, err := fetch(ctx, m, needSum) if err != nil { From 186a3bb4b0939837c855a4f0689d4a4401aff608 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Fri, 25 Jun 2021 12:49:51 -0400 Subject: [PATCH 638/940] cmd/go/internal/modfetch/codehost: skip hg tests if no hg binary is present Change-Id: I5cf57bf1153eb662bcab71e3d2c04848212559a6 Reviewed-on: https://go-review.googlesource.com/c/go/+/330989 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Jay Conrod --- .../go/internal/modfetch/codehost/git_test.go | 49 +++++++++---------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/src/cmd/go/internal/modfetch/codehost/git_test.go b/src/cmd/go/internal/modfetch/codehost/git_test.go index 89a73baad9d..a684fa1a9bb 100644 --- a/src/cmd/go/internal/modfetch/codehost/git_test.go +++ b/src/cmd/go/internal/modfetch/codehost/git_test.go @@ -8,7 +8,6 @@ import ( "archive/zip" "bytes" "flag" - "fmt" "internal/testenv" "io" "io/fs" @@ -47,12 +46,6 @@ var altRepos = []string{ var localGitRepo string func testMain(m *testing.M) int { - if _, err := exec.LookPath("git"); err != nil { - fmt.Fprintln(os.Stderr, "skipping because git binary not found") - fmt.Println("PASS") - return 0 - } - dir, err := os.MkdirTemp("", "gitrepo-test-") if err != nil { log.Fatal(err) @@ -60,23 +53,25 @@ func testMain(m *testing.M) int { defer os.RemoveAll(dir) if testenv.HasExternalNetwork() && testenv.HasExec() { - // Clone gitrepo1 into a local directory. - // If we use a file:// URL to access the local directory, - // then git starts up all the usual protocol machinery, - // which will let us test remote git archive invocations. - localGitRepo = filepath.Join(dir, "gitrepo2") - if _, err := Run("", "git", "clone", "--mirror", gitrepo1, localGitRepo); err != nil { - log.Fatal(err) - } - if _, err := Run(localGitRepo, "git", "config", "daemon.uploadarch", "true"); err != nil { - log.Fatal(err) + if _, err := exec.LookPath("git"); err == nil { + // Clone gitrepo1 into a local directory. + // If we use a file:// URL to access the local directory, + // then git starts up all the usual protocol machinery, + // which will let us test remote git archive invocations. + localGitRepo = filepath.Join(dir, "gitrepo2") + if _, err := Run("", "git", "clone", "--mirror", gitrepo1, localGitRepo); err != nil { + log.Fatal(err) + } + if _, err := Run(localGitRepo, "git", "config", "daemon.uploadarch", "true"); err != nil { + log.Fatal(err) + } } } return m.Run() } -func testRepo(remote string) (Repo, error) { +func testRepo(t *testing.T, remote string) (Repo, error) { if remote == "localGitRepo" { // Convert absolute path to file URL. LocalGitRepo will not accept // Windows absolute paths because they look like a host:path remote. @@ -87,15 +82,17 @@ func testRepo(remote string) (Repo, error) { } else { url = "file:///" + filepath.ToSlash(localGitRepo) } + testenv.MustHaveExecPath(t, "git") return LocalGitRepo(url) } - kind := "git" + vcs := "git" for _, k := range []string{"hg"} { if strings.Contains(remote, "/"+k+"/") { - kind = k + vcs = k } } - return NewRepo(kind, remote) + testenv.MustHaveExecPath(t, vcs) + return NewRepo(vcs, remote) } var tagsTests = []struct { @@ -116,7 +113,7 @@ func TestTags(t *testing.T) { for _, tt := range tagsTests { f := func(t *testing.T) { - r, err := testRepo(tt.repo) + r, err := testRepo(t, tt.repo) if err != nil { t.Fatal(err) } @@ -168,7 +165,7 @@ func TestLatest(t *testing.T) { for _, tt := range latestTests { f := func(t *testing.T) { - r, err := testRepo(tt.repo) + r, err := testRepo(t, tt.repo) if err != nil { t.Fatal(err) } @@ -221,7 +218,7 @@ func TestReadFile(t *testing.T) { for _, tt := range readFileTests { f := func(t *testing.T) { - r, err := testRepo(tt.repo) + r, err := testRepo(t, tt.repo) if err != nil { t.Fatal(err) } @@ -412,7 +409,7 @@ func TestReadZip(t *testing.T) { for _, tt := range readZipTests { f := func(t *testing.T) { - r, err := testRepo(tt.repo) + r, err := testRepo(t, tt.repo) if err != nil { t.Fatal(err) } @@ -581,7 +578,7 @@ func TestStat(t *testing.T) { for _, tt := range statTests { f := func(t *testing.T) { - r, err := testRepo(tt.repo) + r, err := testRepo(t, tt.repo) if err != nil { t.Fatal(err) } From 991fd381d52e7cec37ab54732613d3e465916206 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Tue, 6 Jul 2021 10:38:18 -0700 Subject: [PATCH 639/940] cmd/go: don't lock .mod and .sum files for read in overlay On Plan 9, locking a file requires a chmod call. In general, the go command should not modify files in the overlay, even metadata. With this change, we won't lock these files for reading. The go command already reported errors when attempting to write these files if they were in the overlay, but this change moves those checks to the point of access for clearer error messages. cmd/go/internal/lockedfile no longer imports cmd/go/internal/fsys. Fixes #44700 Change-Id: Ib544459dd6cf56ca0f7a27b3285f045f08040d7e Reviewed-on: https://go-review.googlesource.com/c/go/+/333012 Trust: Jay Conrod Run-TryBot: Jay Conrod TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills --- .../internal/lockedfile/lockedfile_filelock.go | 3 +-- .../go/internal/lockedfile/lockedfile_plan9.go | 6 ++---- src/cmd/go/internal/modfetch/fetch.go | 17 ++++++++++++++++- src/cmd/go/internal/modload/init.go | 18 +++++++++++++++++- src/cmd/go/internal/modload/modfile.go | 14 ++++++++++++-- src/cmd/go/testdata/script/mod_overlay.txt | 10 +++++----- 6 files changed, 53 insertions(+), 15 deletions(-) diff --git a/src/cmd/go/internal/lockedfile/lockedfile_filelock.go b/src/cmd/go/internal/lockedfile/lockedfile_filelock.go index 729df5c681c..e4923f68764 100644 --- a/src/cmd/go/internal/lockedfile/lockedfile_filelock.go +++ b/src/cmd/go/internal/lockedfile/lockedfile_filelock.go @@ -11,7 +11,6 @@ import ( "io/fs" "os" - "cmd/go/internal/fsys" "cmd/go/internal/lockedfile/internal/filelock" ) @@ -21,7 +20,7 @@ func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) { // calls for Linux and Windows anyway, so it's simpler to use that approach // consistently. - f, err := fsys.OpenFile(name, flag&^os.O_TRUNC, perm) + f, err := os.OpenFile(name, flag&^os.O_TRUNC, perm) if err != nil { return nil, err } diff --git a/src/cmd/go/internal/lockedfile/lockedfile_plan9.go b/src/cmd/go/internal/lockedfile/lockedfile_plan9.go index 3d4b97d78e5..979118b10ae 100644 --- a/src/cmd/go/internal/lockedfile/lockedfile_plan9.go +++ b/src/cmd/go/internal/lockedfile/lockedfile_plan9.go @@ -13,8 +13,6 @@ import ( "os" "strings" "time" - - "cmd/go/internal/fsys" ) // Opening an exclusive-use file returns an error. @@ -59,7 +57,7 @@ func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) { // If the file was unpacked or created by some other program, it might not // have the ModeExclusive bit set. Set it before we call OpenFile, so that we // can be confident that a successful OpenFile implies exclusive use. - if fi, err := fsys.Stat(name); err == nil { + if fi, err := os.Stat(name); err == nil { if fi.Mode()&fs.ModeExclusive == 0 { if err := os.Chmod(name, fi.Mode()|fs.ModeExclusive); err != nil { return nil, err @@ -72,7 +70,7 @@ func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) { nextSleep := 1 * time.Millisecond const maxSleep = 500 * time.Millisecond for { - f, err := fsys.OpenFile(name, flag, perm|fs.ModeExclusive) + f, err := os.OpenFile(name, flag, perm|fs.ModeExclusive) if err == nil { return f, nil } diff --git a/src/cmd/go/internal/modfetch/fetch.go b/src/cmd/go/internal/modfetch/fetch.go index e40593abae8..d3d30d970b3 100644 --- a/src/cmd/go/internal/modfetch/fetch.go +++ b/src/cmd/go/internal/modfetch/fetch.go @@ -22,6 +22,7 @@ import ( "cmd/go/internal/base" "cmd/go/internal/cfg" + "cmd/go/internal/fsys" "cmd/go/internal/lockedfile" "cmd/go/internal/par" "cmd/go/internal/robustio" @@ -416,7 +417,18 @@ func initGoSum() (bool, error) { goSum.m = make(map[module.Version][]string) goSum.status = make(map[modSum]modSumStatus) - data, err := lockedfile.Read(GoSumFile) + var ( + data []byte + err error + ) + if actualSumFile, ok := fsys.OverlayPath(GoSumFile); ok { + // Don't lock go.sum if it's part of the overlay. + // On Plan 9, locking requires chmod, and we don't want to modify any file + // in the overlay. See #44700. + data, err = os.ReadFile(actualSumFile) + } else { + data, err = lockedfile.Read(GoSumFile) + } if err != nil && !os.IsNotExist(err) { return false, err } @@ -716,6 +728,9 @@ Outer: if cfg.BuildMod == "readonly" { base.Fatalf("go: updates to go.sum needed, disabled by -mod=readonly") } + if _, ok := fsys.OverlayPath(GoSumFile); ok { + base.Fatalf("go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay") + } // Make a best-effort attempt to acquire the side lock, only to exclude // previous versions of the 'go' command from making simultaneous edits. diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go index 09136b7de1a..a8cbd9fe16d 100644 --- a/src/cmd/go/internal/modload/init.go +++ b/src/cmd/go/internal/modload/init.go @@ -412,7 +412,16 @@ func loadModFile(ctx context.Context) (rs *Requirements, needCommit bool) { } gomod := ModFilePath() - data, err := lockedfile.Read(gomod) + var data []byte + var err error + if gomodActual, ok := fsys.OverlayPath(gomod); ok { + // Don't lock go.mod if it's part of the overlay. + // On Plan 9, locking requires chmod, and we don't want to modify any file + // in the overlay. See #44700. + data, err = os.ReadFile(gomodActual) + } else { + data, err = lockedfile.Read(gomodActual) + } if err != nil { base.Fatalf("go: %v", err) } @@ -1026,6 +1035,13 @@ func commitRequirements(ctx context.Context, goVersion string, rs *Requirements) } return } + gomod := ModFilePath() + if _, ok := fsys.OverlayPath(gomod); ok { + if dirty { + base.Fatalf("go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay") + } + return + } new, err := modFile.Format() if err != nil { diff --git a/src/cmd/go/internal/modload/modfile.go b/src/cmd/go/internal/modload/modfile.go index 1145ac4ba59..d280945ea63 100644 --- a/src/cmd/go/internal/modload/modfile.go +++ b/src/cmd/go/internal/modload/modfile.go @@ -8,6 +8,7 @@ import ( "context" "errors" "fmt" + "os" "path/filepath" "strings" "sync" @@ -15,6 +16,7 @@ import ( "cmd/go/internal/base" "cmd/go/internal/cfg" + "cmd/go/internal/fsys" "cmd/go/internal/lockedfile" "cmd/go/internal/modfetch" "cmd/go/internal/par" @@ -601,8 +603,16 @@ func rawGoModSummary(m module.Version) (*modFileSummary, error) { dir = filepath.Join(ModRoot(), dir) } gomod := filepath.Join(dir, "go.mod") - - data, err := lockedfile.Read(gomod) + var data []byte + var err error + if gomodActual, ok := fsys.OverlayPath(gomod); ok { + // Don't lock go.mod if it's part of the overlay. + // On Plan 9, locking requires chmod, and we don't want to modify any file + // in the overlay. See #44700. + data, err = os.ReadFile(gomodActual) + } else { + data, err = lockedfile.Read(gomodActual) + } if err != nil { return cached{nil, module.VersionError(m, fmt.Errorf("reading %s: %v", base.ShortPath(gomod), err))} } diff --git a/src/cmd/go/testdata/script/mod_overlay.txt b/src/cmd/go/testdata/script/mod_overlay.txt index 92e79c725a3..86ab04bd3cf 100644 --- a/src/cmd/go/testdata/script/mod_overlay.txt +++ b/src/cmd/go/testdata/script/mod_overlay.txt @@ -21,7 +21,7 @@ go list -deps -overlay overlay.json . cd $WORK/gopath/src/get-doesnt-add-dep cp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod ! go get -d -overlay overlay.json . -stderr 'overlaid files can''t be opened for write' +stderr '^go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay$' cmp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod # Content of overlaid go.sum is used. @@ -41,10 +41,10 @@ go mod verify -overlay overlay.json # attempting to update the file cp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums ! go get -d -overlay overlay.json . -stderr 'overlaid files can''t be opened for write' +stderr '^go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay$' cmp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums ! go mod tidy -overlay overlay.json -stderr 'overlaid files can''t be opened for write' +stderr '^go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay$' cmp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums # -overlay works with -modfile. @@ -56,7 +56,7 @@ go list -modfile=alternate.mod -overlay overlay.json . stdout 'found.the/module' # Even with -modfile, overlaid files can't be opened for write. ! go get -modfile=alternate.mod -overlay overlay.json -d rsc.io/quote -stderr 'overlaid files can''t be opened for write' +stderr '^go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay$' # Carving out a module by adding an overlaid go.mod file cd $WORK/gopath/src/carve @@ -78,7 +78,7 @@ go list -overlay overlay.json all stdout ^carve2/nomod$ # Editing go.mod file fails because overlay is read only ! go get -overlay overlay.json -d rsc.io/quote -stderr 'overlaid files can''t be opened for write' +stderr '^go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay$' ! grep rsc.io/quote $WORK/overlay/carve2-nomod-go.mod # Editing go.mod file succeeds because we use -modfile to redirect to same file go get -overlay overlay.json -modfile $WORK/overlay/carve2-nomod-go.mod -d rsc.io/quote From 11f5df2d6703b3fbd61a256e4e32ba67d835e7ad Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 7 Jul 2021 12:11:37 -0700 Subject: [PATCH 640/940] cmd/compile: extract pkgqual from symfmt The logic in symfmt for deciding how to package-qualify an identifier is easily refactored into a separate function, loosely similar to go/types.Qualifier's API. Passes toolstash -cmp. Updates #47087. Change-Id: Ib3e7cc35a6577dc28df8eca79ba3457c48168e86 Reviewed-on: https://go-review.googlesource.com/c/go/+/333161 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types/fmt.go | 43 +++++++++++++-------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/src/cmd/compile/internal/types/fmt.go b/src/cmd/compile/internal/types/fmt.go index b538ea80542..0ce423dae70 100644 --- a/src/cmd/compile/internal/types/fmt.go +++ b/src/cmd/compile/internal/types/fmt.go @@ -137,47 +137,44 @@ func sconv2(b *bytes.Buffer, s *Sym, verb rune, mode fmtMode) { } func symfmt(b *bytes.Buffer, s *Sym, verb rune, mode fmtMode) { + if q := pkgqual(s.Pkg, verb, mode); q != "" { + b.WriteString(q) + b.WriteByte('.') + } + b.WriteString(s.Name) +} + +// pkgqual returns the qualifier that should be used for printing +// symbols from the given package in the given mode. +// If it returns the empty string, no qualification is needed. +func pkgqual(pkg *Pkg, verb rune, mode fmtMode) string { if verb != 'S' { switch mode { case fmtGo: // This is for the user - if s.Pkg == BuiltinPkg || s.Pkg == LocalPkg { - b.WriteString(s.Name) - return + if pkg == BuiltinPkg || pkg == LocalPkg { + return "" } // If the name was used by multiple packages, display the full path, - if s.Pkg.Name != "" && NumImport[s.Pkg.Name] > 1 { - fmt.Fprintf(b, "%q.%s", s.Pkg.Path, s.Name) - return + if pkg.Name != "" && NumImport[pkg.Name] > 1 { + return strconv.Quote(pkg.Path) } - b.WriteString(s.Pkg.Name) - b.WriteByte('.') - b.WriteString(s.Name) - return + return pkg.Name case fmtDebug: - b.WriteString(s.Pkg.Name) - b.WriteByte('.') - b.WriteString(s.Name) - return + return pkg.Name case fmtTypeIDName: // dcommontype, typehash - b.WriteString(s.Pkg.Name) - b.WriteByte('.') - b.WriteString(s.Name) - return + return pkg.Name case fmtTypeID: // (methodsym), typesym, weaksym - b.WriteString(s.Pkg.Prefix) - b.WriteByte('.') - b.WriteString(s.Name) - return + return pkg.Prefix } } - b.WriteString(s.Name) + return "" } // Type From b003a8b1ae26fa684ec35eb7543efa1ded1bcae7 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 7 Jul 2021 12:33:40 -0700 Subject: [PATCH 641/940] cmd/compile: optimize types.sconv Now that symfmt is simpler, we can simply manually inline it into sconv. Importantly, this allows us to avoid allocating a buffer + writing a string + re-interning it when we don't need to qualify the identifier. Passes toolstash -cmp. Updates #47087. Change-Id: I47b57aef22301ba242556a645346f478f0c1a7d1 Reviewed-on: https://go-review.googlesource.com/c/go/+/333162 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types/fmt.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/types/fmt.go b/src/cmd/compile/internal/types/fmt.go index 0ce423dae70..7b284aa6614 100644 --- a/src/cmd/compile/internal/types/fmt.go +++ b/src/cmd/compile/internal/types/fmt.go @@ -112,11 +112,19 @@ func sconv(s *Sym, verb rune, mode fmtMode) string { if s.Name == "_" { return "_" } + + q := pkgqual(s.Pkg, verb, mode) + if q == "" { + return s.Name + } + buf := fmtBufferPool.Get().(*bytes.Buffer) buf.Reset() defer fmtBufferPool.Put(buf) - symfmt(buf, s, verb, mode) + buf.WriteString(q) + buf.WriteByte('.') + buf.WriteString(s.Name) return InternString(buf.Bytes()) } From 5c59e11f5e1fe2e6d5b684f9a348022c07807126 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 7 Jul 2021 13:18:42 -0700 Subject: [PATCH 642/940] cmd/compile: remove special-casing of blank in types.sconv{,2} I'm not sure why blank was special-cased here before, but it's wrong. Blank is a non-exported identifier, and writing it out without package-qualification can result in linker symbol collisions. Fixes #47087. Change-Id: Ie600037c8e54e3d4fdaeec21e2ca212badbd830b Reviewed-on: https://go-review.googlesource.com/c/go/+/333163 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types/fmt.go | 8 -------- test/fixedbugs/issue47087.dir/a.go | 9 +++++++++ test/fixedbugs/issue47087.dir/b.go | 9 +++++++++ test/fixedbugs/issue47087.dir/main.go | 19 +++++++++++++++++++ test/fixedbugs/issue47087.go | 7 +++++++ 5 files changed, 44 insertions(+), 8 deletions(-) create mode 100644 test/fixedbugs/issue47087.dir/a.go create mode 100644 test/fixedbugs/issue47087.dir/b.go create mode 100644 test/fixedbugs/issue47087.dir/main.go create mode 100644 test/fixedbugs/issue47087.go diff --git a/src/cmd/compile/internal/types/fmt.go b/src/cmd/compile/internal/types/fmt.go index 7b284aa6614..8b988952a78 100644 --- a/src/cmd/compile/internal/types/fmt.go +++ b/src/cmd/compile/internal/types/fmt.go @@ -109,10 +109,6 @@ func sconv(s *Sym, verb rune, mode fmtMode) string { return "" } - if s.Name == "_" { - return "_" - } - q := pkgqual(s.Pkg, verb, mode) if q == "" { return s.Name @@ -136,10 +132,6 @@ func sconv2(b *bytes.Buffer, s *Sym, verb rune, mode fmtMode) { b.WriteString("") return } - if s.Name == "_" { - b.WriteString("_") - return - } symfmt(b, s, verb, mode) } diff --git a/test/fixedbugs/issue47087.dir/a.go b/test/fixedbugs/issue47087.dir/a.go new file mode 100644 index 00000000000..6093092acee --- /dev/null +++ b/test/fixedbugs/issue47087.dir/a.go @@ -0,0 +1,9 @@ +// Copyright 2021 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 a + +func F() interface{} { return struct{ _ []int }{} } + +var X = F() diff --git a/test/fixedbugs/issue47087.dir/b.go b/test/fixedbugs/issue47087.dir/b.go new file mode 100644 index 00000000000..8f96d25a12b --- /dev/null +++ b/test/fixedbugs/issue47087.dir/b.go @@ -0,0 +1,9 @@ +// Copyright 2021 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 b + +func F() interface{} { return struct{ _ []int }{} } + +var X = F() diff --git a/test/fixedbugs/issue47087.dir/main.go b/test/fixedbugs/issue47087.dir/main.go new file mode 100644 index 00000000000..ccd0891a61a --- /dev/null +++ b/test/fixedbugs/issue47087.dir/main.go @@ -0,0 +1,19 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "a" + "b" +) + +func main() { + if a.F() == b.F() { + panic("FAIL") + } + if a.X == b.X { + panic("FAIL") + } +} diff --git a/test/fixedbugs/issue47087.go b/test/fixedbugs/issue47087.go new file mode 100644 index 00000000000..40df49f83be --- /dev/null +++ b/test/fixedbugs/issue47087.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 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 ignored From 85267f402c3ba7ec91a3cf5e4e4a763fd1137deb Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Wed, 7 Jul 2021 14:42:26 -0700 Subject: [PATCH 643/940] [dev.typeparams] cmd/compile: move def of comparable to end of predeclared slices This avoids changing the export ABI. Change-Id: I58950c1f4c21859d91d66d352b88e8c0972b5b8c Reviewed-on: https://go-review.googlesource.com/c/go/+/333164 Trust: Dan Scales Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/importer/support.go | 5 +++-- src/cmd/compile/internal/typecheck/bexport.go | 5 +++-- src/go/internal/gcimporter/support.go | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/cmd/compile/internal/importer/support.go b/src/cmd/compile/internal/importer/support.go index 7eecae15a62..6ceb413601f 100644 --- a/src/cmd/compile/internal/importer/support.go +++ b/src/cmd/compile/internal/importer/support.go @@ -101,8 +101,6 @@ var predeclared = []types2.Type{ // error types2.Universe.Lookup("error").Type(), - // comparable - types2.Universe.Lookup("comparable").Type(), // untyped types types2.Typ[types2.UntypedBool], @@ -121,6 +119,9 @@ var predeclared = []types2.Type{ // used internally by gc; never used by this package or in .a files anyType{}, + + // comparable + types2.Universe.Lookup("comparable").Type(), } type anyType struct{} diff --git a/src/cmd/compile/internal/typecheck/bexport.go b/src/cmd/compile/internal/typecheck/bexport.go index 45d67f6ea23..cc7f91f9372 100644 --- a/src/cmd/compile/internal/typecheck/bexport.go +++ b/src/cmd/compile/internal/typecheck/bexport.go @@ -78,8 +78,6 @@ func predeclared() []*types.Type { // error types.ErrorType, - // comparable - types.ComparableType, // untyped types types.UntypedBool, @@ -98,6 +96,9 @@ func predeclared() []*types.Type { // any type, for builtin export data types.Types[types.TANY], + + // comparable + types.ComparableType, } } return predecl diff --git a/src/go/internal/gcimporter/support.go b/src/go/internal/gcimporter/support.go index bb2058172ac..09810dd85b8 100644 --- a/src/go/internal/gcimporter/support.go +++ b/src/go/internal/gcimporter/support.go @@ -104,8 +104,6 @@ var predeclared = []types.Type{ // error types.Universe.Lookup("error").Type(), - // comparable - types.Universe.Lookup("comparable").Type(), // untyped types types.Typ[types.UntypedBool], @@ -124,6 +122,9 @@ var predeclared = []types.Type{ // used internally by gc; never used by this package or in .a files anyType{}, + + // comparable + types.Universe.Lookup("comparable").Type(), } type anyType struct{} From 60cb2cab97ca6a28dcb4a58776ed85f840f534d5 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Wed, 7 Jul 2021 12:03:41 -0700 Subject: [PATCH 644/940] [dev.typeparams] cmd/compile: fix bug with types2.Instantiate with interface type param types2.subst has an assertion that check is non-nil, but which breaks Instantiate() with an interface type param (used when re-importing instatiated type to types2). But this check was added when Instantiate() was added, and things seem to work fine when the assertion is removed. Fixes test/typeparam/mdempsky/7.go. Change-Id: I4980f0b202a0b310a3c91a7a87f97576f54911de Reviewed-on: https://go-review.googlesource.com/c/go/+/333155 Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Robert Griesemer Trust: Dan Scales --- src/cmd/compile/internal/types2/subst.go | 3 --- test/run.go | 1 - 2 files changed, 4 deletions(-) diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index db01c36f7ad..7b4796fa2eb 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -313,9 +313,6 @@ func (subst *subster) typ(typ Type) Type { embeddeds, ecopied := subst.typeList(t.embeddeds) if mcopied || ecopied { iface := &Interface{methods: methods, embeddeds: embeddeds, complete: t.complete} - if subst.check == nil { - panic("internal error: cannot instantiate interfaces yet") - } return iface } diff --git a/test/run.go b/test/run.go index 713e2006dc0..0251dc1c6a4 100644 --- a/test/run.go +++ b/test/run.go @@ -2209,7 +2209,6 @@ var g3Failures = setOf( "typeparam/mdempsky/3.go", "typeparam/mdempsky/4.go", "typeparam/mdempsky/5.go", - "typeparam/mdempsky/7.go", "typeparam/mdempsky/9.go", "typeparam/mdempsky/11.go", "typeparam/mdempsky/12.go", From 47547d8508ab416e28992e0e0965c9c25f840848 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 1 Jul 2021 22:10:01 -0700 Subject: [PATCH 645/940] [dev.typeparams] cmd/compile/internal/types2: disallow "free" type parameter as RHS of a type declaration For #45639. Change-Id: I20e331b04f464db81e916af75f70ec8ae73eb989 Reviewed-on: https://go-review.googlesource.com/c/go/+/332411 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/decl.go | 70 ++++++++++--------- .../types2/testdata/examples/types.go2 | 48 ++++++++----- .../types2/testdata/fixedbugs/issue45639.go2 | 12 ++++ src/cmd/compile/internal/types2/unify.go | 15 ++-- 4 files changed, 89 insertions(+), 56 deletions(-) create mode 100644 src/cmd/compile/internal/types2/testdata/fixedbugs/issue45639.go2 diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go index d36da06f421..4f91bc70c78 100644 --- a/src/cmd/compile/internal/types2/decl.go +++ b/src/cmd/compile/internal/types2/decl.go @@ -626,8 +626,8 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named alias = false } + // alias declaration if alias { - // type alias declaration if !check.allowVersion(check.pkg, 1, 9) { if check.conf.CompilerErrorMessages { check.error(tdecl, "type aliases only supported as of -lang=go1.9") @@ -638,40 +638,44 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named obj.typ = Typ[Invalid] obj.typ = check.anyType(tdecl.Type) - - } else { - // defined type declaration - - named := check.newNamed(obj, nil, nil, nil, nil) - def.setUnderlying(named) - - if tdecl.TParamList != nil { - check.openScope(tdecl, "type parameters") - defer check.closeScope() - named.tparams = check.collectTypeParams(tdecl.TParamList) - } - - // determine underlying type of named - named.fromRHS = check.definedType(tdecl.Type, named) - - // The underlying type of named may be itself a named type that is - // incomplete: - // - // type ( - // A B - // B *C - // C A - // ) - // - // The type of C is the (named) type of A which is incomplete, - // and which has as its underlying type the named type B. - // Determine the (final, unnamed) underlying type by resolving - // any forward chain. - // TODO(gri) Investigate if we can just use named.fromRHS here - // and rely on lazy computation of the underlying type. - named.underlying = under(named) + return } + // type definition or generic type declaration + named := check.newNamed(obj, nil, nil, nil, nil) + def.setUnderlying(named) + + if tdecl.TParamList != nil { + check.openScope(tdecl, "type parameters") + defer check.closeScope() + named.tparams = check.collectTypeParams(tdecl.TParamList) + } + + // determine underlying type of named + named.fromRHS = check.definedType(tdecl.Type, named) + + // The underlying type of named may be itself a named type that is + // incomplete: + // + // type ( + // A B + // B *C + // C A + // ) + // + // The type of C is the (named) type of A which is incomplete, + // and which has as its underlying type the named type B. + // Determine the (final, unnamed) underlying type by resolving + // any forward chain. + // TODO(gri) Investigate if we can just use named.fromRHS here + // and rely on lazy computation of the underlying type. + named.underlying = under(named) + + // If the RHS is a type parameter, it must be from this type declaration. + if tpar, _ := named.underlying.(*TypeParam); tpar != nil && tparamIndex(named.tparams, tpar) < 0 { + check.errorf(tdecl.Type, "cannot use function type parameter %s as RHS in type declaration", tpar) + named.underlying = Typ[Invalid] + } } func (check *Checker) collectTypeParams(list []*syntax.Field) []*TypeName { diff --git a/src/cmd/compile/internal/types2/testdata/examples/types.go2 b/src/cmd/compile/internal/types2/testdata/examples/types.go2 index 66e7a7b90e1..4ecc34dfa45 100644 --- a/src/cmd/compile/internal/types2/testdata/examples/types.go2 +++ b/src/cmd/compile/internal/types2/testdata/examples/types.go2 @@ -155,30 +155,40 @@ type _ struct { List /* ERROR List redeclared */ [int] } +// Issue #45639: We don't allow this anymore. Keep this code +// in case we decide to revisit this decision. +// // It's possible to declare local types whose underlying types // are type parameters. As with ordinary type definitions, the // types underlying properties are "inherited" but the methods // are not. -func _[T interface{ m(); ~int }]() { - type L T - var x L +// func _[T interface{ m(); ~int }]() { +// type L T +// var x L +// +// // m is not defined on L (it is not "inherited" from +// // its underlying type). +// x.m /* ERROR x.m undefined */ () +// +// // But the properties of T, such that as that it supports +// // the operations of the types given by its type bound, +// // are also the properties of L. +// x++ +// _ = x - x +// +// // On the other hand, if we define a local alias for T, +// // that alias stands for T as expected. +// type A = T +// var y A +// y.m() +// _ = y < 0 +// } - // m is not defined on L (it is not "inherited" from - // its underlying type). - x.m /* ERROR x.m undefined */ () - - // But the properties of T, such that as that it supports - // the operations of the types given by its type bound, - // are also the properties of L. - x++ - _ = x - x - - // On the other hand, if we define a local alias for T, - // that alias stands for T as expected. - type A = T - var y A - y.m() - _ = y < 0 +// It is not permitted to declare a local type whose underlying +// type is a type parameters not declared by that type declaration. +func _[T any]() { + type _ T // ERROR cannot use function type parameter T as RHS in type declaration + type _ [_ any] T // ERROR cannot use function type parameter T as RHS in type declaration } // As a special case, an explicit type argument may be omitted diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45639.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45639.go2 new file mode 100644 index 00000000000..441fb4cb346 --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45639.go2 @@ -0,0 +1,12 @@ +// Copyright 2021 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 + +// It is not permitted to declare a local type whose underlying +// type is a type parameters not declared by that type declaration. +func _[T any]() { + type _ T // ERROR cannot use function type parameter T as RHS in type declaration + type _ [_ any] T // ERROR cannot use function type parameter T as RHS in type declaration +} diff --git a/src/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go index 4e1f8322030..755622738a6 100644 --- a/src/cmd/compile/internal/types2/unify.go +++ b/src/cmd/compile/internal/types2/unify.go @@ -150,10 +150,17 @@ func (u *unifier) join(i, j int) bool { // If typ is a type parameter of d, index returns the type parameter index. // Otherwise, the result is < 0. func (d *tparamsList) index(typ Type) int { - if t, ok := typ.(*TypeParam); ok { - if i := t.index; i < len(d.tparams) && d.tparams[i].typ == t { - return i - } + if tpar, ok := typ.(*TypeParam); ok { + return tparamIndex(d.tparams, tpar) + } + return -1 +} + +// If tpar is a type parameter in list, tparamIndex returns the type parameter index. +// Otherwise, the result is < 0. tpar must not be nil. +func tparamIndex(list []*TypeName, tpar *TypeParam) int { + if i := tpar.index; i < len(list) && list[i].typ == tpar { + return i } return -1 } From 03ec8de24b6fc8a2abeb4013ef603f5cdef9f874 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 2 Jul 2021 15:41:28 -0700 Subject: [PATCH 646/940] [dev.typeparams] cmd/compile/internal/types2: clean up index expr implementation for type parameters This makes the implementation match the intended spec behavior: Given an index expression a[x] where a is a type parameter, the index expression is valid if the constraint for a satisfies the following criteria: - Either all types in the constraint type set are maps, or none of them are. - If the (type set) types are maps, they must all have the same key type. (This may be too strict, perhaps it's sufficient to ensure assignability, but we can always relax that later.) - All (type set) types must have the same element types. - If there are any arrays, a constant index must be in range for the shortest array. Change-Id: I8c094c11e6fc9496c293871ccf93e3814c881e6f Reviewed-on: https://go-review.googlesource.com/c/go/+/332553 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/index.go | 129 +++++++++--------- .../types2/testdata/check/typeparams.go2 | 17 ++- .../types2/testdata/fixedbugs/issue45635.go2 | 5 +- src/cmd/compile/internal/types2/typeparam.go | 7 + src/cmd/compile/internal/types2/typeset.go | 15 ++ src/cmd/compile/internal/types2/typestring.go | 2 +- src/cmd/compile/internal/types2/union.go | 2 +- 7 files changed, 98 insertions(+), 79 deletions(-) diff --git a/src/cmd/compile/internal/types2/index.go b/src/cmd/compile/internal/types2/index.go index 47e0853a3b0..5a4dcb47417 100644 --- a/src/cmd/compile/internal/types2/index.go +++ b/src/cmd/compile/internal/types2/index.go @@ -41,7 +41,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo // ordinary index expression valid := false length := int64(-1) // valid if >= 0 - switch typ := optype(x.typ).(type) { + switch typ := under(x.typ).(type) { case *Basic: if isString(typ) { valid = true @@ -80,7 +80,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo index := check.singleIndex(e) if index == nil { x.mode = invalid - return + return false } var key operand check.expr(&key, index) @@ -89,87 +89,80 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo x.mode = mapindex x.typ = typ.elem x.expr = e - return + return false - case *Union: - // A union type can be indexed if all of the union's terms - // support indexing and have the same index and element - // type. Special rules apply for maps in the union type. - var tkey, telem Type // key is for map types only - nmaps := 0 // number of map types in union type - if typ.underIs(func(t Type) bool { - var e Type - switch t := t.(type) { + case *TypeParam: + // TODO(gri) report detailed failure cause for better error messages + var tkey, telem Type // tkey != nil if we have maps + if typ.underIs(func(u Type) bool { + var key, elem Type + alen := int64(-1) // valid if >= 0 + switch t := u.(type) { case *Basic: - if isString(t) { - e = universeByte - } - case *Array: - e = t.elem - case *Pointer: - if t := asArray(t.base); t != nil { - e = t.elem - } - case *Slice: - e = t.elem - case *Map: - // If there are multiple maps in the union type, - // they must have identical key types. - // TODO(gri) We may be able to relax this rule - // but it becomes complicated very quickly. - if tkey != nil && !Identical(t.key, tkey) { + if !isString(t) { return false } - tkey = t.key - e = t.elem - nmaps++ - case *TypeParam: - check.errorf(x, "type of %s contains a type parameter - cannot index (implementation restriction)", x) - case *instance: - unimplemented() - } - if e == nil || telem != nil && !Identical(e, telem) { + elem = universeByte + case *Array: + elem = t.elem + alen = t.len + case *Pointer: + a, _ := under(t.base).(*Array) + if a == nil { + return false + } + elem = a.elem + alen = a.len + case *Slice: + elem = t.elem + case *Map: + key = t.key + elem = t.elem + default: return false } - telem = e + assert(elem != nil) + if telem == nil { + // first type + tkey, telem = key, elem + length = alen + } else { + // all map keys must be identical (incl. all nil) + if !Identical(key, tkey) { + return false + } + // all element types must be identical + if !Identical(elem, telem) { + return false + } + tkey, telem = key, elem + // track the minimal length for arrays + if alen >= 0 && alen < length { + length = alen + } + } return true }) { - // If there are maps, the index expression must be assignable - // to the map key type (as for simple map index expressions). - if nmaps > 0 { + // For maps, the index expression must be assignable to the map key type. + if tkey != nil { index := check.singleIndex(e) if index == nil { x.mode = invalid - return + return false } var key operand check.expr(&key, index) check.assignment(&key, tkey, "map index") // ok to continue even if indexing failed - map element type is known - - // If there are only maps, we are done. - if nmaps == typ.NumTerms() { - x.mode = mapindex - x.typ = telem - x.expr = e - return - } - - // Otherwise we have mix of maps and other types. For - // now we require that the map key be an integer type. - // TODO(gri) This is probably not good enough. - valid = isInteger(tkey) - // avoid 2nd indexing error if indexing failed above - if !valid && key.mode == invalid { - x.mode = invalid - return - } - x.mode = value // map index expressions are not addressable - } else { - // no maps - valid = true - x.mode = variable + x.mode = mapindex + x.typ = telem + x.expr = e + return false } + + // no maps + valid = true + x.mode = variable x.typ = telem } } @@ -177,13 +170,13 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo if !valid { check.errorf(x, invalidOp+"cannot index %s", x) x.mode = invalid - return + return false } index := check.singleIndex(e) if index == nil { x.mode = invalid - return + return false } // In pathological (invalid) cases (e.g.: type T1 [][[]T1{}[0][0]]T0) diff --git a/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 b/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 index 4074ef17ea2..123567682a3 100644 --- a/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 @@ -98,18 +98,23 @@ func _[T any] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } func _[T interface{ ~int }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } func _[T interface{ ~string }] (x T, i int) { _ = x[i] } func _[T interface{ ~[]int }] (x T, i int) { _ = x[i] } -func _[T interface{ ~[10]int | ~*[20]int | ~map[int]int }] (x T, i int) { _ = x[i] } +func _[T interface{ ~[10]int | ~*[20]int | ~map[int]int }] (x T, i int) { _ = x /* ERROR cannot index */ [i] } // map and non-map types func _[T interface{ ~string | ~[]byte }] (x T, i int) { _ = x[i] } func _[T interface{ ~[]int | ~[1]rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } func _[T interface{ ~string | ~[]rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } -// indexing with various combinations of map types in type lists (see issue #42616) -func _[T interface{ ~[]E | ~map[int]E }, E any](x T, i int) { _ = x[i] } +// indexing with various combinations of map types in type sets (see issue #42616) +func _[T interface{ ~[]E | ~map[int]E }, E any](x T, i int) { _ = x /* ERROR cannot index */ [i] } // map and non-map types func _[T interface{ ~[]E }, E any](x T, i int) { _ = &x[i] } func _[T interface{ ~map[int]E }, E any](x T, i int) { _, _ = x[i] } // comma-ok permitted -func _[T interface{ ~[]E | ~map[int]E }, E any](x T, i int) { _ = &x /* ERROR cannot take address */ [i] } -func _[T interface{ ~[]E | ~map[int]E | ~map[uint]E }, E any](x T, i int) { _ = x /* ERROR cannot index */ [i] } // different map element types -func _[T interface{ ~[]E | ~map[string]E }, E any](x T, i int) { _ = x[i /* ERROR cannot use i */ ] } +func _[T interface{ ~map[int]E }, E any](x T, i int) { _ = &x /* ERROR cannot take address */ [i] } +func _[T interface{ ~map[int]E | ~map[uint]E }, E any](x T, i int) { _ = x /* ERROR cannot index */ [i] } // different map element types +func _[T interface{ ~[]E | ~map[string]E }, E any](x T, i int) { _ = x /* ERROR cannot index */ [i] } // map and non-map types + +// indexing with various combinations of array and other types in type sets +func _[T interface{ [10]int }](x T, i int) { _ = x[i]; _ = x[9]; _ = x[10 /* ERROR out of bounds */ ] } +func _[T interface{ [10]byte | string }](x T, i int) { _ = x[i]; _ = x[9]; _ = x[10 /* ERROR out of bounds */ ] } +func _[T interface{ [10]int | *[20]int | []int }](x T, i int) { _ = x[i]; _ = x[9]; _ = x[10 /* ERROR out of bounds */ ] } // slicing // TODO(gri) implement this diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45635.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45635.go2 index e9b57ae8f10..29379591057 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45635.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45635.go2 @@ -13,7 +13,7 @@ type N[T any] struct{} var _ N[] /* ERROR expecting type */ type I interface { - ~map[int]int | ~[]int + ~[]int } func _[T I](i, j int) { @@ -27,6 +27,5 @@ func _[T I](i, j int) { _ = s[i, j /* ERROR more than one index */ ] var t T - // TODO(gri) fix multiple error below - _ = t[i, j /* ERROR more than one index */ /* ERROR more than one index */ ] + _ = t[i, j /* ERROR more than one index */ ] } diff --git a/src/cmd/compile/internal/types2/typeparam.go b/src/cmd/compile/internal/types2/typeparam.go index 5c744059124..b73b4edf79f 100644 --- a/src/cmd/compile/internal/types2/typeparam.go +++ b/src/cmd/compile/internal/types2/typeparam.go @@ -78,3 +78,10 @@ func (t *TypeParam) SetBound(bound Type) { func (t *TypeParam) Underlying() Type { return t } func (t *TypeParam) String() string { return TypeString(t, nil) } + +// ---------------------------------------------------------------------------- +// Implementation + +func (t *TypeParam) underIs(f func(Type) bool) bool { + return t.Bound().typeSet().underIs(f) +} diff --git a/src/cmd/compile/internal/types2/typeset.go b/src/cmd/compile/internal/types2/typeset.go index 265221501f2..6ff85639748 100644 --- a/src/cmd/compile/internal/types2/typeset.go +++ b/src/cmd/compile/internal/types2/typeset.go @@ -75,6 +75,21 @@ func (s *TypeSet) String() string { // ---------------------------------------------------------------------------- // Implementation +// underIs reports whether f returned true for the underlying types of the +// enumerable types in the type set s. If the type set comprises all types +// f is called once with the top type; if the type set is empty, the result +// is false. +func (s *TypeSet) underIs(f func(Type) bool) bool { + switch t := s.types.(type) { + case nil: + return f(theTop) + default: + return f(t) + case *Union: + return t.underIs(f) + } +} + // topTypeSet may be used as type set for the empty interface. var topTypeSet TypeSet diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go index 4925252b394..f63a23c98ce 100644 --- a/src/cmd/compile/internal/types2/typestring.go +++ b/src/cmd/compile/internal/types2/typestring.go @@ -164,7 +164,7 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { } for i, e := range t.types { if i > 0 { - buf.WriteString("|") + buf.WriteByte('|') } if t.tilde[i] { buf.WriteByte('~') diff --git a/src/cmd/compile/internal/types2/union.go b/src/cmd/compile/internal/types2/union.go index 30570b5e802..e5e851c1d26 100644 --- a/src/cmd/compile/internal/types2/union.go +++ b/src/cmd/compile/internal/types2/union.go @@ -57,7 +57,7 @@ func (u *Union) is(f func(Type, bool) bool) bool { return true } -// is reports whether f returned true for the underlying types of all terms of u. +// underIs reports whether f returned true for the underlying types of all terms of u. func (u *Union) underIs(f func(Type) bool) bool { if u.IsEmpty() { return false From d2bf94fb86b45609564919caa21c6b098b5197d3 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 2 Jul 2021 16:54:14 -0700 Subject: [PATCH 647/940] [dev.typeparams] cmd/compile/internal/types2: replace optype() with under() in various cases (cleanup) This makes the behavior for type parameter operands explicit in those cases. Change-Id: I38438af67de4432f1a691dc4947e4576445f031b Reviewed-on: https://go-review.googlesource.com/c/go/+/332555 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/builtins.go | 8 +++++--- src/cmd/compile/internal/types2/expr.go | 6 +++--- src/cmd/compile/internal/types2/index.go | 4 ++-- src/cmd/compile/internal/types2/predicates.go | 19 +++++++++---------- .../types2/testdata/check/typeparams.go2 | 2 +- src/cmd/compile/internal/types2/typeset.go | 1 + 6 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index 7ba26509e8d..83d1743ee2f 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -332,13 +332,15 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( return } var src Type - switch t := optype(y.typ).(type) { + switch t := under(y.typ).(type) { case *Basic: if isString(y.typ) { src = universeByte } case *Slice: src = t.elem + case *TypeParam: + check.error(x, "copy on generic operands not yet implemented") } if dst == nil || src == nil { @@ -455,12 +457,12 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( var valid func(t Type) bool valid = func(t Type) bool { var m int - switch t := optype(t).(type) { + switch t := under(t).(type) { case *Slice: m = 2 case *Map, *Chan: m = 1 - case *Union: + case *TypeParam: return t.underIs(valid) default: return false diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go index 1cb0ad4752b..bd35417c645 100644 --- a/src/cmd/compile/internal/types2/expr.go +++ b/src/cmd/compile/internal/types2/expr.go @@ -691,7 +691,7 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const return nil, nil, _InvalidUntypedConversion } - switch t := optype(target).(type) { + switch t := under(target).(type) { case *Basic: if x.mode == constant_ { v, code := check.representation(x, t) @@ -723,7 +723,7 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const default: return nil, nil, _InvalidUntypedConversion } - case *Union: + case *TypeParam: ok := t.underIs(func(t Type) bool { target, _, _ := check.implicitTypeAndValue(x, t) return target != nil @@ -1197,7 +1197,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin goto Error } - switch utyp := optype(base).(type) { + switch utyp := under(base).(type) { case *Struct: if len(e.ElemList) == 0 { break diff --git a/src/cmd/compile/internal/types2/index.go b/src/cmd/compile/internal/types2/index.go index 5a4dcb47417..d3e0c71f05d 100644 --- a/src/cmd/compile/internal/types2/index.go +++ b/src/cmd/compile/internal/types2/index.go @@ -199,7 +199,7 @@ func (check *Checker) sliceExpr(x *operand, e *syntax.SliceExpr) { valid := false length := int64(-1) // valid if >= 0 - switch typ := optype(x.typ).(type) { + switch typ := under(x.typ).(type) { case *Basic: if isString(typ) { if e.Full { @@ -239,7 +239,7 @@ func (check *Checker) sliceExpr(x *operand, e *syntax.SliceExpr) { valid = true // x.typ doesn't change - case *Union, *TypeParam: + case *TypeParam: check.error(x, "generic slice expressions not yet implemented") x.mode = invalid return diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go index 5ff7840d6f9..2f108985857 100644 --- a/src/cmd/compile/internal/types2/predicates.go +++ b/src/cmd/compile/internal/types2/predicates.go @@ -25,10 +25,10 @@ func isGeneric(typ Type) bool { } func is(typ Type, what BasicInfo) bool { - switch t := optype(typ).(type) { + switch t := under(typ).(type) { case *Basic: return t.info&what != 0 - case *Union: + case *TypeParam: return t.underIs(func(t Type) bool { return is(t, what) }) } return false @@ -56,7 +56,7 @@ func isNumericOrString(typ Type) bool { return is(typ, IsNumeric|IsString) } // are not fully set up. func isTyped(typ Type) bool { // isTyped is called with types that are not fully - // set up. Must not call Basic()! + // set up. Must not call asBasic()! // A *Named or *instance type is always typed, so // we only need to check if we have a true *Basic // type. @@ -97,18 +97,19 @@ func comparable(T Type, seen map[Type]bool) bool { seen[T] = true // If T is a type parameter not constrained by any type - // list (i.e., it's operational type is the top type), + // (i.e., it's operational type is the top type), // T is comparable if it has the == method. Otherwise, // the operational type "wins". For instance // // interface{ comparable; type []byte } // // is not comparable because []byte is not comparable. + // TODO(gri) this code is not 100% correct (see comment for TypeSet.IsComparable) if t := asTypeParam(T); t != nil && optype(t) == theTop { return t.Bound().IsComparable() } - switch t := optype(T).(type) { + switch t := under(T).(type) { case *Basic: // assume invalid types to be comparable // to avoid follow-up errors @@ -124,24 +125,22 @@ func comparable(T Type, seen map[Type]bool) bool { return true case *Array: return comparable(t.elem, seen) - case *Union: + case *TypeParam: return t.underIs(func(t Type) bool { return comparable(t, seen) }) - case *TypeParam: - return t.Bound().IsComparable() } return false } // hasNil reports whether a type includes the nil value. func hasNil(typ Type) bool { - switch t := optype(typ).(type) { + switch t := under(typ).(type) { case *Basic: return t.kind == UnsafePointer case *Slice, *Pointer, *Signature, *Interface, *Map, *Chan: return true - case *Union: + case *TypeParam: return t.underIs(hasNil) } return false diff --git a/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 b/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 index 123567682a3..8a7f6eb2c25 100644 --- a/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 @@ -119,7 +119,7 @@ func _[T interface{ [10]int | *[20]int | []int }](x T, i int) { _ = x[i]; _ = x[ // slicing // TODO(gri) implement this -func _[T interface{ ~string }] (x T, i, j, k int) { _ = x /* ERROR invalid operation */ [i:j:k] } +func _[T interface{ ~string }] (x T, i, j, k int) { _ = x /* ERROR generic slice expressions not yet implemented */ [i:j:k] } // len/cap built-ins diff --git a/src/cmd/compile/internal/types2/typeset.go b/src/cmd/compile/internal/types2/typeset.go index 6ff85639748..4aee8e40972 100644 --- a/src/cmd/compile/internal/types2/typeset.go +++ b/src/cmd/compile/internal/types2/typeset.go @@ -28,6 +28,7 @@ func (s *TypeSet) IsTop() bool { return len(s.methods) == 0 && s.types == nil } func (s *TypeSet) IsMethodSet() bool { return s.types == nil && !s.IsComparable() } // IsComparable reports whether each type in the set is comparable. +// TODO(gri) this is not correct - there may be s.types values containing non-comparable types func (s *TypeSet) IsComparable() bool { _, m := s.LookupMethod(nil, "==") return m != nil From 18135150b0ce945735d242eb6259ffc9b5c767d0 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 2 Jul 2021 18:12:02 -0700 Subject: [PATCH 648/940] [dev.typeparams] cmd/compile/internal/types2: don't permit method calls on ptr to type parameter receivers Simplify the implementation of asInterface while at it. For #47031. Change-Id: Ie7d4fbbab898d961ed3c0b7772ba9604641be13f Reviewed-on: https://go-review.googlesource.com/c/go/+/332609 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/lookup.go | 10 ++++++---- .../internal/types2/testdata/check/issues.go2 | 10 ++++------ .../types2/testdata/fixedbugs/issue47031.go2 | 20 +++++++++++++++++++ src/cmd/compile/internal/types2/type.go | 13 ++++++------ 4 files changed, 37 insertions(+), 16 deletions(-) create mode 100644 src/cmd/compile/internal/types2/testdata/fixedbugs/issue47031.go2 diff --git a/src/cmd/compile/internal/types2/lookup.go b/src/cmd/compile/internal/types2/lookup.go index d59a2f474c6..91be14bde3e 100644 --- a/src/cmd/compile/internal/types2/lookup.go +++ b/src/cmd/compile/internal/types2/lookup.go @@ -73,10 +73,12 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o typ, isPtr := deref(T) - // *typ where typ is an interface has no methods. - // Be cautious: typ may be nil (issue 39634, crash #3). - if typ == nil || isPtr && IsInterface(typ) { - return + // *typ where typ is an interface or type parameter has no methods. + switch under(typ).(type) { + case *Interface, *TypeParam: + if isPtr { + return + } } // Start with typ as single entry at shallowest depth. diff --git a/src/cmd/compile/internal/types2/testdata/check/issues.go2 b/src/cmd/compile/internal/types2/testdata/check/issues.go2 index 59dd4ae465a..88ae294d7c1 100644 --- a/src/cmd/compile/internal/types2/testdata/check/issues.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/issues.go2 @@ -24,22 +24,20 @@ func _() { eql[io.Reader](nil, nil) } -// If we have a receiver of pointer type (below: *T) we must ignore -// the pointer in the implementation of the method lookup because -// the type bound of T is an interface and pointer to interface types -// have no methods and then the lookup would fail. +// If we have a receiver of pointer to type parameter type (below: *T) +// we don't have any methods, like for interfaces. type C[T any] interface { m() } // using type bound C func _[T C[T]](x *T) { - x.m() + x.m /* ERROR x\.m undefined */ () } // using an interface literal as bound func _[T interface{ m() }](x *T) { - x.m() + x.m /* ERROR x\.m undefined */ () } func f2[_ interface{ m1(); m2() }]() diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47031.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47031.go2 new file mode 100644 index 00000000000..b184f9b5b7d --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47031.go2 @@ -0,0 +1,20 @@ +// Copyright 2021 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 + +type Mer interface { M() } + +func F[T Mer](p *T) { + p.M /* ERROR p\.M undefined */ () +} + +type MyMer int + +func (MyMer) M() {} + +func _() { + F(new(MyMer)) + F[Mer](nil) +} diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index e3f63f63b55..c2da97605b1 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -112,11 +112,6 @@ func asSignature(t Type) *Signature { return op } -func asInterface(t Type) *Interface { - op, _ := optype(t).(*Interface) - return op -} - func asMap(t Type) *Map { op, _ := optype(t).(*Map) return op @@ -127,10 +122,16 @@ func asChan(t Type) *Chan { return op } -// If the argument to asNamed and asTypeParam is of the respective types +// If the argument to asInterface, asNamed, or asTypeParam is of the respective type // (possibly after expanding an instance type), these methods return that type. // Otherwise the result is nil. +// asInterface does not need to look at optype (type sets don't contain interfaces) +func asInterface(t Type) *Interface { + u, _ := under(t).(*Interface) + return u +} + func asNamed(t Type) *Named { e, _ := expand(t).(*Named) return e From 2ca44fe2213b53ccaf6f555c11858c6e36490624 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 5 Jul 2021 10:35:53 +0200 Subject: [PATCH 649/940] doc/go1.17: linkify time.UnixMilli and time.UnixMicro Change-Id: I8503c4649fc42670f13d981f98af480467d6a3e8 Reviewed-on: https://go-review.googlesource.com/c/go/+/332829 Trust: Tobias Klauser Reviewed-by: Dmitri Shuralyov --- doc/go1.17.html | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 66b4f48b61e..4fa30158bb2 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -1132,10 +1132,13 @@ func Foo() bool {

The new Time.UnixMilli and - Time.UnixMicro methods return the number of milliseconds and - microseconds elapsed since January 1, 1970 UTC respectively.
- The new UnixMilli and UnixMicro functions return local Time corresponding to given - Unix time. + Time.UnixMicro + methods return the number of milliseconds and microseconds elapsed since + January 1, 1970 UTC respectively. +
+ The new UnixMilli and + UnixMicro functions + return the local Time corresponding to the given Unix time.

From ce76298ee7b2cc237b015f798abbfe891a6f5463 Mon Sep 17 00:00:00 2001 From: makdon Date: Mon, 17 May 2021 16:27:11 +0000 Subject: [PATCH 650/940] Update oudated comment Update comment cause gc/select.go has been moved to walk/select.go and gc/reflect.go has been moved to reflectdata/reflect.go Change-Id: I6894527e1e9dbca50ace92a51bf942f9495ce88c GitHub-Last-Rev: 6d6a4471440403218b68ba32d4038ca41eae2901 GitHub-Pull-Request: golang/go#45976 Reviewed-on: https://go-review.googlesource.com/c/go/+/317191 Reviewed-by: Keith Randall Trust: Michael Pratt --- src/cmd/compile/internal/reflectdata/reflect.go | 2 +- src/cmd/link/internal/ld/decodesym.go | 4 ++-- src/internal/reflectlite/type.go | 4 ++-- src/reflect/type.go | 10 +++++----- src/runtime/runtime2.go | 4 ++-- src/runtime/select.go | 2 +- src/runtime/type.go | 6 +++--- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index e07294be0f9..eb9a8a6c9bc 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -669,7 +669,7 @@ var kinds = []int{ // tflag is documented in reflect/type.go. // // tflag values must be kept in sync with copies in: -// cmd/compile/internal/gc/reflect.go +// cmd/compile/internal/reflectdata/reflect.go // cmd/link/internal/ld/decodesym.go // reflect/type.go // runtime/type.go diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go index c41d97706ef..629bdcf4cac 100644 --- a/src/cmd/link/internal/ld/decodesym.go +++ b/src/cmd/link/internal/ld/decodesym.go @@ -16,12 +16,12 @@ import ( // Decoding the type.* symbols. This has to be in sync with // ../../runtime/type.go, or more specifically, with what -// cmd/compile/internal/gc/reflect.go stuffs in these. +// cmd/compile/internal/reflectdata/reflect.go stuffs in these. // tflag is documented in reflect/type.go. // // tflag values must be kept in sync with copies in: -// cmd/compile/internal/gc/reflect.go +// cmd/compile/internal/reflectdata/reflect.go // cmd/link/internal/ld/decodesym.go // reflect/type.go // runtime/type.go diff --git a/src/internal/reflectlite/type.go b/src/internal/reflectlite/type.go index f529f7c5fcc..b1899b0191f 100644 --- a/src/internal/reflectlite/type.go +++ b/src/internal/reflectlite/type.go @@ -68,7 +68,7 @@ type Type interface { } /* - * These data structures are known to the compiler (../../cmd/internal/gc/reflect.go). + * These data structures are known to the compiler (../../cmd/internal/reflectdata/reflect.go). * A few are known to ../runtime/type.go to convey to debuggers. * They are also known to ../runtime/type.go. */ @@ -111,7 +111,7 @@ const ( // available in the memory directly following the rtype value. // // tflag values must be kept in sync with copies in: -// cmd/compile/internal/gc/reflect.go +// cmd/compile/internal/reflectdata/reflect.go // cmd/link/internal/ld/decodesym.go // runtime/type.go type tflag uint8 diff --git a/src/reflect/type.go b/src/reflect/type.go index df863ae106f..f672a7a5d5f 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -228,7 +228,7 @@ type Type interface { // See https://golang.org/issue/4876 for more details. /* - * These data structures are known to the compiler (../../cmd/internal/gc/reflect.go). + * These data structures are known to the compiler (../../cmd/internal/reflectdata/reflect.go). * A few are known to ../runtime/type.go to convey to debuggers. * They are also known to ../runtime/type.go. */ @@ -271,7 +271,7 @@ const ( // available in the memory directly following the rtype value. // // tflag values must be kept in sync with copies in: -// cmd/compile/internal/gc/reflect.go +// cmd/compile/internal/reflectdata/reflect.go // cmd/link/internal/ld/decodesym.go // runtime/type.go type tflag uint8 @@ -1910,7 +1910,7 @@ func MapOf(key, elem Type) Type { // Make a map type. // Note: flag values must match those used in the TMAP case - // in ../cmd/compile/internal/gc/reflect.go:writeType. + // in ../cmd/compile/internal/reflectdata/reflect.go:writeType. var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil) mt := **(**mapType)(unsafe.Pointer(&imap)) mt.str = resolveReflectName(newName(s, "", false)) @@ -2841,7 +2841,7 @@ func runtimeStructField(field StructField) (structField, string) { // typeptrdata returns the length in bytes of the prefix of t // containing pointer data. Anything after this offset is scalar data. -// keep in sync with ../cmd/compile/internal/gc/reflect.go +// keep in sync with ../cmd/compile/internal/reflectdata/reflect.go func typeptrdata(t *rtype) uintptr { switch t.Kind() { case Struct: @@ -2865,7 +2865,7 @@ func typeptrdata(t *rtype) uintptr { } } -// See cmd/compile/internal/gc/reflect.go for derivation of constant. +// See cmd/compile/internal/reflectdata/reflect.go for derivation of constant. const maxPtrmaskBytes = 2048 // ArrayOf returns the array type with the given length and element type. diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index 0e0eb0b7285..2a66826f34b 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -895,7 +895,7 @@ type funcinl struct { // layout of Itab known to compilers // allocated in non-garbage-collected memory // Needs to be in sync with -// ../cmd/compile/internal/gc/reflect.go:/^func.WriteTabs. +// ../cmd/compile/internal/reflectdata/reflect.go:/^func.WriteTabs. type itab struct { inter *interfacetype _type *_type @@ -940,7 +940,7 @@ func extendRandom(r []byte, n int) { // A _defer holds an entry on the list of deferred calls. // If you add a field here, add code to clear it in freedefer and deferProcStack -// This struct must match the code in cmd/compile/internal/gc/reflect.go:deferstruct +// This struct must match the code in cmd/compile/internal/reflectdata/reflect.go:deferstruct // and cmd/compile/internal/gc/ssa.go:(*state).call. // Some defers will be allocated on the stack and some on the heap. // All defers are logically part of the stack, so write barriers to diff --git a/src/runtime/select.go b/src/runtime/select.go index e72761bfa91..06edb69f429 100644 --- a/src/runtime/select.go +++ b/src/runtime/select.go @@ -15,7 +15,7 @@ const debugSelect = false // Select case descriptor. // Known to compiler. -// Changes here must also be made in src/cmd/internal/gc/select.go's scasetype. +// Changes here must also be made in src/cmd/compile/internal/walk/select.go's scasetype. type scase struct { c *hchan // chan elem unsafe.Pointer // data element diff --git a/src/runtime/type.go b/src/runtime/type.go index 335fc57f4b9..4039273695b 100644 --- a/src/runtime/type.go +++ b/src/runtime/type.go @@ -11,7 +11,7 @@ import "unsafe" // tflag is documented in reflect/type.go. // // tflag values must be kept in sync with copies in: -// cmd/compile/internal/gc/reflect.go +// cmd/compile/internal/reflectdata/reflect.go // cmd/link/internal/ld/decodesym.go // reflect/type.go // internal/reflectlite/type.go @@ -25,7 +25,7 @@ const ( ) // Needs to be in sync with ../cmd/link/internal/ld/decodesym.go:/^func.commonsize, -// ../cmd/compile/internal/gc/reflect.go:/^func.dcommontype and +// ../cmd/compile/internal/reflectdata/reflect.go:/^func.dcommontype and // ../reflect/type.go:/^type.rtype. // ../internal/reflectlite/type.go:/^type.rtype. type _type struct { @@ -383,7 +383,7 @@ type maptype struct { } // Note: flag values must match those used in the TMAP case -// in ../cmd/compile/internal/gc/reflect.go:writeType. +// in ../cmd/compile/internal/reflectdata/reflect.go:writeType. func (mt *maptype) indirectkey() bool { // store ptr to key instead of key itself return mt.flags&1 != 0 } From 296ddf2a936a30866303a64d49bc0e3e034730a8 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Fri, 2 Jul 2021 10:25:49 -0700 Subject: [PATCH 651/940] net: filter bad names from Lookup functions instead of hard failing Instead of hard failing on a single bad record, filter the bad records and return anything valid. This only applies to the methods which can return multiple records, LookupMX, LookupNS, LookupSRV, and LookupAddr. When bad results are filtered out, also return an error, indicating that this filtering has happened. Updates #46241 Fixes #46979 Change-Id: I6493e0002beaf89f5a9795333a93605abd30d171 Reviewed-on: https://go-review.googlesource.com/c/go/+/332549 Trust: Roland Shoemaker Reviewed-by: Filippo Valsorda --- src/net/dnsclient_unix_test.go | 222 +++++++++++++++++++++++++-------- src/net/lookup.go | 74 ++++++++--- 2 files changed, 229 insertions(+), 67 deletions(-) diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go index 59cdd2bf3e2..350ad5def79 100644 --- a/src/net/dnsclient_unix_test.go +++ b/src/net/dnsclient_unix_test.go @@ -1846,6 +1846,17 @@ func TestCVE202133195(t *testing.T) { Target: dnsmessage.MustNewName(".golang.org."), }, }, + dnsmessage.Resource{ + Header: dnsmessage.ResourceHeader{ + Name: n, + Type: dnsmessage.TypeSRV, + Class: dnsmessage.ClassINET, + Length: 4, + }, + Body: &dnsmessage.SRVResource{ + Target: dnsmessage.MustNewName("good.golang.org."), + }, + }, ) case dnsmessage.TypeMX: r.Answers = append(r.Answers, @@ -1860,6 +1871,17 @@ func TestCVE202133195(t *testing.T) { MX: dnsmessage.MustNewName(".golang.org."), }, }, + dnsmessage.Resource{ + Header: dnsmessage.ResourceHeader{ + Name: dnsmessage.MustNewName("good.golang.org."), + Type: dnsmessage.TypeMX, + Class: dnsmessage.ClassINET, + Length: 4, + }, + Body: &dnsmessage.MXResource{ + MX: dnsmessage.MustNewName("good.golang.org."), + }, + }, ) case dnsmessage.TypeNS: r.Answers = append(r.Answers, @@ -1874,6 +1896,17 @@ func TestCVE202133195(t *testing.T) { NS: dnsmessage.MustNewName(".golang.org."), }, }, + dnsmessage.Resource{ + Header: dnsmessage.ResourceHeader{ + Name: dnsmessage.MustNewName("good.golang.org."), + Type: dnsmessage.TypeNS, + Class: dnsmessage.ClassINET, + Length: 4, + }, + Body: &dnsmessage.NSResource{ + NS: dnsmessage.MustNewName("good.golang.org."), + }, + }, ) case dnsmessage.TypePTR: r.Answers = append(r.Answers, @@ -1888,6 +1921,17 @@ func TestCVE202133195(t *testing.T) { PTR: dnsmessage.MustNewName(".golang.org."), }, }, + dnsmessage.Resource{ + Header: dnsmessage.ResourceHeader{ + Name: dnsmessage.MustNewName("good.golang.org."), + Type: dnsmessage.TypePTR, + Class: dnsmessage.ClassINET, + Length: 4, + }, + Body: &dnsmessage.PTRResource{ + PTR: dnsmessage.MustNewName("good.golang.org."), + }, + }, ) } return r, nil @@ -1903,59 +1947,139 @@ func TestCVE202133195(t *testing.T) { defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath) testHookHostsPath = "testdata/hosts" - _, err := r.LookupCNAME(context.Background(), "golang.org") - if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected { - t.Errorf("Resolver.LookupCNAME returned unexpected error, got %q, want %q", err, expected) - } - _, err = LookupCNAME("golang.org") - if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected { - t.Errorf("LookupCNAME returned unexpected error, got %q, want %q", err, expected) + tests := []struct { + name string + f func(*testing.T) + }{ + { + name: "CNAME", + f: func(t *testing.T) { + expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"} + _, err := r.LookupCNAME(context.Background(), "golang.org") + if err.Error() != expectedErr.Error() { + t.Fatalf("unexpected error: %s", err) + } + _, err = LookupCNAME("golang.org") + if err.Error() != expectedErr.Error() { + t.Fatalf("unexpected error: %s", err) + } + }, + }, + { + name: "SRV (bad record)", + f: func(t *testing.T) { + expected := []*SRV{ + { + Target: "good.golang.org.", + }, + } + expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"} + _, records, err := r.LookupSRV(context.Background(), "target", "tcp", "golang.org") + if err.Error() != expectedErr.Error() { + t.Fatalf("unexpected error: %s", err) + } + if !reflect.DeepEqual(records, expected) { + t.Error("Unexpected record set") + } + _, records, err = LookupSRV("target", "tcp", "golang.org") + if err.Error() != expectedErr.Error() { + t.Errorf("unexpected error: %s", err) + } + if !reflect.DeepEqual(records, expected) { + t.Error("Unexpected record set") + } + }, + }, + { + name: "SRV (bad header)", + f: func(t *testing.T) { + _, _, err := r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org.") + if expected := "lookup golang.org.: SRV header name is invalid"; err == nil || err.Error() != expected { + t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err, expected) + } + _, _, err = LookupSRV("hdr", "tcp", "golang.org.") + if expected := "lookup golang.org.: SRV header name is invalid"; err == nil || err.Error() != expected { + t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected) + } + }, + }, + { + name: "MX", + f: func(t *testing.T) { + expected := []*MX{ + { + Host: "good.golang.org.", + }, + } + expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"} + records, err := r.LookupMX(context.Background(), "golang.org") + if err.Error() != expectedErr.Error() { + t.Fatalf("unexpected error: %s", err) + } + if !reflect.DeepEqual(records, expected) { + t.Error("Unexpected record set") + } + records, err = LookupMX("golang.org") + if err.Error() != expectedErr.Error() { + t.Fatalf("unexpected error: %s", err) + } + if !reflect.DeepEqual(records, expected) { + t.Error("Unexpected record set") + } + }, + }, + { + name: "NS", + f: func(t *testing.T) { + expected := []*NS{ + { + Host: "good.golang.org.", + }, + } + expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"} + records, err := r.LookupNS(context.Background(), "golang.org") + if err.Error() != expectedErr.Error() { + t.Fatalf("unexpected error: %s", err) + } + if !reflect.DeepEqual(records, expected) { + t.Error("Unexpected record set") + } + records, err = LookupNS("golang.org") + if err.Error() != expectedErr.Error() { + t.Fatalf("unexpected error: %s", err) + } + if !reflect.DeepEqual(records, expected) { + t.Error("Unexpected record set") + } + }, + }, + { + name: "Addr", + f: func(t *testing.T) { + expected := []string{"good.golang.org."} + expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "192.0.2.42"} + records, err := r.LookupAddr(context.Background(), "192.0.2.42") + if err.Error() != expectedErr.Error() { + t.Fatalf("unexpected error: %s", err) + } + if !reflect.DeepEqual(records, expected) { + t.Error("Unexpected record set") + } + records, err = LookupAddr("192.0.2.42") + if err.Error() != expectedErr.Error() { + t.Fatalf("unexpected error: %s", err) + } + if !reflect.DeepEqual(records, expected) { + t.Error("Unexpected record set") + } + }, + }, } - _, _, err = r.LookupSRV(context.Background(), "target", "tcp", "golang.org") - if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected { - t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err, expected) - } - _, _, err = LookupSRV("target", "tcp", "golang.org") - if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected { - t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected) + for _, tc := range tests { + t.Run(tc.name, tc.f) } - _, _, err = r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org.") - if expected := "lookup golang.org.: SRV header name is invalid"; err == nil || err.Error() != expected { - t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err, expected) - } - _, _, err = LookupSRV("hdr", "tcp", "golang.org.") - if expected := "lookup golang.org.: SRV header name is invalid"; err == nil || err.Error() != expected { - t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected) - } - - _, err = r.LookupMX(context.Background(), "golang.org") - if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected { - t.Errorf("Resolver.LookupMX returned unexpected error, got %q, want %q", err, expected) - } - _, err = LookupMX("golang.org") - if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected { - t.Errorf("LookupMX returned unexpected error, got %q, want %q", err, expected) - } - - _, err = r.LookupNS(context.Background(), "golang.org") - if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected { - t.Errorf("Resolver.LookupNS returned unexpected error, got %q, want %q", err, expected) - } - _, err = LookupNS("golang.org") - if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected { - t.Errorf("LookupNS returned unexpected error, got %q, want %q", err, expected) - } - - _, err = r.LookupAddr(context.Background(), "192.0.2.42") - if expected := "lookup 192.0.2.42: PTR target is invalid"; err == nil || err.Error() != expected { - t.Errorf("Resolver.LookupAddr returned unexpected error, got %q, want %q", err, expected) - } - _, err = LookupAddr("192.0.2.42") - if expected := "lookup 192.0.2.42: PTR target is invalid"; err == nil || err.Error() != expected { - t.Errorf("LookupAddr returned unexpected error, got %q, want %q", err, expected) - } } func TestNullMX(t *testing.T) { diff --git a/src/net/lookup.go b/src/net/lookup.go index b5af3a0f867..d350ef7fc03 100644 --- a/src/net/lookup.go +++ b/src/net/lookup.go @@ -424,7 +424,7 @@ func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error) return "", err } if !isDomainName(cname) { - return "", &DNSError{Err: "CNAME target is invalid", Name: host} + return "", &DNSError{Err: errMalformedDNSRecordsDetail, Name: host} } return cname, nil } @@ -440,7 +440,9 @@ func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error) // and proto are empty strings, LookupSRV looks up name directly. // // The returned service names are validated to be properly -// formatted presentation-format domain names. +// formatted presentation-format domain names. If the response contains +// invalid names, those records are filtered out and an error +// will be returned alongside the the remaining results, if any. func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { return DefaultResolver.LookupSRV(context.Background(), service, proto, name) } @@ -456,7 +458,9 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err // and proto are empty strings, LookupSRV looks up name directly. // // The returned service names are validated to be properly -// formatted presentation-format domain names. +// formatted presentation-format domain names. If the response contains +// invalid names, those records are filtered out and an error +// will be returned alongside the the remaining results, if any. func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) { cname, addrs, err := r.lookupSRV(ctx, service, proto, name) if err != nil { @@ -465,21 +469,28 @@ func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) ( if cname != "" && !isDomainName(cname) { return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name} } + filteredAddrs := make([]*SRV, 0, len(addrs)) for _, addr := range addrs { if addr == nil { continue } if !isDomainName(addr.Target) { - return "", nil, &DNSError{Err: "SRV target is invalid", Name: name} + continue } + filteredAddrs = append(filteredAddrs, addr) } - return cname, addrs, nil + if len(addrs) != len(filteredAddrs) { + return cname, filteredAddrs, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name} + } + return cname, filteredAddrs, nil } // LookupMX returns the DNS MX records for the given domain name sorted by preference. // // The returned mail server names are validated to be properly -// formatted presentation-format domain names. +// formatted presentation-format domain names. If the response contains +// invalid names, those records are filtered out and an error +// will be returned alongside the the remaining results, if any. // // LookupMX uses context.Background internally; to specify the context, use // Resolver.LookupMX. @@ -490,12 +501,15 @@ func LookupMX(name string) ([]*MX, error) { // LookupMX returns the DNS MX records for the given domain name sorted by preference. // // The returned mail server names are validated to be properly -// formatted presentation-format domain names. +// formatted presentation-format domain names. If the response contains +// invalid names, those records are filtered out and an error +// will be returned alongside the the remaining results, if any. func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) { records, err := r.lookupMX(ctx, name) if err != nil { return nil, err } + filteredMX := make([]*MX, 0, len(records)) for _, mx := range records { if mx == nil { continue @@ -503,16 +517,22 @@ func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) { // Bypass the hostname validity check for targets which contain only a dot, // as this is used to represent a 'Null' MX record. if mx.Host != "." && !isDomainName(mx.Host) { - return nil, &DNSError{Err: "MX target is invalid", Name: name} + continue } + filteredMX = append(filteredMX, mx) } - return records, nil + if len(records) != len(filteredMX) { + return filteredMX, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name} + } + return filteredMX, nil } // LookupNS returns the DNS NS records for the given domain name. // // The returned name server names are validated to be properly -// formatted presentation-format domain names. +// formatted presentation-format domain names. If the response contains +// invalid names, those records are filtered out and an error +// will be returned alongside the the remaining results, if any. // // LookupNS uses context.Background internally; to specify the context, use // Resolver.LookupNS. @@ -523,21 +543,28 @@ func LookupNS(name string) ([]*NS, error) { // LookupNS returns the DNS NS records for the given domain name. // // The returned name server names are validated to be properly -// formatted presentation-format domain names. +// formatted presentation-format domain names. If the response contains +// invalid names, those records are filtered out and an error +// will be returned alongside the the remaining results, if any. func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) { records, err := r.lookupNS(ctx, name) if err != nil { return nil, err } + filteredNS := make([]*NS, 0, len(records)) for _, ns := range records { if ns == nil { continue } if !isDomainName(ns.Host) { - return nil, &DNSError{Err: "NS target is invalid", Name: name} + continue } + filteredNS = append(filteredNS, ns) } - return records, nil + if len(records) != len(filteredNS) { + return filteredNS, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name} + } + return filteredNS, nil } // LookupTXT returns the DNS TXT records for the given domain name. @@ -557,7 +584,8 @@ func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) // of names mapping to that address. // // The returned names are validated to be properly formatted presentation-format -// domain names. +// domain names. If the response contains invalid names, those records are filtered +// out and an error will be returned alongside the the remaining results, if any. // // When using the host C library resolver, at most one result will be // returned. To bypass the host resolver, use a custom Resolver. @@ -572,16 +600,26 @@ func LookupAddr(addr string) (names []string, err error) { // of names mapping to that address. // // The returned names are validated to be properly formatted presentation-format -// domain names. +// domain names. If the response contains invalid names, those records are filtered +// out and an error will be returned alongside the the remaining results, if any. func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) { names, err := r.lookupAddr(ctx, addr) if err != nil { return nil, err } + filteredNames := make([]string, 0, len(names)) for _, name := range names { - if !isDomainName(name) { - return nil, &DNSError{Err: "PTR target is invalid", Name: addr} + if isDomainName(name) { + filteredNames = append(filteredNames, name) } } - return names, nil + if len(names) != len(filteredNames) { + return filteredNames, &DNSError{Err: errMalformedDNSRecordsDetail, Name: addr} + } + return filteredNames, nil } + +// errMalformedDNSRecordsDetail is the DNSError detail which is returned when a Resolver.Lookup... +// method recieves DNS records which contain invalid DNS names. This may be returned alongside +// results which have had the malformed records filtered out. +var errMalformedDNSRecordsDetail = "DNS response contained records which contain invalid names" From d4f6d161e439b3c2a56a4583d4b5acebe3fdeeee Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Wed, 7 Jul 2021 11:49:57 -0700 Subject: [PATCH 652/940] [dev.typeparams] cmd/compile: fix bunch of -G=3 bugs for test cases in test/typeparams/mdempsky 1.go, 12.go: similar to calculating type sizes, we delay computing instantiations during import until we get up to a top-level type, in order to make sure recursive types are complete. But we should always delay calculating sizes when we delay instantiating types, since otherwise we may try to calculate the size of an incomplete type. So, needed to add Defer/ResumeCheckSize in (*importReader).typ where we also defer instantiations. (iimport.go) 2.go: when doing type substition, we have to handle named, parameterized basic types i.e. the type has a type parameter even though the underlying type is a basic type that doesn't depend on the parameter. (subr.go) 3.go: for go 1.18, we allow arbitrary types in interfaces. We had already allowed union types and tilde types, but didn't allow regular non-interface types in Go 1.17 for compatibility. Just skip an error in the case of 1.18. (size.go) 5.go: types2 and types1 differ in how they print out interfaces. types1 puts a space between "interface" and "{", types2 does not. So, since some typenames come from types2 and some from types1, we need to remove the space when printing out type arguments. (iimport.go/subr.go) 9.go: in subst.node(), we were missing the KeyExpr case where a node has no type. The assertion is just there, to make sure we understand all the cases where there is no type to translate. We could just remove the whole error check. (stencil.go) 13.go: in subst.node(), missed handling the case where a method expression is immediate called (which of course, is quite unusual, since then there's no real reason to have used the method expression syntax in that case). Just needed to add ir.OMETHEXPR in the OCALL switch statement. (stencil.go) Change-Id: I202cbe9541dfafe740e3b84b44982d6181738ea0 Reviewed-on: https://go-review.googlesource.com/c/go/+/333165 Trust: Dan Scales Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/noder/stencil.go | 5 +++-- src/cmd/compile/internal/typecheck/iimport.go | 8 +++++++- src/cmd/compile/internal/typecheck/subr.go | 10 +++++++++- src/cmd/compile/internal/types/size.go | 7 +++++-- test/run.go | 11 ++--------- 5 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index ce9dc09bc3b..d292bfd5c69 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -1026,7 +1026,8 @@ func (subst *subster) node(n ir.Node) ir.Node { // an error. _, isCallExpr := m.(*ir.CallExpr) _, isStructKeyExpr := m.(*ir.StructKeyExpr) - if !isCallExpr && !isStructKeyExpr && x.Op() != ir.OPANIC && + _, isKeyExpr := m.(*ir.KeyExpr) + if !isCallExpr && !isStructKeyExpr && !isKeyExpr && x.Op() != ir.OPANIC && x.Op() != ir.OCLOSE { base.Fatalf(fmt.Sprintf("Nil type for %v", x)) } @@ -1136,7 +1137,7 @@ func (subst *subster) node(n ir.Node) ir.Node { } } - case ir.OMETHVALUE: + case ir.OMETHVALUE, ir.OMETHEXPR: // Redo the transformation of OXDOT, now that we // know the method value is being called. Then // transform the call. diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 7b7cd7f148d..4a97267f05f 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -567,9 +567,11 @@ func (r *importReader) pos() src.XPos { func (r *importReader) typ() *types.Type { // If this is a top-level type call, defer type instantiations until the // type is fully constructed. + types.DeferCheckSize() deferDoInst() t := r.p.typAt(r.uint64()) resumeDoInst() + types.ResumeCheckSize() return t } @@ -1738,7 +1740,11 @@ func InstTypeName(name string, targs []*types.Type) string { b.WriteString(targ.Sym().Pkg.Name) b.WriteByte('.') } - b.WriteString(targ.String()) + // types1 uses "interface {" and types2 uses "interface{" - convert + // to consistent types2 format. + tstring := targ.String() + tstring = strings.Replace(tstring, "interface {", "interface{", -1) + b.WriteString(tstring) } b.WriteByte(']') return b.String() diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index db1faaf6f73..d9e6612dfc3 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -931,7 +931,11 @@ func makeGenericName(name string, targs []*types.Type, hasBrackets bool) string b.WriteString(targ.Sym().Pkg.Name) b.WriteByte('.') } - b.WriteString(targ.String()) + // types1 uses "interface {" and types2 uses "interface{" - convert + // to consistent types2 format. + tstring := targ.String() + tstring = strings.Replace(tstring, "interface {", "interface{", -1) + b.WriteString(tstring) } b.WriteString("]") if i >= 0 { @@ -1163,6 +1167,10 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type { } else { assert(false) } + case types.TINT, types.TINT8, types.TINT16, types.TINT32, types.TINT64, + types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, + types.TUINTPTR, types.TBOOL, types.TSTRING: + newt = t.Underlying() } if newt == nil { // Even though there were typeparams in the type, there may be no diff --git a/src/cmd/compile/internal/types/size.go b/src/cmd/compile/internal/types/size.go index f5a74f83b39..89391ade683 100644 --- a/src/cmd/compile/internal/types/size.go +++ b/src/cmd/compile/internal/types/size.go @@ -128,9 +128,12 @@ func expandiface(t *Type) { continue } - // Once we go to 1.18, then embedded types can be anything, but - // for now, just interfaces and unions. + // In 1.18, embedded types can be anything. In Go 1.17, we disallow + // embedding anything other than interfaces. if !m.Type.IsInterface() { + if AllowsGoVersion(t.Pkg(), 1, 18) { + continue + } base.ErrorfAt(m.Pos, "interface contains embedded non-interface, non-union %v", m.Type) m.SetBroke(true) t.SetBroke(true) diff --git a/test/run.go b/test/run.go index 0251dc1c6a4..90861786df9 100644 --- a/test/run.go +++ b/test/run.go @@ -2204,15 +2204,8 @@ var g3Failures = setOf( "typeparam/nested.go", // -G=3 doesn't support function-local types with generics - "typeparam/mdempsky/1.go", - "typeparam/mdempsky/2.go", - "typeparam/mdempsky/3.go", - "typeparam/mdempsky/4.go", - "typeparam/mdempsky/5.go", - "typeparam/mdempsky/9.go", - "typeparam/mdempsky/11.go", - "typeparam/mdempsky/12.go", - "typeparam/mdempsky/13.go", + "typeparam/mdempsky/4.go", // -G=3 can't export functions with labeled breaks in loops + "typeparam/mdempsky/11.go", // types2/noder2 should give conversion error, because of "notinheap" mismatch ) var unifiedFailures = setOf( From 42fe1327878dc0956d2c6407a54112fa5e75bd34 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 7 Jul 2021 16:15:53 -0700 Subject: [PATCH 653/940] [dev.typeparams] cmd/compile: cleanup ABI utils tests This CL cleans a few minor nits with the ABI utils tests that are now necessary because of cleanups that happened on master: 1. Initialize types.LocalPkg; this needs to be set for selector names to be handled correctly. 2. In TestABIUtilsInterfaces, switch to using an exported identifier, so it doesn't need to be package qualified. 3. While here, change the method result type from "untyped string" to just "string". Constants are the only declared object that can ever have an untyped type. Change-Id: Iabed46594361a516317a1c2d20c3d59bdb519844 Reviewed-on: https://go-review.googlesource.com/c/go/+/333189 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- src/cmd/compile/internal/test/abiutils_test.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/cmd/compile/internal/test/abiutils_test.go b/src/cmd/compile/internal/test/abiutils_test.go index b7901be69b6..839546bcb8a 100644 --- a/src/cmd/compile/internal/test/abiutils_test.go +++ b/src/cmd/compile/internal/test/abiutils_test.go @@ -33,6 +33,8 @@ func TestMain(m *testing.M) { base.Ctxt.DiagFunc = base.Errorf base.Ctxt.DiagFlush = base.FlushErrors base.Ctxt.Bso = bufio.NewWriter(os.Stdout) + types.LocalPkg = types.NewPkg("", "local") + types.LocalPkg.Prefix = `""` types.PtrSize = ssagen.Arch.LinkArch.PtrSize types.RegSize = ssagen.Arch.LinkArch.RegSize typecheck.InitUniverse() @@ -309,8 +311,8 @@ func TestABIUtilsInterfaces(t *testing.T) { ei := types.Types[types.TINTER] // interface{} pei := types.NewPtr(ei) // *interface{} fldt := mkFuncType(types.FakeRecvType(), []*types.Type{}, - []*types.Type{types.UntypedString}) - field := types.NewField(src.NoXPos, typecheck.Lookup("f"), fldt) + []*types.Type{types.Types[types.TSTRING]}) + field := types.NewField(src.NoXPos, typecheck.Lookup("F"), fldt) nei := types.NewInterface(types.LocalPkg, []*types.Field{field}) i16 := types.Types[types.TINT16] tb := types.Types[types.TBOOL] @@ -322,12 +324,12 @@ func TestABIUtilsInterfaces(t *testing.T) { IN 0: R{ I0 I1 I2 } spilloffset: 0 typ: struct { int16; int16; bool } IN 1: R{ I3 I4 } spilloffset: 8 typ: interface {} IN 2: R{ I5 I6 } spilloffset: 24 typ: interface {} - IN 3: R{ I7 I8 } spilloffset: 40 typ: interface { .f() untyped string } + IN 3: R{ I7 I8 } spilloffset: 40 typ: interface { F() string } IN 4: R{ } offset: 0 typ: *interface {} - IN 5: R{ } offset: 8 typ: interface { .f() untyped string } + IN 5: R{ } offset: 8 typ: interface { F() string } IN 6: R{ } offset: 24 typ: int16 OUT 0: R{ I0 I1 } spilloffset: -1 typ: interface {} - OUT 1: R{ I2 I3 } spilloffset: -1 typ: interface { .f() untyped string } + OUT 1: R{ I2 I3 } spilloffset: -1 typ: interface { F() string } OUT 2: R{ I4 } spilloffset: -1 typ: *interface {} offsetToSpillArea: 32 spillAreaSize: 56 `) From 04acb8a7b9fc0212687cc25aa2598d12f6aceb74 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Thu, 8 Jul 2021 12:07:01 -0700 Subject: [PATCH 654/940] [dev.typeparams] cmd/compile: report mismatch between types because of //go:notinheap types2 currently ignores pragmas, so it does not catch a conversion error when converting a pointer to a type which is NOT marked notinheap to a pointer to a convertible type, but which is marked notinheap. So, we specifically check for this error in transformConv() and report it during noder2. Change-Id: I6e9c9ee29f53fa5e490c1ac8306e2191db59eeb4 Reviewed-on: https://go-review.googlesource.com/c/go/+/333369 Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Robert Griesemer Trust: Robert Griesemer Trust: Dan Scales --- src/cmd/compile/internal/noder/irgen.go | 4 ++++ src/cmd/compile/internal/noder/transform.go | 10 +++++++++- test/run.go | 3 +-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go index 64c29435b5e..880073a89ec 100644 --- a/src/cmd/compile/internal/noder/irgen.go +++ b/src/cmd/compile/internal/noder/irgen.go @@ -219,6 +219,10 @@ Outer: } } + // Check for unusual case where noder2 encounters a type error that types2 + // doesn't check for (e.g. notinheap incompatibility). + base.ExitIfErrors() + typecheck.DeclareUniverse() for _, p := range noders { diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go index e02b7e758db..efbc8f68cee 100644 --- a/src/cmd/compile/internal/noder/transform.go +++ b/src/cmd/compile/internal/noder/transform.go @@ -85,7 +85,15 @@ func stringtoruneslit(n *ir.ConvExpr) ir.Node { // etc. Corresponds to typecheck.tcConv. func transformConv(n *ir.ConvExpr) ir.Node { t := n.X.Type() - op, _ := typecheck.Convertop(n.X.Op() == ir.OLITERAL, t, n.Type()) + op, why := typecheck.Convertop(n.X.Op() == ir.OLITERAL, t, n.Type()) + if op == ir.OXXX { + // types2 currently ignores pragmas, so a 'notinheap' mismatch is the + // one type-related error that it does not catch. This error will be + // caught here by Convertop (see two checks near beginning of + // Convertop) and reported at the end of noding. + base.ErrorfAt(n.Pos(), "cannot convert %L to type %v%s", n.X, n.Type(), why) + return n + } n.SetOp(op) switch n.Op() { case ir.OCONVNOP: diff --git a/test/run.go b/test/run.go index 90861786df9..d6209c25915 100644 --- a/test/run.go +++ b/test/run.go @@ -2204,8 +2204,7 @@ var g3Failures = setOf( "typeparam/nested.go", // -G=3 doesn't support function-local types with generics - "typeparam/mdempsky/4.go", // -G=3 can't export functions with labeled breaks in loops - "typeparam/mdempsky/11.go", // types2/noder2 should give conversion error, because of "notinheap" mismatch + "typeparam/mdempsky/4.go", // -G=3 can't export functions with labeled breaks in loops ) var unifiedFailures = setOf( From 69d945fc6e80475c163f96ba86fe716e77bb0104 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 7 Jul 2021 21:38:49 -0700 Subject: [PATCH 655/940] [dev.typeparams] cmd/compile/internal/types2: use scope numbers to identify local types Rather than using a local types' position information, use the type name's scope numbers to uniquely identify the type from others with the same name. We use scope numbers rather than indices (with number-1 == index) to preserve the invariant that the zero value for a scope is a ready to use empty scope. Using scope numbers turned out to be fairly simple after all and provides a reasonably stable identification which will make debugging simpler. A scope number series may be a bit longer than a unique ID for each type name but local types should be reasonably rare. Also did a minor cleanup in universe.go to ensure Named.orig is set up correctly (there's still an open TODO but with a work-around). Change-Id: I73935fa9bd960809fd5c95fe8b8a535c313cfc8f Reviewed-on: https://go-review.googlesource.com/c/go/+/333192 Trust: Robert Griesemer Run-TryBot: Robert Griesemer Reviewed-by: Robert Findley TryBot-Result: Go Bot --- src/cmd/compile/internal/types2/instance.go | 2 +- src/cmd/compile/internal/types2/scope.go | 4 ++- .../compile/internal/types2/sizeof_test.go | 2 +- src/cmd/compile/internal/types2/subst.go | 2 -- src/cmd/compile/internal/types2/typestring.go | 29 +++++++++++-------- src/cmd/compile/internal/types2/universe.go | 12 +++++--- 6 files changed, 30 insertions(+), 21 deletions(-) diff --git a/src/cmd/compile/internal/types2/instance.go b/src/cmd/compile/internal/types2/instance.go index 9d6097e8742..b133fd1e65d 100644 --- a/src/cmd/compile/internal/types2/instance.go +++ b/src/cmd/compile/internal/types2/instance.go @@ -16,7 +16,7 @@ type instance struct { base *Named // parameterized type to be instantiated targs []Type // type arguments poslist []syntax.Pos // position of each targ; for error reporting only - value Type // base(targs...) after instantiation or Typ[Invalid]; nil if not yet set + value Type // base[targs...] after instantiation or Typ[Invalid]; nil if not yet set } // expand returns the instantiated (= expanded) type of t. diff --git a/src/cmd/compile/internal/types2/scope.go b/src/cmd/compile/internal/types2/scope.go index 2f1814a6319..095875d94b0 100644 --- a/src/cmd/compile/internal/types2/scope.go +++ b/src/cmd/compile/internal/types2/scope.go @@ -23,6 +23,7 @@ import ( type Scope struct { parent *Scope children []*Scope + number int // parent.children[number-1] is this scope; 0 if there is no parent elems map[string]Object // lazily allocated pos, end syntax.Pos // scope extent; may be invalid comment string // for debugging only @@ -32,10 +33,11 @@ type Scope struct { // NewScope returns a new, empty scope contained in the given parent // scope, if any. The comment is for debugging only. func NewScope(parent *Scope, pos, end syntax.Pos, comment string) *Scope { - s := &Scope{parent, nil, nil, pos, end, comment, false} + s := &Scope{parent, nil, 0, nil, pos, end, comment, false} // don't add children to Universe scope! if parent != nil && parent != Universe { parent.children = append(parent.children, s) + s.number = len(parent.children) } return s } diff --git a/src/cmd/compile/internal/types2/sizeof_test.go b/src/cmd/compile/internal/types2/sizeof_test.go index 0b1f7dacad3..a51d0c43d5a 100644 --- a/src/cmd/compile/internal/types2/sizeof_test.go +++ b/src/cmd/compile/internal/types2/sizeof_test.go @@ -47,7 +47,7 @@ func TestSizeof(t *testing.T) { {Nil{}, 56, 88}, // Misc - {Scope{}, 56, 96}, + {Scope{}, 60, 104}, {Package{}, 40, 80}, {TypeSet{}, 20, 40}, } diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index 7b4796fa2eb..59efe8a0459 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -422,8 +422,6 @@ func (subst *subster) typ(typ Type) Type { var instanceHashing = 0 -// TODO(gri) Eventually, this should be more sophisticated. -// It won't work correctly for locally declared types. func instantiatedHash(typ *Named, targs []Type) string { assert(instanceHashing == 0) instanceHashing++ diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go index f63a23c98ce..44099133a03 100644 --- a/src/cmd/compile/internal/types2/typestring.go +++ b/src/cmd/compile/internal/types2/typestring.go @@ -363,22 +363,27 @@ func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) { buf.WriteString(obj.name) if instanceHashing != 0 { - // For local defined types, use the (original!) TypeName's position - // to disambiguate. This is overkill, and could probably instead - // just be the pointer value (if we assume a non-moving GC) or - // a unique ID (like cmd/compile uses). But this works for now, - // and is convenient for debugging. - - // TODO(mdempsky): I still don't fully understand why typ.orig.orig - // can differ from typ.orig, or whether looping more than twice is - // ever necessary. + // For local defined types, use the (original!) TypeName's scope + // numbers to disambiguate. typ := obj.typ.(*Named) + // TODO(gri) Figure out why typ.orig != typ.orig.orig sometimes + // and whether the loop can iterate more than twice. + // (It seems somehow connected to instance types.) for typ.orig != typ { typ = typ.orig } - if orig := typ.obj; orig.pkg != nil && orig.parent != orig.pkg.scope { - fmt.Fprintf(buf, "@%q", orig.pos) - } + writeScopeNumbers(buf, typ.obj.parent) + } +} + +// writeScopeNumbers writes the number sequence for this scope to buf +// in the form ".i.j.k" where i, j, k, etc. stand for scope numbers. +// If a scope is nil or has no parent (such as a package scope), nothing +// is written. +func writeScopeNumbers(buf *bytes.Buffer, s *Scope) { + if s != nil && s.number > 0 { + writeScopeNumbers(buf, s.parent) + fmt.Fprintf(buf, ".%d", s.number) } } diff --git a/src/cmd/compile/internal/types2/universe.go b/src/cmd/compile/internal/types2/universe.go index c9b53bac921..d328b13a8e1 100644 --- a/src/cmd/compile/internal/types2/universe.go +++ b/src/cmd/compile/internal/types2/universe.go @@ -86,21 +86,25 @@ func defPredeclaredTypes() { // type error interface{ Error() string } { + obj := NewTypeName(nopos, nil, "error", nil) + obj.setColor(black) res := NewVar(nopos, nil, "", Typ[String]) sig := NewSignature(nil, nil, NewTuple(res), false) err := NewFunc(nopos, nil, "Error", sig) - typ := &Named{underlying: NewInterfaceType([]*Func{err}, nil)} + typ := NewNamed(obj, NewInterfaceType([]*Func{err}, nil), nil) sig.recv = NewVar(nopos, nil, "", typ) - def(NewTypeName(nopos, nil, "error", typ)) + def(obj) } // type comparable interface{ ==() } { + obj := NewTypeName(nopos, nil, "comparable", nil) + obj.setColor(black) sig := NewSignature(nil, nil, nil, false) eql := NewFunc(nopos, nil, "==", sig) - typ := &Named{underlying: NewInterfaceType([]*Func{eql}, nil)} + typ := NewNamed(obj, NewInterfaceType([]*Func{eql}, nil), nil) sig.recv = NewVar(nopos, nil, "", typ) - def(NewTypeName(nopos, nil, "comparable", typ)) + def(obj) } } From f2ed30c31edf67bd753a10891dfeb5aeb65c95dd Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 8 Jul 2021 19:57:24 -0700 Subject: [PATCH 656/940] [dev.typeparams] cmd/compile/internal/types2: recursive substitution must terminate (bug fix) When types2.Instantiate is called externally, no *Checker is provided and substitution doesn't have access to Checker.typMap; and instantiation of recursive generic types leads to an infinite recursion in subst. There was a local subster.cache but it was only set and never used. Replaced subster.cache with subster.typMap, which is set to the global Checker.typMap if available, and set to a local map otherwise. This prevents such infinite recursions. Added a simple test. More generally, because we don't have a global type map for external instantiations, instantiating the same type twice, independently but with the same type arguments, will result in two different types. This is not correct. We need to provide some form of context for external instantiations (which means the importers). This is a separate but related issue which is not yet addressed (filed #47103). Change-Id: I541556c677db54f7396fd0c88c7467894dfcf2e7 Reviewed-on: https://go-review.googlesource.com/c/go/+/333383 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/api_test.go | 23 +++++++++++++ src/cmd/compile/internal/types2/subst.go | 38 ++++++++++++--------- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/cmd/compile/internal/types2/api_test.go b/src/cmd/compile/internal/types2/api_test.go index c7f3e490aa0..1c535387d40 100644 --- a/src/cmd/compile/internal/types2/api_test.go +++ b/src/cmd/compile/internal/types2/api_test.go @@ -1846,3 +1846,26 @@ func f(x T) T { return foo.F(x) } } } } + +func TestInstantiate(t *testing.T) { + // eventually we like more tests but this is a start + const src = genericPkg + "p; type T[P any] *T[P]" + pkg, err := pkgFor(".", src, nil) + if err != nil { + t.Fatal(err) + } + + // type T should have one type parameter + T := pkg.Scope().Lookup("T").Type().(*Named) + if n := len(T.TParams()); n != 1 { + t.Fatalf("expected 1 type parameter; found %d", n) + } + + // instantiation should succeed (no endless recursion) + res := Instantiate(nopos, T, []Type{Typ[Int]}) + + // instantiated type should point to itself + if res.Underlying().(*Pointer).Elem() != res { + t.Fatalf("unexpected result type: %s", res) + } +} diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index 59efe8a0459..6e4e778b208 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -233,15 +233,27 @@ func (check *Checker) subst(pos syntax.Pos, typ Type, smap *substMap) Type { } // general case - subst := subster{check, pos, make(map[Type]Type), smap} + var subst subster + subst.pos = pos + subst.smap = smap + if check != nil { + subst.check = check + subst.typMap = check.typMap + } else { + // If we don't have a *Checker and its global type map, + // use a local version. Besides avoiding duplicate work, + // the type map prevents infinite recursive substitution + // for recursive types (example: type T[P any] *T[P]). + subst.typMap = make(map[string]*Named) + } return subst.typ(typ) } type subster struct { - check *Checker - pos syntax.Pos - cache map[Type]Type - smap *substMap + pos syntax.Pos + smap *substMap + check *Checker // nil if called via Instantiate + typMap map[string]*Named } func (subst *subster) typ(typ Type) Type { @@ -382,22 +394,16 @@ func (subst *subster) typ(typ Type) Type { // before creating a new named type, check if we have this one already h := instantiatedHash(t, new_targs) dump(">>> new type hash: %s", h) - if subst.check != nil { - if named, found := subst.check.typMap[h]; found { - dump(">>> found %s", named) - subst.cache[t] = named - return named - } + if named, found := subst.typMap[h]; found { + dump(">>> found %s", named) + return named } - // create a new named type and populate caches to avoid endless recursion + // create a new named type and populate typMap to avoid endless recursion tname := NewTypeName(subst.pos, t.obj.pkg, t.obj.name, nil) named := subst.check.newNamed(tname, t, t.Underlying(), t.TParams(), t.methods) // method signatures are updated lazily named.targs = new_targs - if subst.check != nil { - subst.check.typMap[h] = named - } - subst.cache[t] = named + subst.typMap[h] = named // do the substitution dump(">>> subst %s with %s (new: %s)", t.underlying, subst.smap, new_targs) From ab4085ce84f8378b4ec2dfdbbc44c98cb92debe5 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Fri, 9 Jul 2021 17:34:07 +0000 Subject: [PATCH 657/940] runtime/pprof: call runtime.GC twice in memory profile test This change fixes #46500 by working around #45315 which may cause freed objects to get missed in the heap profile published for the test. By calling runtime.GC one more time this change ensures that all freed objects are accounted for. Fixes #46500. Change-Id: Iedcd0b37dbaffa688b0ff8631a8b79f7a1169634 Reviewed-on: https://go-review.googlesource.com/c/go/+/333549 Trust: Michael Knyszek Run-TryBot: Michael Knyszek TryBot-Result: Go Bot Reviewed-by: Austin Clements --- src/runtime/pprof/mprof_test.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/runtime/pprof/mprof_test.go b/src/runtime/pprof/mprof_test.go index 3ef40d3de7d..b4680fbdee9 100644 --- a/src/runtime/pprof/mprof_test.go +++ b/src/runtime/pprof/mprof_test.go @@ -86,6 +86,17 @@ func TestMemoryProfiler(t *testing.T) { runtime.GC() // materialize stats + // TODO(mknyszek): Fix #45315 and remove this extra call. + // + // Unfortunately, it's possible for the sweep termination condition + // to flap, so with just one runtime.GC call, a freed object could be + // missed, leading this test to fail. A second call reduces the chance + // of this happening to zero, because sweeping actually has to finish + // to move on to the next GC, during which nothing will happen. + // + // See #46500 for more details. + runtime.GC() + memoryProfilerRun++ tests := []struct { From 5059aed9dd33e35d3d0d88be945b2aed8265e1c3 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 9 Jul 2021 11:15:23 -0700 Subject: [PATCH 658/940] [dev.typeparams] internal/buildcfg: allow regabiwrappers on all GOARCH There's nothing GOARCH-specific about ABI wrappers, so allow enabling them on all architectures. For unified IR, I want to have a testing mode where we add dictionary parameters even to non-generic functions, as a way to help stress test that they're handled correctly. This requires callers to know to supply the appropriate dictionary arguments when calling them. Calls generated by the Go compiler know to do this, but calls written in assembly won't. Reusing the regabi wrappers is a convenient choke-point for inserting dictionary arguments for assembly calls. Change-Id: Ic2c06b7626730289c5405829b61653d1daec430b Reviewed-on: https://go-review.googlesource.com/c/go/+/333453 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- src/internal/buildcfg/exp.go | 1 - 1 file changed, 1 deletion(-) diff --git a/src/internal/buildcfg/exp.go b/src/internal/buildcfg/exp.go index 6e8bf30743d..0245574ec1c 100644 --- a/src/internal/buildcfg/exp.go +++ b/src/internal/buildcfg/exp.go @@ -111,7 +111,6 @@ func ParseGOEXPERIMENT(goos, goarch, goexp string) (flags, baseline goexperiment } // regabi is only supported on amd64 and arm64. if goarch != "amd64" && goarch != "arm64" { - flags.RegabiWrappers = false flags.RegabiReflect = false flags.RegabiArgs = false } From a12ad271195d88ffa8f68ad01547560fb4d2ab49 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 7 Jul 2021 23:32:49 -0700 Subject: [PATCH 659/940] [dev.typeparams] cmd/compile: report functions declared in Go and assembly This CL reuses the symabi wrapper information to warn when a function is defined both in Go (i.e., has a function declaration with a body) and in assembly (i.e., has a TEXT instruction). This will eventually produce a linker error anyway, but we can provide a slightly nicer error message earlier. Change-Id: Ia107f813343c0b10f4cd1013e7c72e67149ee52e Reviewed-on: https://go-review.googlesource.com/c/go/+/333454 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- src/cmd/compile/internal/ssagen/abi.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cmd/compile/internal/ssagen/abi.go b/src/cmd/compile/internal/ssagen/abi.go index e460adaf95d..6d8c53e7225 100644 --- a/src/cmd/compile/internal/ssagen/abi.go +++ b/src/cmd/compile/internal/ssagen/abi.go @@ -152,6 +152,9 @@ func (s *SymABIs) GenABIWrappers() { // Apply definitions. defABI, hasDefABI := s.defs[symName] if hasDefABI { + if len(fn.Body) != 0 { + base.ErrorfAt(fn.Pos(), "%v defined in both Go and assembly", fn) + } fn.ABI = defABI } From 3c3c1d8d2856e7859f4ba36b19c91f1538546d2a Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 9 Jul 2021 17:47:15 -0700 Subject: [PATCH 660/940] [dev.typeparams] cmd/compile: more incremental typecheck for unified IR CL 332469 changed the unified IR reader to incrementally typecheck each statement as they're read/constructed. This CL goes further to incrementally typecheck each expression. While here, this CL reorganizes a few things to make this go more smoothly. In particular, it renames expr to expr0 and adds a new expr wrapper that applies typecheck.Expr; gets rid of exprTypeSwitchguard by moving that logic into switchStmt; and splits exprConvert out from exprCall, which simplifies the logic for typechecking the calleee expression somewhat. Change-Id: I6289de9388dc94a947971f4b7213aafeb2faa5dc Reviewed-on: https://go-review.googlesource.com/c/go/+/333730 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Trust: Matthew Dempsky Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/noder/codes.go | 4 +-- src/cmd/compile/internal/noder/reader.go | 43 ++++++++++++++++++------ src/cmd/compile/internal/noder/writer.go | 34 +++++++++++++------ 3 files changed, 57 insertions(+), 24 deletions(-) diff --git a/src/cmd/compile/internal/noder/codes.go b/src/cmd/compile/internal/noder/codes.go index 4a6a4e83071..f8cb7729acc 100644 --- a/src/cmd/compile/internal/noder/codes.go +++ b/src/cmd/compile/internal/noder/codes.go @@ -107,9 +107,7 @@ const ( exprUnaryOp exprBinaryOp exprCall - - // TODO(mdempsky): Handle in switchStmt directly instead. - exprTypeSwitchGuard + exprConvert ) type codeDecl int diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 122bc70f24b..19e51d9eba9 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -1252,7 +1252,7 @@ func (r *reader) assignList() ([]*ir.Name, []ir.Node) { continue } - lhs[i] = r.expr() + lhs[i] = typecheck.AssignExpr(r.expr0()) } return names, lhs @@ -1351,7 +1351,21 @@ func (r *reader) switchStmt(label *types.Sym) ir.Node { r.openScope() pos := r.pos() init := r.stmt() - tag := r.expr() + + var tag ir.Node + if r.bool() { + pos := r.pos() + var ident *ir.Ident + if r.bool() { + pos := r.pos() + sym := typecheck.Lookup(r.string()) + ident = ir.NewIdent(pos, sym) + } + x := r.expr() + tag = ir.NewTypeSwitchGuard(pos, ident, x) + } else { + tag = r.expr() + } tswitch, ok := tag.(*ir.TypeSwitchGuard) if ok && tswitch.Tag == nil { @@ -1432,7 +1446,19 @@ func (r *reader) initDefn(defn ir.InitNode, names []*ir.Name) bool { // @@@ Expressions +// expr reads and returns a typechecked expression. func (r *reader) expr() ir.Node { + n := r.expr0() + if n == nil || n.Op() == ir.OTYPE { + // TODO(mdempsky): Push this responsibility up to callers? + return n + } + return typecheck.Expr(n) +} + +// expr0 reads and returns an expression, possibly untypechecked. +// The caller must typecheck the result as appropriate for its context. +func (r *reader) expr0() ir.Node { switch tag := codeExpr(r.code(syncExpr)); tag { default: panic("unhandled expression") @@ -1522,22 +1548,17 @@ func (r *reader) expr() ir.Node { return ir.NewBinaryExpr(pos, op, x, y) case exprCall: - fun := r.expr() + fun := typecheck.Callee(r.expr0()) pos := r.pos() args := r.exprs() dots := r.bool() return typecheck.Call(pos, fun, args, dots) - case exprTypeSwitchGuard: + case exprConvert: + typ := r.typ() pos := r.pos() - var tag *ir.Ident - if r.bool() { - pos := r.pos() - sym := typecheck.Lookup(r.string()) - tag = ir.NewIdent(pos, sym) - } x := r.expr() - return ir.NewTypeSwitchGuard(pos, tag, x) + return ir.NewConvExpr(pos, ir.OCONV, typ, x) } } diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go index 6348a567414..3f9310514a4 100644 --- a/src/cmd/compile/internal/noder/writer.go +++ b/src/cmd/compile/internal/noder/writer.go @@ -1033,7 +1033,17 @@ func (w *writer) switchStmt(stmt *syntax.SwitchStmt) { w.openScope(stmt.Pos()) w.pos(stmt) w.stmt(stmt.Init) - w.expr(stmt.Tag) + + if guard, ok := stmt.Tag.(*syntax.TypeSwitchGuard); w.bool(ok) { + w.pos(guard) + if tag := guard.Lhs; w.bool(tag != nil) { + w.pos(tag) + w.string(tag.Value) + } + w.expr(guard.X) + } else { + w.expr(stmt.Tag) + } w.len(len(stmt.Body)) for i, clause := range stmt.Body { @@ -1207,6 +1217,19 @@ func (w *writer) expr(expr syntax.Expr) { w.expr(expr.Y) case *syntax.CallExpr: + tv, ok := w.p.info.Types[expr.Fun] + assert(ok) + if tv.IsType() { + assert(len(expr.ArgList) == 1) + assert(!expr.HasDots) + + w.code(exprConvert) + w.typ(tv.Type) + w.pos(expr) + w.expr(expr.ArgList[0]) + break + } + w.code(exprCall) if inf, ok := w.p.info.Inferred[expr]; ok { @@ -1223,15 +1246,6 @@ func (w *writer) expr(expr syntax.Expr) { w.pos(expr) w.exprs(expr.ArgList) w.bool(expr.HasDots) - - case *syntax.TypeSwitchGuard: - w.code(exprTypeSwitchGuard) - w.pos(expr) - if tag := expr.Lhs; w.bool(tag != nil) { - w.pos(tag) - w.string(tag.Value) - } - w.expr(expr.X) } } From 0dcab98fd829e845a83fed996025f96b8b1165b1 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 9 Jul 2021 19:47:45 -0700 Subject: [PATCH 661/940] [dev.typeparams] cmd/compile: slightly more incremental unified typecheck This CL pushes the typecheck.Expr calls further down to the IR construction points. It turns out we don't really care about typecheck.AssignExpr, because it's only used to distinguish whether ir.BlankNode is allowed. We can avoid that issue by just skipping the call to typecheck.Expr for blank nodes. Similarly, for typecheck.Callee, only two details matter: (1) don't report errors for builtin functions (which aren't allowed outside of callee contexts); and (2) method-value selector expressions need to have Op ODOTMETH/ODOTINTER rather than OMETHVALUE. The first can be handled by simply skipping typecheck on Names (as with ir.BlankNode, we don't need to typecheck these). The second currently requires adding a 'callee bool' parameter to disambiguate the context. The other option would be for exprCall to reset the fun's Op from OMETHVALUE to OXDOT and let typecheck handle it a second time. But I anticipate needing to add extra logic in the exprSelector case which would be harder to undo, so this seems somewhat better. Change-Id: I1a8dfb6af04265ab466fd7f4cb6ee8b479e92282 Reviewed-on: https://go-review.googlesource.com/c/go/+/333769 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le Trust: Matthew Dempsky --- src/cmd/compile/internal/noder/reader.go | 76 +++++++++++++----------- src/cmd/compile/internal/noder/writer.go | 31 +++++++--- 2 files changed, 64 insertions(+), 43 deletions(-) diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 19e51d9eba9..25aac6c026a 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -1252,7 +1252,7 @@ func (r *reader) assignList() ([]*ir.Name, []ir.Node) { continue } - lhs[i] = typecheck.AssignExpr(r.expr0()) + lhs[i] = r.expr() } return names, lhs @@ -1447,18 +1447,13 @@ func (r *reader) initDefn(defn ir.InitNode, names []*ir.Name) bool { // @@@ Expressions // expr reads and returns a typechecked expression. -func (r *reader) expr() ir.Node { - n := r.expr0() - if n == nil || n.Op() == ir.OTYPE { - // TODO(mdempsky): Push this responsibility up to callers? - return n - } - return typecheck.Expr(n) -} +func (r *reader) expr() (res ir.Node) { + defer func() { + if res != nil && res.Typecheck() == 0 { + base.FatalfAt(res.Pos(), "%v missed typecheck", res) + } + }() -// expr0 reads and returns an expression, possibly untypechecked. -// The caller must typecheck the result as appropriate for its context. -func (r *reader) expr0() ir.Node { switch tag := codeExpr(r.code(syncExpr)); tag { default: panic("unhandled expression") @@ -1467,23 +1462,30 @@ func (r *reader) expr0() ir.Node { return nil case exprBlank: - return ir.BlankNode + // blank only allowed in LHS of assignments + // TODO(mdempsky): Handle directly in assignList instead? + return typecheck.AssignExpr(ir.BlankNode) case exprLocal: - return r.useLocal() + return typecheck.Expr(r.useLocal()) case exprName: - return r.obj() + // Callee instead of Expr allows builtins + // TODO(mdempsky): Handle builtins directly in exprCall, like method calls? + return typecheck.Callee(r.obj()) case exprType: - return ir.TypeNode(r.typ()) + // TODO(mdempsky): ir.TypeNode should probably return a typecheck'd node. + n := ir.TypeNode(r.typ()) + n.SetTypecheck(1) + return n case exprConst: pos := r.pos() typ, val := r.value() op := r.op() orig := r.string() - return OrigConst(pos, typ, val, op, orig) + return typecheck.Expr(OrigConst(pos, typ, val, op, orig)) case exprCompLit: return r.compLit() @@ -1495,13 +1497,13 @@ func (r *reader) expr0() ir.Node { x := r.expr() pos := r.pos() _, sym := r.selector() - return ir.NewSelectorExpr(pos, ir.OXDOT, x, sym) + return typecheck.Expr(ir.NewSelectorExpr(pos, ir.OXDOT, x, sym)) case exprIndex: x := r.expr() pos := r.pos() index := r.expr() - return ir.NewIndexExpr(pos, x, index) + return typecheck.Expr(ir.NewIndexExpr(pos, x, index)) case exprSlice: x := r.expr() @@ -1514,13 +1516,13 @@ func (r *reader) expr0() ir.Node { if index[2] != nil { op = ir.OSLICE3 } - return ir.NewSliceExpr(pos, op, x, index[0], index[1], index[2]) + return typecheck.Expr(ir.NewSliceExpr(pos, op, x, index[0], index[1], index[2])) case exprAssert: x := r.expr() pos := r.pos() typ := r.expr().(ir.Ntype) - return ir.NewTypeAssertExpr(pos, x, typ) + return typecheck.Expr(ir.NewTypeAssertExpr(pos, x, typ)) case exprUnaryOp: op := r.op() @@ -1529,11 +1531,11 @@ func (r *reader) expr0() ir.Node { switch op { case ir.OADDR: - return typecheck.NodAddrAt(pos, x) + return typecheck.Expr(typecheck.NodAddrAt(pos, x)) case ir.ODEREF: - return ir.NewStarExpr(pos, x) + return typecheck.Expr(ir.NewStarExpr(pos, x)) } - return ir.NewUnaryExpr(pos, op, x) + return typecheck.Expr(ir.NewUnaryExpr(pos, op, x)) case exprBinaryOp: op := r.op() @@ -1543,12 +1545,17 @@ func (r *reader) expr0() ir.Node { switch op { case ir.OANDAND, ir.OOROR: - return ir.NewLogicalExpr(pos, op, x, y) + return typecheck.Expr(ir.NewLogicalExpr(pos, op, x, y)) } - return ir.NewBinaryExpr(pos, op, x, y) + return typecheck.Expr(ir.NewBinaryExpr(pos, op, x, y)) case exprCall: - fun := typecheck.Callee(r.expr0()) + fun := r.expr() + if r.bool() { // method call + pos := r.pos() + _, sym := r.selector() + fun = typecheck.Callee(ir.NewSelectorExpr(pos, ir.OXDOT, fun, sym)) + } pos := r.pos() args := r.exprs() dots := r.bool() @@ -1558,17 +1565,17 @@ func (r *reader) expr0() ir.Node { typ := r.typ() pos := r.pos() x := r.expr() - return ir.NewConvExpr(pos, ir.OCONV, typ, x) + return typecheck.Expr(ir.NewConvExpr(pos, ir.OCONV, typ, x)) } } func (r *reader) compLit() ir.Node { r.sync(syncCompLit) pos := r.pos() - typ := r.typ() + typ0 := r.typ() - isPtrLit := typ.IsPtr() - if isPtrLit { + typ := typ0 + if typ.IsPtr() { typ = typ.Elem() } if typ.Kind() == types.TFORW { @@ -1591,9 +1598,10 @@ func (r *reader) compLit() ir.Node { *elemp = wrapName(r.pos(), r.expr()) } - lit := ir.NewCompLitExpr(pos, ir.OCOMPLIT, ir.TypeNode(typ), elems) - if isPtrLit { - return typecheck.NodAddrAt(pos, lit) + lit := typecheck.Expr(ir.NewCompLitExpr(pos, ir.OCOMPLIT, ir.TypeNode(typ), elems)) + if typ0.IsPtr() { + lit = typecheck.Expr(typecheck.NodAddrAt(pos, lit)) + lit.SetType(typ0) } return lit } diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go index 3f9310514a4..21aeb5678d3 100644 --- a/src/cmd/compile/internal/noder/writer.go +++ b/src/cmd/compile/internal/noder/writer.go @@ -1230,19 +1230,32 @@ func (w *writer) expr(expr syntax.Expr) { break } - w.code(exprCall) + writeFunExpr := func() { + if selector, ok := unparen(expr.Fun).(*syntax.SelectorExpr); ok { + if sel, ok := w.p.info.Selections[selector]; ok && sel.Kind() == types2.MethodVal { + w.expr(selector.X) + w.bool(true) // method call + w.pos(selector) + w.selector(sel.Obj()) + return + } + } - if inf, ok := w.p.info.Inferred[expr]; ok { - obj, _ := lookupObj(w.p.info, expr.Fun) - assert(obj != nil) + if inf, ok := w.p.info.Inferred[expr]; ok { + obj, _ := lookupObj(w.p.info, expr.Fun) + assert(obj != nil) - // As if w.expr(expr.Fun), but using inf.TArgs instead. - w.code(exprName) - w.obj(obj, inf.TArgs) - } else { - w.expr(expr.Fun) + // As if w.expr(expr.Fun), but using inf.TArgs instead. + w.code(exprName) + w.obj(obj, inf.TArgs) + } else { + w.expr(expr.Fun) + } + w.bool(false) // not a method call (i.e., normal function call) } + w.code(exprCall) + writeFunExpr() w.pos(expr) w.exprs(expr.ArgList) w.bool(expr.HasDots) From 1c783dc1480e8dec8bd4e76b744238607ea527f0 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Fri, 2 Jul 2021 17:51:20 -0700 Subject: [PATCH 662/940] [dev.typeparams] Add optional sub-dict entry for typeparam bound calls In the case that a generic function/method f does a method call on a type param allowed by its bound, an instantiation of f may do a direct method call of a concrete type or a method call defined on a generic type, depending on whether the passed type in a concrete type or an instantiated type with the appropriate method defined. See the test case boundmethod.go added to this change. In order to keep the dictionary format the same for all instantiations of a generic function/method, I decided to have an optional sub-dictionary entry for "bounds" calls. At the point that we are creating the actual dictionary, we can then fill in the needed sub-dictionary, if the type arg is an instantiated type, or a zeroed dictionary entry, if type arg is not instantiated and the method will be on a concrete type. In order to implement this, I now fill in n.Selection for "bounds" method calls in generic functions as well. Also, I need to calculate n.Selection correctly during import for the case where it is now set - method calls on generic types, and bounds calls on typeparams. With this change, the dictionaries/sub-dictionaries are correct for absdiff.go. The new test boundmethod.go illustrates the case where the bound sub-dict entry is not used for a dictionary for stringify[myint], but is used for a dictionary for stringify[StringInt[myint]]. Change-Id: Ie2bcb971b7019a9f1da68c97eb03da2333327457 Reviewed-on: https://go-review.googlesource.com/c/go/+/333456 Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall Trust: Dan Scales --- src/cmd/compile/internal/noder/expr.go | 30 +++++-- src/cmd/compile/internal/noder/stencil.go | 81 ++++++++++++++----- src/cmd/compile/internal/typecheck/iexport.go | 6 +- src/cmd/compile/internal/typecheck/iimport.go | 22 +++++ test/typeparam/boundmethod.go | 60 ++++++++++++++ 5 files changed, 172 insertions(+), 27 deletions(-) create mode 100644 test/typeparam/boundmethod.go diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go index d974b291d08..16470a54495 100644 --- a/src/cmd/compile/internal/noder/expr.go +++ b/src/cmd/compile/internal/noder/expr.go @@ -207,29 +207,43 @@ func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.Selecto n := ir.NewSelectorExpr(pos, ir.OXDOT, x, typecheck.Lookup(expr.Sel.Value)) typed(g.typ(typ), n) - // Fill in n.Selection for a generic method reference, even though we - // won't use it directly, since it is useful for analysis. - // Specifically do not fill in for fields or interfaces methods, so - // n.Selection being non-nil means a method reference, rather than an - // interface reference or reference to a field with a function value. + // Fill in n.Selection for a generic method reference or a bound + // interface method, even though we won't use it directly, since it + // is useful for analysis. Specifically do not fill in for fields or + // other interfaces methods (method call on an interface value), so + // n.Selection being non-nil means a method reference for a generic + // type or a method reference due to a bound. obj2 := g.info.Selections[expr].Obj() sig := types2.AsSignature(obj2.Type()) if sig == nil || sig.Recv() == nil { return n } - // recvType is the type of the last embedded field. Because of the + index := g.info.Selections[expr].Index() + last := index[len(index)-1] + // recvType is the receiver of the method being called. Because of the // way methods are imported, g.obj(obj2) doesn't work across // packages, so we have to lookup the method via the receiver type. recvType := deref2(sig.Recv().Type()) if types2.AsInterface(recvType.Underlying()) != nil { + fieldType := n.X.Type() + for _, ix := range index[:len(index)-1] { + fieldType = fieldType.Field(ix).Type + } + if fieldType.Kind() == types.TTYPEPARAM { + n.Selection = fieldType.Bound().AllMethods().Index(last) + //fmt.Printf(">>>>> %v: Bound call %v\n", base.FmtPos(pos), n.Sel) + } else { + assert(fieldType.Kind() == types.TINTER) + //fmt.Printf(">>>>> %v: Interface call %v\n", base.FmtPos(pos), n.Sel) + } return n } - index := g.info.Selections[expr].Index() - last := index[len(index)-1] recvObj := types2.AsNamed(recvType).Obj() recv := g.pkg(recvObj.Pkg()).Lookup(recvObj.Name()).Def n.Selection = recv.Type().Methods().Index(last) + //fmt.Printf(">>>>> %v: Method call %v\n", base.FmtPos(pos), n.Sel) + return n } diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index d292bfd5c69..1759fbc4cfd 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -158,12 +158,9 @@ func (g *irgen) stencil() { st := g.getInstantiation(gf, targs, true) dictValue, usingSubdict := g.getDictOrSubdict(declInfo, n, gf, targs, true) - _ = usingSubdict - // TODO: We should do assert(usingSubdict) here, but - // not creating sub-dictionary entry for - // absDifference in absdiff.go yet. Unusual case, - // where there are different generic method - // implementations of Abs in absDifference. + // We have to be using a subdictionary, since this is + // a generic method call. + assert(usingSubdict) call.SetOp(ir.OCALL) call.X = st.Nname @@ -741,10 +738,9 @@ func gcshapeType(t *types.Type) (*types.Type, string) { return gcshape, buf.String() } -// getInstantiation gets the instantiantion and dictionary of the function or method nameNode -// with the type arguments targs. If the instantiated function is not already -// cached, then it calls genericSubst to create the new instantiation. -func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth bool) *ir.Func { +// checkFetchBody checks if a generic body can be fetched, but hasn't been loaded +// yet. If so, it imports the body. +func checkFetchBody(nameNode *ir.Name) { if nameNode.Func.Body == nil && nameNode.Func.Inl != nil { // If there is no body yet but Func.Inl exists, then we can can // import the whole generic body. @@ -754,6 +750,13 @@ func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth nameNode.Func.Body = nameNode.Func.Inl.Body nameNode.Func.Dcl = nameNode.Func.Inl.Dcl } +} + +// getInstantiation gets the instantiantion and dictionary of the function or method nameNode +// with the type arguments targs. If the instantiated function is not already +// cached, then it calls genericSubst to create the new instantiation. +func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth bool) *ir.Func { + checkFetchBody(nameNode) sym := typecheck.MakeInstName(nameNode.Sym(), targs, isMeth) info := g.instInfoMap[sym] if info == nil { @@ -1405,13 +1408,41 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) case ir.OCALL: call := n.(*ir.CallExpr) if call.X.Op() == ir.OXDOT { - subtargs := deref(call.X.(*ir.SelectorExpr).X.Type()).RParams() - s2targs := make([]*types.Type, len(subtargs)) - for i, t := range subtargs { - s2targs[i] = subst.Typ(t) + var nameNode *ir.Name + se := call.X.(*ir.SelectorExpr) + if types.IsInterfaceMethod(se.Selection.Type) { + // This is a method call enabled by a type bound. + tmpse := ir.NewSelectorExpr(base.Pos, ir.OXDOT, se.X, se.Sel) + tmpse = typecheck.AddImplicitDots(tmpse) + tparam := tmpse.X.Type() + assert(tparam.IsTypeParam()) + recvType := targs[tparam.Index()] + if len(recvType.RParams()) == 0 { + // No sub-dictionary entry is + // actually needed, since the + // typeparam is not an + // instantiated type that + // will have generic methods. + break + } + // This is a method call for an + // instantiated type, so we need a + // sub-dictionary. + targs := recvType.RParams() + genRecvType := recvType.OrigSym.Def.Type() + nameNode = typecheck.Lookdot1(call.X, se.Sel, genRecvType, genRecvType.Methods(), 1).Nname.(*ir.Name) + sym = g.getDictionarySym(nameNode, targs, true) + } else { + // This is the case of a normal + // method call on a generic type. + nameNode = call.X.(*ir.SelectorExpr).Selection.Nname.(*ir.Name) + subtargs := deref(call.X.(*ir.SelectorExpr).X.Type()).RParams() + s2targs := make([]*types.Type, len(subtargs)) + for i, t := range subtargs { + s2targs[i] = subst.Typ(t) + } + sym = g.getDictionarySym(nameNode, s2targs, true) } - nameNode := call.X.(*ir.SelectorExpr).Selection.Nname.(*ir.Name) - sym = g.getDictionarySym(nameNode, s2targs, true) } else { inst := call.X.(*ir.InstExpr) var nameNode *ir.Name @@ -1452,8 +1483,14 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) assert(false) } - off = objw.SymPtr(lsym, off, sym.Linksym(), 0) - infoPrint(" - Subdict %v\n", sym.Name) + if sym == nil { + // Unused sub-dictionary entry, just emit 0. + off = objw.Uintptr(lsym, off, 0) + infoPrint(" - Unused subdict entry\n") + } else { + off = objw.SymPtr(lsym, off, sym.Linksym(), 0) + infoPrint(" - Subdict %v\n", sym.Name) + } } objw.Global(lsym, int32(off), obj.DUPOK|obj.RODATA) infoPrint("=== Done dictionary\n") @@ -1512,6 +1549,7 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo { return infop } + checkFetchBody(gn) var info gfInfo gf := gn.Func recv := gf.Type().Recv() @@ -1575,6 +1613,13 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo { info.subDictCalls = append(info.subDictCalls, n) } } + if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OXDOT && + n.(*ir.CallExpr).X.(*ir.SelectorExpr).Selection != nil && + deref(n.(*ir.CallExpr).X.(*ir.SelectorExpr).X.Type()).IsTypeParam() { + n.(*ir.CallExpr).X.(*ir.SelectorExpr).SetImplicit(true) + infoPrint(" Optional subdictionary at generic bound call: %v\n", n) + info.subDictCalls = append(info.subDictCalls, n) + } if n.Op() == ir.OCLOSURE { // Visit the closure body and add all relevant entries to the // dictionary of the outer function (closure will just use diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index 0a48078bd0f..4fbc48f17be 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -1789,7 +1789,11 @@ func (w *exportWriter) expr(n ir.Node) { w.exoticSelector(n.Sel) if go117ExportTypes { w.exoticType(n.Type()) - if n.Op() == ir.ODOT || n.Op() == ir.ODOTPTR || n.Op() == ir.ODOTINTER { + if n.Op() == ir.OXDOT { + // n.Selection for method references will be + // reconstructed during import. + w.bool(n.Selection != nil) + } else if n.Op() == ir.ODOT || n.Op() == ir.ODOTPTR || n.Op() == ir.ODOTINTER { w.exoticField(n.Selection) } // n.Selection is not required for OMETHEXPR, ODOTMETH, and OMETHVALUE. It will diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 4a97267f05f..bf7f84b5cd9 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -1376,6 +1376,28 @@ func (r *importReader) node() ir.Node { if go117ExportTypes { n.SetType(r.exoticType()) switch op { + case ir.OXDOT: + hasSelection := r.bool() + // We reconstruct n.Selection for method calls on + // generic types and method calls due to type param + // bounds. Otherwise, n.Selection is nil. + if hasSelection { + n1 := ir.NewSelectorExpr(pos, op, expr, sel) + AddImplicitDots(n1) + var m *types.Field + if n1.X.Type().IsTypeParam() { + genType := n1.X.Type().Bound() + m = Lookdot1(n1, sel, genType, genType.AllMethods(), 1) + } else { + genType := types.ReceiverBaseType(n1.X.Type()) + if genType.IsInstantiatedGeneric() { + genType = genType.OrigSym.Def.Type() + } + m = Lookdot1(n1, sel, genType, genType.Methods(), 1) + } + assert(m != nil) + n.Selection = m + } case ir.ODOT, ir.ODOTPTR, ir.ODOTINTER: n.Selection = r.exoticField() case ir.ODOTMETH, ir.OMETHVALUE, ir.OMETHEXPR: diff --git a/test/typeparam/boundmethod.go b/test/typeparam/boundmethod.go new file mode 100644 index 00000000000..c150f9d85ae --- /dev/null +++ b/test/typeparam/boundmethod.go @@ -0,0 +1,60 @@ +// run -gcflags=-G=3 + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This test illustrates how a type bound method (String below) can be implemented +// either by a concrete type (myint below) or a instantiated generic type +// (StringInt[myint] below). + +package main + +import ( + "fmt" + "reflect" + "strconv" +) + +type myint int + +//go:noinline +func (m myint) String() string { + return strconv.Itoa(int(m)) +} + +type Stringer interface { + String() string +} + +func stringify[T Stringer](s []T) (ret []string) { + for _, v := range s { + ret = append(ret, v.String()) + } + return ret +} + +type StringInt[T any] T + +//go:noinline +func (m StringInt[T]) String() string { + return "aa" +} + +func main() { + x := []myint{myint(1), myint(2), myint(3)} + + got := stringify(x) + want := []string{"1", "2", "3"} + if !reflect.DeepEqual(got, want) { + panic(fmt.Sprintf("got %s, want %s", got, want)) + } + + x2 := []StringInt[myint]{StringInt[myint](1), StringInt[myint](2), StringInt[myint](3)} + + got2 := stringify(x2) + want2 := []string{"aa", "aa", "aa"} + if !reflect.DeepEqual(got2, want2) { + panic(fmt.Sprintf("got %s, want %s", got2, want2)) + } +} From cfbd73ba33fc6a3635b3a63096fd6c6bff9d73e8 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 9 Jul 2021 16:22:32 -0400 Subject: [PATCH 663/940] doc/go1.17: editing pass over the "Compiler" section Change-Id: I08c082f548daa7011a8dc42769371329684c90e6 Reviewed-on: https://go-review.googlesource.com/c/go/+/333609 Trust: Austin Clements Trust: Dan Scales Reviewed-by: Dan Scales --- doc/go1.17.html | 62 ++++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 4fa30158bb2..fa8f14de99d 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -401,30 +401,37 @@ func Foo() bool {

Go 1.17 implements a new way of passing function arguments and results using - registers instead of the stack. This work is enabled for Linux, macOS, and - Windows on the 64-bit x86 architecture (the linux/amd64, - darwin/amd64, windows/amd64 ports). For a - representative set of Go packages and programs, benchmarking has shown - performance improvements of about 5%, and a typical reduction in binary size - of about 2%. + registers instead of the stack. + Benchmarks for a representative set of Go packages and programs show + performance improvements of about 5%, and a typical reduction in + binary size of about 2%. + This is currently enabled for Linux, macOS, and Windows on the + 64-bit x86 architecture (the linux/amd64, + darwin/amd64, and windows/amd64 ports).

- This change does not affect the functionality of any safe Go code. It can affect - code outside the compatibility guidelines with - minimal impact. To maintain compatibility with existing assembly functions, - adapter functions converting between the new register-based calling convention - and the previous stack-based calling convention (also known as ABI wrappers) - are sometimes used. This is mostly invisible to users, except for assembly - functions that have their addresses taken in Go. Using reflect.ValueOf(fn).Pointer() - (or similar approaches such as via unsafe.Pointer) to get the address - of an assembly function will now return the address of the ABI wrapper. This is - mostly harmless, except for special-purpose assembly code (such as accessing - thread-local storage or requiring a special stack alignment). Assembly functions - called indirectly from Go via func values will now be made through - ABI wrappers, which may cause a very small performance overhead. Also, calling - Go functions from assembly may now go through ABI wrappers, with a very small - performance overhead. + This change does not affect the functionality of any safe Go code + and is designed to have no impact on most assembly code. + It may affect code that violates + the unsafe.Pointer + rules when accessing function arguments, or that depends on + undocumented behavior involving comparing function code pointers. + To maintain compatibility with existing assembly functions, the + compiler generates adapter functions that convert between the new + register-based calling convention and the previous stack-based + calling convention. + These adapters are typically invisible to users, except that taking + the address of a Go function in assembly code or taking the address + of an assembly function in Go code + using reflect.ValueOf(fn).Pointer() + or unsafe.Pointer will now return the address of the + adapter. + Code that depends on the value of these code pointers may no longer + behave as expected. + Adapters also may cause a very small performance overhead in two + cases: calling an assembly function indirectly from Go via + a func value, and calling Go functions from assembly.

@@ -440,11 +447,14 @@ func Foo() bool {

- Functions containing closures can now be inlined. One effect of this change is - that a function with a closure may actually produce a distinct closure function - for each place that the function is inlined. Hence, this change could reveal - bugs where Go functions are compared (incorrectly) by pointer value. Go - functions are by definition not comparable. + Functions containing closures can now be inlined. + One effect of this change is that a function with a closure may + produce a distinct closure code pointer for each place that the + function is inlined. + Go function values are not directly comparable, but this change + could reveal bugs in code that uses reflect + or unsafe.Pointer to bypass this language restriction + and compare functions by code pointer.

Core library

From a98589711da5e9d935e8d690cfca92892e86d557 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Wed, 9 Jun 2021 11:31:27 -0700 Subject: [PATCH 664/940] crypto/tls: test key type when casting When casting the certificate public key in generateClientKeyExchange, check the type is appropriate. This prevents a panic when a server agrees to a RSA based key exchange, but then sends an ECDSA (or other) certificate. Fixes #47143 Fixes CVE-2021-34558 Thanks to Imre Rad for reporting this issue. Change-Id: Iabccacca6052769a605cccefa1216a9f7b7f6aea Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1116723 Reviewed-by: Filippo Valsorda Reviewed-by: Katie Hockman Reviewed-on: https://go-review.googlesource.com/c/go/+/334031 Trust: Filippo Valsorda Run-TryBot: Filippo Valsorda TryBot-Result: Go Bot Reviewed-by: Dmitri Shuralyov --- src/crypto/tls/key_agreement.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/crypto/tls/key_agreement.go b/src/crypto/tls/key_agreement.go index 8cfbd734f15..c28a64f3a8b 100644 --- a/src/crypto/tls/key_agreement.go +++ b/src/crypto/tls/key_agreement.go @@ -86,7 +86,11 @@ func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello return nil, nil, err } - encrypted, err := rsa.EncryptPKCS1v15(config.rand(), cert.PublicKey.(*rsa.PublicKey), preMasterSecret) + rsaKey, ok := cert.PublicKey.(*rsa.PublicKey) + if !ok { + return nil, nil, errors.New("tls: server certificate contains incorrect key type for selected ciphersuite") + } + encrypted, err := rsa.EncryptPKCS1v15(config.rand(), rsaKey, preMasterSecret) if err != nil { return nil, nil, err } From 22e926546732e4ea1fb20551be4b91f51f3b6e65 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 9 Jul 2021 13:02:24 -0700 Subject: [PATCH 665/940] [dev.typeparams] cmd/compile/internal/types2: replace types2.Instantiate with Checker.Instantiate Allow Checker.Instantiate to work with a nil *Checker receiver (for now). This opens the door to passing in a *Checker at all times. Also, added a verify flag to Instantiate, InstantiateLazy, and instance, to be able to control if constraint satisfaction should be checked or not. Removed types2.Instantiate. For #47103. Change-Id: Ie00ce41b3e50a0fc4341e013922e5f874276d282 Reviewed-on: https://go-review.googlesource.com/c/go/+/333569 Trust: Robert Griesemer Reviewed-by: Robert Findley Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/importer/iimport.go | 3 +- src/cmd/compile/internal/noder/reader2.go | 2 +- src/cmd/compile/internal/types2/api_test.go | 4 +- src/cmd/compile/internal/types2/call.go | 4 +- src/cmd/compile/internal/types2/instance.go | 3 +- .../compile/internal/types2/instantiate.go | 64 ++----------------- .../compile/internal/types2/sizeof_test.go | 2 +- src/cmd/compile/internal/types2/subst.go | 55 ++++++++++------ src/cmd/compile/internal/types2/typexpr.go | 2 + 9 files changed, 56 insertions(+), 83 deletions(-) diff --git a/src/cmd/compile/internal/importer/iimport.go b/src/cmd/compile/internal/importer/iimport.go index 14e64891b80..453fa40f2d6 100644 --- a/src/cmd/compile/internal/importer/iimport.go +++ b/src/cmd/compile/internal/importer/iimport.go @@ -665,7 +665,8 @@ func (r *importReader) doType(base *types2.Named) types2.Type { baseType := r.typ() // The imported instantiated type doesn't include any methods, so // we must always use the methods of the base (orig) type. - t := types2.Instantiate(pos, baseType, targs) + var check *types2.Checker // TODO provide a non-nil *Checker + t := check.Instantiate(pos, baseType, targs, nil, false) return t case unionType: diff --git a/src/cmd/compile/internal/noder/reader2.go b/src/cmd/compile/internal/noder/reader2.go index 89f224d389c..92569ff843f 100644 --- a/src/cmd/compile/internal/noder/reader2.go +++ b/src/cmd/compile/internal/noder/reader2.go @@ -224,7 +224,7 @@ func (r *reader2) doTyp() (res types2.Type) { obj, targs := r.obj() name := obj.(*types2.TypeName) if len(targs) != 0 { - return r.p.check.InstantiateLazy(syntax.Pos{}, name.Type(), targs) + return r.p.check.InstantiateLazy(syntax.Pos{}, name.Type(), targs, false) } return name.Type() diff --git a/src/cmd/compile/internal/types2/api_test.go b/src/cmd/compile/internal/types2/api_test.go index 1c535387d40..74e3da3fe13 100644 --- a/src/cmd/compile/internal/types2/api_test.go +++ b/src/cmd/compile/internal/types2/api_test.go @@ -1862,7 +1862,9 @@ func TestInstantiate(t *testing.T) { } // instantiation should succeed (no endless recursion) - res := Instantiate(nopos, T, []Type{Typ[Int]}) + // even with a nil *Checker + var check *Checker + res := check.Instantiate(nopos, T, []Type{Typ[Int]}, nil, false) // instantiated type should point to itself if res.Underlying().(*Pointer).Elem() != res { diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index 3377270ef80..0d9637e696b 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -56,7 +56,7 @@ func (check *Checker) funcInst(x *operand, inst *syntax.IndexExpr) { } // instantiate function signature - res := check.instantiate(x.Pos(), sig, targs, poslist).(*Signature) + res := check.Instantiate(x.Pos(), sig, targs, poslist, true).(*Signature) assert(res.tparams == nil) // signature is not generic anymore if inferred { check.recordInferred(inst, targs, res) @@ -326,7 +326,7 @@ func (check *Checker) arguments(call *syntax.CallExpr, sig *Signature, targs []T } // compute result signature - rsig = check.instantiate(call.Pos(), sig, targs, nil).(*Signature) + rsig = check.Instantiate(call.Pos(), sig, targs, nil, true).(*Signature) assert(rsig.tparams == nil) // signature is not generic anymore check.recordInferred(call, targs, rsig) diff --git a/src/cmd/compile/internal/types2/instance.go b/src/cmd/compile/internal/types2/instance.go index b133fd1e65d..65c20155073 100644 --- a/src/cmd/compile/internal/types2/instance.go +++ b/src/cmd/compile/internal/types2/instance.go @@ -16,6 +16,7 @@ type instance struct { base *Named // parameterized type to be instantiated targs []Type // type arguments poslist []syntax.Pos // position of each targ; for error reporting only + verify bool // if set, constraint satisfaction is verified value Type // base[targs...] after instantiation or Typ[Invalid]; nil if not yet set } @@ -25,7 +26,7 @@ type instance struct { func (t *instance) expand() Type { v := t.value if v == nil { - v = t.check.instantiate(t.pos, t.base, t.targs, t.poslist) + v = t.check.Instantiate(t.pos, t.base, t.targs, t.poslist, t.verify) if v == nil { v = Typ[Invalid] } diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go index 85c897a9097..b289607de67 100644 --- a/src/cmd/compile/internal/types2/instantiate.go +++ b/src/cmd/compile/internal/types2/instantiate.go @@ -9,71 +9,19 @@ import ( "fmt" ) -// Instantiate instantiates the type typ with the given type arguments. -// typ must be a *Named or a *Signature type, it must be generic, and -// its number of type parameters must match the number of provided type -// arguments. The result is a new, instantiated (not generic) type of -// the same kind (either a *Named or a *Signature). The type arguments -// are not checked against the constraints of the type parameters. -// Any methods attached to a *Named are simply copied; they are not -// instantiated. -func Instantiate(pos syntax.Pos, typ Type, targs []Type) (res Type) { - // TODO(gri) This code is basically identical to the prolog - // in Checker.instantiate. Factor. - var tparams []*TypeName - switch t := typ.(type) { - case *Named: - tparams = t.TParams() - case *Signature: - tparams = t.tparams - defer func() { - // If we had an unexpected failure somewhere don't panic below when - // asserting res.(*Signature). Check for *Signature in case Typ[Invalid] - // is returned. - if _, ok := res.(*Signature); !ok { - return - } - // If the signature doesn't use its type parameters, subst - // will not make a copy. In that case, make a copy now (so - // we can set tparams to nil w/o causing side-effects). - if t == res { - copy := *t - res = © - } - // After instantiating a generic signature, it is not generic - // anymore; we need to set tparams to nil. - res.(*Signature).tparams = nil - }() - - default: - panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) - } - - // the number of supplied types must match the number of type parameters - if len(targs) != len(tparams) { - panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, len(targs), len(tparams))) - } - - if len(tparams) == 0 { - return typ // nothing to do (minor optimization) - } - - smap := makeSubstMap(tparams, targs) - return (*Checker)(nil).subst(pos, typ, smap) -} - // InstantiateLazy is like Instantiate, but avoids actually // instantiating the type until needed. -func (check *Checker) InstantiateLazy(pos syntax.Pos, typ Type, targs []Type) (res Type) { +func (check *Checker) InstantiateLazy(pos syntax.Pos, typ Type, targs []Type, verify bool) (res Type) { base := asNamed(typ) if base == nil { panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) } return &instance{ - check: check, - pos: pos, - base: base, - targs: targs, + check: check, + pos: pos, + base: base, + targs: targs, + verify: verify, } } diff --git a/src/cmd/compile/internal/types2/sizeof_test.go b/src/cmd/compile/internal/types2/sizeof_test.go index a51d0c43d5a..f7f191f6292 100644 --- a/src/cmd/compile/internal/types2/sizeof_test.go +++ b/src/cmd/compile/internal/types2/sizeof_test.go @@ -33,7 +33,7 @@ func TestSizeof(t *testing.T) { {Chan{}, 12, 24}, {Named{}, 84, 160}, {TypeParam{}, 28, 48}, - {instance{}, 52, 96}, + {instance{}, 56, 104}, {top{}, 0, 0}, // Objects diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index 6e4e778b208..32cf5273725 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -53,8 +53,24 @@ func (m *substMap) lookup(tpar *TypeParam) Type { return tpar } -func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, poslist []syntax.Pos) (res Type) { - if check.conf.Trace { +// Instantiate instantiates the type typ with the given type arguments +// targs. To check type constraint satisfaction, verify must be set. +// pos and posList correspond to the instantiation and type argument +// positions respectively; posList may be nil or shorter than the number +// of type arguments provided. +// typ must be a *Named or a *Signature type, and its number of type +// parameters must match the number of provided type arguments. +// The receiver (check) may be nil if and only if verify is not set. +// The result is a new, instantiated (not generic) type of the same kind +// (either a *Named or a *Signature). +// Any methods attached to a *Named are simply copied; they are not +// instantiated. +func (check *Checker) Instantiate(pos syntax.Pos, typ Type, targs []Type, posList []syntax.Pos, verify bool) (res Type) { + if verify && check == nil { + panic("cannot have nil receiver if verify is set") + } + + if check != nil && check.conf.Trace { check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs)) check.indent++ defer func() { @@ -70,7 +86,7 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, poslis }() } - assert(len(poslist) <= len(targs)) + assert(len(posList) <= len(targs)) // TODO(gri) What is better here: work with TypeParams, or work with TypeNames? var tparams []*TypeName @@ -97,18 +113,19 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, poslis // anymore; we need to set tparams to nil. res.(*Signature).tparams = nil }() - default: - check.dump("%v: cannot instantiate %v", pos, typ) - unreachable() // only defined types and (defined) functions can be generic - + // only types and functions can be generic + panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) } // the number of supplied types must match the number of type parameters if len(targs) != len(tparams) { // TODO(gri) provide better error message - check.errorf(pos, "got %d arguments but %d type parameters", len(targs), len(tparams)) - return Typ[Invalid] + if check != nil { + check.errorf(pos, "got %d arguments but %d type parameters", len(targs), len(tparams)) + return Typ[Invalid] + } + panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, len(targs), len(tparams))) } if len(tparams) == 0 { @@ -118,15 +135,17 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, poslis smap := makeSubstMap(tparams, targs) // check bounds - for i, tname := range tparams { - // best position for error reporting - pos := pos - if i < len(poslist) { - pos = poslist[i] - } - // stop checking bounds after the first failure - if !check.satisfies(pos, targs[i], tname.typ.(*TypeParam), smap) { - break + if verify { + for i, tname := range tparams { + // best position for error reporting + pos := pos + if i < len(posList) { + pos = posList[i] + } + // stop checking bounds after the first failure + if !check.satisfies(pos, targs[i], tname.typ.(*TypeParam), smap) { + break + } } } diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index e861f7e7848..d69dd3c496f 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -423,12 +423,14 @@ func (check *Checker) instantiatedType(x syntax.Expr, targs []syntax.Expr, def * // create a new type instance rather than instantiate the type // TODO(gri) should do argument number check here rather than // when instantiating the type? + // TODO(gri) use InstantiateLazy here (cleanup) typ := new(instance) def.setUnderlying(typ) typ.check = check typ.pos = x.Pos() typ.base = base + typ.verify = true // evaluate arguments (always) typ.targs = check.typeList(targs) From 70f1246a9f861bdfe2ea81db0f1545bd31ff6d49 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 9 Jul 2021 13:15:46 -0700 Subject: [PATCH 666/940] [dev.typeparams] cmd/compile/internal/types2: move instantiation code to instantiate.go (cleanup) No code changes besides moving the two functions and updating a couple of file comments. Change-Id: I13a6a78b6e8c132c20c7f81a329f31d5edab0453 Reviewed-on: https://go-review.googlesource.com/c/go/+/333589 Trust: Robert Griesemer Reviewed-by: Robert Findley --- .../compile/internal/types2/instantiate.go | 183 +++++++++++++++++ src/cmd/compile/internal/types2/subst.go | 184 +----------------- 2 files changed, 184 insertions(+), 183 deletions(-) diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go index b289607de67..5ccd511acb0 100644 --- a/src/cmd/compile/internal/types2/instantiate.go +++ b/src/cmd/compile/internal/types2/instantiate.go @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// This file implements instantiation of generic types +// through substitution of type parameters by type arguments. + package types2 import ( @@ -9,6 +12,105 @@ import ( "fmt" ) +// Instantiate instantiates the type typ with the given type arguments +// targs. To check type constraint satisfaction, verify must be set. +// pos and posList correspond to the instantiation and type argument +// positions respectively; posList may be nil or shorter than the number +// of type arguments provided. +// typ must be a *Named or a *Signature type, and its number of type +// parameters must match the number of provided type arguments. +// The receiver (check) may be nil if and only if verify is not set. +// The result is a new, instantiated (not generic) type of the same kind +// (either a *Named or a *Signature). +// Any methods attached to a *Named are simply copied; they are not +// instantiated. +func (check *Checker) Instantiate(pos syntax.Pos, typ Type, targs []Type, posList []syntax.Pos, verify bool) (res Type) { + if verify && check == nil { + panic("cannot have nil receiver if verify is set") + } + + if check != nil && check.conf.Trace { + check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs)) + check.indent++ + defer func() { + check.indent-- + var under Type + if res != nil { + // Calling under() here may lead to endless instantiations. + // Test case: type T[P any] T[P] + // TODO(gri) investigate if that's a bug or to be expected. + under = res.Underlying() + } + check.trace(pos, "=> %s (under = %s)", res, under) + }() + } + + assert(len(posList) <= len(targs)) + + // TODO(gri) What is better here: work with TypeParams, or work with TypeNames? + var tparams []*TypeName + switch t := typ.(type) { + case *Named: + tparams = t.TParams() + case *Signature: + tparams = t.tparams + defer func() { + // If we had an unexpected failure somewhere don't panic below when + // asserting res.(*Signature). Check for *Signature in case Typ[Invalid] + // is returned. + if _, ok := res.(*Signature); !ok { + return + } + // If the signature doesn't use its type parameters, subst + // will not make a copy. In that case, make a copy now (so + // we can set tparams to nil w/o causing side-effects). + if t == res { + copy := *t + res = © + } + // After instantiating a generic signature, it is not generic + // anymore; we need to set tparams to nil. + res.(*Signature).tparams = nil + }() + default: + // only types and functions can be generic + panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) + } + + // the number of supplied types must match the number of type parameters + if len(targs) != len(tparams) { + // TODO(gri) provide better error message + if check != nil { + check.errorf(pos, "got %d arguments but %d type parameters", len(targs), len(tparams)) + return Typ[Invalid] + } + panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, len(targs), len(tparams))) + } + + if len(tparams) == 0 { + return typ // nothing to do (minor optimization) + } + + smap := makeSubstMap(tparams, targs) + + // check bounds + if verify { + for i, tname := range tparams { + // best position for error reporting + pos := pos + if i < len(posList) { + pos = posList[i] + } + // stop checking bounds after the first failure + if !check.satisfies(pos, targs[i], tname.typ.(*TypeParam), smap) { + break + } + } + } + + return check.subst(pos, typ, smap) +} + // InstantiateLazy is like Instantiate, but avoids actually // instantiating the type until needed. func (check *Checker) InstantiateLazy(pos syntax.Pos, typ Type, targs []Type, verify bool) (res Type) { @@ -25,3 +127,84 @@ func (check *Checker) InstantiateLazy(pos syntax.Pos, typ Type, targs []Type, ve verify: verify, } } + +// satisfies reports whether the type argument targ satisfies the constraint of type parameter +// parameter tpar (after any of its type parameters have been substituted through smap). +// A suitable error is reported if the result is false. +// TODO(gri) This should be a method of interfaces or type sets. +func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap *substMap) bool { + iface := tpar.Bound() + if iface.Empty() { + return true // no type bound + } + + // The type parameter bound is parameterized with the same type parameters + // as the instantiated type; before we can use it for bounds checking we + // need to instantiate it with the type arguments with which we instantiate + // the parameterized type. + iface = check.subst(pos, iface, smap).(*Interface) + + // targ must implement iface (methods) + // - check only if we have methods + if iface.NumMethods() > 0 { + // If the type argument is a pointer to a type parameter, the type argument's + // method set is empty. + // TODO(gri) is this what we want? (spec question) + if base, isPtr := deref(targ); isPtr && asTypeParam(base) != nil { + check.errorf(pos, "%s has no methods", targ) + return false + } + if m, wrong := check.missingMethod(targ, iface, true); m != nil { + // TODO(gri) needs to print updated name to avoid major confusion in error message! + // (print warning for now) + // Old warning: + // check.softErrorf(pos, "%s does not satisfy %s (warning: name not updated) = %s (missing method %s)", targ, tpar.bound, iface, m) + if m.name == "==" { + // We don't want to report "missing method ==". + check.softErrorf(pos, "%s does not satisfy comparable", targ) + } else if wrong != nil { + // TODO(gri) This can still report uninstantiated types which makes the error message + // more difficult to read then necessary. + check.softErrorf(pos, + "%s does not satisfy %s: wrong method signature\n\tgot %s\n\twant %s", + targ, tpar.bound, wrong, m, + ) + } else { + check.softErrorf(pos, "%s does not satisfy %s (missing method %s)", targ, tpar.bound, m.name) + } + return false + } + } + + // targ's underlying type must also be one of the interface types listed, if any + if iface.typeSet().types == nil { + return true // nothing to do + } + + // If targ is itself a type parameter, each of its possible types, but at least one, must be in the + // list of iface types (i.e., the targ type list must be a non-empty subset of the iface types). + if targ := asTypeParam(targ); targ != nil { + targBound := targ.Bound() + if targBound.typeSet().types == nil { + check.softErrorf(pos, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ) + return false + } + return iface.is(func(typ Type, tilde bool) bool { + // TODO(gri) incorporate tilde information! + if !iface.isSatisfiedBy(typ) { + // TODO(gri) match this error message with the one below (or vice versa) + check.softErrorf(pos, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, typ, iface.typeSet().types) + return false + } + return true + }) + } + + // Otherwise, targ's type or underlying type must also be one of the interface types listed, if any. + if !iface.isSatisfiedBy(targ) { + check.softErrorf(pos, "%s does not satisfy %s (%s not found in %s)", targ, tpar.bound, targ, iface.typeSet().types) + return false + } + + return true +} diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index 32cf5273725..63b234a60e2 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -2,9 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// This file implements instantiation of generic types -// through substitution of type parameters by actual -// types. +// This file implements type parameter substitution. package types2 @@ -53,186 +51,6 @@ func (m *substMap) lookup(tpar *TypeParam) Type { return tpar } -// Instantiate instantiates the type typ with the given type arguments -// targs. To check type constraint satisfaction, verify must be set. -// pos and posList correspond to the instantiation and type argument -// positions respectively; posList may be nil or shorter than the number -// of type arguments provided. -// typ must be a *Named or a *Signature type, and its number of type -// parameters must match the number of provided type arguments. -// The receiver (check) may be nil if and only if verify is not set. -// The result is a new, instantiated (not generic) type of the same kind -// (either a *Named or a *Signature). -// Any methods attached to a *Named are simply copied; they are not -// instantiated. -func (check *Checker) Instantiate(pos syntax.Pos, typ Type, targs []Type, posList []syntax.Pos, verify bool) (res Type) { - if verify && check == nil { - panic("cannot have nil receiver if verify is set") - } - - if check != nil && check.conf.Trace { - check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs)) - check.indent++ - defer func() { - check.indent-- - var under Type - if res != nil { - // Calling under() here may lead to endless instantiations. - // Test case: type T[P any] T[P] - // TODO(gri) investigate if that's a bug or to be expected. - under = res.Underlying() - } - check.trace(pos, "=> %s (under = %s)", res, under) - }() - } - - assert(len(posList) <= len(targs)) - - // TODO(gri) What is better here: work with TypeParams, or work with TypeNames? - var tparams []*TypeName - switch t := typ.(type) { - case *Named: - tparams = t.TParams() - case *Signature: - tparams = t.tparams - defer func() { - // If we had an unexpected failure somewhere don't panic below when - // asserting res.(*Signature). Check for *Signature in case Typ[Invalid] - // is returned. - if _, ok := res.(*Signature); !ok { - return - } - // If the signature doesn't use its type parameters, subst - // will not make a copy. In that case, make a copy now (so - // we can set tparams to nil w/o causing side-effects). - if t == res { - copy := *t - res = © - } - // After instantiating a generic signature, it is not generic - // anymore; we need to set tparams to nil. - res.(*Signature).tparams = nil - }() - default: - // only types and functions can be generic - panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) - } - - // the number of supplied types must match the number of type parameters - if len(targs) != len(tparams) { - // TODO(gri) provide better error message - if check != nil { - check.errorf(pos, "got %d arguments but %d type parameters", len(targs), len(tparams)) - return Typ[Invalid] - } - panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, len(targs), len(tparams))) - } - - if len(tparams) == 0 { - return typ // nothing to do (minor optimization) - } - - smap := makeSubstMap(tparams, targs) - - // check bounds - if verify { - for i, tname := range tparams { - // best position for error reporting - pos := pos - if i < len(posList) { - pos = posList[i] - } - // stop checking bounds after the first failure - if !check.satisfies(pos, targs[i], tname.typ.(*TypeParam), smap) { - break - } - } - } - - return check.subst(pos, typ, smap) -} - -// satisfies reports whether the type argument targ satisfies the constraint of type parameter -// parameter tpar (after any of its type parameters have been substituted through smap). -// A suitable error is reported if the result is false. -// TODO(gri) This should be a method of interfaces or type sets. -func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap *substMap) bool { - iface := tpar.Bound() - if iface.Empty() { - return true // no type bound - } - - // The type parameter bound is parameterized with the same type parameters - // as the instantiated type; before we can use it for bounds checking we - // need to instantiate it with the type arguments with which we instantiate - // the parameterized type. - iface = check.subst(pos, iface, smap).(*Interface) - - // targ must implement iface (methods) - // - check only if we have methods - if iface.NumMethods() > 0 { - // If the type argument is a pointer to a type parameter, the type argument's - // method set is empty. - // TODO(gri) is this what we want? (spec question) - if base, isPtr := deref(targ); isPtr && asTypeParam(base) != nil { - check.errorf(pos, "%s has no methods", targ) - return false - } - if m, wrong := check.missingMethod(targ, iface, true); m != nil { - // TODO(gri) needs to print updated name to avoid major confusion in error message! - // (print warning for now) - // Old warning: - // check.softErrorf(pos, "%s does not satisfy %s (warning: name not updated) = %s (missing method %s)", targ, tpar.bound, iface, m) - if m.name == "==" { - // We don't want to report "missing method ==". - check.softErrorf(pos, "%s does not satisfy comparable", targ) - } else if wrong != nil { - // TODO(gri) This can still report uninstantiated types which makes the error message - // more difficult to read then necessary. - check.softErrorf(pos, - "%s does not satisfy %s: wrong method signature\n\tgot %s\n\twant %s", - targ, tpar.bound, wrong, m, - ) - } else { - check.softErrorf(pos, "%s does not satisfy %s (missing method %s)", targ, tpar.bound, m.name) - } - return false - } - } - - // targ's underlying type must also be one of the interface types listed, if any - if iface.typeSet().types == nil { - return true // nothing to do - } - - // If targ is itself a type parameter, each of its possible types, but at least one, must be in the - // list of iface types (i.e., the targ type list must be a non-empty subset of the iface types). - if targ := asTypeParam(targ); targ != nil { - targBound := targ.Bound() - if targBound.typeSet().types == nil { - check.softErrorf(pos, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ) - return false - } - return iface.is(func(typ Type, tilde bool) bool { - // TODO(gri) incorporate tilde information! - if !iface.isSatisfiedBy(typ) { - // TODO(gri) match this error message with the one below (or vice versa) - check.softErrorf(pos, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, typ, iface.typeSet().types) - return false - } - return true - }) - } - - // Otherwise, targ's type or underlying type must also be one of the interface types listed, if any. - if !iface.isSatisfiedBy(targ) { - check.softErrorf(pos, "%s does not satisfy %s (%s not found in %s)", targ, tpar.bound, targ, iface.typeSet().types) - return false - } - - return true -} - // subst returns the type typ with its type parameters tpars replaced by // the corresponding type arguments targs, recursively. // subst is functional in the sense that it doesn't modify the incoming From d0324eb8fbabc6295d0170ba1527517d014a84a4 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 9 Jul 2021 15:04:15 -0700 Subject: [PATCH 667/940] [dev.typeparams] cmd/compile/internal/types2: use InstantiateLazy to create instance types (cleanup) This change concentrates the creation is lazily instantiated types in one place (InstantiateLazy). This should also make it easier to replace the implementation of lazily instantiated types (e.g. getting rid of instance types). Change-Id: I452c463219b466ce79f227c44fb67b79d428842a Reviewed-on: https://go-review.googlesource.com/c/go/+/333669 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/noder/reader2.go | 2 +- src/cmd/compile/internal/types2/instance.go | 4 +- .../compile/internal/types2/instantiate.go | 16 ++++--- src/cmd/compile/internal/types2/typexpr.go | 43 +++++++------------ 4 files changed, 27 insertions(+), 38 deletions(-) diff --git a/src/cmd/compile/internal/noder/reader2.go b/src/cmd/compile/internal/noder/reader2.go index 92569ff843f..ac29f6f5192 100644 --- a/src/cmd/compile/internal/noder/reader2.go +++ b/src/cmd/compile/internal/noder/reader2.go @@ -224,7 +224,7 @@ func (r *reader2) doTyp() (res types2.Type) { obj, targs := r.obj() name := obj.(*types2.TypeName) if len(targs) != 0 { - return r.p.check.InstantiateLazy(syntax.Pos{}, name.Type(), targs, false) + return r.p.check.InstantiateLazy(syntax.Pos{}, name.Type(), targs, nil, false) } return name.Type() diff --git a/src/cmd/compile/internal/types2/instance.go b/src/cmd/compile/internal/types2/instance.go index 65c20155073..798d58811f5 100644 --- a/src/cmd/compile/internal/types2/instance.go +++ b/src/cmd/compile/internal/types2/instance.go @@ -15,7 +15,7 @@ type instance struct { pos syntax.Pos // position of type instantiation; for error reporting only base *Named // parameterized type to be instantiated targs []Type // type arguments - poslist []syntax.Pos // position of each targ; for error reporting only + posList []syntax.Pos // position of each targ; for error reporting only verify bool // if set, constraint satisfaction is verified value Type // base[targs...] after instantiation or Typ[Invalid]; nil if not yet set } @@ -26,7 +26,7 @@ type instance struct { func (t *instance) expand() Type { v := t.value if v == nil { - v = t.check.Instantiate(t.pos, t.base, t.targs, t.poslist, t.verify) + v = t.check.Instantiate(t.pos, t.base, t.targs, t.posList, t.verify) if v == nil { v = Typ[Invalid] } diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go index 5ccd511acb0..cc96375027f 100644 --- a/src/cmd/compile/internal/types2/instantiate.go +++ b/src/cmd/compile/internal/types2/instantiate.go @@ -112,19 +112,21 @@ func (check *Checker) Instantiate(pos syntax.Pos, typ Type, targs []Type, posLis } // InstantiateLazy is like Instantiate, but avoids actually -// instantiating the type until needed. -func (check *Checker) InstantiateLazy(pos syntax.Pos, typ Type, targs []Type, verify bool) (res Type) { +// instantiating the type until needed. typ must be a *Named +// type. +func (check *Checker) InstantiateLazy(pos syntax.Pos, typ Type, targs []Type, posList []syntax.Pos, verify bool) Type { base := asNamed(typ) if base == nil { panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) } return &instance{ - check: check, - pos: pos, - base: base, - targs: targs, - verify: verify, + check: check, + pos: pos, + base: base, + targs: targs, + posList: posList, + verify: verify, } } diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index d69dd3c496f..a14d498cec0 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -410,45 +410,32 @@ func (check *Checker) typOrNil(e syntax.Expr) Type { return Typ[Invalid] } -func (check *Checker) instantiatedType(x syntax.Expr, targs []syntax.Expr, def *Named) Type { - b := check.genericType(x, true) // TODO(gri) what about cycles? - if b == Typ[Invalid] { - return b // error already reported - } - base := asNamed(b) - if base == nil { - unreachable() // should have been caught by genericType +func (check *Checker) instantiatedType(x syntax.Expr, targsx []syntax.Expr, def *Named) Type { + base := check.genericType(x, true) + if base == Typ[Invalid] { + return base // error already reported } - // create a new type instance rather than instantiate the type - // TODO(gri) should do argument number check here rather than - // when instantiating the type? - // TODO(gri) use InstantiateLazy here (cleanup) - typ := new(instance) - def.setUnderlying(typ) - - typ.check = check - typ.pos = x.Pos() - typ.base = base - typ.verify = true - - // evaluate arguments (always) - typ.targs = check.typeList(targs) - if typ.targs == nil { + // evaluate arguments + targs := check.typeList(targsx) + if targs == nil { def.setUnderlying(Typ[Invalid]) // avoid later errors due to lazy instantiation return Typ[Invalid] } - // determine argument positions (for error reporting) - typ.poslist = make([]syntax.Pos, len(targs)) - for i, arg := range targs { - typ.poslist[i] = syntax.StartPos(arg) + // determine argument positions + posList := make([]syntax.Pos, len(targs)) + for i, arg := range targsx { + posList[i] = syntax.StartPos(arg) } + typ := check.InstantiateLazy(x.Pos(), base, targs, posList, true) + def.setUnderlying(typ) + // make sure we check instantiation works at least once // and that the resulting type is valid check.later(func() { - t := typ.expand() + t := typ.(*instance).expand() check.validType(t, nil) }) From e5faa8d84ba8583dd16758227249fab42ef3a1e0 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 9 Jul 2021 16:02:45 -0700 Subject: [PATCH 668/940] [dev.typeparams] cmd/compile/internal/types2: move methods on *Named into named.go (cleanup) No other code changes except for an additional comment. Change-Id: Ica3cea446c6c88f4f81a86d77b289a0b54b1e76f Reviewed-on: https://go-review.googlesource.com/c/go/+/333671 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/decl.go | 96 ----------------------- src/cmd/compile/internal/types2/named.go | 99 ++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 96 deletions(-) diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go index 4f91bc70c78..9fb9815f4db 100644 --- a/src/cmd/compile/internal/types2/decl.go +++ b/src/cmd/compile/internal/types2/decl.go @@ -515,102 +515,6 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init syntax.Expr) { check.initVars(lhs, []syntax.Expr{init}, nopos) } -// under returns the expanded underlying type of n0; possibly by following -// forward chains of named types. If an underlying type is found, resolve -// the chain by setting the underlying type for each defined type in the -// chain before returning it. If no underlying type is found or a cycle -// is detected, the result is Typ[Invalid]. If a cycle is detected and -// n0.check != nil, the cycle is reported. -func (n0 *Named) under() Type { - u := n0.Underlying() - - if u == Typ[Invalid] { - return u - } - - // If the underlying type of a defined type is not a defined - // (incl. instance) type, then that is the desired underlying - // type. - switch u.(type) { - case nil: - return Typ[Invalid] - default: - // common case - return u - case *Named, *instance: - // handled below - } - - if n0.check == nil { - panic("internal error: Named.check == nil but type is incomplete") - } - - // Invariant: after this point n0 as well as any named types in its - // underlying chain should be set up when this function exits. - check := n0.check - - // If we can't expand u at this point, it is invalid. - n := asNamed(u) - if n == nil { - n0.underlying = Typ[Invalid] - return n0.underlying - } - - // Otherwise, follow the forward chain. - seen := map[*Named]int{n0: 0} - path := []Object{n0.obj} - for { - u = n.Underlying() - if u == nil { - u = Typ[Invalid] - break - } - var n1 *Named - switch u1 := u.(type) { - case *Named: - n1 = u1 - case *instance: - n1, _ = u1.expand().(*Named) - if n1 == nil { - u = Typ[Invalid] - } - } - if n1 == nil { - break // end of chain - } - - seen[n] = len(seen) - path = append(path, n.obj) - n = n1 - - if i, ok := seen[n]; ok { - // cycle - check.cycleError(path[i:]) - u = Typ[Invalid] - break - } - } - - for n := range seen { - // We should never have to update the underlying type of an imported type; - // those underlying types should have been resolved during the import. - // Also, doing so would lead to a race condition (was issue #31749). - // Do this check always, not just in debug mode (it's cheap). - if n.obj.pkg != check.pkg { - panic("internal error: imported type with unresolved underlying type") - } - n.underlying = u - } - - return u -} - -func (n *Named) setUnderlying(typ Type) { - if n != nil { - n.underlying = typ - } -} - func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named) { assert(obj.typ == nil) diff --git a/src/cmd/compile/internal/types2/named.go b/src/cmd/compile/internal/types2/named.go index 2005dfbd84a..da098b58b7a 100644 --- a/src/cmd/compile/internal/types2/named.go +++ b/src/cmd/compile/internal/types2/named.go @@ -142,3 +142,102 @@ func (t *Named) AddMethod(m *Func) { func (t *Named) Underlying() Type { return t.expand().underlying } func (t *Named) String() string { return TypeString(t, nil) } + +// ---------------------------------------------------------------------------- +// Implementation + +// under returns the expanded underlying type of n0; possibly by following +// forward chains of named types. If an underlying type is found, resolve +// the chain by setting the underlying type for each defined type in the +// chain before returning it. If no underlying type is found or a cycle +// is detected, the result is Typ[Invalid]. If a cycle is detected and +// n0.check != nil, the cycle is reported. +func (n0 *Named) under() Type { + u := n0.Underlying() + + if u == Typ[Invalid] { + return u + } + + // If the underlying type of a defined type is not a defined + // (incl. instance) type, then that is the desired underlying + // type. + switch u.(type) { + case nil: + return Typ[Invalid] + default: + // common case + return u + case *Named, *instance: + // handled below + } + + if n0.check == nil { + panic("internal error: Named.check == nil but type is incomplete") + } + + // Invariant: after this point n0 as well as any named types in its + // underlying chain should be set up when this function exits. + check := n0.check + + // If we can't expand u at this point, it is invalid. + n := asNamed(u) + if n == nil { + n0.underlying = Typ[Invalid] + return n0.underlying + } + + // Otherwise, follow the forward chain. + seen := map[*Named]int{n0: 0} + path := []Object{n0.obj} + for { + u = n.Underlying() + if u == nil { + u = Typ[Invalid] + break + } + var n1 *Named + switch u1 := u.(type) { + case *Named: + n1 = u1 + case *instance: + n1, _ = u1.expand().(*Named) + if n1 == nil { + u = Typ[Invalid] + } + } + if n1 == nil { + break // end of chain + } + + seen[n] = len(seen) + path = append(path, n.obj) + n = n1 + + if i, ok := seen[n]; ok { + // cycle + check.cycleError(path[i:]) + u = Typ[Invalid] + break + } + } + + for n := range seen { + // We should never have to update the underlying type of an imported type; + // those underlying types should have been resolved during the import. + // Also, doing so would lead to a race condition (was issue #31749). + // Do this check always, not just in debug mode (it's cheap). + if n.obj.pkg != check.pkg { + panic("internal error: imported type with unresolved underlying type") + } + n.underlying = u + } + + return u +} + +func (n *Named) setUnderlying(typ Type) { + if n != nil { + n.underlying = typ + } +} From d8f348a589b3df4bb48636023be4ccf9ac96d307 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Tue, 13 Jul 2021 17:25:26 -0400 Subject: [PATCH 669/940] cmd/go: remove a duplicated word from 'go help mod graph' For #46366 Change-Id: Ie9735027a3c4c0f4a604df30ca4d64dcdc62b45a Reviewed-on: https://go-review.googlesource.com/c/go/+/334375 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills Reviewed-by: Jay Conrod TryBot-Result: Go Bot --- src/cmd/go/alldocs.go | 2 +- src/cmd/go/internal/modcmd/graph.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index 90eb3e2a00b..954caae9fb1 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -1193,7 +1193,7 @@ // and one of its requirements. Each module is identified as a string of the form // path@version, except for the main module, which has no @version suffix. // -// The -go flag causes graph to report the module graph as loaded by by the +// The -go flag causes graph to report the module graph as loaded by the // given Go version, instead of the version indicated by the 'go' directive // in the go.mod file. // diff --git a/src/cmd/go/internal/modcmd/graph.go b/src/cmd/go/internal/modcmd/graph.go index 903bd9970f1..ac81f26dade 100644 --- a/src/cmd/go/internal/modcmd/graph.go +++ b/src/cmd/go/internal/modcmd/graph.go @@ -26,7 +26,7 @@ in text form. Each line in the output has two space-separated fields: a module and one of its requirements. Each module is identified as a string of the form path@version, except for the main module, which has no @version suffix. -The -go flag causes graph to report the module graph as loaded by by the +The -go flag causes graph to report the module graph as loaded by the given Go version, instead of the version indicated by the 'go' directive in the go.mod file. From 82744bfbfc2d0407ecf1bf055f548c3948d4683b Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 13 Jul 2021 13:25:16 -0700 Subject: [PATCH 670/940] [dev.typeparams] cmd/compile: handle objStub earlier in reader There's no point in reading the object dictionary for a stub declaration. Only the package that contains the full object definition will contain an object dictionary. Change-Id: I458b77d20745105bf46190ef552312bdb5ca4d06 Reviewed-on: https://go-review.googlesource.com/c/go/+/334409 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/noder/reader.go | 38 +++++++++++++----------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 25aac6c026a..2351d1d0ba6 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -520,14 +520,22 @@ func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node r.typeParamBounds(sym, implicits, explicits) - origSym := sym - - sym = r.mangle(sym) - if !sym.IsBlank() && sym.Def != nil { - return sym.Def.(ir.Node) - } - tag := codeObj(r.code(syncCodeObj)) + if tag == objStub { + assert(!sym.IsBlank()) + switch sym.Pkg { + case types.BuiltinPkg, ir.Pkgs.Unsafe: + return sym.Def.(ir.Node) + } + if pri, ok := objReader[sym]; ok { + return pri.pr.objIdx(pri.idx, nil, explicits) + } + if haveLegacyImports { + assert(!r.hasTypeParams()) + return typecheck.Resolve(ir.NewIdent(src.NoXPos, sym)) + } + base.Fatalf("unresolved stub: %v", sym) + } { rdict := pr.newReader(relocObjDict, idx, syncObject1) @@ -538,6 +546,11 @@ func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node } } + sym = r.mangle(sym) + if !sym.IsBlank() && sym.Def != nil { + return sym.Def.(*ir.Name) + } + do := func(op ir.Op, hasTParams bool) *ir.Name { pos := r.pos() if hasTParams { @@ -560,17 +573,6 @@ func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node default: panic("unexpected object") - case objStub: - if pri, ok := objReader[origSym]; ok { - return pri.pr.objIdx(pri.idx, nil, explicits) - } - if haveLegacyImports { - assert(!r.hasTypeParams()) - return typecheck.Resolve(ir.NewIdent(src.NoXPos, origSym)) - } - base.Fatalf("unresolved stub: %v", origSym) - panic("unreachable") - case objAlias: name := do(ir.OTYPE, false) r.setType(name, r.typ()) From 5517053d178d1259f6f1a9c2d65efbf335002cea Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 13 Jul 2021 09:09:32 -0700 Subject: [PATCH 671/940] [dev.typeparams] cmd/compile: record more typ/fun info for dictionaries in unified IR Records whether a derived type is needed at run-time as well as instantiated functions that rely on derived types (and thus need sub-dictionaries). Change-Id: I2f2036976bfce5b3b4372fba88b4116dafa7e6b7 Reviewed-on: https://go-review.googlesource.com/c/go/+/334349 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/noder/reader.go | 63 +++++++--- src/cmd/compile/internal/noder/reader2.go | 56 ++++----- src/cmd/compile/internal/noder/unified.go | 3 + src/cmd/compile/internal/noder/writer.go | 139 ++++++++++++++++++---- 4 files changed, 194 insertions(+), 67 deletions(-) diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 2351d1d0ba6..de708769bab 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -142,8 +142,11 @@ type readerDict struct { // arguments; the rest are explicit. implicits int - derivedReloc []int // reloc index of the derived type's descriptor - derived []*types.Type // slice of previously computed derived types + derived []derivedInfo // reloc index of the derived type's descriptor + derivedTypes []*types.Type // slice of previously computed derived types + + funcs []objInfo + funcsObj []ir.Node } func (r *reader) setType(n ir.Node, typ *types.Type) { @@ -293,18 +296,23 @@ func (r *reader) doPkg() *types.Pkg { // @@@ Types func (r *reader) typ() *types.Type { - r.sync(syncType) - if r.bool() { - return r.p.typIdx(r.len(), r.dict) - } - return r.p.typIdx(r.reloc(relocType), nil) + return r.p.typIdx(r.typInfo(), r.dict) } -func (pr *pkgReader) typIdx(idx int, dict *readerDict) *types.Type { +func (r *reader) typInfo() typeInfo { + r.sync(syncType) + if r.bool() { + return typeInfo{idx: r.len(), derived: true} + } + return typeInfo{idx: r.reloc(relocType), derived: false} +} + +func (pr *pkgReader) typIdx(info typeInfo, dict *readerDict) *types.Type { + idx := info.idx var where **types.Type - if dict != nil { - where = &dict.derived[idx] - idx = dict.derivedReloc[idx] + if info.derived { + where = &dict.derivedTypes[idx] + idx = dict.derived[idx].idx } else { where = &pr.typs[idx] } @@ -493,6 +501,23 @@ var objReader = map[*types.Sym]pkgReaderIndex{} func (r *reader) obj() ir.Node { r.sync(syncObject) + if r.bool() { + idx := r.len() + obj := r.dict.funcsObj[idx] + if obj == nil { + fn := r.dict.funcs[idx] + targs := make([]*types.Type, len(fn.explicits)) + for i, targ := range fn.explicits { + targs[i] = r.p.typIdx(targ, r.dict) + } + + obj = r.p.objIdx(fn.idx, nil, targs) + assert(r.dict.funcsObj[idx] == nil) + r.dict.funcsObj[idx] = obj + } + return obj + } + idx := r.reloc(relocObj) explicits := make([]*types.Type, r.len()) @@ -539,10 +564,20 @@ func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node { rdict := pr.newReader(relocObjDict, idx, syncObject1) - r.dict.derivedReloc = make([]int, rdict.len()) - r.dict.derived = make([]*types.Type, len(r.dict.derivedReloc)) + r.dict.derived = make([]derivedInfo, rdict.len()) + r.dict.derivedTypes = make([]*types.Type, len(r.dict.derived)) for i := range r.dict.derived { - r.dict.derivedReloc[i] = rdict.reloc(relocType) + r.dict.derived[i] = derivedInfo{rdict.reloc(relocType), rdict.bool()} + } + r.dict.funcs = make([]objInfo, rdict.len()) + r.dict.funcsObj = make([]ir.Node, len(r.dict.funcs)) + for i := range r.dict.funcs { + objIdx := rdict.reloc(relocObj) + targs := make([]typeInfo, rdict.len()) + for j := range targs { + targs[j] = rdict.typInfo() + } + r.dict.funcs[i] = objInfo{idx: objIdx, explicits: targs} } } diff --git a/src/cmd/compile/internal/noder/reader2.go b/src/cmd/compile/internal/noder/reader2.go index ac29f6f5192..a2339145fa5 100644 --- a/src/cmd/compile/internal/noder/reader2.go +++ b/src/cmd/compile/internal/noder/reader2.go @@ -61,12 +61,12 @@ type reader2 struct { } type reader2Dict struct { - bounds []reader2TypeBound + bounds []typeInfo tparams []*types2.TypeParam - derivedReloc []int - derived []types2.Type + derived []derivedInfo + derivedTypes []types2.Type } type reader2TypeBound struct { @@ -176,18 +176,23 @@ func (r *reader2) doPkg() *types2.Package { // @@@ Types func (r *reader2) typ() types2.Type { - r.sync(syncType) - if r.bool() { - return r.p.typIdx(r.len(), r.dict) - } - return r.p.typIdx(r.reloc(relocType), nil) + return r.p.typIdx(r.typInfo(), r.dict) } -func (pr *pkgReader2) typIdx(idx int, dict *reader2Dict) types2.Type { +func (r *reader2) typInfo() typeInfo { + r.sync(syncType) + if r.bool() { + return typeInfo{idx: r.len(), derived: true} + } + return typeInfo{idx: r.reloc(relocType), derived: false} +} + +func (pr *pkgReader2) typIdx(info typeInfo, dict *reader2Dict) types2.Type { + idx := info.idx var where *types2.Type - if dict != nil { - where = &dict.derived[idx] - idx = dict.derivedReloc[idx] + if info.derived { + where = &dict.derivedTypes[idx] + idx = dict.derived[idx].idx } else { where = &pr.typs[idx] } @@ -339,6 +344,8 @@ func (r *reader2) param() *types2.Var { func (r *reader2) obj() (types2.Object, []types2.Type) { r.sync(syncObject) + assert(!r.bool()) + pkg, name := r.p.objIdx(r.reloc(relocObj)) obj := pkg.Scope().Lookup(name) @@ -367,11 +374,12 @@ func (pr *pkgReader2) objIdx(idx int) (*types2.Package, string) { { rdict := r.p.newReader(relocObjDict, idx, syncObject1) - r.dict.derivedReloc = make([]int, rdict.len()) - r.dict.derived = make([]types2.Type, len(r.dict.derivedReloc)) + r.dict.derived = make([]derivedInfo, rdict.len()) + r.dict.derivedTypes = make([]types2.Type, len(r.dict.derived)) for i := range r.dict.derived { - r.dict.derivedReloc[i] = rdict.reloc(relocType) + r.dict.derived[i] = derivedInfo{rdict.reloc(relocType), rdict.bool()} } + // function references follow, but reader2 doesn't need those } objPkg.Scope().InsertLazy(objName, func() types2.Object { @@ -438,16 +446,9 @@ func (r *reader2) typeParamBounds() { base.Fatalf("unexpected object with %v implicit type parameter(s)", implicits) } - r.dict.bounds = make([]reader2TypeBound, r.len()) + r.dict.bounds = make([]typeInfo, r.len()) for i := range r.dict.bounds { - b := &r.dict.bounds[i] - r.sync(syncType) - b.derived = r.bool() - if b.derived { - b.boundIdx = r.len() - } else { - b.boundIdx = r.reloc(relocType) - } + r.dict.bounds[i] = r.typInfo() } } @@ -479,12 +480,7 @@ func (r *reader2) typeParamNames() []*types2.TypeName { } for i, bound := range r.dict.bounds { - var dict *reader2Dict - if bound.derived { - dict = r.dict - } - boundType := r.p.typIdx(bound.boundIdx, dict) - r.dict.tparams[i].SetBound(boundType) + r.dict.tparams[i].SetBound(r.p.typIdx(bound, r.dict)) } return names diff --git a/src/cmd/compile/internal/noder/unified.go b/src/cmd/compile/internal/noder/unified.go index 39989778f80..e8c203ae463 100644 --- a/src/cmd/compile/internal/noder/unified.go +++ b/src/cmd/compile/internal/noder/unified.go @@ -259,6 +259,7 @@ func readPackage(pr *pkgReader, importpkg *types.Pkg) { for i, n := 0, r.len(); i < n; i++ { r.sync(syncObject) + assert(!r.bool()) idx := r.reloc(relocObj) assert(r.len() == 0) @@ -293,6 +294,7 @@ func writeNewExport(out io.Writer) { for i, n := 0, r.len(); i < n; i++ { r.sync(syncObject) + assert(!r.bool()) idx := r.reloc(relocObj) assert(r.len() == 0) @@ -325,6 +327,7 @@ func writeNewExport(out io.Writer) { w.len(len(idxs)) for _, idx := range idxs { w.sync(syncObject) + w.bool(false) w.reloc(relocObj, idx) w.len(0) } diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go index 21aeb5678d3..48884056f32 100644 --- a/src/cmd/compile/internal/noder/writer.go +++ b/src/cmd/compile/internal/noder/writer.go @@ -103,11 +103,53 @@ type writerDict struct { // derived is a slice of type indices for computing derived types // (i.e., types that depend on the declaration's type parameters). - derived []int + derived []derivedInfo // derivedIdx maps a Type to its corresponding index within the // derived slice, if present. derivedIdx map[types2.Type]int + + // funcs lists references to generic functions that were + // instantiated with derived types (i.e., that require + // sub-dictionaries when called at run time). + funcs []objInfo +} + +type derivedInfo struct { + idx int + needed bool +} + +type typeInfo struct { + idx int + derived bool +} + +type objInfo struct { + idx int // index for the generic function declaration + explicits []typeInfo // info for the type arguments +} + +func (info objInfo) anyDerived() bool { + for _, explicit := range info.explicits { + if explicit.derived { + return true + } + } + return false +} + +func (info objInfo) equals(other objInfo) bool { + if info.idx != other.idx { + return false + } + assert(len(info.explicits) == len(other.explicits)) + for i, targ := range info.explicits { + if targ != other.explicits[i] { + return false + } + } + return true } func (pw *pkgWriter) newWriter(k reloc, marker syncMarker) *writer { @@ -200,14 +242,16 @@ func (pw *pkgWriter) pkgIdx(pkg *types2.Package) int { // @@@ Types func (w *writer) typ(typ types2.Type) { - idx, derived := w.p.typIdx(typ, w.dict) + w.typInfo(w.p.typIdx(typ, w.dict)) +} +func (w *writer) typInfo(info typeInfo) { w.sync(syncType) - if w.bool(derived) { - w.len(idx) + if w.bool(info.derived) { + w.len(info.idx) w.derived = true } else { - w.reloc(relocType, idx) + w.reloc(relocType, info.idx) } } @@ -216,17 +260,17 @@ func (w *writer) typ(typ types2.Type) { // // typIdx also reports whether typ is a derived type; that is, whether // its identity depends on type parameters. -func (pw *pkgWriter) typIdx(typ types2.Type, dict *writerDict) (int, bool) { +func (pw *pkgWriter) typIdx(typ types2.Type, dict *writerDict) typeInfo { if quirksMode() { typ = pw.dups.orig(typ) } if idx, ok := pw.typsIdx[typ]; ok { - return idx, false + return typeInfo{idx: idx, derived: false} } if dict != nil { if idx, ok := dict.derivedIdx[typ]; ok { - return idx, true + return typeInfo{idx: idx, derived: true} } } @@ -324,13 +368,13 @@ func (pw *pkgWriter) typIdx(typ types2.Type, dict *writerDict) (int, bool) { if w.derived { idx := len(dict.derived) - dict.derived = append(dict.derived, w.flush()) + dict.derived = append(dict.derived, derivedInfo{idx: w.flush()}) dict.derivedIdx[typ] = idx - return idx, true + return typeInfo{idx: idx, derived: true} } pw.typsIdx[typ] = w.idx - return w.flush(), false + return typeInfo{idx: w.flush(), derived: false} } func (w *writer) structType(typ *types2.Struct) { @@ -398,6 +442,34 @@ func (w *writer) param(param *types2.Var) { // @@@ Objects func (w *writer) obj(obj types2.Object, explicits []types2.Type) { + explicitInfos := make([]typeInfo, len(explicits)) + for i, explicit := range explicits { + explicitInfos[i] = w.p.typIdx(explicit, w.dict) + } + info := objInfo{idx: w.p.objIdx(obj), explicits: explicitInfos} + + if _, ok := obj.(*types2.Func); ok && info.anyDerived() { + idx := -1 + for i, prev := range w.dict.funcs { + if prev.equals(info) { + idx = i + } + } + if idx < 0 { + idx = len(w.dict.funcs) + w.dict.funcs = append(w.dict.funcs, info) + } + + // TODO(mdempsky): Push up into expr; this shouldn't appear + // outside of expression context. + w.sync(syncObject) + w.bool(true) + w.len(idx) + return + } + + // TODO(mdempsky): Push up into typIdx; this shouldn't be needed + // except while writing out types. if isDefinedType(obj) && obj.Pkg() == w.p.curpkg { decl, ok := w.p.typDecls[obj.(*types2.TypeName)] assert(ok) @@ -407,11 +479,12 @@ func (w *writer) obj(obj types2.Object, explicits []types2.Type) { } w.sync(syncObject) - w.reloc(relocObj, w.p.objIdx(obj)) + w.bool(false) + w.reloc(relocObj, info.idx) - w.len(len(explicits)) - for _, explicit := range explicits { - w.typ(explicit) + w.len(len(info.explicits)) + for _, info := range info.explicits { + w.typInfo(info) } } @@ -453,16 +526,19 @@ func (pw *pkgWriter) objIdx(obj types2.Object) int { w.ext.flush() // Done writing out the object description; write out the list of - // derived types that we found along the way. - // - // TODO(mdempsky): Record details about how derived types are - // actually used so reader can optimize its runtime dictionaries. - // - // TODO(mdempsky): Record details about which instantiated functions - // are used too. + // derived types and instantiated functions found along the way. wdict.len(len(dict.derived)) for _, typ := range dict.derived { - wdict.reloc(relocType, typ) + wdict.reloc(relocType, typ.idx) + wdict.bool(typ.needed) + } + wdict.len(len(dict.funcs)) + for _, fn := range dict.funcs { + wdict.reloc(relocObj, fn.idx) + wdict.len(len(fn.explicits)) + for _, targ := range fn.explicits { + wdict.typInfo(targ) + } } wdict.flush() @@ -1103,6 +1179,9 @@ func (w *writer) expr(expr syntax.Expr) { obj, targs := lookupObj(w.p.info, expr) if tv, ok := w.p.info.Types[expr]; ok { + // TODO(mdempsky): Be more judicious about which types are marked as "needed". + w.needType(tv.Type) + if tv.IsType() { w.code(exprType) w.typ(tv.Type) @@ -1356,6 +1435,20 @@ func (w *writer) op(op ir.Op) { w.len(int(op)) } +func (w *writer) needType(typ types2.Type) { + // Decompose tuple into component element types. + if typ, ok := typ.(*types2.Tuple); ok { + for i := 0; i < typ.Len(); i++ { + w.needType(typ.At(i).Type()) + } + return + } + + if info := w.p.typIdx(typ, w.dict); info.derived { + w.dict.derived[info.idx].needed = true + } +} + // @@@ Package initialization // Caution: This code is still clumsy, because toolstash -cmp is From 60ddf42b4627fb4ff5f92d2193c294456175af9a Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Fri, 2 Jul 2021 16:41:22 -0400 Subject: [PATCH 672/940] cmd/go: change link in error message from /wiki to /doc. The /doc link is currently a redirect (CL 334389), but I plan to update it soon with a more detailed guide. Updates #36460 Change-Id: I9e4a47ad0c8bcb7361cfa3e5b9d07ad241b13ba6 Reviewed-on: https://go-review.googlesource.com/c/go/+/332573 Trust: Bryan C. Mills Reviewed-by: Jay Conrod Reviewed-by: Michael Matloob --- src/cmd/go/internal/modload/load.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go index 771b142b73e..bce9ad85f42 100644 --- a/src/cmd/go/internal/modload/load.go +++ b/src/cmd/go/internal/modload/load.go @@ -1808,7 +1808,7 @@ func (ld *loader) checkTidyCompatibility(ctx context.Context, rs *Requirements) fmt.Fprintf(os.Stderr, "If reproducibility with go %s is not needed:\n\tgo mod tidy%s -compat=%s\n", ld.TidyCompatibleVersion, goFlag, ld.GoVersion) // TODO(#46141): Populate the linked wiki page. - fmt.Fprintf(os.Stderr, "For other options, see:\n\thttps://golang.org/wiki/PruningModules\n") + fmt.Fprintf(os.Stderr, "For other options, see:\n\thttps://golang.org/doc/modules/pruning\n") } mg, err := rs.Graph(ctx) From 2b10d7ff0be9ee5ebe1856349714f78936bf059d Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Wed, 14 Jul 2021 14:19:36 -0400 Subject: [PATCH 673/940] [dev.typeparams] go/types: export the Config.GoVersion field Export the types.Config.GoVersion field, so that users can specify a language compatibility version for go/types to enforce. Updates #46648 Change-Id: I9e00122925faf0006cfb08c3f2d022619d5d54d5 Reviewed-on: https://go-review.googlesource.com/c/go/+/334533 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/api.go | 4 ++-- src/go/types/check.go | 4 ++-- src/go/types/check_test.go | 2 +- src/go/types/stdlib_test.go | 3 +-- src/go/types/types_test.go | 6 ------ 5 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/go/types/api.go b/src/go/types/api.go index d3a95bc9910..2bfbb8ce0cb 100644 --- a/src/go/types/api.go +++ b/src/go/types/api.go @@ -103,12 +103,12 @@ type ImporterFrom interface { // A Config specifies the configuration for type checking. // The zero value for Config is a ready-to-use default configuration. type Config struct { - // goVersion describes the accepted Go language version. The string + // GoVersion describes the accepted Go language version. The string // must follow the format "go%d.%d" (e.g. "go1.12") or it must be // empty; an empty string indicates the latest language version. // If the format is invalid, invoking the type checker will cause a // panic. - goVersion string + GoVersion string // If IgnoreFuncBodies is set, function bodies are not // type-checked. diff --git a/src/go/types/check.go b/src/go/types/check.go index e82056e7225..aea319f4635 100644 --- a/src/go/types/check.go +++ b/src/go/types/check.go @@ -180,9 +180,9 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch info = new(Info) } - version, err := parseGoVersion(conf.goVersion) + version, err := parseGoVersion(conf.GoVersion) if err != nil { - panic(fmt.Sprintf("invalid Go version %q (%v)", conf.goVersion, err)) + panic(fmt.Sprintf("invalid Go version %q (%v)", conf.GoVersion, err)) } return &Checker{ diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go index a5720f992e9..f0cfced97f2 100644 --- a/src/go/types/check_test.go +++ b/src/go/types/check_test.go @@ -244,7 +244,7 @@ func testFiles(t *testing.T, sizes Sizes, filenames []string, srcs [][]byte, man // typecheck and collect typechecker errors var conf Config conf.Sizes = sizes - SetGoVersion(&conf, goVersion) + conf.GoVersion = goVersion // special case for importC.src if len(filenames) == 1 { diff --git a/src/go/types/stdlib_test.go b/src/go/types/stdlib_test.go index d86a77a110f..3eb7519a91a 100644 --- a/src/go/types/stdlib_test.go +++ b/src/go/types/stdlib_test.go @@ -140,8 +140,7 @@ func testTestDir(t *testing.T, path string, ignore ...string) { // parse and type-check file file, err := parser.ParseFile(fset, filename, nil, 0) if err == nil { - conf := Config{Importer: stdLibImporter} - SetGoVersion(&conf, goVersion) + conf := Config{GoVersion: goVersion, Importer: stdLibImporter} _, err = conf.Check(filename, fset, []*ast.File{file}, nil) } diff --git a/src/go/types/types_test.go b/src/go/types/types_test.go index 7990414f424..f2358c6e198 100644 --- a/src/go/types/types_test.go +++ b/src/go/types/types_test.go @@ -4,11 +4,5 @@ package types -// SetGoVersion sets the unexported goVersion field on config, so that tests -// which assert on behavior for older Go versions can set it. -func SetGoVersion(config *Config, goVersion string) { - config.goVersion = goVersion -} - // Debug is set if go/types is built with debug mode enabled. const Debug = debug From e3e6cd30221185d6e4fa76f109f96fdede580729 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Tue, 13 Jul 2021 22:21:54 -0700 Subject: [PATCH 674/940] [dev.typeparams] cmd/compile: fix escape printout bugs for -G=3 Call SetPos() in g.expr() so it is available for any new nodes. Print out the actual type for a composite literal in exprFmt() if available, else use Ntype if available. Seems generally useful, since the type name is always more useful than just 'composite literal'. Fixes a bunch of cases that are excluded in run.go for -G=3. Change-Id: I40b9bba88027ea4f36d419e3989e7f14891bea04 Reviewed-on: https://go-review.googlesource.com/c/go/+/334609 Trust: Dan Scales Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/ir/fmt.go | 4 +++ src/cmd/compile/internal/noder/expr.go | 5 ++++ test/run.go | 34 +++----------------------- 3 files changed, 12 insertions(+), 31 deletions(-) diff --git a/src/cmd/compile/internal/ir/fmt.go b/src/cmd/compile/internal/ir/fmt.go index 6f6e26dec42..e8dd9df69d0 100644 --- a/src/cmd/compile/internal/ir/fmt.go +++ b/src/cmd/compile/internal/ir/fmt.go @@ -714,6 +714,10 @@ func exprFmt(n Node, s fmt.State, prec int) { fmt.Fprintf(s, "... argument") return } + if typ := n.Type(); typ != nil { + fmt.Fprintf(s, "%v{%s}", typ, ellipsisIf(len(n.List) != 0)) + return + } if n.Ntype != nil { fmt.Fprintf(s, "%v{%s}", n.Ntype, ellipsisIf(len(n.List) != 0)) return diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go index 16470a54495..66ce1bfe4c8 100644 --- a/src/cmd/compile/internal/noder/expr.go +++ b/src/cmd/compile/internal/noder/expr.go @@ -88,6 +88,11 @@ func (g *irgen) expr(expr syntax.Expr) ir.Node { func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node { pos := g.pos(expr) + assert(pos.IsKnown()) + + // Set base.Pos for transformation code that still uses base.Pos, rather than + // the pos of the node being converted. + base.Pos = pos switch expr := expr.(type) { case *syntax.Name: diff --git a/test/run.go b/test/run.go index d6209c25915..82d49270f26 100644 --- a/test/run.go +++ b/test/run.go @@ -2167,40 +2167,12 @@ var types2Failures32Bit = setOf( ) var g3Failures = setOf( - // TODO: Triage tests without explicit failure explanations. From a - // cursory inspection, they mostly fall into: - // - Anonymous result parameters given different names (e.g., ~r0 vs ~r1) - // - Some escape analysis diagnostics being printed without position information - // - Some expressions printed differently (e.g., "int(100)" instead - // of "100" or "&composite literal" instead of "&[4]int{...}"). - - "closure3.go", // prints "s escapes to heap" without line number - "escape2.go", - "escape2n.go", - "escape4.go", // prints "1 escapes to heap" without line number - "escape_calls.go", - "escape_field.go", - "escape_iface.go", - "escape_indir.go", - "escape_level.go", - "escape_map.go", - "escape_param.go", - "escape_slice.go", - "escape_struct_param1.go", - "escape_struct_param2.go", - "writebarrier.go", // correct diagnostics, but different lines (probably irgen's fault) - - "fixedbugs/issue12006.go", - "fixedbugs/issue13799.go", + "writebarrier.go", // correct diagnostics, but different lines (probably irgen's fault) "fixedbugs/issue17270.go", // ICE in irgen "fixedbugs/issue20174.go", // ICE due to width not calculated (probably irgen's fault) "fixedbugs/issue20250.go", // correct diagnostics, but different lines (probably irgen's fault) - "fixedbugs/issue21709.go", - "fixedbugs/issue31573.go", - "fixedbugs/issue37837.go", - "fixedbugs/issue39292.go", - "fixedbugs/issue7921.go", // prints "composite literal does not escape" but test expects "[]byte{...} does not escape" - "fixedbugs/issue9691.go", // "cannot assign to int(.autotmp_4)" (probably irgen's fault) + "fixedbugs/issue37837.go", // ICE due to width not calculated + "fixedbugs/issue9691.go", // "cannot assign to int(.autotmp_4)" (probably irgen's fault) "typeparam/nested.go", // -G=3 doesn't support function-local types with generics From 2b00a54baf2b677b2aaddd93c25b11ea4642a86f Mon Sep 17 00:00:00 2001 From: WANG Xuerui Date: Mon, 12 Jul 2021 04:40:28 +0000 Subject: [PATCH 675/940] go/build, runtime/internal/sys: reserve GOARCH=loong64 Per discussion at #46229 we are taking the "loong64" GOARCH value for the upcoming LoongArch 64-bit port. It is not clear whether any 32-bit non-bare-metal userland will exist for LoongArch, so only reserve "loong64" for now. Change-Id: I97d262b4ab68ff61c22ccf83e26baf70eefd568d GitHub-Last-Rev: ecdd8c53bdee57fec093ddba18ec8878b8ae7c74 GitHub-Pull-Request: golang/go#47129 Reviewed-on: https://go-review.googlesource.com/c/go/+/333909 Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor Trust: Alexander Rakoczy --- src/go/build/syslist.go | 2 +- src/runtime/internal/sys/zgoarch_386.go | 1 + src/runtime/internal/sys/zgoarch_amd64.go | 1 + src/runtime/internal/sys/zgoarch_arm.go | 1 + src/runtime/internal/sys/zgoarch_arm64.go | 1 + src/runtime/internal/sys/zgoarch_arm64be.go | 1 + src/runtime/internal/sys/zgoarch_armbe.go | 1 + src/runtime/internal/sys/zgoarch_loong64.go | 33 +++++++++++++++++++ src/runtime/internal/sys/zgoarch_mips.go | 1 + src/runtime/internal/sys/zgoarch_mips64.go | 1 + src/runtime/internal/sys/zgoarch_mips64le.go | 1 + src/runtime/internal/sys/zgoarch_mips64p32.go | 1 + .../internal/sys/zgoarch_mips64p32le.go | 1 + src/runtime/internal/sys/zgoarch_mipsle.go | 1 + src/runtime/internal/sys/zgoarch_ppc.go | 1 + src/runtime/internal/sys/zgoarch_ppc64.go | 1 + src/runtime/internal/sys/zgoarch_ppc64le.go | 1 + src/runtime/internal/sys/zgoarch_riscv.go | 1 + src/runtime/internal/sys/zgoarch_riscv64.go | 1 + src/runtime/internal/sys/zgoarch_s390.go | 1 + src/runtime/internal/sys/zgoarch_s390x.go | 1 + src/runtime/internal/sys/zgoarch_sparc.go | 1 + src/runtime/internal/sys/zgoarch_sparc64.go | 1 + src/runtime/internal/sys/zgoarch_wasm.go | 1 + 24 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 src/runtime/internal/sys/zgoarch_loong64.go diff --git a/src/go/build/syslist.go b/src/go/build/syslist.go index 1275f7c986d..60ac5511bda 100644 --- a/src/go/build/syslist.go +++ b/src/go/build/syslist.go @@ -8,4 +8,4 @@ package build // Do not remove from this list, as these are used for go/build filename matching. const goosList = "aix android darwin dragonfly freebsd hurd illumos ios js linux nacl netbsd openbsd plan9 solaris windows zos " -const goarchList = "386 amd64 amd64p32 arm armbe arm64 arm64be ppc64 ppc64le mips mipsle mips64 mips64le mips64p32 mips64p32le ppc riscv riscv64 s390 s390x sparc sparc64 wasm " +const goarchList = "386 amd64 amd64p32 arm armbe arm64 arm64be ppc64 ppc64le loong64 mips mipsle mips64 mips64le mips64p32 mips64p32le ppc riscv riscv64 s390 s390x sparc sparc64 wasm " diff --git a/src/runtime/internal/sys/zgoarch_386.go b/src/runtime/internal/sys/zgoarch_386.go index 98a2401bfe9..5b189e7e738 100644 --- a/src/runtime/internal/sys/zgoarch_386.go +++ b/src/runtime/internal/sys/zgoarch_386.go @@ -16,6 +16,7 @@ const GoarchArm64 = 0 const GoarchArm64be = 0 const GoarchPpc64 = 0 const GoarchPpc64le = 0 +const GoarchLoong64 = 0 const GoarchMips = 0 const GoarchMipsle = 0 const GoarchMips64 = 0 diff --git a/src/runtime/internal/sys/zgoarch_amd64.go b/src/runtime/internal/sys/zgoarch_amd64.go index d8faa5c7860..312977d0792 100644 --- a/src/runtime/internal/sys/zgoarch_amd64.go +++ b/src/runtime/internal/sys/zgoarch_amd64.go @@ -16,6 +16,7 @@ const GoarchArm64 = 0 const GoarchArm64be = 0 const GoarchPpc64 = 0 const GoarchPpc64le = 0 +const GoarchLoong64 = 0 const GoarchMips = 0 const GoarchMipsle = 0 const GoarchMips64 = 0 diff --git a/src/runtime/internal/sys/zgoarch_arm.go b/src/runtime/internal/sys/zgoarch_arm.go index b64a69c9b44..5781870324e 100644 --- a/src/runtime/internal/sys/zgoarch_arm.go +++ b/src/runtime/internal/sys/zgoarch_arm.go @@ -16,6 +16,7 @@ const GoarchArm64 = 0 const GoarchArm64be = 0 const GoarchPpc64 = 0 const GoarchPpc64le = 0 +const GoarchLoong64 = 0 const GoarchMips = 0 const GoarchMipsle = 0 const GoarchMips64 = 0 diff --git a/src/runtime/internal/sys/zgoarch_arm64.go b/src/runtime/internal/sys/zgoarch_arm64.go index de6f85347b1..f72a1f2161c 100644 --- a/src/runtime/internal/sys/zgoarch_arm64.go +++ b/src/runtime/internal/sys/zgoarch_arm64.go @@ -16,6 +16,7 @@ const GoarchArm64 = 1 const GoarchArm64be = 0 const GoarchPpc64 = 0 const GoarchPpc64le = 0 +const GoarchLoong64 = 0 const GoarchMips = 0 const GoarchMipsle = 0 const GoarchMips64 = 0 diff --git a/src/runtime/internal/sys/zgoarch_arm64be.go b/src/runtime/internal/sys/zgoarch_arm64be.go index b762bb069f8..e8056460587 100644 --- a/src/runtime/internal/sys/zgoarch_arm64be.go +++ b/src/runtime/internal/sys/zgoarch_arm64be.go @@ -16,6 +16,7 @@ const GoarchArm64 = 0 const GoarchArm64be = 1 const GoarchPpc64 = 0 const GoarchPpc64le = 0 +const GoarchLoong64 = 0 const GoarchMips = 0 const GoarchMipsle = 0 const GoarchMips64 = 0 diff --git a/src/runtime/internal/sys/zgoarch_armbe.go b/src/runtime/internal/sys/zgoarch_armbe.go index e5297e4b169..d8d4e56d9a4 100644 --- a/src/runtime/internal/sys/zgoarch_armbe.go +++ b/src/runtime/internal/sys/zgoarch_armbe.go @@ -16,6 +16,7 @@ const GoarchArm64 = 0 const GoarchArm64be = 0 const GoarchPpc64 = 0 const GoarchPpc64le = 0 +const GoarchLoong64 = 0 const GoarchMips = 0 const GoarchMipsle = 0 const GoarchMips64 = 0 diff --git a/src/runtime/internal/sys/zgoarch_loong64.go b/src/runtime/internal/sys/zgoarch_loong64.go new file mode 100644 index 00000000000..6f35eb44a3b --- /dev/null +++ b/src/runtime/internal/sys/zgoarch_loong64.go @@ -0,0 +1,33 @@ +// Code generated by gengoos.go using 'go generate'. DO NOT EDIT. + +//go:build loong64 +// +build loong64 + +package sys + +const GOARCH = `loong64` + +const Goarch386 = 0 +const GoarchAmd64 = 0 +const GoarchAmd64p32 = 0 +const GoarchArm = 0 +const GoarchArmbe = 0 +const GoarchArm64 = 0 +const GoarchArm64be = 0 +const GoarchPpc64 = 0 +const GoarchPpc64le = 0 +const GoarchLoong64 = 1 +const GoarchMips = 0 +const GoarchMipsle = 0 +const GoarchMips64 = 0 +const GoarchMips64le = 0 +const GoarchMips64p32 = 0 +const GoarchMips64p32le = 0 +const GoarchPpc = 0 +const GoarchRiscv = 0 +const GoarchRiscv64 = 0 +const GoarchS390 = 0 +const GoarchS390x = 0 +const GoarchSparc = 0 +const GoarchSparc64 = 0 +const GoarchWasm = 0 diff --git a/src/runtime/internal/sys/zgoarch_mips.go b/src/runtime/internal/sys/zgoarch_mips.go index b5f4ed390c6..bd58a92a0e4 100644 --- a/src/runtime/internal/sys/zgoarch_mips.go +++ b/src/runtime/internal/sys/zgoarch_mips.go @@ -16,6 +16,7 @@ const GoarchArm64 = 0 const GoarchArm64be = 0 const GoarchPpc64 = 0 const GoarchPpc64le = 0 +const GoarchLoong64 = 0 const GoarchMips = 1 const GoarchMipsle = 0 const GoarchMips64 = 0 diff --git a/src/runtime/internal/sys/zgoarch_mips64.go b/src/runtime/internal/sys/zgoarch_mips64.go index 73777cceb21..8e4a3dcd526 100644 --- a/src/runtime/internal/sys/zgoarch_mips64.go +++ b/src/runtime/internal/sys/zgoarch_mips64.go @@ -16,6 +16,7 @@ const GoarchArm64 = 0 const GoarchArm64be = 0 const GoarchPpc64 = 0 const GoarchPpc64le = 0 +const GoarchLoong64 = 0 const GoarchMips = 0 const GoarchMipsle = 0 const GoarchMips64 = 1 diff --git a/src/runtime/internal/sys/zgoarch_mips64le.go b/src/runtime/internal/sys/zgoarch_mips64le.go index 0c81c36c097..d8e00339ea8 100644 --- a/src/runtime/internal/sys/zgoarch_mips64le.go +++ b/src/runtime/internal/sys/zgoarch_mips64le.go @@ -16,6 +16,7 @@ const GoarchArm64 = 0 const GoarchArm64be = 0 const GoarchPpc64 = 0 const GoarchPpc64le = 0 +const GoarchLoong64 = 0 const GoarchMips = 0 const GoarchMipsle = 0 const GoarchMips64 = 0 diff --git a/src/runtime/internal/sys/zgoarch_mips64p32.go b/src/runtime/internal/sys/zgoarch_mips64p32.go index d63ce27d24d..8549cc0ba34 100644 --- a/src/runtime/internal/sys/zgoarch_mips64p32.go +++ b/src/runtime/internal/sys/zgoarch_mips64p32.go @@ -16,6 +16,7 @@ const GoarchArm64 = 0 const GoarchArm64be = 0 const GoarchPpc64 = 0 const GoarchPpc64le = 0 +const GoarchLoong64 = 0 const GoarchMips = 0 const GoarchMipsle = 0 const GoarchMips64 = 0 diff --git a/src/runtime/internal/sys/zgoarch_mips64p32le.go b/src/runtime/internal/sys/zgoarch_mips64p32le.go index 2d577890b2e..667b6fe514b 100644 --- a/src/runtime/internal/sys/zgoarch_mips64p32le.go +++ b/src/runtime/internal/sys/zgoarch_mips64p32le.go @@ -16,6 +16,7 @@ const GoarchArm64 = 0 const GoarchArm64be = 0 const GoarchPpc64 = 0 const GoarchPpc64le = 0 +const GoarchLoong64 = 0 const GoarchMips = 0 const GoarchMipsle = 0 const GoarchMips64 = 0 diff --git a/src/runtime/internal/sys/zgoarch_mipsle.go b/src/runtime/internal/sys/zgoarch_mipsle.go index 8af919d03a3..8bedb2bb901 100644 --- a/src/runtime/internal/sys/zgoarch_mipsle.go +++ b/src/runtime/internal/sys/zgoarch_mipsle.go @@ -16,6 +16,7 @@ const GoarchArm64 = 0 const GoarchArm64be = 0 const GoarchPpc64 = 0 const GoarchPpc64le = 0 +const GoarchLoong64 = 0 const GoarchMips = 0 const GoarchMipsle = 1 const GoarchMips64 = 0 diff --git a/src/runtime/internal/sys/zgoarch_ppc.go b/src/runtime/internal/sys/zgoarch_ppc.go index f6f12a5ddce..fe2196a3278 100644 --- a/src/runtime/internal/sys/zgoarch_ppc.go +++ b/src/runtime/internal/sys/zgoarch_ppc.go @@ -16,6 +16,7 @@ const GoarchArm64 = 0 const GoarchArm64be = 0 const GoarchPpc64 = 0 const GoarchPpc64le = 0 +const GoarchLoong64 = 0 const GoarchMips = 0 const GoarchMipsle = 0 const GoarchMips64 = 0 diff --git a/src/runtime/internal/sys/zgoarch_ppc64.go b/src/runtime/internal/sys/zgoarch_ppc64.go index a8379601f47..bd7cc43de39 100644 --- a/src/runtime/internal/sys/zgoarch_ppc64.go +++ b/src/runtime/internal/sys/zgoarch_ppc64.go @@ -16,6 +16,7 @@ const GoarchArm64 = 0 const GoarchArm64be = 0 const GoarchPpc64 = 1 const GoarchPpc64le = 0 +const GoarchLoong64 = 0 const GoarchMips = 0 const GoarchMipsle = 0 const GoarchMips64 = 0 diff --git a/src/runtime/internal/sys/zgoarch_ppc64le.go b/src/runtime/internal/sys/zgoarch_ppc64le.go index f2ec5dcba72..e1018924016 100644 --- a/src/runtime/internal/sys/zgoarch_ppc64le.go +++ b/src/runtime/internal/sys/zgoarch_ppc64le.go @@ -16,6 +16,7 @@ const GoarchArm64 = 0 const GoarchArm64be = 0 const GoarchPpc64 = 0 const GoarchPpc64le = 1 +const GoarchLoong64 = 0 const GoarchMips = 0 const GoarchMipsle = 0 const GoarchMips64 = 0 diff --git a/src/runtime/internal/sys/zgoarch_riscv.go b/src/runtime/internal/sys/zgoarch_riscv.go index 83a3312f5f3..559f86071a7 100644 --- a/src/runtime/internal/sys/zgoarch_riscv.go +++ b/src/runtime/internal/sys/zgoarch_riscv.go @@ -16,6 +16,7 @@ const GoarchArm64 = 0 const GoarchArm64be = 0 const GoarchPpc64 = 0 const GoarchPpc64le = 0 +const GoarchLoong64 = 0 const GoarchMips = 0 const GoarchMipsle = 0 const GoarchMips64 = 0 diff --git a/src/runtime/internal/sys/zgoarch_riscv64.go b/src/runtime/internal/sys/zgoarch_riscv64.go index 1dfcc84997b..8485a94b3dd 100644 --- a/src/runtime/internal/sys/zgoarch_riscv64.go +++ b/src/runtime/internal/sys/zgoarch_riscv64.go @@ -16,6 +16,7 @@ const GoarchArm64 = 0 const GoarchArm64be = 0 const GoarchPpc64 = 0 const GoarchPpc64le = 0 +const GoarchLoong64 = 0 const GoarchMips = 0 const GoarchMipsle = 0 const GoarchMips64 = 0 diff --git a/src/runtime/internal/sys/zgoarch_s390.go b/src/runtime/internal/sys/zgoarch_s390.go index 91aba5a0f6c..4c4569e3762 100644 --- a/src/runtime/internal/sys/zgoarch_s390.go +++ b/src/runtime/internal/sys/zgoarch_s390.go @@ -16,6 +16,7 @@ const GoarchArm64 = 0 const GoarchArm64be = 0 const GoarchPpc64 = 0 const GoarchPpc64le = 0 +const GoarchLoong64 = 0 const GoarchMips = 0 const GoarchMipsle = 0 const GoarchMips64 = 0 diff --git a/src/runtime/internal/sys/zgoarch_s390x.go b/src/runtime/internal/sys/zgoarch_s390x.go index edce50234e5..e50d2edbb55 100644 --- a/src/runtime/internal/sys/zgoarch_s390x.go +++ b/src/runtime/internal/sys/zgoarch_s390x.go @@ -16,6 +16,7 @@ const GoarchArm64 = 0 const GoarchArm64be = 0 const GoarchPpc64 = 0 const GoarchPpc64le = 0 +const GoarchLoong64 = 0 const GoarchMips = 0 const GoarchMipsle = 0 const GoarchMips64 = 0 diff --git a/src/runtime/internal/sys/zgoarch_sparc.go b/src/runtime/internal/sys/zgoarch_sparc.go index 5ae9560ab01..0d08752c7bc 100644 --- a/src/runtime/internal/sys/zgoarch_sparc.go +++ b/src/runtime/internal/sys/zgoarch_sparc.go @@ -16,6 +16,7 @@ const GoarchArm64 = 0 const GoarchArm64be = 0 const GoarchPpc64 = 0 const GoarchPpc64le = 0 +const GoarchLoong64 = 0 const GoarchMips = 0 const GoarchMipsle = 0 const GoarchMips64 = 0 diff --git a/src/runtime/internal/sys/zgoarch_sparc64.go b/src/runtime/internal/sys/zgoarch_sparc64.go index e2a0134affd..ba405bbf355 100644 --- a/src/runtime/internal/sys/zgoarch_sparc64.go +++ b/src/runtime/internal/sys/zgoarch_sparc64.go @@ -16,6 +16,7 @@ const GoarchArm64 = 0 const GoarchArm64be = 0 const GoarchPpc64 = 0 const GoarchPpc64le = 0 +const GoarchLoong64 = 0 const GoarchMips = 0 const GoarchMipsle = 0 const GoarchMips64 = 0 diff --git a/src/runtime/internal/sys/zgoarch_wasm.go b/src/runtime/internal/sys/zgoarch_wasm.go index 52e85dea371..7c3e5afd1ee 100644 --- a/src/runtime/internal/sys/zgoarch_wasm.go +++ b/src/runtime/internal/sys/zgoarch_wasm.go @@ -16,6 +16,7 @@ const GoarchArm64 = 0 const GoarchArm64be = 0 const GoarchPpc64 = 0 const GoarchPpc64le = 0 +const GoarchLoong64 = 0 const GoarchMips = 0 const GoarchMipsle = 0 const GoarchMips64 = 0 From ff33d3dc3a47a4eed17728b8460de4572198cec3 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 9 Jul 2021 17:12:07 -0700 Subject: [PATCH 676/940] [dev.typeparams] cmd/compile/internal/types2: implement <-ch where ch is of type parameter type For #43671 Change-Id: I7db4b3886fab44ec0de7c0935e0ab21c26e3335c Reviewed-on: https://go-review.googlesource.com/c/go/+/333709 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/expr.go | 36 +++++++++--- .../types2/testdata/fixedbugs/issue43671.go2 | 58 +++++++++++++++++++ 2 files changed, 85 insertions(+), 9 deletions(-) create mode 100644 src/cmd/compile/internal/types2/testdata/fixedbugs/issue43671.go2 diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go index bd35417c645..d4425a2bfd5 100644 --- a/src/cmd/compile/internal/types2/expr.go +++ b/src/cmd/compile/internal/types2/expr.go @@ -157,6 +157,14 @@ var op2str2 = [...]string{ syntax.Shl: "shift", } +func underIs(typ Type, f func(Type) bool) bool { + u := under(typ) + if tpar, _ := u.(*TypeParam); tpar != nil { + return tpar.underIs(f) + } + return f(u) +} + func (check *Checker) unary(x *operand, e *syntax.Operation) { check.expr(x, e.X) if x.mode == invalid { @@ -177,19 +185,29 @@ func (check *Checker) unary(x *operand, e *syntax.Operation) { return case syntax.Recv: - typ := asChan(x.typ) - if typ == nil { - check.errorf(x, invalidOp+"cannot receive from non-channel %s", x) - x.mode = invalid - return - } - if typ.dir == SendOnly { - check.errorf(x, invalidOp+"cannot receive from send-only channel %s", x) + var elem Type + if !underIs(x.typ, func(u Type) bool { + ch, _ := u.(*Chan) + if ch == nil { + check.errorf(x, invalidOp+"cannot receive from non-channel %s", x) + return false + } + if ch.dir == SendOnly { + check.errorf(x, invalidOp+"cannot receive from send-only channel %s", x) + return false + } + if elem != nil && !Identical(ch.elem, elem) { + check.errorf(x, invalidOp+"channels of %s must have the same element type", x) + return false + } + elem = ch.elem + return true + }) { x.mode = invalid return } x.mode = commaok - x.typ = typ.elem + x.typ = elem check.hasCallOrRecv = true return } diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue43671.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue43671.go2 new file mode 100644 index 00000000000..6cc3801cc96 --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue43671.go2 @@ -0,0 +1,58 @@ +// Copyright 2021 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 + +type C0 interface{ int } +type C1 interface{ chan int } +type C2 interface{ chan int | <-chan int } +type C3 interface{ chan int | chan float32 } +type C4 interface{ chan int | chan<- int } +type C5[T any] interface{ ~chan T | <-chan T } + +func _[T any](ch T) { + <-ch // ERROR cannot receive from non-channel +} + +func _[T C0](ch T) { + <-ch // ERROR cannot receive from non-channel +} + +func _[T C1](ch T) { + <-ch +} + +func _[T C2](ch T) { + <-ch +} + +func _[T C3](ch T) { + <-ch // ERROR channels of ch .* must have the same element type +} + +func _[T C4](ch T) { + <-ch // ERROR cannot receive from send-only channel +} + +func _[T C5[X], X any](ch T, x X) { + x = <-ch +} + +// test case from issue, slightly modified +type RecvChan[T any] interface { + ~chan T | ~<-chan T +} + +func _[T any, C RecvChan[T]](ch C) T { + return <-ch +} + +func f[T any, C interface{ chan T }](ch C) T { + return <-ch +} + +func _(ch chan int) { + var x int = f(ch) // test constraint type inference for this case + _ = x +} From 6511922a142e6adbd91bec93e2c4d51a93955713 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 9 Jul 2021 17:43:25 -0700 Subject: [PATCH 677/940] [dev.typeparams] cmd/compile/internal/types2: implement ch <- x where ch is of type parameter type For #47115. Change-Id: Ib9c8652c0346029369735ccf7ee9098ab1ae7fd3 Reviewed-on: https://go-review.googlesource.com/c/go/+/333712 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/stmt.go | 36 ++++++++++------- .../types2/testdata/fixedbugs/issue47115.go2 | 40 +++++++++++++++++++ 2 files changed, 62 insertions(+), 14 deletions(-) create mode 100644 src/cmd/compile/internal/types2/testdata/fixedbugs/issue47115.go2 diff --git a/src/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go index b41b23fedbc..9b8295c4f4d 100644 --- a/src/cmd/compile/internal/types2/stmt.go +++ b/src/cmd/compile/internal/types2/stmt.go @@ -352,25 +352,33 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) { check.errorf(&x, "%s %s", &x, msg) case *syntax.SendStmt: - var ch, x operand + var ch, val operand check.expr(&ch, s.Chan) - check.expr(&x, s.Value) - if ch.mode == invalid || x.mode == invalid { + check.expr(&val, s.Value) + if ch.mode == invalid || val.mode == invalid { return } - - tch := asChan(ch.typ) - if tch == nil { - check.errorf(s, invalidOp+"cannot send to non-chan type %s", ch.typ) + var elem Type + if !underIs(ch.typ, func(u Type) bool { + uch, _ := u.(*Chan) + if uch == nil { + check.errorf(s, invalidOp+"cannot send to non-channel %s", &ch) + return false + } + if uch.dir == RecvOnly { + check.errorf(s, invalidOp+"cannot send to receive-only channel %s", &ch) + return false + } + if elem != nil && !Identical(uch.elem, elem) { + check.errorf(s, invalidOp+"channels of %s must have the same element type", &ch) + return false + } + elem = uch.elem + return true + }) { return } - - if tch.dir == RecvOnly { - check.errorf(s, invalidOp+"cannot send to receive-only type %s", tch) - return - } - - check.assignment(&x, tch.elem, "send") + check.assignment(&val, elem, "send") case *syntax.AssignStmt: lhs := unpackExpr(s.Lhs) diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47115.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47115.go2 new file mode 100644 index 00000000000..00828eb997b --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47115.go2 @@ -0,0 +1,40 @@ +// Copyright 2021 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 + +type C0 interface{ int } +type C1 interface{ chan int } +type C2 interface{ chan int | <-chan int } +type C3 interface{ chan int | chan float32 } +type C4 interface{ chan int | chan<- int } +type C5[T any] interface{ ~chan T | chan<- T } + +func _[T any](ch T) { + ch /* ERROR cannot send to non-channel */ <- 0 +} + +func _[T C0](ch T) { + ch /* ERROR cannot send to non-channel */ <- 0 +} + +func _[T C1](ch T) { + ch <- 0 +} + +func _[T C2](ch T) { + ch /* ERROR cannot send to receive-only channel */ <- 0 +} + +func _[T C3](ch T) { + ch /* ERROR channels of ch .* must have the same element type */ <- 0 +} + +func _[T C4](ch T) { + ch <- 0 +} + +func _[T C5[X], X any](ch T, x X) { + ch <- x +} From 5f0ea40c67839ae82b6018fe881f173f9b09d306 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 9 Jul 2021 18:26:57 -0700 Subject: [PATCH 678/940] [dev.typeparams] cmd/compile/internal/types2: implement close(ch) where ch is of type parameter type Change-Id: I45189468553e83390fd2640b5708c60a7852fbb5 Reviewed-on: https://go-review.googlesource.com/c/go/+/333713 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/builtins.go | 22 +++++--- .../types2/testdata/check/builtins.go2 | 55 ++++++++++++++++--- .../types2/testdata/check/builtins.src | 2 +- src/cmd/compile/internal/types2/type.go | 7 --- test/chan/perm.go | 2 +- 5 files changed, 62 insertions(+), 26 deletions(-) diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index 83d1743ee2f..e1795aedace 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -212,19 +212,23 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( case _Close: // close(c) - c := asChan(x.typ) - if c == nil { - check.errorf(x, invalidArg+"%s is not a channel", x) + if !underIs(x.typ, func(u Type) bool { + uch, _ := u.(*Chan) + if uch == nil { + check.errorf(x, invalidOp+"cannot close non-channel %s", x) + return false + } + if uch.dir == RecvOnly { + check.errorf(x, invalidOp+"cannot close receive-only channel %s", x) + return false + } + return true + }) { return } - if c.dir == RecvOnly { - check.errorf(x, invalidArg+"%s must not be a receive-only channel", x) - return - } - x.mode = novalue if check.Types != nil { - check.recordBuiltinType(call.Fun, makeSig(nil, c)) + check.recordBuiltinType(call.Fun, makeSig(nil, x.typ)) } case _Complex: diff --git a/src/cmd/compile/internal/types2/testdata/check/builtins.go2 b/src/cmd/compile/internal/types2/testdata/check/builtins.go2 index 5bb67efec9d..71295bf4342 100644 --- a/src/cmd/compile/internal/types2/testdata/check/builtins.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/builtins.go2 @@ -6,6 +6,45 @@ package builtins +// close + +type C0 interface{ int } +type C1 interface{ chan int } +type C2 interface{ chan int | <-chan int } +type C3 interface{ chan int | chan float32 } +type C4 interface{ chan int | chan<- int } +type C5[T any] interface{ ~chan T | chan<- T } + +func _[T any](ch T) { + close(ch /* ERROR cannot close non-channel */) +} + +func _[T C0](ch T) { + close(ch /* ERROR cannot close non-channel */) +} + +func _[T C1](ch T) { + close(ch) +} + +func _[T C2](ch T) { + close(ch /* ERROR cannot close receive-only channel */) +} + +func _[T C3](ch T) { + close(ch) +} + +func _[T C4](ch T) { + close(ch) +} + +func _[T C5[X], X any](ch T) { + close(ch) +} + +// make + type Bmc interface { ~map[rune]string | ~chan int } @@ -22,31 +61,31 @@ type Bss interface { ~[]int | ~[]string } -func _[T any] () { - _ = make(T /* ERROR invalid argument */ ) - _ = make(T /* ERROR invalid argument */ , 10) - _ = make(T /* ERROR invalid argument */ , 10, 20) +func _[T any]() { + _ = make(T /* ERROR invalid argument */) + _ = make(T /* ERROR invalid argument */, 10) + _ = make(T /* ERROR invalid argument */, 10, 20) } -func _[T Bmc] () { +func _[T Bmc]() { _ = make(T) _ = make(T, 10) _ = make /* ERROR expects 1 or 2 arguments */ (T, 10, 20) } -func _[T Bms] () { +func _[T Bms]() { _ = make /* ERROR expects 2 arguments */ (T) _ = make(T, 10) _ = make /* ERROR expects 2 arguments */ (T, 10, 20) } -func _[T Bcs] () { +func _[T Bcs]() { _ = make /* ERROR expects 2 arguments */ (T) _ = make(T, 10) _ = make /* ERROR expects 2 arguments */ (T, 10, 20) } -func _[T Bss] () { +func _[T Bss]() { _ = make /* ERROR expects 2 or 3 arguments */ (T) _ = make(T, 10) _ = make(T, 10, 20) diff --git a/src/cmd/compile/internal/types2/testdata/check/builtins.src b/src/cmd/compile/internal/types2/testdata/check/builtins.src index 6d1f47129b9..17e4068d654 100644 --- a/src/cmd/compile/internal/types2/testdata/check/builtins.src +++ b/src/cmd/compile/internal/types2/testdata/check/builtins.src @@ -144,7 +144,7 @@ func close1() { var r <-chan int close() // ERROR not enough arguments close(1, 2) // ERROR too many arguments - close(42 /* ERROR not a channel */) + close(42 /* ERROR cannot close non-channel */) close(r /* ERROR receive-only channel */) close(c) _ = close /* ERROR used as value */ (c) diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index c2da97605b1..84cf36de2c1 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -105,8 +105,6 @@ func asPointer(t Type) *Pointer { return op } -// asTuple is not needed - not provided - func asSignature(t Type) *Signature { op, _ := optype(t).(*Signature) return op @@ -117,11 +115,6 @@ func asMap(t Type) *Map { return op } -func asChan(t Type) *Chan { - op, _ := optype(t).(*Chan) - return op -} - // If the argument to asInterface, asNamed, or asTypeParam is of the respective type // (possibly after expanding an instance type), these methods return that type. // Otherwise the result is nil. diff --git a/test/chan/perm.go b/test/chan/perm.go index 4c94ab7ffae..04046723a4f 100644 --- a/test/chan/perm.go +++ b/test/chan/perm.go @@ -66,5 +66,5 @@ func main() { close(c) close(cs) close(cr) // ERROR "receive" - close(n) // ERROR "invalid operation.*non-chan type|must be channel|not a channel" + close(n) // ERROR "invalid operation.*non-chan type|must be channel|non-channel" } From 95f8e64fc0ff53e4df6ba03e8dbbaf3d18695d1b Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 9 Jul 2021 19:03:48 -0700 Subject: [PATCH 679/940] [dev.typeparams] cmd/compile/internal/types2: implement delete(m, k) where m is of type parameter type Change-Id: Iaf33c15128af911b6101df9885cb8b5a8495b942 Reviewed-on: https://go-review.googlesource.com/c/go/+/333729 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/builtins.go | 27 +++++++++++--- .../types2/testdata/check/builtins.go2 | 37 +++++++++++++++++++ src/cmd/compile/internal/types2/type.go | 5 --- 3 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index e1795aedace..1f7eb23cdf0 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -364,25 +364,40 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( x.typ = Typ[Int] case _Delete: - // delete(m, k) - m := asMap(x.typ) - if m == nil { - check.errorf(x, invalidArg+"%s is not a map", x) + // delete(map_, key) + // map_ must be a map type or a type parameter describing map types. + // The key cannot be a type parameter for now. + map_ := x.typ + var key Type + if !underIs(map_, func(u Type) bool { + map_, _ := u.(*Map) + if map_ == nil { + check.errorf(x, invalidArg+"%s is not a map", x) + return false + } + if key != nil && !Identical(map_.key, key) { + check.errorf(x, invalidArg+"maps of %s must have identical key types", x) + return false + } + key = map_.key + return true + }) { return } + arg(x, 1) // k if x.mode == invalid { return } - check.assignment(x, m.key, "argument to delete") + check.assignment(x, key, "argument to delete") if x.mode == invalid { return } x.mode = novalue if check.Types != nil { - check.recordBuiltinType(call.Fun, makeSig(nil, m, m.key)) + check.recordBuiltinType(call.Fun, makeSig(nil, map_, key)) } case _Imag, _Real: diff --git a/src/cmd/compile/internal/types2/testdata/check/builtins.go2 b/src/cmd/compile/internal/types2/testdata/check/builtins.go2 index 71295bf4342..8fe6d7b332e 100644 --- a/src/cmd/compile/internal/types2/testdata/check/builtins.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/builtins.go2 @@ -43,6 +43,43 @@ func _[T C5[X], X any](ch T) { close(ch) } +// delete + +type M0 interface{ int } +type M1 interface{ map[string]int } +type M2 interface { map[string]int | map[string]float64 } +type M3 interface{ map[string]int | map[rune]int } +type M4[K comparable, V any] interface{ map[K]V | map[rune]V } + +func _[T any](m T) { + delete(m /* ERROR not a map */, "foo") +} + +func _[T M0](m T) { + delete(m /* ERROR not a map */, "foo") +} + +func _[T M1](m T) { + delete(m, "foo") +} + +func _[T M2](m T) { + delete(m, "foo") + delete(m, 0 /* ERROR cannot use .* as string */) +} + +func _[T M3](m T) { + delete(m /* ERROR must have identical key types */, "foo") +} + +func _[T M4[rune, V], V any](m T) { + delete(m, 'k') +} + +func _[T M4[K, V], K comparable, V any](m T) { + delete(m /* ERROR must have identical key types */, "foo") +} + // make type Bmc interface { diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index 84cf36de2c1..b41b50393dc 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -110,11 +110,6 @@ func asSignature(t Type) *Signature { return op } -func asMap(t Type) *Map { - op, _ := optype(t).(*Map) - return op -} - // If the argument to asInterface, asNamed, or asTypeParam is of the respective type // (possibly after expanding an instance type), these methods return that type. // Otherwise the result is nil. From 2a8087817c18314d81c4165258487cdba73ebc71 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 9 Jul 2021 21:18:12 -0700 Subject: [PATCH 680/940] [dev.typeparams] cmd/compile/internal/types2: cleanups around receiver type checks Generic receiver types may be defined such that an instantiated receiver ends up being a pointer type. Disallow them as we do for non-generic receivers. Change-Id: I6612a52615a2999375c35aa1d69ab42f37d9f55d Reviewed-on: https://go-review.googlesource.com/c/go/+/333770 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/signature.go | 32 ++++++++++++------- .../types2/testdata/examples/methods.go2 | 17 ++++++++++ 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go index ab9a1c487eb..fa5c3f7a9b8 100644 --- a/src/cmd/compile/internal/types2/signature.go +++ b/src/cmd/compile/internal/types2/signature.go @@ -211,9 +211,10 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams [] // spec: "The receiver type must be of the form T or *T where T is a type name." // (ignore invalid types - error was reported before) - if t := rtyp; t != Typ[Invalid] { + if rtyp != Typ[Invalid] { var err string - if T := asNamed(t); T != nil { + switch T := rtyp.(type) { + case *Named: // spec: "The type denoted by T is called the receiver base type; it must not // be a pointer or interface type and it must be declared in the same package // as the method." @@ -224,23 +225,30 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams [] err = "" } } else { - switch u := optype(T).(type) { - case *Basic: - // unsafe.Pointer is treated like a regular pointer - if u.kind == UnsafePointer { - err = "unsafe.Pointer" + // The underlying type of a receiver base type can be a type parameter; + // e.g. for methods with a generic receiver T[P] with type T[P any] P. + underIs(T, func(u Type) bool { + switch u := u.(type) { + case *Basic: + // unsafe.Pointer is treated like a regular pointer + if u.kind == UnsafePointer { + err = "unsafe.Pointer" + return false + } + case *Pointer, *Interface: + err = "pointer or interface type" + return false } - case *Pointer, *Interface: - err = "pointer or interface type" - } + return true + }) } - } else if T := asBasic(t); T != nil { + case *Basic: err = "basic or unnamed type" if check.conf.CompilerErrorMessages { check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ) err = "" } - } else { + default: check.errorf(recv.pos, "invalid receiver type %s", recv.typ) } if err != "" { diff --git a/src/cmd/compile/internal/types2/testdata/examples/methods.go2 b/src/cmd/compile/internal/types2/testdata/examples/methods.go2 index 76c6539e1b7..4e87041e547 100644 --- a/src/cmd/compile/internal/types2/testdata/examples/methods.go2 +++ b/src/cmd/compile/internal/types2/testdata/examples/methods.go2 @@ -6,6 +6,8 @@ package p +import "unsafe" + // Parameterized types may have methods. type T1[A any] struct{ a A } @@ -94,3 +96,18 @@ func (_ T2[_, _, _]) _() int { return 42 } type T0 struct{} func (T0) _() {} func (T1[A]) _() {} + +// A generic receiver type may constrain its type parameter such +// that it must be a pointer type. Such receiver types are not +// permitted. +type T3a[P interface{ ~int | ~string | ~float64 }] P + +func (T3a[_]) m() {} // this is ok + +type T3b[P interface{ ~unsafe.Pointer }] P + +func (T3b /* ERROR invalid receiver */ [_]) m() {} + +type T3c[P interface{ *int | *string }] P + +func (T3c /* ERROR invalid receiver */ [_]) m() {} From dd8bdf4a1fceb06231eb73c026f4a7fe41f00dc1 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Sun, 11 Jul 2021 15:27:49 -0700 Subject: [PATCH 681/940] [dev.typeparams] cmd/compile/internal/types2: interface identity must consider full type set There is no (obvious) way to test this at the moment because we don't permit such constraint interfaces as ordinary types. Change-Id: Ieeec023ed82a2c71ed50d111f26916aba4a59099 Reviewed-on: https://go-review.googlesource.com/c/go/+/333889 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/predicates.go | 17 +++++++++++++---- src/cmd/compile/internal/types2/unify.go | 12 ++++++++---- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go index 2f108985857..e862c0fca8a 100644 --- a/src/cmd/compile/internal/types2/predicates.go +++ b/src/cmd/compile/internal/types2/predicates.go @@ -270,12 +270,21 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { } case *Interface: + // Two interface types are identical if they describe the same type sets. + // With the existing implementation restriction, this simplifies to: + // // Two interface types are identical if they have the same set of methods with - // the same names and identical function types. Lower-case method names from - // different packages are always different. The order of the methods is irrelevant. + // the same names and identical function types, and if any type restrictions + // are the same. Lower-case method names from different packages are always + // different. The order of the methods is irrelevant. if y, ok := y.(*Interface); ok { - a := x.typeSet().methods - b := y.typeSet().methods + xset := x.typeSet() + yset := y.typeSet() + if !Identical(xset.types, yset.types) { + return false + } + a := xset.methods + b := yset.methods if len(a) == len(b) { // Interface types are the only types where cycles can occur // that are not "terminated" via named types; and such cycles diff --git a/src/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go index 755622738a6..7221356354a 100644 --- a/src/cmd/compile/internal/types2/unify.go +++ b/src/cmd/compile/internal/types2/unify.go @@ -362,16 +362,20 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool { } case *Union: - // This should not happen with the current internal use of union types. - panic("type inference across union types not implemented") + panic("unimplemented: unification with type sets described by types") case *Interface: // Two interface types are identical if they have the same set of methods with // the same names and identical function types. Lower-case method names from // different packages are always different. The order of the methods is irrelevant. if y, ok := y.(*Interface); ok { - a := x.typeSet().methods - b := y.typeSet().methods + xset := x.typeSet() + yset := y.typeSet() + if !Identical(xset.types, yset.types) { + return false + } + a := xset.methods + b := yset.methods if len(a) == len(b) { // Interface types are the only types where cycles can occur // that are not "terminated" via named types; and such cycles From 3a047326e896302724378e5d6b8684851ccfdbfd Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Sun, 11 Jul 2021 15:59:22 -0700 Subject: [PATCH 682/940] [dev.typeparams] cmd/compile/internal/types2: fix generic type indirection Change-Id: If25ceb2aa403b94608760be331faa2aff11c47cc Reviewed-on: https://go-review.googlesource.com/c/go/+/333890 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/expr.go | 21 ++++++++++---- .../types2/testdata/examples/operations.go2 | 29 +++++++++++++++++++ 2 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 src/cmd/compile/internal/types2/testdata/examples/operations.go2 diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go index d4425a2bfd5..008c2446fcd 100644 --- a/src/cmd/compile/internal/types2/expr.go +++ b/src/cmd/compile/internal/types2/expr.go @@ -1479,13 +1479,24 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin case typexpr: x.typ = &Pointer{base: x.typ} default: - if typ := asPointer(x.typ); typ != nil { - x.mode = variable - x.typ = typ.base - } else { - check.errorf(x, invalidOp+"cannot indirect %s", x) + var base Type + if !underIs(x.typ, func(u Type) bool { + p, _ := u.(*Pointer) + if p == nil { + check.errorf(x, invalidOp+"cannot indirect %s", x) + return false + } + if base != nil && !Identical(p.base, base) { + check.errorf(x, invalidOp+"pointers of %s must have identical base types", x) + return false + } + base = p.base + return true + }) { goto Error } + x.mode = variable + x.typ = base } break } diff --git a/src/cmd/compile/internal/types2/testdata/examples/operations.go2 b/src/cmd/compile/internal/types2/testdata/examples/operations.go2 new file mode 100644 index 00000000000..18e4d6080c5 --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/examples/operations.go2 @@ -0,0 +1,29 @@ +// Copyright 2021 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 + +// indirection + +func _[P any](p P) { + _ = *p // ERROR cannot indirect p +} + +func _[P interface{ int }](p P) { + _ = *p // ERROR cannot indirect p +} + +func _[P interface{ *int }](p P) { + _ = *p +} + +func _[P interface{ *int | *string }](p P) { + _ = *p // ERROR must have identical base types +} + +type intPtr *int + +func _[P interface{ *int | intPtr } ](p P) { + var _ int = *p +} From 4ff0e04c2e409aaeebe0cf5287dbed735f84e974 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 12 Jul 2021 22:39:39 -0700 Subject: [PATCH 683/940] [dev.typeparams] cmd/compile/internal/types2: embedding stand-alone type parameters is not permitted For #47127. Change-Id: Ie979ff56ae7c2dd0e5ce0ff39588f98ae68b5ee9 Reviewed-on: https://go-review.googlesource.com/c/go/+/334151 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- .../internal/types2/testdata/check/issues.go2 | 2 +- .../types2/testdata/check/tinference.go2 | 42 ++++++++++--------- .../types2/testdata/fixedbugs/issue39634.go2 | 7 ++-- .../types2/testdata/fixedbugs/issue39680.go2 | 4 ++ .../types2/testdata/fixedbugs/issue39948.go2 | 10 +---- .../types2/testdata/fixedbugs/issue47127.go2 | 37 ++++++++++++++++ src/cmd/compile/internal/types2/typeset.go | 8 ++-- src/cmd/compile/internal/types2/union.go | 11 +++-- test/typeparam/typelist.go | 6 +++ 9 files changed, 87 insertions(+), 40 deletions(-) create mode 100644 src/cmd/compile/internal/types2/testdata/fixedbugs/issue47127.go2 diff --git a/src/cmd/compile/internal/types2/testdata/check/issues.go2 b/src/cmd/compile/internal/types2/testdata/check/issues.go2 index 88ae294d7c1..32c4320d271 100644 --- a/src/cmd/compile/internal/types2/testdata/check/issues.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/issues.go2 @@ -232,7 +232,7 @@ func _[T interface{ ~func() }](f T) { type sliceOf[E any] interface{ ~[]E } -func append[T interface{}, S sliceOf[T], T2 interface{ T }](s S, t ...T2) S +func append[T interface{}, S sliceOf[T], T2 interface{}](s S, t ...T2) S var f func() var cancelSlice []context.CancelFunc diff --git a/src/cmd/compile/internal/types2/testdata/check/tinference.go2 b/src/cmd/compile/internal/types2/testdata/check/tinference.go2 index 2fdb39ca7a8..1b709817595 100644 --- a/src/cmd/compile/internal/types2/testdata/check/tinference.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/tinference.go2 @@ -8,19 +8,20 @@ import "strconv" type any interface{} -func f0[A any, B interface{~C}, C interface{~D}, D interface{~A}](A, B, C, D) -func _() { - f := f0[string] - f("a", "b", "c", "d") - f0("a", "b", "c", "d") -} - -func f1[A any, B interface{~A}](A, B) -func _() { - f := f1[int] - f(int(0), int(0)) - f1(int(0), int(0)) -} +// Embedding stand-alone type parameters is not permitted for now. Disabled. +// func f0[A any, B interface{~C}, C interface{~D}, D interface{~A}](A, B, C, D) +// func _() { +// f := f0[string] +// f("a", "b", "c", "d") +// f0("a", "b", "c", "d") +// } +// +// func f1[A any, B interface{~A}](A, B) +// func _() { +// f := f1[int] +// f(int(0), int(0)) +// f1(int(0), int(0)) +// } func f2[A any, B interface{~[]A}](A, B) func _() { @@ -29,13 +30,14 @@ func _() { f2(byte(0), []byte{}) } -func f3[A any, B interface{~C}, C interface{~*A}](A, B, C) -func _() { - f := f3[int] - var x int - f(x, &x, &x) - f3(x, &x, &x) -} +// Embedding stand-alone type parameters is not permitted for now. Disabled. +// func f3[A any, B interface{~C}, C interface{~*A}](A, B, C) +// func _() { +// f := f3[int] +// var x int +// f(x, &x, &x) +// f3(x, &x, &x) +// } func f4[A any, B interface{~[]C}, C interface{~*A}](A, B, C) func _() { diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2 index 6d002f5d2fc..5cb15e7e58a 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2 @@ -31,9 +31,10 @@ type x7[A any] struct{ foo7 } func main7() { var _ foo7 = x7[int]{} } // crash 8 -type foo8[A any] interface { ~A } -func bar8[A foo8[A]](a A) {} -func main8() {} +// Embedding stand-alone type parameters is not permitted for now. Disabled. +// type foo8[A any] interface { ~A } +// func bar8[A foo8[A]](a A) {} +// func main8() {} // crash 9 type foo9[A any] interface { foo9 /* ERROR illegal cycle */ [A] } diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39680.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39680.go2 index 01eadd2dbf9..e56bc354758 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39680.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39680.go2 @@ -4,6 +4,9 @@ package p +// Embedding stand-alone type parameters is not permitted for now. Disabled. + +/* import "fmt" // Minimal test case. @@ -25,3 +28,4 @@ func Print[T constr[T]](s []T) { func f() { Print([]string{"Hello, ", "playground\n"}) } +*/ diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39948.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39948.go2 index 6372397ed92..e38e57268d6 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39948.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39948.go2 @@ -2,14 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// TODO(gri) Eventually, once we disallow type lists, we need to -// adjust this code: for 1.17 we don't accept type parameters, -// and for 1.18 this code is valid. -// Leaving for now so we can see that existing errors -// are being reported. - -package go1_17 // don't permit non-interface elements in interfaces +package p type T[P any] interface{ - P // ERROR P is a type parameter, not an interface + P // ERROR cannot embed a type parameter } diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47127.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47127.go2 new file mode 100644 index 00000000000..387c946957c --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47127.go2 @@ -0,0 +1,37 @@ +// Copyright 2021 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. + +// Embedding of stand-alone type parameters is not permitted. + +package p + +type ( + _[P any] interface{ *P | []P | chan P | map[string]P } + _[P any] interface{ P /* ERROR "cannot embed a type parameter" */ } + _[P any] interface{ ~P /* ERROR "cannot embed a type parameter" */ } + _[P any] interface{ int | P /* ERROR "cannot embed a type parameter" */ } + _[P any] interface{ int | ~P /* ERROR "cannot embed a type parameter" */ } +) + +func _[P any]() { + type ( + _[P any] interface{ *P | []P | chan P | map[string]P } + _[P any] interface{ P /* ERROR "cannot embed a type parameter" */ } + _[P any] interface{ ~P /* ERROR "cannot embed a type parameter" */ } + _[P any] interface{ int | P /* ERROR "cannot embed a type parameter" */ } + _[P any] interface{ int | ~P /* ERROR "cannot embed a type parameter" */ } + + _ interface{ *P | []P | chan P | map[string]P } + _ interface{ P /* ERROR "cannot embed a type parameter" */ } + _ interface{ ~P /* ERROR "cannot embed a type parameter" */ } + _ interface{ int | P /* ERROR "cannot embed a type parameter" */ } + _ interface{ int | ~P /* ERROR "cannot embed a type parameter" */ } + ) +} + +func _[P any, Q interface{ *P | []P | chan P | map[string]P }]() +func _[P any, Q interface{ P /* ERROR "cannot embed a type parameter" */ }]() +func _[P any, Q interface{ ~P /* ERROR "cannot embed a type parameter" */ }]() +func _[P any, Q interface{ int | P /* ERROR "cannot embed a type parameter" */ }]() +func _[P any, Q interface{ int | ~P /* ERROR "cannot embed a type parameter" */ }]() diff --git a/src/cmd/compile/internal/types2/typeset.go b/src/cmd/compile/internal/types2/typeset.go index 4aee8e40972..8e6af8e65ce 100644 --- a/src/cmd/compile/internal/types2/typeset.go +++ b/src/cmd/compile/internal/types2/typeset.go @@ -216,11 +216,9 @@ func computeTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet { // interface before go1.18. types = typ case *TypeParam: - if check != nil && !check.allowVersion(check.pkg, 1, 18) { - check.errorf(pos, "%s is a type parameter, not an interface", typ) - continue - } - types = typ + // Embedding stand-alone type parameters is not permitted for now. + // This case is handled during union parsing. + unreachable() default: if typ == Typ[Invalid] { continue diff --git a/src/cmd/compile/internal/types2/union.go b/src/cmd/compile/internal/types2/union.go index e5e851c1d26..5983a73ec69 100644 --- a/src/cmd/compile/internal/types2/union.go +++ b/src/cmd/compile/internal/types2/union.go @@ -128,13 +128,18 @@ func parseUnion(check *Checker, tlist []syntax.Expr) Type { return newUnion(types, tilde) } -func parseTilde(check *Checker, x syntax.Expr) (Type, bool) { - tilde := false +func parseTilde(check *Checker, x syntax.Expr) (typ Type, tilde bool) { if op, _ := x.(*syntax.Operation); op != nil && op.Op == syntax.Tilde { x = op.X tilde = true } - return check.anyType(x), tilde + typ = check.anyType(x) + // embedding stand-alone type parameters is not permitted (issue #47127). + if _, ok := under(typ).(*TypeParam); ok { + check.error(x, "cannot embed a type parameter") + typ = Typ[Invalid] + } + return } // intersect computes the intersection of the types x and y, diff --git a/test/typeparam/typelist.go b/test/typeparam/typelist.go index bd90d86fcf2..5c51c9c4617 100644 --- a/test/typeparam/typelist.go +++ b/test/typeparam/typelist.go @@ -67,6 +67,8 @@ func _[V any, T interface { type map[string]V }](p T) V { // Testing partial and full type inference, including the case where the types can // be inferred without needing the types of the function arguments. +// Cannot embed stand-alone type parameters. Disabled for now. +/* func f0[A any, B interface{type C}, C interface{type D}, D interface{type A}](A, B, C, D) func _() { f := f0[string] @@ -82,6 +84,7 @@ func _() { f(0, 0) f1(0, 0) } +*/ func f2[A any, B interface{type []A}](_ A, _ B) func _() { @@ -92,6 +95,8 @@ func _() { // f2(0, []byte{}) - this one doesn't work } +// Cannot embed stand-alone type parameters. Disabled for now. +/* func f3[A any, B interface{type C}, C interface{type *A}](a A, _ B, c C) func _() { f := f3[int] @@ -99,6 +104,7 @@ func _() { f(x, &x, &x) f3(x, &x, &x) } +*/ func f4[A any, B interface{type []C}, C interface{type *A}](_ A, _ B, c C) func _() { From 21a04e33353316635b5f3351e807916f3bb1e844 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 14 Jul 2021 16:04:49 -0700 Subject: [PATCH 684/940] doc/go1.17: mention GOARCH=loong64 For #46229 Change-Id: I54d01d90f2b0c892d76121f1350c0e8cf4b2772f Reviewed-on: https://go-review.googlesource.com/c/go/+/334729 Trust: Ian Lance Taylor Reviewed-by: Dmitri Shuralyov --- doc/go1.17.html | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/go1.17.html b/doc/go1.17.html index fa8f14de99d..b31006fe656 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -119,6 +119,17 @@ Do not send CLs removing the interior tags from such phrases. stack frame pointers only on Linux, macOS, and iOS.

+

loong64 GOARCH value reserved

+ +

+ The main Go compiler does not yet support the LoongArch + architecture, but we've reserved the GOARCH value + "loong64". + This means that Go files named *_loong64.go will now + be ignored by Go + tools except when that GOARCH value is being used. +

+

Tools

Go command

From c1cc9f9c3d5ed789a080ef9f8dd9c11eca7e2026 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Thu, 15 Jul 2021 00:56:44 +0700 Subject: [PATCH 685/940] cmd/compile: fix lookup package of redeclared dot import symbol The compiler is relying on Sym.Def field to lookup symbol package in DotImportRefs map. But the Sym.Def field is clear whenever the compiler finish processing a file. If the dot import happen in file A, then the redeclaration happen in file B, then the symbol lookup in file B will see a nil Sym.Def, that cause the compiler crashes. To fix this, we can interate over DotImportRefs and check for matching symbol name and return the corresponding package. Though this operation can be slow, but it only happens in invalid program, when printing error message, so it's not worth to optimize it further. Fixes #47201 Change-Id: I4ca1cb0a8e7432b19cf71434592a4cbb58d54adf Reviewed-on: https://go-review.googlesource.com/c/go/+/334589 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/typecheck/dcl.go | 12 +++++++++++- test/fixedbugs/issue47201.dir/a.go | 13 +++++++++++++ test/fixedbugs/issue47201.dir/b.go | 9 +++++++++ test/fixedbugs/issue47201.go | 7 +++++++ 4 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue47201.dir/a.go create mode 100644 test/fixedbugs/issue47201.dir/b.go create mode 100644 test/fixedbugs/issue47201.go diff --git a/src/cmd/compile/internal/typecheck/dcl.go b/src/cmd/compile/internal/typecheck/dcl.go index f3058d8811a..5b771e3c0b1 100644 --- a/src/cmd/compile/internal/typecheck/dcl.go +++ b/src/cmd/compile/internal/typecheck/dcl.go @@ -106,7 +106,17 @@ func Export(n *ir.Name) { // Redeclared emits a diagnostic about symbol s being redeclared at pos. func Redeclared(pos src.XPos, s *types.Sym, where string) { if !s.Lastlineno.IsKnown() { - pkgName := DotImportRefs[s.Def.(*ir.Ident)] + var pkgName *ir.PkgName + if s.Def == nil { + for id, pkg := range DotImportRefs { + if id.Sym().Name == s.Name { + pkgName = pkg + break + } + } + } else { + pkgName = DotImportRefs[s.Def.(*ir.Ident)] + } base.ErrorfAt(pos, "%v redeclared %s\n"+ "\t%v: previous declaration during import %q", s, where, base.FmtPos(pkgName.Pos()), pkgName.Pkg.Path) } else { diff --git a/test/fixedbugs/issue47201.dir/a.go b/test/fixedbugs/issue47201.dir/a.go new file mode 100644 index 00000000000..54b70790926 --- /dev/null +++ b/test/fixedbugs/issue47201.dir/a.go @@ -0,0 +1,13 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + . "fmt" +) + +func test() { + Println("foo") +} diff --git a/test/fixedbugs/issue47201.dir/b.go b/test/fixedbugs/issue47201.dir/b.go new file mode 100644 index 00000000000..5fd0635af2e --- /dev/null +++ b/test/fixedbugs/issue47201.dir/b.go @@ -0,0 +1,9 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func Println() {} // ERROR "Println redeclared in this block" + +func main() {} diff --git a/test/fixedbugs/issue47201.go b/test/fixedbugs/issue47201.go new file mode 100644 index 00000000000..e3a470b4195 --- /dev/null +++ b/test/fixedbugs/issue47201.go @@ -0,0 +1,7 @@ +// errorcheckdir + +// Copyright 2021 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 ignored From 69728ead871f15cc1fd7e70b67e6768dd1100bae Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Thu, 15 Jul 2021 14:48:45 -0400 Subject: [PATCH 686/940] cmd/go: update error messages in tests to match CL 332573 I neglected to run the 'longtest' builder, and the tests that cover the error message changed in CL 332573 apparently do not run in short mode. Updates #36460 Updates #42661 Change-Id: I53500ddaca8ac9f0dfaab538923b3c9a4f71665e Reviewed-on: https://go-review.googlesource.com/c/go/+/334889 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills Reviewed-by: Jay Conrod TryBot-Result: Go Bot --- src/cmd/go/testdata/script/mod_tidy_compat_ambiguous.txt | 2 +- src/cmd/go/testdata/script/mod_tidy_compat_deleted.txt | 2 +- src/cmd/go/testdata/script/mod_tidy_compat_implicit.txt | 2 +- src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_ambiguous.txt b/src/cmd/go/testdata/script/mod_tidy_compat_ambiguous.txt index ed1dd53eff1..c544cb7413f 100644 --- a/src/cmd/go/testdata/script/mod_tidy_compat_ambiguous.txt +++ b/src/cmd/go/testdata/script/mod_tidy_compat_ambiguous.txt @@ -23,7 +23,7 @@ cp go.mod go.mod.orig stderr '^example\.com/m imports\n\texample\.net/indirect imports\n\texample\.net/ambiguous/nested/pkg loaded from example\.net/ambiguous/nested@v0\.1\.0,\n\tbut go 1.16 would fail to locate it:\n\tambiguous import: found package example\.net/ambiguous/nested/pkg in multiple modules:\n\texample\.net/ambiguous v0.1.0 \(.*\)\n\texample\.net/ambiguous/nested v0.1.0 \(.*\)\n\n' -stderr '\n\nTo proceed despite packages unresolved in go 1\.16:\n\tgo mod tidy -e\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1\.17\nFor other options, see:\n\thttps://golang\.org/wiki/PruningModules\n' +stderr '\n\nTo proceed despite packages unresolved in go 1\.16:\n\tgo mod tidy -e\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1\.17\nFor other options, see:\n\thttps://golang\.org/doc/modules/pruning\n' cmp go.mod go.mod.orig diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_deleted.txt b/src/cmd/go/testdata/script/mod_tidy_compat_deleted.txt index 3aacde2025d..dcf13e20490 100644 --- a/src/cmd/go/testdata/script/mod_tidy_compat_deleted.txt +++ b/src/cmd/go/testdata/script/mod_tidy_compat_deleted.txt @@ -19,7 +19,7 @@ cp go.mod go.mod.orig stderr '^example\.com/m imports\n\texample\.net/deleted loaded from example\.net/deleted@v0\.1\.0,\n\tbut go 1\.16 would fail to locate it in example\.net/deleted@v0\.2\.0\n\n' -stderr '\n\nTo upgrade to the versions selected by go 1.16, leaving some packages unresolved:\n\tgo mod tidy -e -go=1\.16 && go mod tidy -e -go=1\.17\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1\.17\nFor other options, see:\n\thttps://golang\.org/wiki/PruningModules\n' +stderr '\n\nTo upgrade to the versions selected by go 1.16, leaving some packages unresolved:\n\tgo mod tidy -e -go=1\.16 && go mod tidy -e -go=1\.17\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1\.17\nFor other options, see:\n\thttps://golang\.org/doc/modules/pruning\n' # The suggested 'go mod tidy -e' command should proceed anyway. diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_implicit.txt b/src/cmd/go/testdata/script/mod_tidy_compat_implicit.txt index e00aea930ee..186a3f8e672 100644 --- a/src/cmd/go/testdata/script/mod_tidy_compat_implicit.txt +++ b/src/cmd/go/testdata/script/mod_tidy_compat_implicit.txt @@ -33,7 +33,7 @@ env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}' cp go.mod go.mod.orig ! go mod tidy stderr '^example\.com/m imports\n\texample\.net/lazy tested by\n\texample\.net/lazy.test imports\n\texample\.com/retract/incompatible loaded from example\.com/retract/incompatible@v1\.0\.0,\n\tbut go 1\.16 would select v2\.0\.0\+incompatible\n\n' -stderr '\n\nTo upgrade to the versions selected by go 1\.16:\n\tgo mod tidy -go=1\.16 && go mod tidy -go=1\.17\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1.17\nFor other options, see:\n\thttps://golang\.org/wiki/PruningModules\n' +stderr '\n\nTo upgrade to the versions selected by go 1\.16:\n\tgo mod tidy -go=1\.16 && go mod tidy -go=1\.17\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1.17\nFor other options, see:\n\thttps://golang\.org/doc/modules/pruning\n' cmp go.mod go.mod.orig diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt b/src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt index 2d8726544a3..ea9e42e87e2 100644 --- a/src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt +++ b/src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt @@ -33,7 +33,7 @@ env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}' cp go.mod go.mod.orig ! go mod tidy stderr '^example\.com/m imports\n\texample\.net/lazy imports\n\texample\.com/retract/incompatible loaded from example\.com/retract/incompatible@v1\.0\.0,\n\tbut go 1\.16 would select v2\.0\.0\+incompatible\n\n' -stderr '\n\nTo upgrade to the versions selected by go 1\.16:\n\tgo mod tidy -go=1\.16 && go mod tidy -go=1\.17\nIf reproducibility with go 1\.16 is not needed:\n\tgo mod tidy -compat=1.17\nFor other options, see:\n\thttps://golang\.org/wiki/PruningModules\n' +stderr '\n\nTo upgrade to the versions selected by go 1\.16:\n\tgo mod tidy -go=1\.16 && go mod tidy -go=1\.17\nIf reproducibility with go 1\.16 is not needed:\n\tgo mod tidy -compat=1.17\nFor other options, see:\n\thttps://golang\.org/doc/modules/pruning\n' cmp go.mod go.mod.orig From 0941dbca6ae805dd7b5f7871d5811b7b7f14f77f Mon Sep 17 00:00:00 2001 From: "Matt T. Proud" Date: Wed, 14 Jul 2021 22:42:31 +0200 Subject: [PATCH 687/940] testing: clarify in docs that TestMain is advanced Beginner and intermediate Go users periodically use TestMain when requirements do not necessitate TestMain (exceeding least-mechanism design). This commit expands package testing's documentation to convey that the TestMain feature itself is somewhat low-level and potentially unsuitable for casual testing where ordinary test functions would suffice. Fixes #42161 Updates #44200 Change-Id: I91ba0b048c3d6f79110fe8f0fbb58d896edca366 Reviewed-on: https://go-review.googlesource.com/c/go/+/334649 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Rob Pike --- src/testing/testing.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/testing/testing.go b/src/testing/testing.go index eeee0aac172..681f99ef934 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -233,6 +233,8 @@ // os.Exit(m.Run()) // } // +// TestMain is a low-level primitive and should not be necessary for casual +// testing needs, where ordinary test functions suffice. package testing import ( From 6b85a218b86fbc46916d838724d674baf312cc3c Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 15 Jul 2021 13:06:13 -0700 Subject: [PATCH 688/940] [dev.typeparams] cmd/compile: make TestUnifiedCompare insensitive to default -G level The test currently fails if the default -G level is changed from 0 to 3, and it only makes sense to run in -G=0 mode anyway. So might as well hard code it that way. Change-Id: I026d25d567157df5d3f2ca3c68d31d75d9c74532 Reviewed-on: https://go-review.googlesource.com/c/go/+/334910 Trust: Matthew Dempsky Trust: Dan Scales Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/noder/unified_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/noder/unified_test.go b/src/cmd/compile/internal/noder/unified_test.go index 26173682fbd..96cc66f775d 100644 --- a/src/cmd/compile/internal/noder/unified_test.go +++ b/src/cmd/compile/internal/noder/unified_test.go @@ -54,8 +54,8 @@ func TestUnifiedCompare(t *testing.T) { t.Parallel() } - pkgs1 := loadPackages(t, goos, goarch, "-d=unified=0 -d=inlfuncswithclosures=0 -d=unifiedquirks=1") - pkgs2 := loadPackages(t, goos, goarch, "-d=unified=1 -d=inlfuncswithclosures=0 -d=unifiedquirks=1") + pkgs1 := loadPackages(t, goos, goarch, "-d=unified=0 -d=inlfuncswithclosures=0 -d=unifiedquirks=1 -G=0") + pkgs2 := loadPackages(t, goos, goarch, "-d=unified=1 -d=inlfuncswithclosures=0 -d=unifiedquirks=1 -G=0") if len(pkgs1) != len(pkgs2) { t.Fatalf("length mismatch: %v != %v", len(pkgs1), len(pkgs2)) From 334f2fc045b7d9d846cccba01b3a0dbf70ddb0db Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 11 Jun 2021 10:58:43 -0400 Subject: [PATCH 689/940] [dev.typeparams] go/*: switch from ListExpr to MultiIndexExpr When instantiating a generic type or function with multiple type arguments, we need to represent an index expression with multiple indexes in the AST. Previous to this CL this was done with a new ast.ListExpr node, which allowed packing multiple expressions into a single ast.Expr. This compositional pattern can be both inefficient and cumbersome to work with, and introduces a new node type that only exists to augment the meaning of an existing node type. By comparison, other specializations of syntax are given distinct nodes in go/ast, for example variations of switch or for statements, so the use of ListExpr was also (arguably) inconsistent. This CL removes ListExpr, and instead adds a MultiIndexExpr node, which is exactly like IndexExpr but allows for multiple index arguments. This requires special handling for this new node type, but a new wrapper in the typeparams helper package largely mitigates this special handling. Change-Id: I65eb29c025c599bae37501716284dc7eb953b2ad Reviewed-on: https://go-review.googlesource.com/c/go/+/327149 Trust: Robert Findley Reviewed-by: Robert Griesemer Run-TryBot: Robert Findley TryBot-Result: Go Bot --- src/go/ast/ast.go | 56 ++++++++---------- src/go/ast/walk.go | 11 ++-- src/go/internal/typeparams/typeparams.go | 58 ++++++++++++------- src/go/parser/parser.go | 22 +++++-- src/go/printer/nodes.go | 20 +++---- src/go/types/call.go | 46 +++++++-------- src/go/types/expr.go | 14 ++--- src/go/types/exprstring.go | 8 +-- src/go/types/index.go | 37 +++++------- src/go/types/resolver.go | 10 ++-- src/go/types/signature.go | 27 ++++----- src/go/types/testdata/check/typeinst.go2 | 6 +- .../types/testdata/fixedbugs/issue45635.go2 | 2 +- src/go/types/typexpr.go | 20 +++---- 14 files changed, 170 insertions(+), 167 deletions(-) diff --git a/src/go/ast/ast.go b/src/go/ast/ast.go index a34cafcb4e7..b0f13305642 100644 --- a/src/go/ast/ast.go +++ b/src/go/ast/ast.go @@ -344,6 +344,15 @@ type ( Rbrack token.Pos // position of "]" } + // A MultiIndexExpr node represents an expression followed by multiple + // indices. + MultiIndexExpr struct { + X Expr // expression + Lbrack token.Pos // position of "[" + Indices []Expr // index expressions + Rbrack token.Pos // position of "]" + } + // A SliceExpr node represents an expression followed by slice indices. SliceExpr struct { X Expr // expression @@ -374,13 +383,6 @@ type ( Rparen token.Pos // position of ")" } - // A ListExpr node represents a list of expressions separated by commas. - // ListExpr nodes are used as index in IndexExpr nodes representing type - // or function instantiations with more than one type argument. - ListExpr struct { - ElemList []Expr - } - // A StarExpr node represents an expression of the form "*" Expression. // Semantically it could be a unary "*" expression, or a pointer type. // @@ -494,21 +496,16 @@ func (x *CompositeLit) Pos() token.Pos { func (x *ParenExpr) Pos() token.Pos { return x.Lparen } func (x *SelectorExpr) Pos() token.Pos { return x.X.Pos() } func (x *IndexExpr) Pos() token.Pos { return x.X.Pos() } +func (x *MultiIndexExpr) Pos() token.Pos { return x.X.Pos() } func (x *SliceExpr) Pos() token.Pos { return x.X.Pos() } func (x *TypeAssertExpr) Pos() token.Pos { return x.X.Pos() } func (x *CallExpr) Pos() token.Pos { return x.Fun.Pos() } -func (x *ListExpr) Pos() token.Pos { - if len(x.ElemList) > 0 { - return x.ElemList[0].Pos() - } - return token.NoPos -} -func (x *StarExpr) Pos() token.Pos { return x.Star } -func (x *UnaryExpr) Pos() token.Pos { return x.OpPos } -func (x *BinaryExpr) Pos() token.Pos { return x.X.Pos() } -func (x *KeyValueExpr) Pos() token.Pos { return x.Key.Pos() } -func (x *ArrayType) Pos() token.Pos { return x.Lbrack } -func (x *StructType) Pos() token.Pos { return x.Struct } +func (x *StarExpr) Pos() token.Pos { return x.Star } +func (x *UnaryExpr) Pos() token.Pos { return x.OpPos } +func (x *BinaryExpr) Pos() token.Pos { return x.X.Pos() } +func (x *KeyValueExpr) Pos() token.Pos { return x.Key.Pos() } +func (x *ArrayType) Pos() token.Pos { return x.Lbrack } +func (x *StructType) Pos() token.Pos { return x.Struct } func (x *FuncType) Pos() token.Pos { if x.Func.IsValid() || x.Params == nil { // see issue 3870 return x.Func @@ -533,21 +530,16 @@ func (x *CompositeLit) End() token.Pos { return x.Rbrace + 1 } func (x *ParenExpr) End() token.Pos { return x.Rparen + 1 } func (x *SelectorExpr) End() token.Pos { return x.Sel.End() } func (x *IndexExpr) End() token.Pos { return x.Rbrack + 1 } +func (x *MultiIndexExpr) End() token.Pos { return x.Rbrack + 1 } func (x *SliceExpr) End() token.Pos { return x.Rbrack + 1 } func (x *TypeAssertExpr) End() token.Pos { return x.Rparen + 1 } func (x *CallExpr) End() token.Pos { return x.Rparen + 1 } -func (x *ListExpr) End() token.Pos { - if len(x.ElemList) > 0 { - return x.ElemList[len(x.ElemList)-1].End() - } - return token.NoPos -} -func (x *StarExpr) End() token.Pos { return x.X.End() } -func (x *UnaryExpr) End() token.Pos { return x.X.End() } -func (x *BinaryExpr) End() token.Pos { return x.Y.End() } -func (x *KeyValueExpr) End() token.Pos { return x.Value.End() } -func (x *ArrayType) End() token.Pos { return x.Elt.End() } -func (x *StructType) End() token.Pos { return x.Fields.End() } +func (x *StarExpr) End() token.Pos { return x.X.End() } +func (x *UnaryExpr) End() token.Pos { return x.X.End() } +func (x *BinaryExpr) End() token.Pos { return x.Y.End() } +func (x *KeyValueExpr) End() token.Pos { return x.Value.End() } +func (x *ArrayType) End() token.Pos { return x.Elt.End() } +func (x *StructType) End() token.Pos { return x.Fields.End() } func (x *FuncType) End() token.Pos { if x.Results != nil { return x.Results.End() @@ -570,10 +562,10 @@ func (*CompositeLit) exprNode() {} func (*ParenExpr) exprNode() {} func (*SelectorExpr) exprNode() {} func (*IndexExpr) exprNode() {} +func (*MultiIndexExpr) exprNode() {} func (*SliceExpr) exprNode() {} func (*TypeAssertExpr) exprNode() {} func (*CallExpr) exprNode() {} -func (*ListExpr) exprNode() {} func (*StarExpr) exprNode() {} func (*UnaryExpr) exprNode() {} func (*BinaryExpr) exprNode() {} diff --git a/src/go/ast/walk.go b/src/go/ast/walk.go index 02fef5901dd..c8abc409728 100644 --- a/src/go/ast/walk.go +++ b/src/go/ast/walk.go @@ -116,6 +116,12 @@ func Walk(v Visitor, node Node) { Walk(v, n.X) Walk(v, n.Index) + case *MultiIndexExpr: + Walk(v, n.X) + for _, index := range n.Indices { + Walk(v, index) + } + case *SliceExpr: Walk(v, n.X) if n.Low != nil { @@ -138,11 +144,6 @@ func Walk(v Visitor, node Node) { Walk(v, n.Fun) walkExprList(v, n.Args) - case *ListExpr: - for _, elem := range n.ElemList { - Walk(v, elem) - } - case *StarExpr: Walk(v, n.X) diff --git a/src/go/internal/typeparams/typeparams.go b/src/go/internal/typeparams/typeparams.go index b4251bda7e3..e102b77ef84 100644 --- a/src/go/internal/typeparams/typeparams.go +++ b/src/go/internal/typeparams/typeparams.go @@ -7,42 +7,56 @@ package typeparams import ( "fmt" "go/ast" + "go/token" ) const Enabled = true -func PackExpr(list []ast.Expr) ast.Expr { - switch len(list) { +func PackIndexExpr(x ast.Expr, lbrack token.Pos, exprs []ast.Expr, rbrack token.Pos) ast.Expr { + switch len(exprs) { case 0: - // Return an empty ListExpr here, rather than nil, as IndexExpr.Index must - // never be nil. - // TODO(rFindley) would a BadExpr be more appropriate here? - return &ast.ListExpr{} + panic("internal error: PackIndexExpr with empty expr slice") case 1: - return list[0] + return &ast.IndexExpr{ + X: x, + Lbrack: lbrack, + Index: exprs[0], + Rbrack: rbrack, + } default: - return &ast.ListExpr{ElemList: list} + return &ast.MultiIndexExpr{ + X: x, + Lbrack: lbrack, + Indices: exprs, + Rbrack: rbrack, + } } } -// TODO(gri) Should find a more efficient solution that doesn't -// require introduction of a new slice for simple -// expressions. -func UnpackExpr(x ast.Expr) []ast.Expr { - if x, _ := x.(*ast.ListExpr); x != nil { - return x.ElemList - } - if x != nil { - return []ast.Expr{x} +// IndexExpr wraps an ast.IndexExpr or ast.MultiIndexExpr into the +// MultiIndexExpr interface. +// +// Orig holds the original ast.Expr from which this IndexExpr was derived. +type IndexExpr struct { + Orig ast.Expr // the wrapped expr, which may be distinct from MultiIndexExpr below. + *ast.MultiIndexExpr +} + +func UnpackIndexExpr(n ast.Node) *IndexExpr { + switch e := n.(type) { + case *ast.IndexExpr: + return &IndexExpr{e, &ast.MultiIndexExpr{ + X: e.X, + Lbrack: e.Lbrack, + Indices: []ast.Expr{e.Index}, + Rbrack: e.Rbrack, + }} + case *ast.MultiIndexExpr: + return &IndexExpr{e, e} } return nil } -func IsListExpr(n ast.Node) bool { - _, ok := n.(*ast.ListExpr) - return ok -} - func Get(n ast.Node) *ast.FieldList { switch n := n.(type) { case *ast.TypeSpec: diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go index c0a3cc66fed..d1082591710 100644 --- a/src/go/parser/parser.go +++ b/src/go/parser/parser.go @@ -600,7 +600,7 @@ func (p *parser) parseArrayFieldOrTypeInstance(x *ast.Ident) (*ast.Ident, ast.Ex } // x[P], x[P1, P2], ... - return nil, &ast.IndexExpr{X: x, Lbrack: lbrack, Index: typeparams.PackExpr(args), Rbrack: rbrack} + return nil, typeparams.PackIndexExpr(x, lbrack, args, rbrack) } func (p *parser) parseFieldDecl() *ast.Field { @@ -991,7 +991,7 @@ func (p *parser) parseMethodSpec() *ast.Field { p.exprLev-- } rbrack := p.expectClosing(token.RBRACK, "type argument list") - typ = &ast.IndexExpr{X: ident, Lbrack: lbrack, Index: typeparams.PackExpr(list), Rbrack: rbrack} + typ = typeparams.PackIndexExpr(ident, lbrack, list, rbrack) } case p.tok == token.LPAREN: // ordinary method @@ -1178,7 +1178,6 @@ func (p *parser) parseTypeInstance(typ ast.Expr) ast.Expr { } opening := p.expect(token.LBRACK) - p.exprLev++ var list []ast.Expr for p.tok != token.RBRACK && p.tok != token.EOF { @@ -1192,7 +1191,17 @@ func (p *parser) parseTypeInstance(typ ast.Expr) ast.Expr { closing := p.expectClosing(token.RBRACK, "type argument list") - return &ast.IndexExpr{X: typ, Lbrack: opening, Index: typeparams.PackExpr(list), Rbrack: closing} + if len(list) == 0 { + p.errorExpected(closing, "type argument list") + return &ast.IndexExpr{ + X: typ, + Lbrack: opening, + Index: &ast.BadExpr{From: opening + 1, To: closing}, + Rbrack: closing, + } + } + + return typeparams.PackIndexExpr(typ, opening, list, closing) } func (p *parser) tryIdentOrType() ast.Expr { @@ -1455,7 +1464,7 @@ func (p *parser) parseIndexOrSliceOrInstance(x ast.Expr) ast.Expr { } // instance expression - return &ast.IndexExpr{X: x, Lbrack: lbrack, Index: typeparams.PackExpr(args), Rbrack: rbrack} + return typeparams.PackIndexExpr(x, lbrack, args, rbrack) } func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr { @@ -1557,6 +1566,7 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr { panic("unreachable") case *ast.SelectorExpr: case *ast.IndexExpr: + case *ast.MultiIndexExpr: case *ast.SliceExpr: case *ast.TypeAssertExpr: // If t.Type == nil we have a type assertion of the form @@ -1646,7 +1656,7 @@ func (p *parser) parsePrimaryExpr() (x ast.Expr) { return } // x is possibly a composite literal type - case *ast.IndexExpr: + case *ast.IndexExpr, *ast.MultiIndexExpr: if p.exprLev < 0 { return } diff --git a/src/go/printer/nodes.go b/src/go/printer/nodes.go index 913281ea6c1..239fcbde1c8 100644 --- a/src/go/printer/nodes.go +++ b/src/go/printer/nodes.go @@ -871,17 +871,15 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) { // TODO(gri): should treat[] like parentheses and undo one level of depth p.expr1(x.X, token.HighestPrec, 1) p.print(x.Lbrack, token.LBRACK) - // Note: we're a bit defensive here to handle the case of a ListExpr of - // length 1. - if list := typeparams.UnpackExpr(x.Index); len(list) > 0 { - if len(list) > 1 { - p.exprList(x.Lbrack, list, depth+1, commaTerm, x.Rbrack, false) - } else { - p.expr0(list[0], depth+1) - } - } else { - p.expr0(x.Index, depth+1) - } + p.expr0(x.Index, depth+1) + p.print(x.Rbrack, token.RBRACK) + + case *ast.MultiIndexExpr: + // TODO(gri): as for IndexExpr, should treat [] like parentheses and undo + // one level of depth + p.expr1(x.X, token.HighestPrec, 1) + p.print(x.Lbrack, token.LBRACK) + p.exprList(x.Lbrack, x.Indices, depth+1, commaTerm, x.Rbrack, false) p.print(x.Rbrack, token.RBRACK) case *ast.SliceExpr: diff --git a/src/go/types/call.go b/src/go/types/call.go index 039c7bbaf59..337ee741c66 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -16,23 +16,22 @@ import ( // funcInst type-checks a function instantiation inst and returns the result in x. // The operand x must be the evaluation of inst.X and its type must be a signature. -func (check *Checker) funcInst(x *operand, inst *ast.IndexExpr) { - xlist := typeparams.UnpackExpr(inst.Index) - targs := check.typeList(xlist) +func (check *Checker) funcInst(x *operand, ix *typeparams.IndexExpr) { + targs := check.typeList(ix.Indices) if targs == nil { x.mode = invalid - x.expr = inst + x.expr = ix.Orig return } - assert(len(targs) == len(xlist)) + assert(len(targs) == len(ix.Indices)) // check number of type arguments (got) vs number of type parameters (want) sig := x.typ.(*Signature) got, want := len(targs), len(sig.tparams) if got > want { - check.errorf(xlist[got-1], _Todo, "got %d type arguments but want %d", got, want) + check.errorf(ix.Indices[got-1], _Todo, "got %d type arguments but want %d", got, want) x.mode = invalid - x.expr = inst + x.expr = ix.Orig return } @@ -40,11 +39,11 @@ func (check *Checker) funcInst(x *operand, inst *ast.IndexExpr) { inferred := false if got < want { - targs = check.infer(inst, sig.tparams, targs, nil, nil, true) + targs = check.infer(ix.Orig, sig.tparams, targs, nil, nil, true) if targs == nil { // error was already reported x.mode = invalid - x.expr = inst + x.expr = ix.Orig return } got = len(targs) @@ -55,8 +54,8 @@ func (check *Checker) funcInst(x *operand, inst *ast.IndexExpr) { // determine argument positions (for error reporting) // TODO(rFindley) use a positioner here? instantiate would need to be // updated accordingly. - poslist := make([]token.Pos, len(xlist)) - for i, x := range xlist { + poslist := make([]token.Pos, len(ix.Indices)) + for i, x := range ix.Indices { poslist[i] = x.Pos() } @@ -64,25 +63,27 @@ func (check *Checker) funcInst(x *operand, inst *ast.IndexExpr) { res := check.instantiate(x.Pos(), sig, targs, poslist).(*Signature) assert(res.tparams == nil) // signature is not generic anymore if inferred { - check.recordInferred(inst, targs, res) + check.recordInferred(ix.Orig, targs, res) } x.typ = res x.mode = value - x.expr = inst + x.expr = ix.Orig } func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind { - var inst *ast.IndexExpr - if iexpr, _ := call.Fun.(*ast.IndexExpr); iexpr != nil { - if check.indexExpr(x, iexpr) { + ix := typeparams.UnpackIndexExpr(call.Fun) + if ix != nil { + if check.indexExpr(x, ix) { // Delay function instantiation to argument checking, // where we combine type and value arguments for type // inference. assert(x.mode == value) - inst = iexpr + } else { + ix = nil } - x.expr = iexpr + x.expr = call.Fun check.record(x) + } else { check.exprOrType(x, call.Fun) } @@ -149,21 +150,20 @@ func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind { // evaluate type arguments, if any var targs []Type - if inst != nil { - xlist := typeparams.UnpackExpr(inst.Index) - targs = check.typeList(xlist) + if ix != nil { + targs = check.typeList(ix.Indices) if targs == nil { check.use(call.Args...) x.mode = invalid x.expr = call return statement } - assert(len(targs) == len(xlist)) + assert(len(targs) == len(ix.Indices)) // check number of type arguments (got) vs number of type parameters (want) got, want := len(targs), len(sig.tparams) if got > want { - check.errorf(xlist[want], _Todo, "got %d type arguments but want %d", got, want) + check.errorf(ix.Indices[want], _Todo, "got %d type arguments but want %d", got, want) check.use(call.Args...) x.mode = invalid x.expr = call diff --git a/src/go/types/expr.go b/src/go/types/expr.go index 402d96f66a4..95f2a8d6ab5 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -1331,9 +1331,10 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind { case *ast.SelectorExpr: check.selector(x, e) - case *ast.IndexExpr: - if check.indexExpr(x, e) { - check.funcInst(x, e) + case *ast.IndexExpr, *ast.MultiIndexExpr: + ix := typeparams.UnpackIndexExpr(e) + if check.indexExpr(x, ix) { + check.funcInst(x, ix) } if x.mode == invalid { goto Error @@ -1423,12 +1424,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind { // types, which are comparatively rare. default: - if typeparams.IsListExpr(e) { - // catch-all for unexpected expression lists - check.errorf(e, _Todo, "unexpected list of expressions") - } else { - panic(fmt.Sprintf("%s: unknown expression type %T", check.fset.Position(e.Pos()), e)) - } + panic(fmt.Sprintf("%s: unknown expression type %T", check.fset.Position(e.Pos()), e)) } // everything went well diff --git a/src/go/types/exprstring.go b/src/go/types/exprstring.go index f05e6424d44..aee8a5ba5f7 100644 --- a/src/go/types/exprstring.go +++ b/src/go/types/exprstring.go @@ -67,11 +67,11 @@ func WriteExpr(buf *bytes.Buffer, x ast.Expr) { buf.WriteByte('.') buf.WriteString(x.Sel.Name) - case *ast.IndexExpr: - WriteExpr(buf, x.X) + case *ast.IndexExpr, *ast.MultiIndexExpr: + ix := typeparams.UnpackIndexExpr(x) + WriteExpr(buf, ix.X) buf.WriteByte('[') - exprs := typeparams.UnpackExpr(x.Index) - for i, e := range exprs { + for i, e := range ix.Indices { if i > 0 { buf.WriteString(", ") } diff --git a/src/go/types/index.go b/src/go/types/index.go index 5bc1d0af8da..7c7aa382ff8 100644 --- a/src/go/types/index.go +++ b/src/go/types/index.go @@ -15,18 +15,18 @@ import ( // If e is a valid function instantiation, indexExpr returns true. // In that case x represents the uninstantiated function value and // it is the caller's responsibility to instantiate the function. -func (check *Checker) indexExpr(x *operand, e *ast.IndexExpr) (isFuncInst bool) { - check.exprOrType(x, e.X) +func (check *Checker) indexExpr(x *operand, expr *typeparams.IndexExpr) (isFuncInst bool) { + check.exprOrType(x, expr.X) switch x.mode { case invalid: - check.use(typeparams.UnpackExpr(e.Index)...) + check.use(expr.Indices...) return false case typexpr: // type instantiation x.mode = invalid - x.typ = check.varType(e) + x.typ = check.varType(expr.Orig) if x.typ != Typ[Invalid] { x.mode = typexpr } @@ -77,7 +77,7 @@ func (check *Checker) indexExpr(x *operand, e *ast.IndexExpr) (isFuncInst bool) x.typ = typ.elem case *Map: - index := check.singleIndex(e) + index := check.singleIndex(expr) if index == nil { x.mode = invalid return @@ -88,7 +88,7 @@ func (check *Checker) indexExpr(x *operand, e *ast.IndexExpr) (isFuncInst bool) // ok to continue even if indexing failed - map element type is known x.mode = mapindex x.typ = typ.elem - x.expr = e + x.expr = expr.Orig return case *Union: @@ -137,7 +137,7 @@ func (check *Checker) indexExpr(x *operand, e *ast.IndexExpr) (isFuncInst bool) // If there are maps, the index expression must be assignable // to the map key type (as for simple map index expressions). if nmaps > 0 { - index := check.singleIndex(e) + index := check.singleIndex(expr) if index == nil { x.mode = invalid return @@ -151,7 +151,7 @@ func (check *Checker) indexExpr(x *operand, e *ast.IndexExpr) (isFuncInst bool) if nmaps == typ.NumTerms() { x.mode = mapindex x.typ = telem - x.expr = e + x.expr = expr.Orig return } @@ -180,7 +180,7 @@ func (check *Checker) indexExpr(x *operand, e *ast.IndexExpr) (isFuncInst bool) return } - index := check.singleIndex(e) + index := check.singleIndex(expr) if index == nil { x.mode = invalid return @@ -311,23 +311,16 @@ L: // singleIndex returns the (single) index from the index expression e. // If the index is missing, or if there are multiple indices, an error // is reported and the result is nil. -func (check *Checker) singleIndex(e *ast.IndexExpr) ast.Expr { - index := e.Index - if index == nil { - check.invalidAST(e, "missing index for %s", e) +func (check *Checker) singleIndex(expr *typeparams.IndexExpr) ast.Expr { + if len(expr.Indices) == 0 { + check.invalidAST(expr.Orig, "index expression %v with 0 indices", expr) return nil } - - indexes := typeparams.UnpackExpr(index) - if len(indexes) == 0 { - check.invalidAST(index, "index expression %v with 0 indices", index) - return nil - } - if len(indexes) > 1 { + if len(expr.Indices) > 1 { // TODO(rFindley) should this get a distinct error code? - check.invalidOp(indexes[1], _InvalidIndex, "more than one index") + check.invalidOp(expr.Indices[1], _InvalidIndex, "more than one index") } - return indexes[0] + return expr.Indices[0] } // index checks an index expression for validity. diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go index 4892218b754..1434e6deb11 100644 --- a/src/go/types/resolver.go +++ b/src/go/types/resolver.go @@ -499,10 +499,12 @@ L: // unpack receiver type } // unpack type parameters, if any - if ptyp, _ := rtyp.(*ast.IndexExpr); ptyp != nil { - rtyp = ptyp.X + switch rtyp.(type) { + case *ast.IndexExpr, *ast.MultiIndexExpr: + ix := typeparams.UnpackIndexExpr(rtyp) + rtyp = ix.X if unpackParams { - for _, arg := range typeparams.UnpackExpr(ptyp.Index) { + for _, arg := range ix.Indices { var par *ast.Ident switch arg := arg.(type) { case *ast.Ident: @@ -510,7 +512,7 @@ L: // unpack receiver type case *ast.BadExpr: // ignore - error already reported by parser case nil: - check.invalidAST(ptyp, "parameterized receiver contains nil parameters") + check.invalidAST(ix.Orig, "parameterized receiver contains nil parameters") default: check.errorf(arg, _Todo, "receiver type parameter %s must be an identifier", arg) } diff --git a/src/go/types/signature.go b/src/go/types/signature.go index 5489b493baa..f56fe047c84 100644 --- a/src/go/types/signature.go +++ b/src/go/types/signature.go @@ -244,24 +244,21 @@ func isubst(x ast.Expr, smap map[*ast.Ident]*ast.Ident) ast.Expr { new.X = X return &new } - case *ast.IndexExpr: - elems := typeparams.UnpackExpr(n.Index) - var newElems []ast.Expr - for i, elem := range elems { - new := isubst(elem, smap) - if new != elem { - if newElems == nil { - newElems = make([]ast.Expr, len(elems)) - copy(newElems, elems) + case *ast.IndexExpr, *ast.MultiIndexExpr: + ix := typeparams.UnpackIndexExpr(x) + var newIndexes []ast.Expr + for i, index := range ix.Indices { + new := isubst(index, smap) + if new != index { + if newIndexes == nil { + newIndexes = make([]ast.Expr, len(ix.Indices)) + copy(newIndexes, ix.Indices) } - newElems[i] = new + newIndexes[i] = new } } - if newElems != nil { - index := typeparams.PackExpr(newElems) - new := *n - new.Index = index - return &new + if newIndexes != nil { + return typeparams.PackIndexExpr(ix.X, ix.Lbrack, newIndexes, ix.Rbrack) } case *ast.ParenExpr: return isubst(n.X, smap) // no need to keep parentheses diff --git a/src/go/types/testdata/check/typeinst.go2 b/src/go/types/testdata/check/typeinst.go2 index 3184a4b5b1c..069bd3bc169 100644 --- a/src/go/types/testdata/check/typeinst.go2 +++ b/src/go/types/testdata/check/typeinst.go2 @@ -33,11 +33,11 @@ var _ A3 var x int type _ x /* ERROR not a type */ [int] -type _ int /* ERROR not a generic type */ [] -type _ myInt /* ERROR not a generic type */ [] +type _ int /* ERROR not a generic type */ [] // ERROR expected type argument list +type _ myInt /* ERROR not a generic type */ [] // ERROR expected type argument list // TODO(gri) better error messages -type _ T1 /* ERROR got 0 arguments but 1 type parameters */ [] +type _ T1[] // ERROR expected type argument list type _ T1[x /* ERROR not a type */ ] type _ T1 /* ERROR got 2 arguments but 1 type parameters */ [int, float32] diff --git a/src/go/types/testdata/fixedbugs/issue45635.go2 b/src/go/types/testdata/fixedbugs/issue45635.go2 index 0f629803434..c6784e12fda 100644 --- a/src/go/types/testdata/fixedbugs/issue45635.go2 +++ b/src/go/types/testdata/fixedbugs/issue45635.go2 @@ -10,7 +10,7 @@ func main() { type N[T any] struct{} -var _ N /* ERROR "0 arguments but 1 type parameters" */ [] +var _ N [] // ERROR expected type argument list type I interface { ~map[int]int | ~[]int diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index e6be7b72e46..f62b41831e2 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -261,13 +261,13 @@ func (check *Checker) typInternal(e0 ast.Expr, def *Named) (T Type) { check.errorf(&x, _NotAType, "%s is not a type", &x) } - case *ast.IndexExpr: + case *ast.IndexExpr, *ast.MultiIndexExpr: + ix := typeparams.UnpackIndexExpr(e) if typeparams.Enabled { - exprs := typeparams.UnpackExpr(e.Index) - return check.instantiatedType(e.X, exprs, def) + return check.instantiatedType(ix, def) } check.errorf(e0, _NotAType, "%s is not a type", e0) - check.use(e.X) + check.use(ix.X) case *ast.ParenExpr: // Generic types must be instantiated before they can be used in any form. @@ -403,8 +403,8 @@ func (check *Checker) typeOrNil(e ast.Expr) Type { return Typ[Invalid] } -func (check *Checker) instantiatedType(x ast.Expr, targs []ast.Expr, def *Named) Type { - b := check.genericType(x, true) // TODO(gri) what about cycles? +func (check *Checker) instantiatedType(ix *typeparams.IndexExpr, def *Named) Type { + b := check.genericType(ix.X, true) // TODO(gri) what about cycles? if b == Typ[Invalid] { return b // error already reported } @@ -420,19 +420,19 @@ func (check *Checker) instantiatedType(x ast.Expr, targs []ast.Expr, def *Named) def.setUnderlying(typ) typ.check = check - typ.pos = x.Pos() + typ.pos = ix.X.Pos() typ.base = base // evaluate arguments (always) - typ.targs = check.typeList(targs) + typ.targs = check.typeList(ix.Indices) if typ.targs == nil { def.setUnderlying(Typ[Invalid]) // avoid later errors due to lazy instantiation return Typ[Invalid] } // determine argument positions (for error reporting) - typ.poslist = make([]token.Pos, len(targs)) - for i, arg := range targs { + typ.poslist = make([]token.Pos, len(ix.Indices)) + for i, arg := range ix.Indices { typ.poslist[i] = arg.Pos() } From aa4e0f528e1e018e2847decb549cfc5ac07ecf20 Mon Sep 17 00:00:00 2001 From: shota3506 Date: Tue, 13 Jul 2021 21:27:05 +0000 Subject: [PATCH 690/940] net/http: correct capitalization in cancelTimeBody comment Change-Id: I7acda22c01c5350ebf5ddabb1c12af96d368de5d GitHub-Last-Rev: 3e5c022f8764d4abf91c964ceb4fc0e01ebd1352 GitHub-Pull-Request: golang/go#47160 Reviewed-on: https://go-review.googlesource.com/c/go/+/334229 Reviewed-by: Ian Lance Taylor Trust: Cherry Mui Run-TryBot: Ian Lance Taylor --- src/net/http/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net/http/client.go b/src/net/http/client.go index e0cabc9d4cf..4d380c65db9 100644 --- a/src/net/http/client.go +++ b/src/net/http/client.go @@ -951,7 +951,7 @@ func (c *Client) CloseIdleConnections() { } // cancelTimerBody is an io.ReadCloser that wraps rc with two features: -// 1) on Read error or close, the stop func is called. +// 1) On Read error or close, the stop func is called. // 2) On Read failure, if reqDidTimeout is true, the error is wrapped and // marked as net.Error that hit its timeout. type cancelTimerBody struct { From 3d8453e00e3d0a6f23cec06bcad08cf740ec5940 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 15 Jul 2021 16:42:25 -0700 Subject: [PATCH 691/940] [dev.typeparams] cmd/compile/internal/types2: more consistent handling of predeclared "any" Rather than removing "any" from the universe scope, keep it predeclared but provide a better error message. While at it, remove some unnecessary type assertions. Change-Id: I10603274282ea6afc107f703ab194f32bd334dd1 Reviewed-on: https://go-review.googlesource.com/c/go/+/334911 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/decl.go | 5 ++-- .../compile/internal/types2/object_test.go | 2 +- .../types2/testdata/check/typeparams.go2 | 8 +++--- src/cmd/compile/internal/types2/typexpr.go | 13 +++++++++- src/cmd/compile/internal/types2/universe.go | 26 +++++++------------ test/fixedbugs/issue14652.go | 2 +- test/typeparam/tparam1.go | 4 +-- 7 files changed, 33 insertions(+), 27 deletions(-) diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go index 9fb9815f4db..4f656e374af 100644 --- a/src/cmd/compile/internal/types2/decl.go +++ b/src/cmd/compile/internal/types2/decl.go @@ -617,8 +617,9 @@ func (check *Checker) declareTypeParam(index int, name *syntax.Name) *TypeName { // The type must be an interface, including the predeclared type "any". func (check *Checker) boundType(e syntax.Expr) Type { // The predeclared identifier "any" is visible only as a type bound in a type parameter list. - if name, _ := unparen(e).(*syntax.Name); name != nil && name.Value == "any" && check.lookup("any") == nil { - return universeAny + // If we allow "any" for general use, this if-statement can be removed (issue #33232). + if name, _ := unparen(e).(*syntax.Name); name != nil && name.Value == "any" && check.lookup("any") == universeAny { + return universeAny.Type() } bound := check.typ(e) diff --git a/src/cmd/compile/internal/types2/object_test.go b/src/cmd/compile/internal/types2/object_test.go index 7f63c793325..a86733a5c99 100644 --- a/src/cmd/compile/internal/types2/object_test.go +++ b/src/cmd/compile/internal/types2/object_test.go @@ -25,7 +25,7 @@ func TestIsAlias(t *testing.T) { check(Unsafe.Scope().Lookup("Pointer").(*TypeName), false) for _, name := range Universe.Names() { if obj, _ := Universe.Lookup(name).(*TypeName); obj != nil { - check(obj, name == "byte" || name == "rune") + check(obj, name == "any" || name == "byte" || name == "rune") } } diff --git a/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 b/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 index 8a7f6eb2c25..2755a539e52 100644 --- a/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 @@ -6,11 +6,11 @@ package p // import "io" // for type assertion tests -// The predeclared identifier "any" is only visible as a constraint +// The predeclared identifier "any" can only be used as a constraint // in a type parameter list. -var _ any // ERROR undeclared -func _[_ any /* ok here */ , _ interface{any /* ERROR undeclared */ }](any /* ERROR undeclared */ ) { - var _ any /* ERROR undeclared */ +var _ any // ERROR cannot use any outside constraint position +func _[_ any /* ok here */ , _ interface{any /* ERROR constraint */ }](any /* ERROR constraint */ ) { + var _ any /* ERROR constraint */ } func identity[T any](x T) T { return x } diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index a14d498cec0..83cefa19bae 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -25,7 +25,8 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *Named, wantType boo // Note that we cannot use check.lookup here because the returned scope // may be different from obj.Parent(). See also Scope.LookupParent doc. scope, obj := check.scope.LookupParent(e.Value, check.pos) - if obj == nil || obj == universeComparable && !check.allowVersion(check.pkg, 1, 18) { + switch obj { + case nil: if e.Value == "_" { check.error(e, "cannot use _ as value or type") } else { @@ -36,6 +37,16 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *Named, wantType boo } } return + case universeAny, universeComparable: + if !check.allowVersion(check.pkg, 1, 18) { + check.errorf(e, "undeclared name: %s (requires version go1.18 or later)", e.Value) + return + } + // If we allow "any" for general use, this if-statement can be removed (issue #33232). + if obj == universeAny { + check.error(e, "cannot use any outside constraint position") + return + } } check.recordUse(e, obj) diff --git a/src/cmd/compile/internal/types2/universe.go b/src/cmd/compile/internal/types2/universe.go index d328b13a8e1..e2dd0df69e8 100644 --- a/src/cmd/compile/internal/types2/universe.go +++ b/src/cmd/compile/internal/types2/universe.go @@ -20,11 +20,11 @@ var Universe *Scope var Unsafe *Package var ( - universeIota *Const - universeByte *Basic // uint8 alias, but has name "byte" - universeRune *Basic // int32 alias, but has name "rune" - universeAny *Interface - universeError *Named + universeIota Object + universeByte Type // uint8 alias, but has name "byte" + universeRune Type // int32 alias, but has name "rune" + universeAny Object + universeError Type universeComparable Object ) @@ -79,9 +79,6 @@ func defPredeclaredTypes() { } // type any = interface{} - // Entered into universe scope so we do all the usual checks; - // but removed again from scope later since it's only visible - // as constraint in a type parameter list. def(NewTypeName(nopos, nil, "any", &emptyInterface)) // type error interface{ Error() string } @@ -224,15 +221,12 @@ func init() { defPredeclaredNil() defPredeclaredFuncs() - universeIota = Universe.Lookup("iota").(*Const) - universeByte = Universe.Lookup("byte").(*TypeName).typ.(*Basic) - universeRune = Universe.Lookup("rune").(*TypeName).typ.(*Basic) - universeAny = Universe.Lookup("any").(*TypeName).typ.(*Interface) - universeError = Universe.Lookup("error").(*TypeName).typ.(*Named) + universeIota = Universe.Lookup("iota") + universeByte = Universe.Lookup("byte").Type() + universeRune = Universe.Lookup("rune").Type() + universeAny = Universe.Lookup("any") + universeError = Universe.Lookup("error").Type() universeComparable = Universe.Lookup("comparable") - - // "any" is only visible as constraint in a type parameter list - delete(Universe.elems, "any") } // Objects with names containing blanks are internal and not entered into diff --git a/test/fixedbugs/issue14652.go b/test/fixedbugs/issue14652.go index d53b4126683..14a223977b4 100644 --- a/test/fixedbugs/issue14652.go +++ b/test/fixedbugs/issue14652.go @@ -6,4 +6,4 @@ package p -var x any // ERROR "undefined: any|undefined type .*any.*" +var x any // ERROR "undefined: any|undefined type .*any.*|cannot use any outside constraint position" diff --git a/test/typeparam/tparam1.go b/test/typeparam/tparam1.go index 70439333269..2bcc4af3dba 100644 --- a/test/typeparam/tparam1.go +++ b/test/typeparam/tparam1.go @@ -10,8 +10,8 @@ package tparam1 // The predeclared identifier "any" is only visible as a constraint // in a type parameter list. -var _ any // ERROR "undefined" -func _(_ any) // ERROR "undefined" +var _ any // ERROR "cannot use any outside constraint position" +func _(_ any) // ERROR "cannot use any outside constraint position" type _[_ any /* ok here */ ] struct{} const N = 10 From ed9e109dc9a3523100d19e6f259edccbd7dd3cba Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Sun, 11 Jul 2021 13:06:54 -0700 Subject: [PATCH 692/940] [dev.typeparams] cmd/compile: fix small -G=3 issues for tests disabled in run.go - set correct position for closure capture variable in (*irgen).use() (issue20250.go) Also, evaluate rhs, lhs in that order in assignment statements to match noder1 (affects ordering of closure variables). - make sure to set Assign flag properly in (*irgen).forStmt() for range variables which are map accesses (issue9691.go) - make sure CheckSize() is call on the base type for top-level types converted by (*irgen).typ() that are pointer types (issue20174.go and issue37837.go) - deal with parentheses properly in validation function (*irgen).validate() (issue17270.go) - avoid HasNil call on type TTYPEPARAM - types2 typechecker will have already checked validity of the typeparam having nil value (new test issue39755.go) Change-Id: Ie68004d964698aea047e19e7dcd79b297e9d47ca Reviewed-on: https://go-review.googlesource.com/c/go/+/334733 Trust: Dan Scales Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/noder/object.go | 2 +- src/cmd/compile/internal/noder/stmt.go | 14 ++++++++-- src/cmd/compile/internal/noder/types.go | 5 ++++ src/cmd/compile/internal/noder/validate.go | 10 ++++++- src/cmd/compile/internal/typecheck/iexport.go | 4 ++- test/run.go | 7 +---- test/typeparam/issue39755.go | 27 +++++++++++++++++++ 7 files changed, 58 insertions(+), 11 deletions(-) create mode 100644 test/typeparam/issue39755.go diff --git a/src/cmd/compile/internal/noder/object.go b/src/cmd/compile/internal/noder/object.go index 581a3652ec2..40c0b9cf422 100644 --- a/src/cmd/compile/internal/noder/object.go +++ b/src/cmd/compile/internal/noder/object.go @@ -29,7 +29,7 @@ func (g *irgen) use(name *syntax.Name) *ir.Name { if !ok { base.FatalfAt(g.pos(name), "unknown name %v", name) } - obj := ir.CaptureName(g.pos(obj2), ir.CurFunc, g.obj(obj2)) + obj := ir.CaptureName(g.pos(name), ir.CurFunc, g.obj(obj2)) if obj.Defn != nil && obj.Defn.Op() == ir.ONAME { // If CaptureName created a closure variable, then transfer the // type of the captured name to the new closure variable. diff --git a/src/cmd/compile/internal/noder/stmt.go b/src/cmd/compile/internal/noder/stmt.go index 672a732187e..b7085c4776e 100644 --- a/src/cmd/compile/internal/noder/stmt.go +++ b/src/cmd/compile/internal/noder/stmt.go @@ -57,7 +57,10 @@ func (g *irgen) stmt(stmt syntax.Stmt) ir.Node { if stmt.Rhs == nil { n = IncDec(g.pos(stmt), op, g.expr(stmt.Lhs)) } else { - n = ir.NewAssignOpStmt(g.pos(stmt), op, g.expr(stmt.Lhs), g.expr(stmt.Rhs)) + // Eval rhs before lhs, for compatibility with noder1 + rhs := g.expr(stmt.Rhs) + lhs := g.expr(stmt.Lhs) + n = ir.NewAssignOpStmt(g.pos(stmt), op, lhs, rhs) } if n.X.Typecheck() == 3 { n.SetTypecheck(3) @@ -68,8 +71,9 @@ func (g *irgen) stmt(stmt syntax.Stmt) ir.Node { return n } - names, lhs := g.assignList(stmt.Lhs, stmt.Op == syntax.Def) + // Eval rhs before lhs, for compatibility with noder1 rhs := g.exprList(stmt.Rhs) + names, lhs := g.assignList(stmt.Lhs, stmt.Op == syntax.Def) // We must delay transforming the assign statement if any of the // lhs or rhs nodes are also delayed, since transformAssign needs @@ -262,6 +266,12 @@ func (g *irgen) forStmt(stmt *syntax.ForStmt) ir.Node { key, value := unpackTwo(lhs) n := ir.NewRangeStmt(g.pos(r), key, value, g.expr(r.X), g.blockStmt(stmt.Body)) n.Def = initDefn(n, names) + if key != nil { + transformCheckAssign(n, key) + } + if value != nil { + transformCheckAssign(n, value) + } return n } diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go index d925f991c87..c18ae3a1fc3 100644 --- a/src/cmd/compile/internal/noder/types.go +++ b/src/cmd/compile/internal/noder/types.go @@ -39,6 +39,11 @@ func (g *irgen) typ(typ types2.Type) *types.Type { // recursive types have been fully constructed before we call CheckSize. if res != nil && !res.IsUntyped() && !res.IsFuncArgStruct() && !res.HasTParam() { types.CheckSize(res) + if res.IsPtr() { + // Pointers always have their size set, even though their element + // may not have its size set. + types.CheckSize(res.Elem()) + } } return res } diff --git a/src/cmd/compile/internal/noder/validate.go b/src/cmd/compile/internal/noder/validate.go index b926222c89c..68a059b96f4 100644 --- a/src/cmd/compile/internal/noder/validate.go +++ b/src/cmd/compile/internal/noder/validate.go @@ -55,7 +55,15 @@ func (g *irgen) validate(n syntax.Node) { case *syntax.CallExpr: tv := g.info.Types[n.Fun] if tv.IsBuiltin() { - switch builtin := n.Fun.(type) { + fun := n.Fun + for { + builtin, ok := fun.(*syntax.ParenExpr) + if !ok { + break + } + fun = builtin.X + } + switch builtin := fun.(type) { case *syntax.Name: g.validateBuiltin(builtin.Value, n) case *syntax.SelectorExpr: diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index 4fbc48f17be..b054c73ad80 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -1636,7 +1636,9 @@ func (w *exportWriter) expr(n ir.Node) { // (somewhat closely following the structure of exprfmt in fmt.go) case ir.ONIL: n := n.(*ir.NilExpr) - if !n.Type().HasNil() { + // If n is a typeparam, it will have already been checked + // for proper use by the types2 typechecker. + if !n.Type().IsTypeParam() && !n.Type().HasNil() { base.Fatalf("unexpected type for nil: %v", n.Type()) } w.op(ir.ONIL) diff --git a/test/run.go b/test/run.go index 82d49270f26..3ccf1046ceb 100644 --- a/test/run.go +++ b/test/run.go @@ -2167,12 +2167,7 @@ var types2Failures32Bit = setOf( ) var g3Failures = setOf( - "writebarrier.go", // correct diagnostics, but different lines (probably irgen's fault) - "fixedbugs/issue17270.go", // ICE in irgen - "fixedbugs/issue20174.go", // ICE due to width not calculated (probably irgen's fault) - "fixedbugs/issue20250.go", // correct diagnostics, but different lines (probably irgen's fault) - "fixedbugs/issue37837.go", // ICE due to width not calculated - "fixedbugs/issue9691.go", // "cannot assign to int(.autotmp_4)" (probably irgen's fault) + "writebarrier.go", // correct diagnostics, but different lines (probably irgen's fault) "typeparam/nested.go", // -G=3 doesn't support function-local types with generics diff --git a/test/typeparam/issue39755.go b/test/typeparam/issue39755.go new file mode 100644 index 00000000000..13a575d16fb --- /dev/null +++ b/test/typeparam/issue39755.go @@ -0,0 +1,27 @@ +// compile -G=3 + +// Copyright 2020 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. + +// copied from cmd/compile/internal/types2/testdata/fixedbugs/issue39755.go + +package p + +func _[T interface{~map[string]int}](x T) { + _ = x == nil +} + +// simplified test case from issue + +type PathParamsConstraint interface { + ~map[string]string | ~[]struct{key, value string} +} + +type PathParams[T PathParamsConstraint] struct { + t T +} + +func (pp *PathParams[T]) IsNil() bool { + return pp.t == nil // this must succeed +} From 10c8b7c1d7bb973a0b2bc6858b4d5b705cdaa402 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 12 Jul 2021 16:12:55 -0700 Subject: [PATCH 693/940] [dev.typeparams] cmd/compile: use dictionary to convert arguments of ==, != to interfaces When comparing a value whose type is a type parameter to an interface, we need to convert that type parameter to an interface using the dictionary entries. Change-Id: I409c9e36e376fe4ef8163407d0fd4e84496d5b65 Reviewed-on: https://go-review.googlesource.com/c/go/+/334150 Trust: Keith Randall Trust: Dan Scales Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/noder/stencil.go | 15 +++++ test/typeparam/equal.go | 71 +++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 test/typeparam/equal.go diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 1759fbc4cfd..f4935fe22a4 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -1242,6 +1242,21 @@ func (subst *subster) node(n ir.Node) ir.Node { if ix := subst.findDictType(t); ix >= 0 { m = subst.convertUsingDictionary(x.Pos(), m.(*ir.ConvExpr).X, m.Type(), t, ix) } + case ir.OEQ, ir.ONE: + // Equality between a non-interface and an interface requires the non-interface + // to be promoted to an interface. + x := x.(*ir.BinaryExpr) + m := m.(*ir.BinaryExpr) + if i := x.Y.Type(); i.IsInterface() { + if ix := subst.findDictType(x.X.Type()); ix >= 0 { + m.X = subst.convertUsingDictionary(m.X.Pos(), m.X, i, x.X.Type(), ix) + } + } + if i := x.X.Type(); i.IsInterface() { + if ix := subst.findDictType(x.Y.Type()); ix >= 0 { + m.Y = subst.convertUsingDictionary(m.Y.Pos(), m.Y, i, x.X.Type(), ix) + } + } } return m } diff --git a/test/typeparam/equal.go b/test/typeparam/equal.go new file mode 100644 index 00000000000..6776b19d125 --- /dev/null +++ b/test/typeparam/equal.go @@ -0,0 +1,71 @@ +// run -gcflags=-G=3 + +// Copyright 2021 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. + +// comparisons of type parameters to interfaces + +package main + +func f[T comparable](t, u T) bool { + // Comparing two type parameters directly. + // (Not really testing comparisons to interfaces, but just 'cause we're here.) + return t == u +} + +func g[T comparable](t T, i interface{}) bool { + // Compare type parameter value to empty interface. + return t == i +} + +type I interface { + foo() +} + +type C interface { + comparable + I +} + +func h[T C](t T, i I) bool { + // Compare type parameter value to nonempty interface. + return t == i +} + +type myint int + +func (x myint) foo() { +} + +func k[T comparable](t T, i interface{}) bool { + // Compare derived type value to interface. + return struct{a, b T}{t, t} == i +} + +func main() { + assert(f(3, 3)) + assert(!f(3, 5)) + assert(g(3, 3)) + assert(!g(3, 5)) + assert(h(myint(3), myint(3))) + assert(!h(myint(3), myint(5))) + + type S struct { a, b float64 } + + assert(f(S{3,5}, S{3,5})) + assert(!f(S{3,5}, S{4,6})) + assert(g(S{3,5}, S{3,5})) + assert(!g(S{3,5}, S{4,6})) + + assert(k(3, struct{a, b int}{3, 3})) + assert(!k(3, struct{a, b int}{3, 4})) +} + +func assert(b bool) { + if !b { + panic("assertion failed") + } +} + + From b296e54618ea09b89154173a2bfb200203a731bf Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 15 Jul 2021 22:06:38 -0400 Subject: [PATCH 694/940] [dev.typeparams] go/types: port lazy import resolution from types2 This is a straightforward port of CL 323569 to go/types. It is line-for-line identical, except where names are unexported to preserve the current go/types API. Change-Id: I4c78211bff90f982ca2e90ed224946716118ee31 Reviewed-on: https://go-review.googlesource.com/c/go/+/334893 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/check.go | 2 +- src/go/types/decl.go | 7 +-- src/go/types/instantiate.go | 18 ++++++- src/go/types/labels.go | 3 +- src/go/types/lookup.go | 5 +- src/go/types/object.go | 8 ++++ src/go/types/predicates.go | 2 +- src/go/types/resolver.go | 19 +++++--- src/go/types/sanitize.go | 1 + src/go/types/scope.go | 93 +++++++++++++++++++++++++++++++++---- src/go/types/signature.go | 2 +- src/go/types/sizeof_test.go | 2 +- src/go/types/stmt.go | 3 +- src/go/types/subst.go | 12 ++--- src/go/types/type.go | 46 +++++++++++++++--- src/go/types/typestring.go | 4 +- src/go/types/typexpr.go | 2 +- 17 files changed, 186 insertions(+), 43 deletions(-) diff --git a/src/go/types/check.go b/src/go/types/check.go index aea319f4635..3e534de08a6 100644 --- a/src/go/types/check.go +++ b/src/go/types/check.go @@ -73,7 +73,7 @@ type importKey struct { // A dotImportKey describes a dot-imported object in the given scope. type dotImportKey struct { scope *Scope - obj Object + name string } // A Checker maintains the state of the type checker. diff --git a/src/go/types/decl.go b/src/go/types/decl.go index 12ee51b9201..761418c4fb9 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -576,7 +576,7 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) { // is detected, the result is Typ[Invalid]. If a cycle is detected and // n0.check != nil, the cycle is reported. func (n0 *Named) under() Type { - u := n0.underlying + u := n0.Underlying() if u == Typ[Invalid] { return u @@ -614,7 +614,7 @@ func (n0 *Named) under() Type { seen := map[*Named]int{n0: 0} path := []Object{n0.obj} for { - u = n.underlying + u = n.Underlying() if u == nil { u = Typ[Invalid] break @@ -814,7 +814,7 @@ func (check *Checker) collectMethods(obj *TypeName) { // and field names must be distinct." base := asNamed(obj.typ) // shouldn't fail but be conservative if base != nil { - if t, _ := base.underlying.(*Struct); t != nil { + if t, _ := base.Underlying().(*Struct); t != nil { for _, fld := range t.fields { if fld.name != "_" { assert(mset.insert(fld) == nil) @@ -850,6 +850,7 @@ func (check *Checker) collectMethods(obj *TypeName) { } if base != nil { + base.expand() // TODO(mdempsky): Probably unnecessary. base.methods = append(base.methods, m) } } diff --git a/src/go/types/instantiate.go b/src/go/types/instantiate.go index 6f8c4983f4a..1c15ac199ce 100644 --- a/src/go/types/instantiate.go +++ b/src/go/types/instantiate.go @@ -23,7 +23,7 @@ func Instantiate(pos token.Pos, typ Type, targs []Type) (res Type) { var tparams []*TypeName switch t := typ.(type) { case *Named: - tparams = t.tparams + tparams = t.TParams() case *Signature: tparams = t.tparams defer func() { @@ -61,3 +61,19 @@ func Instantiate(pos token.Pos, typ Type, targs []Type) (res Type) { smap := makeSubstMap(tparams, targs) return (*Checker)(nil).subst(pos, typ, smap) } + +// InstantiateLazy is like Instantiate, but avoids actually +// instantiating the type until needed. +func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type) (res Type) { + base := asNamed(typ) + if base == nil { + panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) + } + + return &instance{ + check: check, + pos: pos, + base: base, + targs: targs, + } +} diff --git a/src/go/types/labels.go b/src/go/types/labels.go index 8cf6e63645e..f3b7f211f37 100644 --- a/src/go/types/labels.go +++ b/src/go/types/labels.go @@ -36,7 +36,8 @@ func (check *Checker) labels(body *ast.BlockStmt) { } // spec: "It is illegal to define a label that is never used." - for _, obj := range all.elems { + for name, obj := range all.elems { + obj = resolve(name, obj) if lbl := obj.(*Label); !lbl.used { check.softErrorf(lbl, _UnusedLabel, "label %s declared but not used", lbl.name) } diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go index 3e89b6cc2b5..5b22c4744e4 100644 --- a/src/go/types/lookup.go +++ b/src/go/types/lookup.go @@ -56,7 +56,7 @@ func (check *Checker) lookupFieldOrMethod(T Type, addressable bool, pkg *Package // pointer type but discard the result if it is a method since we would // not have found it for T (see also issue 8590). if t := asNamed(T); t != nil { - if p, _ := t.underlying.(*Pointer); p != nil { + if p, _ := t.Underlying().(*Pointer); p != nil { obj, index, indirect = check.rawLookupFieldOrMethod(p, false, pkg, name) if _, ok := obj.(*Func); ok { return nil, nil, false @@ -128,6 +128,7 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack seen[named] = true // look for a matching attached method + named.expand() if i, m := lookupMethod(named.methods, pkg, name); m != nil { // potential match // caution: method may not have a proper signature yet @@ -400,7 +401,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // In order to compare the signatures, substitute the receiver // type parameters of ftyp with V's instantiation type arguments. // This lazily instantiates the signature of method f. - if Vn != nil && len(Vn.tparams) > 0 { + if Vn != nil && len(Vn.TParams()) > 0 { // Be careful: The number of type arguments may not match // the number of receiver parameters. If so, an error was // reported earlier but the length discrepancy is still diff --git a/src/go/types/object.go b/src/go/types/object.go index 50346ec6919..7913008814c 100644 --- a/src/go/types/object.go +++ b/src/go/types/object.go @@ -230,6 +230,14 @@ func NewTypeName(pos token.Pos, pkg *Package, name string, typ Type) *TypeName { return &TypeName{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}} } +// _NewTypeNameLazy returns a new defined type like NewTypeName, but it +// lazily calls resolve to finish constructing the Named object. +func _NewTypeNameLazy(pos token.Pos, pkg *Package, name string, resolve func(named *Named) (tparams []*TypeName, underlying Type, methods []*Func)) *TypeName { + obj := NewTypeName(pos, pkg, name, nil) + NewNamed(obj, nil, nil).resolve = resolve + return obj +} + // IsAlias reports whether obj is an alias name for a type. func (obj *TypeName) IsAlias() bool { switch t := obj.typ.(type) { diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index 6aa58259431..9f3e3245978 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -25,7 +25,7 @@ func isNamed(typ Type) bool { func isGeneric(typ Type) bool { // A parameterized type is only instantiated if it doesn't have an instantiation already. named, _ := typ.(*Named) - return named != nil && named.obj != nil && named.tparams != nil && named.targs == nil + return named != nil && named.obj != nil && named.TParams() != nil && named.targs == nil } func is(typ Type, what BasicInfo) bool { diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go index 1434e6deb11..5e58c3dcfd5 100644 --- a/src/go/types/resolver.go +++ b/src/go/types/resolver.go @@ -309,20 +309,24 @@ func (check *Checker) collectObjects() { check.dotImportMap = make(map[dotImportKey]*PkgName) } // merge imported scope with file scope - for _, obj := range imp.scope.elems { + for name, obj := range imp.scope.elems { + // Note: Avoid eager resolve(name, obj) here, so we only + // resolve dot-imported objects as needed. + // A package scope may contain non-exported objects, // do not import them! - if obj.Exported() { + if token.IsExported(name) { // declare dot-imported object // (Do not use check.declare because it modifies the object // via Object.setScopePos, which leads to a race condition; // the object may be imported into more than one file scope // concurrently. See issue #32154.) - if alt := fileScope.Insert(obj); alt != nil { - check.errorf(d.spec.Name, _DuplicateDecl, "%s redeclared in this block", obj.Name()) + if alt := fileScope.Lookup(name); alt != nil { + check.errorf(d.spec.Name, _DuplicateDecl, "%s redeclared in this block", alt.Name()) check.reportAltDecl(alt) } else { - check.dotImportMap[dotImportKey{fileScope, obj}] = pkgName + fileScope.insert(name, obj) + check.dotImportMap[dotImportKey{fileScope, name}] = pkgName } } } @@ -443,8 +447,9 @@ func (check *Checker) collectObjects() { // verify that objects in package and file scopes have different names for _, scope := range fileScopes { - for _, obj := range scope.elems { - if alt := pkg.scope.Lookup(obj.Name()); alt != nil { + for name, obj := range scope.elems { + if alt := pkg.scope.Lookup(name); alt != nil { + obj = resolve(name, obj) if pkg, ok := obj.(*PkgName); ok { check.errorf(alt, _DuplicateDecl, "%s already declared through import of %s", alt.Name(), pkg.Imported()) check.reportAltDecl(pkg) diff --git a/src/go/types/sanitize.go b/src/go/types/sanitize.go index 05e7d8b4bfe..f54ab68624b 100644 --- a/src/go/types/sanitize.go +++ b/src/go/types/sanitize.go @@ -135,6 +135,7 @@ func (s sanitizer) typ(typ Type) Type { if debug && t.check != nil { panic("internal error: Named.check != nil") } + t.expand() if orig := s.typ(t.fromRHS); orig != t.fromRHS { t.fromRHS = orig } diff --git a/src/go/types/scope.go b/src/go/types/scope.go index 26c28d1c4e3..fa6e0ecb8ff 100644 --- a/src/go/types/scope.go +++ b/src/go/types/scope.go @@ -13,6 +13,7 @@ import ( "io" "sort" "strings" + "sync" ) // A Scope maintains a set of objects and links to its containing @@ -66,7 +67,7 @@ func (s *Scope) Child(i int) *Scope { return s.children[i] } // Lookup returns the object in scope s with the given name if such an // object exists; otherwise the result is nil. func (s *Scope) Lookup(name string) Object { - return s.elems[name] + return resolve(name, s.elems[name]) } // LookupParent follows the parent chain of scopes starting with s until @@ -81,7 +82,7 @@ func (s *Scope) Lookup(name string) Object { // whose scope is the scope of the package that exported them. func (s *Scope) LookupParent(name string, pos token.Pos) (*Scope, Object) { for ; s != nil; s = s.parent { - if obj := s.elems[name]; obj != nil && (!pos.IsValid() || obj.scopePos() <= pos) { + if obj := s.Lookup(name); obj != nil && (!pos.IsValid() || obj.scopePos() <= pos) { return s, obj } } @@ -95,19 +96,38 @@ func (s *Scope) LookupParent(name string, pos token.Pos) (*Scope, Object) { // if not already set, and returns nil. func (s *Scope) Insert(obj Object) Object { name := obj.Name() - if alt := s.elems[name]; alt != nil { + if alt := s.Lookup(name); alt != nil { return alt } - if s.elems == nil { - s.elems = make(map[string]Object) - } - s.elems[name] = obj + s.insert(name, obj) if obj.Parent() == nil { obj.setParent(s) } return nil } +// _InsertLazy is like Insert, but allows deferring construction of the +// inserted object until it's accessed with Lookup. The Object +// returned by resolve must have the same name as given to _InsertLazy. +// If s already contains an alternative object with the same name, +// _InsertLazy leaves s unchanged and returns false. Otherwise it +// records the binding and returns true. The object's parent scope +// will be set to s after resolve is called. +func (s *Scope) _InsertLazy(name string, resolve func() Object) bool { + if s.elems[name] != nil { + return false + } + s.insert(name, &lazyObject{parent: s, resolve: resolve}) + return true +} + +func (s *Scope) insert(name string, obj Object) { + if s.elems == nil { + s.elems = make(map[string]Object) + } + s.elems[name] = obj +} + // squash merges s with its parent scope p by adding all // objects of s to p, adding all children of s to the // children of p, and removing s from p's children. @@ -117,7 +137,8 @@ func (s *Scope) Insert(obj Object) Object { func (s *Scope) squash(err func(obj, alt Object)) { p := s.parent assert(p != nil) - for _, obj := range s.elems { + for name, obj := range s.elems { + obj = resolve(name, obj) obj.setParent(nil) if alt := p.Insert(obj); alt != nil { err(obj, alt) @@ -196,7 +217,7 @@ func (s *Scope) WriteTo(w io.Writer, n int, recurse bool) { indn1 := indn + ind for _, name := range s.Names() { - fmt.Fprintf(w, "%s%s\n", indn1, s.elems[name]) + fmt.Fprintf(w, "%s%s\n", indn1, s.Lookup(name)) } if recurse { @@ -214,3 +235,57 @@ func (s *Scope) String() string { s.WriteTo(&buf, 0, false) return buf.String() } + +// A lazyObject represents an imported Object that has not been fully +// resolved yet by its importer. +type lazyObject struct { + parent *Scope + resolve func() Object + obj Object + once sync.Once +} + +// resolve returns the Object represented by obj, resolving lazy +// objects as appropriate. +func resolve(name string, obj Object) Object { + if lazy, ok := obj.(*lazyObject); ok { + lazy.once.Do(func() { + obj := lazy.resolve() + + if _, ok := obj.(*lazyObject); ok { + panic("recursive lazy object") + } + if obj.Name() != name { + panic("lazy object has unexpected name") + } + + if obj.Parent() == nil { + obj.setParent(lazy.parent) + } + lazy.obj = obj + }) + + obj = lazy.obj + } + return obj +} + +// stub implementations so *lazyObject implements Object and we can +// store them directly into Scope.elems. +func (*lazyObject) Parent() *Scope { panic("unreachable") } +func (*lazyObject) Pos() token.Pos { panic("unreachable") } +func (*lazyObject) Pkg() *Package { panic("unreachable") } +func (*lazyObject) Name() string { panic("unreachable") } +func (*lazyObject) Type() Type { panic("unreachable") } +func (*lazyObject) Exported() bool { panic("unreachable") } +func (*lazyObject) Id() string { panic("unreachable") } +func (*lazyObject) String() string { panic("unreachable") } +func (*lazyObject) order() uint32 { panic("unreachable") } +func (*lazyObject) color() color { panic("unreachable") } +func (*lazyObject) setType(Type) { panic("unreachable") } +func (*lazyObject) setOrder(uint32) { panic("unreachable") } +func (*lazyObject) setColor(color color) { panic("unreachable") } +func (*lazyObject) setParent(*Scope) { panic("unreachable") } +func (*lazyObject) sameId(pkg *Package, name string) bool { panic("unreachable") } +func (*lazyObject) scopePos() token.Pos { panic("unreachable") } +func (*lazyObject) setScopePos(pos token.Pos) { panic("unreachable") } diff --git a/src/go/types/signature.go b/src/go/types/signature.go index f56fe047c84..9be2cce752f 100644 --- a/src/go/types/signature.go +++ b/src/go/types/signature.go @@ -57,7 +57,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast // again when we type-check the signature. // TODO(gri) maybe the receiver should be marked as invalid instead? if recv := asNamed(check.genericType(rname, false)); recv != nil { - recvTParams = recv.tparams + recvTParams = recv.TParams() } } // provide type parameter bounds diff --git a/src/go/types/sizeof_test.go b/src/go/types/sizeof_test.go index 9459f677697..9710edab15b 100644 --- a/src/go/types/sizeof_test.go +++ b/src/go/types/sizeof_test.go @@ -30,7 +30,7 @@ func TestSizeof(t *testing.T) { {Interface{}, 52, 104}, {Map{}, 16, 32}, {Chan{}, 12, 24}, - {Named{}, 68, 136}, + {Named{}, 84, 160}, {_TypeParam{}, 28, 48}, {instance{}, 44, 88}, {top{}, 0, 0}, diff --git a/src/go/types/stmt.go b/src/go/types/stmt.go index 9dcaceaca77..afef8334900 100644 --- a/src/go/types/stmt.go +++ b/src/go/types/stmt.go @@ -65,7 +65,8 @@ func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body func (check *Checker) usage(scope *Scope) { var unused []*Var - for _, elem := range scope.elems { + for name, elem := range scope.elems { + elem = resolve(name, elem) if v, _ := elem.(*Var); v != nil && !v.used { unused = append(unused, v) } diff --git a/src/go/types/subst.go b/src/go/types/subst.go index 025eba0f8c3..dc30bfbe673 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -79,7 +79,7 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist var tparams []*TypeName switch t := typ.(type) { case *Named: - tparams = t.tparams + tparams = t.TParams() case *Signature: tparams = t.tparams defer func() { @@ -351,7 +351,7 @@ func (subst *subster) typ(typ Type) Type { } } - if t.tparams == nil { + if t.TParams() == nil { dump(">>> %s is not parameterized", t) return t // type is not parameterized } @@ -361,7 +361,7 @@ func (subst *subster) typ(typ Type) Type { if len(t.targs) > 0 { // already instantiated dump(">>> %s already instantiated", t) - assert(len(t.targs) == len(t.tparams)) + assert(len(t.targs) == len(t.TParams())) // For each (existing) type argument targ, determine if it needs // to be substituted; i.e., if it is or contains a type parameter // that has a type argument for it. @@ -371,7 +371,7 @@ func (subst *subster) typ(typ Type) Type { if newTarg != targ { dump(">>> substituted %d targ %s => %s", i, targ, newTarg) if newTargs == nil { - newTargs = make([]Type, len(t.tparams)) + newTargs = make([]Type, len(t.TParams())) copy(newTargs, t.targs) } newTargs[i] = newTarg @@ -402,7 +402,7 @@ func (subst *subster) typ(typ Type) Type { // create a new named type and populate caches to avoid endless recursion tname := NewTypeName(subst.pos, t.obj.pkg, t.obj.name, nil) - named := subst.check.newNamed(tname, t, t.underlying, t.tparams, t.methods) // method signatures are updated lazily + named := subst.check.newNamed(tname, t, t.Underlying(), t.TParams(), t.methods) // method signatures are updated lazily named.targs = newTargs if subst.check != nil { subst.check.typMap[h] = named @@ -411,7 +411,7 @@ func (subst *subster) typ(typ Type) Type { // do the substitution dump(">>> subst %s with %s (new: %s)", t.underlying, subst.smap, newTargs) - named.underlying = subst.typOrNil(t.underlying) + named.underlying = subst.typOrNil(t.Underlying()) named.fromRHS = named.underlying // for cycle detection (Checker.validType) return named diff --git a/src/go/types/type.go b/src/go/types/type.go index 7429056865e..d555a8f684d 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -6,6 +6,7 @@ package types import ( "go/token" + "sync" "sync/atomic" ) @@ -504,6 +505,9 @@ type Named struct { tparams []*TypeName // type parameters, or nil targs []Type // type arguments (after instantiation), or nil methods []*Func // methods declared for this type (not the method set of this type); signatures are type-checked lazily + + resolve func(*Named) ([]*TypeName, Type, []*Func) + once sync.Once } // NewNamed returns a new named type for the given type name, underlying type, and associated methods. @@ -516,6 +520,35 @@ func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named { return (*Checker)(nil).newNamed(obj, nil, underlying, nil, methods) } +func (t *Named) expand() *Named { + if t.resolve == nil { + return t + } + + t.once.Do(func() { + // TODO(mdempsky): Since we're passing t to resolve anyway + // (necessary because types2 expects the receiver type for methods + // on defined interface types to be the Named rather than the + // underlying Interface), maybe it should just handle calling + // SetTParams, SetUnderlying, and AddMethod instead? Those + // methods would need to support reentrant calls though. It would + // also make the API more future-proof towards further extensions + // (like SetTParams). + + tparams, underlying, methods := t.resolve(t) + + switch underlying.(type) { + case nil, *Named: + panic("invalid underlying type") + } + + t.tparams = tparams + t.underlying = underlying + t.methods = methods + }) + return t +} + func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams []*TypeName, methods []*Func) *Named { typ := &Named{check: check, obj: obj, orig: orig, fromRHS: underlying, underlying: underlying, tparams: tparams, methods: methods} if typ.orig == nil { @@ -556,10 +589,10 @@ func (t *Named) _Orig() *Named { return t.orig } // _TParams returns the type parameters of the named type t, or nil. // The result is non-nil for an (originally) parameterized type even if it is instantiated. -func (t *Named) _TParams() []*TypeName { return t.tparams } +func (t *Named) _TParams() []*TypeName { return t.expand().tparams } // _SetTParams sets the type parameters of the named type t. -func (t *Named) _SetTParams(tparams []*TypeName) { t.tparams = tparams } +func (t *Named) _SetTParams(tparams []*TypeName) { t.expand().tparams = tparams } // _TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated. func (t *Named) _TArgs() []Type { return t.targs } @@ -568,10 +601,10 @@ func (t *Named) _TArgs() []Type { return t.targs } func (t *Named) _SetTArgs(args []Type) { t.targs = args } // NumMethods returns the number of explicit methods whose receiver is named type t. -func (t *Named) NumMethods() int { return len(t.methods) } +func (t *Named) NumMethods() int { return len(t.expand().methods) } // Method returns the i'th method of named type t for 0 <= i < t.NumMethods(). -func (t *Named) Method(i int) *Func { return t.methods[i] } +func (t *Named) Method(i int) *Func { return t.expand().methods[i] } // SetUnderlying sets the underlying type and marks t as complete. func (t *Named) SetUnderlying(underlying Type) { @@ -581,11 +614,12 @@ func (t *Named) SetUnderlying(underlying Type) { if _, ok := underlying.(*Named); ok { panic("types.Named.SetUnderlying: underlying type must not be *Named") } - t.underlying = underlying + t.expand().underlying = underlying } // AddMethod adds method m unless it is already in the method list. func (t *Named) AddMethod(m *Func) { + t.expand() if i, _ := lookupMethod(t.methods, m.pkg, m.name); i < 0 { t.methods = append(t.methods, m) } @@ -736,7 +770,7 @@ func (t *Signature) Underlying() Type { return t } func (t *Interface) Underlying() Type { return t } func (t *Map) Underlying() Type { return t } func (t *Chan) Underlying() Type { return t } -func (t *Named) Underlying() Type { return t.underlying } +func (t *Named) Underlying() Type { return t.expand().underlying } func (t *_TypeParam) Underlying() Type { return t } func (t *instance) Underlying() Type { return t } func (t *top) Underlying() Type { return t } diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go index 73465a35b77..79b4f74ff3e 100644 --- a/src/go/types/typestring.go +++ b/src/go/types/typestring.go @@ -273,9 +273,9 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { buf.WriteByte('[') writeTypeList(buf, t.targs, qf, visited) buf.WriteByte(']') - } else if t.tparams != nil { + } else if t.TParams() != nil { // parameterized type - writeTParamList(buf, t.tparams, qf, visited) + writeTParamList(buf, t.TParams(), qf, visited) } case *_TypeParam: diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index f62b41831e2..249a3ac5c5c 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -56,7 +56,7 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, wantType bool) // If so, mark the respective package as used. // (This code is only needed for dot-imports. Without them, // we only have to mark variables, see *Var case below). - if pkgName := check.dotImportMap[dotImportKey{scope, obj}]; pkgName != nil { + if pkgName := check.dotImportMap[dotImportKey{scope, obj.Name()}]; pkgName != nil { pkgName.used = true } From 24f9eb2de34d8d92dac4c6ffaa55ff2234c639d2 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 15 Jul 2021 22:49:00 -0400 Subject: [PATCH 695/940] [dev.typeparams] go/types: introduce type set abstraction for interfaces This is a port of CL 329309 to go/types, with minor updates for API differences and to handle methodset.go, which doesn't exist in types2. A couple pre-existing comments were adjusted to match types2. Change-Id: I3fd556e1326013a694ff5edb8518ca24c27bd10b Reviewed-on: https://go-review.googlesource.com/c/go/+/334894 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/api_typeparams.go | 4 - src/go/types/builtins.go | 2 +- src/go/types/call.go | 3 +- src/go/types/expr.go | 1 - src/go/types/infer.go | 27 ++---- src/go/types/interface.go | 63 ++++++------ src/go/types/lookup.go | 19 ++-- src/go/types/methodset.go | 4 +- src/go/types/predicates.go | 20 +--- src/go/types/sanitize.go | 8 +- src/go/types/sizeof_test.go | 3 +- src/go/types/subst.go | 15 ++- src/go/types/testdata/check/cycles4.src | 15 ++- src/go/types/type.go | 121 ++++++++---------------- src/go/types/typeset.go | 70 ++++++++++++++ src/go/types/typestring.go | 13 ++- src/go/types/typexpr.go | 8 +- src/go/types/unify.go | 13 +-- src/go/types/universe.go | 4 +- 19 files changed, 210 insertions(+), 203 deletions(-) create mode 100644 src/go/types/typeset.go diff --git a/src/go/types/api_typeparams.go b/src/go/types/api_typeparams.go index 6aaefbb6b29..864103df637 100644 --- a/src/go/types/api_typeparams.go +++ b/src/go/types/api_typeparams.go @@ -21,10 +21,6 @@ func NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam { func (s *Signature) TParams() []*TypeName { return s._TParams() } func (s *Signature) SetTParams(tparams []*TypeName) { s._SetTParams(tparams) } -func (t *Interface) HasTypeList() bool { return t._HasTypeList() } -func (t *Interface) IsComparable() bool { return t._IsComparable() } -func (t *Interface) IsConstraint() bool { return t._IsConstraint() } - func (t *Named) TParams() []*TypeName { return t._TParams() } func (t *Named) TArgs() []Type { return t._TArgs() } func (t *Named) SetTArgs(args []Type) { t._SetTArgs(args) } diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index cfaeab611b0..5670790856a 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -785,7 +785,7 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { tpar := NewTypeName(token.NoPos, nil /* = Universe pkg */, "", nil) ptyp := check.newTypeParam(tpar, 0, &emptyInterface) // assigns type to tpar as a side-effect tsum := newUnion(rtypes, tildes) - ptyp.bound = &Interface{allMethods: markComplete, allTypes: tsum} + ptyp.bound = &Interface{complete: true, tset: &TypeSet{types: tsum}} return ptyp } diff --git a/src/go/types/call.go b/src/go/types/call.go index 337ee741c66..cef5e9fc590 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -109,8 +109,7 @@ func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind { break } if t := asInterface(T); t != nil { - check.completeInterface(token.NoPos, t) - if t._IsConstraint() { + if t.IsConstraint() { check.errorf(call, _Todo, "cannot use interface %s in conversion (contains type list or is comparable)", T) break } diff --git a/src/go/types/expr.go b/src/go/types/expr.go index 95f2a8d6ab5..c8adea45e29 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -682,7 +682,6 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const return Typ[UntypedNil], nil, 0 } // cannot assign untyped values to non-empty interfaces - check.completeInterface(token.NoPos, t) if !t.Empty() { return nil, nil, _InvalidUntypedConversion } diff --git a/src/go/types/infer.go b/src/go/types/infer.go index 5a4f939bb13..ae53f68e48a 100644 --- a/src/go/types/infer.go +++ b/src/go/types/infer.go @@ -316,24 +316,13 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { return w.isParameterized(t.params) || w.isParameterized(t.results) case *Interface: - if t.allMethods != nil { - // TODO(rFindley) at some point we should enforce completeness here - for _, m := range t.allMethods { - if w.isParameterized(m.typ) { - return true - } + tset := t.typeSet() + for _, m := range tset.methods { + if w.isParameterized(m.typ) { + return true } - return w.isParameterized(t.allTypes) } - - return t.iterate(func(t *Interface) bool { - for _, m := range t.methods { - if w.isParameterized(m.typ) { - return true - } - } - return w.isParameterizedList(t.embeddeds) - }, nil) + return w.isParameterized(tset.types) case *Map: return w.isParameterized(t.key) || w.isParameterized(t.elem) @@ -471,15 +460,15 @@ func (check *Checker) inferB(tparams []*TypeName, targs []Type, report bool) (ty // structuralType returns the structural type of a constraint, if any. func (check *Checker) structuralType(constraint Type) Type { if iface, _ := under(constraint).(*Interface); iface != nil { - check.completeInterface(token.NoPos, iface) - if u, _ := iface.allTypes.(*Union); u != nil { + types := iface.typeSet().types + if u, _ := types.(*Union); u != nil { if u.NumTerms() == 1 { // TODO(gri) do we need to respect tilde? return u.types[0] } return nil } - return iface.allTypes + return types } return nil } diff --git a/src/go/types/interface.go b/src/go/types/interface.go index 947e76dc17e..3a4da569ab2 100644 --- a/src/go/types/interface.go +++ b/src/go/types/interface.go @@ -98,9 +98,13 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d check.posMap[ityp] = append(check.posMap[ityp], tlist[0].(*ast.UnaryExpr).X.Pos()) } + // All methods and embedded elements for this interface are collected; + // i.e., this interface is may be used in a type set computation. + ityp.complete = true + if len(ityp.methods) == 0 && len(ityp.embeddeds) == 0 { // empty interface - ityp.allMethods = markComplete + ityp.tset = &topTypeSet return } @@ -108,7 +112,10 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d sortMethods(ityp.methods) sortTypes(ityp.embeddeds) - check.later(func() { check.completeInterface(iface.Pos(), ityp) }) + // Compute type set with a non-nil *Checker as soon as possible + // to report any errors. Subsequent uses of type sets should be + // using this computed type set and won't need to pass in a *Checker. + check.later(func() { newTypeSet(check, iface.Pos(), ityp) }) } func flattenUnion(list []ast.Expr, x ast.Expr) []ast.Expr { @@ -119,24 +126,26 @@ func flattenUnion(list []ast.Expr, x ast.Expr) []ast.Expr { return append(list, x) } -func (check *Checker) completeInterface(pos token.Pos, ityp *Interface) { - if ityp.allMethods != nil { - return +// newTypeSet may be called with check == nil. +// TODO(gri) move this function into typeset.go eventually +func newTypeSet(check *Checker, pos token.Pos, ityp *Interface) *TypeSet { + if ityp.tset != nil { + return ityp.tset } - // completeInterface may be called via the LookupFieldOrMethod, - // MissingMethod, Identical, or IdenticalIgnoreTags external API - // in which case check will be nil. In this case, type-checking - // must be finished and all interfaces should have been completed. - if check == nil { - panic("internal error: incomplete interface") + // If the interface is not fully set up yet, the type set will + // not be complete, which may lead to errors when using the the + // type set (e.g. missing method). Don't compute a partial type + // set (and don't store it!), so that we still compute the full + // type set eventually. Instead, return the top type set and + // let any follow-on errors play out. + // + // TODO(gri) Consider recording when this happens and reporting + // it as an error (but only if there were no other errors so to + // to not have unnecessary follow-on errors). + if !ityp.complete { + return &topTypeSet } - completeInterface(check, pos, ityp) -} - -// completeInterface may be called with check == nil. -func completeInterface(check *Checker, pos token.Pos, ityp *Interface) { - assert(ityp.allMethods == nil) if check != nil && trace { // Types don't generally have position information. @@ -146,11 +155,11 @@ func completeInterface(check *Checker, pos token.Pos, ityp *Interface) { pos = ityp.methods[0].pos } - check.trace(pos, "complete %s", ityp) + check.trace(pos, "type set for %s", ityp) check.indent++ defer func() { check.indent-- - check.trace(pos, "=> %s (methods = %v, types = %v)", ityp, ityp.allMethods, ityp.allTypes) + check.trace(pos, "=> %s ", ityp.typeSet()) }() } @@ -159,7 +168,7 @@ func completeInterface(check *Checker, pos token.Pos, ityp *Interface) { // have valid interfaces. Mark the interface as complete to avoid // infinite recursion if the validType check occurs later for some // reason. - ityp.allMethods = markComplete + ityp.tset = new(TypeSet) // TODO(gri) is this sufficient? // Methods of embedded interfaces are collected unchanged; i.e., the identity // of a method I.m's Func Object of an interface I is the same as that of @@ -229,14 +238,12 @@ func completeInterface(check *Checker, pos token.Pos, ityp *Interface) { var types Type switch t := under(typ).(type) { case *Interface: - if t.allMethods == nil { - completeInterface(check, pos, t) - } - for _, m := range t.allMethods { + tset := newTypeSet(check, pos, t) + for _, m := range tset.methods { addMethod(pos, m, false) // use embedding position pos rather than m.pos } - types = t.allTypes + types = tset.types case *Union: // TODO(gri) combine with default case once we have // converted all tests to new notation and we @@ -273,9 +280,11 @@ func completeInterface(check *Checker, pos token.Pos, ityp *Interface) { if methods != nil { sort.Sort(byUniqueMethodName(methods)) - ityp.allMethods = methods + ityp.tset.methods = methods } - ityp.allTypes = allTypes + ityp.tset.types = allTypes + + return ityp.tset } func sortTypes(list []Type) { diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go index 5b22c4744e4..4ce4b3217c9 100644 --- a/src/go/types/lookup.go +++ b/src/go/types/lookup.go @@ -186,9 +186,7 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack case *Interface: // look for a matching method - // TODO(gri) t.allMethods is sorted - use binary search - check.completeInterface(token.NoPos, t) - if i, m := lookupMethod(t.allMethods, pkg, name); m != nil { + if i, m := t.typeSet().LookupMethod(pkg, name); m != nil { assert(m.typ != nil) index = concat(e.index, i) if obj != nil || e.multiples { @@ -199,9 +197,7 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack } case *_TypeParam: - // only consider explicit methods in the type parameter bound, not - // methods that may be common to all types in the type list. - if i, m := lookupMethod(t.Bound().allMethods, pkg, name); m != nil { + if i, m := t.Bound().typeSet().LookupMethod(pkg, name); m != nil { assert(m.typ != nil) index = concat(e.index, i) if obj != nil || e.multiples { @@ -307,18 +303,15 @@ func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType b // To improve error messages, also report the wrong signature // when the method exists on *V instead of V. func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, wrongType *Func) { - check.completeInterface(token.NoPos, T) - // fast path for common case if T.Empty() { return } if ityp := asInterface(V); ityp != nil { - check.completeInterface(token.NoPos, ityp) - // TODO(gri) allMethods is sorted - can do this more efficiently - for _, m := range T.allMethods { - _, f := lookupMethod(ityp.allMethods, m.pkg, m.name) + // TODO(gri) the methods are sorted - could do this more efficiently + for _, m := range T.typeSet().methods { + _, f := ityp.typeSet().LookupMethod(m.pkg, m.name) if f == nil { // if m is the magic method == we're ok (interfaces are comparable) @@ -356,7 +349,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // A concrete type implements T if it implements all methods of T. Vd, _ := deref(V) Vn := asNamed(Vd) - for _, m := range T.allMethods { + for _, m := range T.typeSet().methods { // TODO(gri) should this be calling lookupFieldOrMethod instead (and why not)? obj, _, _ := check.rawLookupFieldOrMethod(V, false, m.pkg, m.name) diff --git a/src/go/types/methodset.go b/src/go/types/methodset.go index ae8011a2eee..71d634bf36e 100644 --- a/src/go/types/methodset.go +++ b/src/go/types/methodset.go @@ -157,10 +157,10 @@ func NewMethodSet(T Type) *MethodSet { } case *Interface: - mset = mset.add(t.allMethods, e.index, true, e.multiples) + mset = mset.add(t.typeSet().methods, e.index, true, e.multiples) case *_TypeParam: - mset = mset.add(t.Bound().allMethods, e.index, true, e.multiples) + mset = mset.add(t.Bound().typeSet().methods, e.index, true, e.multiples) } } diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index 9f3e3245978..7f6eee81209 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -6,10 +6,6 @@ package types -import ( - "go/token" -) - // isNamed reports whether typ has a name. // isNamed may be called with types that are not fully set up. func isNamed(typ Type) bool { @@ -109,7 +105,7 @@ func comparable(T Type, seen map[Type]bool) bool { // // is not comparable because []byte is not comparable. if t := asTypeParam(T); t != nil && optype(t) == theTop { - return t.Bound()._IsComparable() + return t.Bound().IsComparable() } switch t := optype(T).(type) { @@ -133,7 +129,7 @@ func comparable(T Type, seen map[Type]bool) bool { return comparable(t, seen) }) case *_TypeParam: - return t.Bound()._IsComparable() + return t.Bound().IsComparable() } return false } @@ -291,16 +287,8 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { // the same names and identical function types. Lower-case method names from // different packages are always different. The order of the methods is irrelevant. if y, ok := y.(*Interface); ok { - // If identical0 is called (indirectly) via an external API entry point - // (such as Identical, IdenticalIgnoreTags, etc.), check is nil. But in - // that case, interfaces are expected to be complete and lazy completion - // here is not needed. - if check != nil { - check.completeInterface(token.NoPos, x) - check.completeInterface(token.NoPos, y) - } - a := x.allMethods - b := y.allMethods + a := x.typeSet().methods + b := y.typeSet().methods if len(a) == len(b) { // Interface types are the only types where cycles can occur // that are not "terminated" via named types; and such cycles diff --git a/src/go/types/sanitize.go b/src/go/types/sanitize.go index f54ab68624b..df09a6a38f6 100644 --- a/src/go/types/sanitize.go +++ b/src/go/types/sanitize.go @@ -113,9 +113,11 @@ func (s sanitizer) typ(typ Type) Type { case *Interface: s.funcList(t.methods) s.typeList(t.embeddeds) - s.funcList(t.allMethods) - if allTypes := s.typ(t.allTypes); allTypes != t.allTypes { - t.allTypes = allTypes + // TODO(gri) do we need to sanitize type sets? + tset := t.typeSet() + s.funcList(tset.methods) + if types := s.typ(tset.types); types != tset.types { + tset.types = types } case *Map: diff --git a/src/go/types/sizeof_test.go b/src/go/types/sizeof_test.go index 9710edab15b..05a171f4989 100644 --- a/src/go/types/sizeof_test.go +++ b/src/go/types/sizeof_test.go @@ -27,7 +27,7 @@ func TestSizeof(t *testing.T) { {Tuple{}, 12, 24}, {Signature{}, 44, 88}, {Union{}, 24, 48}, - {Interface{}, 52, 104}, + {Interface{}, 40, 80}, {Map{}, 16, 32}, {Chan{}, 12, 24}, {Named{}, 84, 160}, @@ -48,6 +48,7 @@ func TestSizeof(t *testing.T) { // Misc {Scope{}, 40, 80}, {Package{}, 40, 80}, + {TypeSet{}, 20, 40}, } for _, test := range tests { got := reflect.TypeOf(test.val).Size() diff --git a/src/go/types/subst.go b/src/go/types/subst.go index dc30bfbe673..0e2e7f408ac 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -139,6 +139,7 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist // satisfies reports whether the type argument targ satisfies the constraint of type parameter // parameter tpar (after any of its type parameters have been substituted through smap). // A suitable error is reported if the result is false. +// TODO(gri) This should be a method of interfaces or type sets. func (check *Checker) satisfies(pos token.Pos, targ Type, tpar *_TypeParam, smap *substMap) bool { iface := tpar.Bound() if iface.Empty() { @@ -153,8 +154,7 @@ func (check *Checker) satisfies(pos token.Pos, targ Type, tpar *_TypeParam, smap // targ must implement iface (methods) // - check only if we have methods - check.completeInterface(token.NoPos, iface) - if len(iface.allMethods) > 0 { + if iface.NumMethods() > 0 { // If the type argument is a pointer to a type parameter, the type argument's // method set is empty. // TODO(gri) is this what we want? (spec question) @@ -186,7 +186,7 @@ func (check *Checker) satisfies(pos token.Pos, targ Type, tpar *_TypeParam, smap } // targ's underlying type must also be one of the interface types listed, if any - if iface.allTypes == nil { + if iface.typeSet().types == nil { return true // nothing to do } @@ -194,7 +194,7 @@ func (check *Checker) satisfies(pos token.Pos, targ Type, tpar *_TypeParam, smap // list of iface types (i.e., the targ type list must be a non-empty subset of the iface types). if targ := asTypeParam(targ); targ != nil { targBound := targ.Bound() - if targBound.allTypes == nil { + if targBound.typeSet().types == nil { check.softErrorf(atPos(pos), _Todo, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ) return false } @@ -202,7 +202,7 @@ func (check *Checker) satisfies(pos token.Pos, targ Type, tpar *_TypeParam, smap // TODO(gri) incorporate tilde information! if !iface.isSatisfiedBy(typ) { // TODO(gri) match this error message with the one below (or vice versa) - check.softErrorf(atPos(pos), 0, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, typ, iface.allTypes) + check.softErrorf(atPos(pos), 0, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, typ, iface.typeSet().types) return false } return true @@ -211,7 +211,7 @@ func (check *Checker) satisfies(pos token.Pos, targ Type, tpar *_TypeParam, smap // Otherwise, targ's type or underlying type must also be one of the interface types listed, if any. if !iface.isSatisfiedBy(targ) { - check.softErrorf(atPos(pos), _Todo, "%s does not satisfy %s (%s not found in %s)", targ, tpar.bound, targ, iface.allTypes) + check.softErrorf(atPos(pos), _Todo, "%s does not satisfy %s (%s not found in %s)", targ, tpar.bound, targ, iface.typeSet().types) return false } @@ -316,12 +316,11 @@ func (subst *subster) typ(typ Type) Type { methods, mcopied := subst.funcList(t.methods) embeddeds, ecopied := subst.typeList(t.embeddeds) if mcopied || ecopied { - iface := &Interface{methods: methods, embeddeds: embeddeds} + iface := &Interface{methods: methods, embeddeds: embeddeds, complete: t.complete} if subst.check == nil { panic("internal error: cannot instantiate interfaces yet") } subst.check.posMap[iface] = subst.check.posMap[t] // satisfy completeInterface requirement - subst.check.completeInterface(token.NoPos, iface) return iface } diff --git a/src/go/types/testdata/check/cycles4.src b/src/go/types/testdata/check/cycles4.src index 445babca68b..924aabf475f 100644 --- a/src/go/types/testdata/check/cycles4.src +++ b/src/go/types/testdata/check/cycles4.src @@ -4,6 +4,8 @@ package p +import "unsafe" + // Check that all methods of T are collected before // determining the result type of m (which embeds // all methods of T). @@ -13,7 +15,7 @@ type T interface { E } -var _ = T.m(nil).m().e() +var _ int = T.m(nil).m().e() type E interface { e() int @@ -22,7 +24,7 @@ type E interface { // Check that unresolved forward chains are followed // (see also comment in resolver.go, checker.typeDecl). -var _ = C.m(nil).m().e() +var _ int = C.m(nil).m().e() type A B @@ -108,3 +110,12 @@ type Element interface { type Event interface { Target() Element } + +// Check that accessing an interface method too early doesn't lead +// to follow-on errors due to an incorrectly computed type set. + +type T8 interface { + m() [unsafe.Sizeof(T8.m /* ERROR undefined */ )]int +} + +var _ = T8.m // no error expected here diff --git a/src/go/types/type.go b/src/go/types/type.go index d555a8f684d..4dcc511b931 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -258,18 +258,20 @@ func (s *Signature) Variadic() bool { return s.variadic } // An Interface represents an interface type. type Interface struct { + obj Object // type name object defining this interface; or nil (for better error messages) methods []*Func // ordered list of explicitly declared methods - embeddeds []Type // ordered list of explicitly embedded types + embeddeds []Type // ordered list of explicitly embedded elements + complete bool // indicates that obj, methods, and embeddeds are set and type set can be computed - allMethods []*Func // ordered list of methods declared with or embedded in this interface (TODO(gri): replace with mset) - allTypes Type // intersection of all embedded and locally declared types (TODO(gri) need better field name) - - obj Object // type declaration defining this interface; or nil (for better error messages) + tset *TypeSet // type set described by this interface, computed lazily } +// typeSet returns the type set for interface t. +func (t *Interface) typeSet() *TypeSet { return newTypeSet(nil, token.NoPos, t) } + // is reports whether interface t represents types that all satisfy f. func (t *Interface) is(f func(Type, bool) bool) bool { - switch t := t.allTypes.(type) { + switch t := t.typeSet().types.(type) { case nil, *top: // TODO(gri) should settle on top or nil to represent this case return false // we must have at least one type! (was bug) @@ -281,20 +283,13 @@ func (t *Interface) is(f func(Type, bool) bool) bool { } // emptyInterface represents the empty (completed) interface -var emptyInterface = Interface{allMethods: markComplete} +var emptyInterface = Interface{complete: true, tset: &topTypeSet} -// markComplete is used to mark an empty interface as completely -// set up by setting the allMethods field to a non-nil empty slice. -var markComplete = make([]*Func, 0) - -// NewInterface returns a new (incomplete) interface for the given methods and embedded types. -// Each embedded type must have an underlying type of interface type. -// NewInterface takes ownership of the provided methods and may modify their types by setting -// missing receivers. To compute the method set of the interface, Complete must be called. +// NewInterface returns a new interface for the given methods and embedded types. +// NewInterface takes ownership of the provided methods and may modify their types +// by setting missing receivers. // -// Deprecated: Use NewInterfaceType instead which allows any (even non-defined) interface types -// to be embedded. This is necessary for interfaces that embed alias type names referring to -// non-defined (literal) interface types. +// Deprecated: Use NewInterfaceType instead which allows arbitrary embedded types. func NewInterface(methods []*Func, embeddeds []*Named) *Interface { tnames := make([]Type, len(embeddeds)) for i, t := range embeddeds { @@ -303,12 +298,9 @@ func NewInterface(methods []*Func, embeddeds []*Named) *Interface { return NewInterfaceType(methods, tnames) } -// NewInterfaceType returns a new (incomplete) interface for the given methods and embedded types. -// Each embedded type must have an underlying type of interface type (this property is not -// verified for defined types, which may be in the process of being set up and which don't -// have a valid underlying type yet). -// NewInterfaceType takes ownership of the provided methods and may modify their types by setting -// missing receivers. To compute the method set of the interface, Complete must be called. +// NewInterfaceType returns a new interface for the given methods and embedded types. +// NewInterfaceType takes ownership of the provided methods and may modify their types +// by setting missing receivers. func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface { if len(methods) == 0 && len(embeddeds) == 0 { return &emptyInterface @@ -338,6 +330,8 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface { typ.methods = methods typ.embeddeds = embeddeds + typ.complete = true + return typ } @@ -361,64 +355,20 @@ func (t *Interface) Embedded(i int) *Named { tname, _ := t.embeddeds[i].(*Named) func (t *Interface) EmbeddedType(i int) Type { return t.embeddeds[i] } // NumMethods returns the total number of methods of interface t. -// The interface must have been completed. -func (t *Interface) NumMethods() int { t.Complete(); return len(t.allMethods) } +func (t *Interface) NumMethods() int { return t.typeSet().NumMethods() } // Method returns the i'th method of interface t for 0 <= i < t.NumMethods(). // The methods are ordered by their unique Id. -// The interface must have been completed. -func (t *Interface) Method(i int) *Func { t.Complete(); return t.allMethods[i] } +func (t *Interface) Method(i int) *Func { return t.typeSet().Method(i) } // Empty reports whether t is the empty interface. -func (t *Interface) Empty() bool { - t.Complete() - return len(t.allMethods) == 0 && t.allTypes == nil -} +func (t *Interface) Empty() bool { return t.typeSet().IsTop() } -// _HasTypeList reports whether interface t has a type list, possibly from an embedded type. -func (t *Interface) _HasTypeList() bool { - t.Complete() - return t.allTypes != nil -} +// IsComparable reports whether interface t is or embeds the predeclared interface "comparable". +func (t *Interface) IsComparable() bool { return t.typeSet().IsComparable() } -// _IsComparable reports whether interface t is or embeds the predeclared interface "comparable". -func (t *Interface) _IsComparable() bool { - t.Complete() - _, m := lookupMethod(t.allMethods, nil, "==") - return m != nil -} - -// _IsConstraint reports t.HasTypeList() || t.IsComparable(). -func (t *Interface) _IsConstraint() bool { - return t._HasTypeList() || t._IsComparable() -} - -// iterate calls f with t and then with any embedded interface of t, recursively, until f returns true. -// iterate reports whether any call to f returned true. -// TODO(rfindley) This is now only used by infer.go - see if we can eliminate it. -func (t *Interface) iterate(f func(*Interface) bool, seen map[*Interface]bool) bool { - if f(t) { - return true - } - for _, e := range t.embeddeds { - // e should be an interface but be careful (it may be invalid) - if e := asInterface(e); e != nil { - // Cyclic interfaces such as "type E interface { E }" are not permitted - // but they are still constructed and we need to detect such cycles. - if seen[e] { - continue - } - if seen == nil { - seen = make(map[*Interface]bool) - } - seen[e] = true - if e.iterate(f, seen) { - return true - } - } - } - return false -} +// IsConstraint reports whether interface t is not just a method set. +func (t *Interface) IsConstraint() bool { return !t.typeSet().IsMethodSet() } // isSatisfiedBy reports whether interface t's type list is satisfied by the type typ. // If the type list is empty (absent), typ trivially satisfies the interface. @@ -426,7 +376,7 @@ func (t *Interface) iterate(f func(*Interface) bool, seen map[*Interface]bool) b // "implements" predicate. func (t *Interface) isSatisfiedBy(typ Type) bool { t.Complete() - switch t := t.allTypes.(type) { + switch t := t.typeSet().types.(type) { case nil: return true // no type restrictions case *Union: @@ -437,15 +387,22 @@ func (t *Interface) isSatisfiedBy(typ Type) bool { } } -// Complete computes the interface's method set. It must be called by users of +// Complete computes the interface's type set. It must be called by users of // NewInterfaceType and NewInterface after the interface's embedded types are // fully defined and before using the interface type in any way other than to // form other types. The interface must not contain duplicate methods or a // panic occurs. Complete returns the receiver. +// +// Deprecated: Type sets are now computed lazily, on demand; this function +// is only here for backward-compatibility. It does not have to +// be called explicitly anymore. func (t *Interface) Complete() *Interface { - if t.allMethods == nil { - completeInterface(nil, token.NoPos, t) - } + // Some tests are still depending on the state change + // (string representation of an Interface not containing an + // /* incomplete */ marker) caused by the explicit Complete + // call, so we compute the type set eagerly here. + t.complete = true + t.typeSet() return t } @@ -668,7 +625,7 @@ func (t *_TypeParam) Bound() *Interface { pos = n.obj.pos } // TODO(rFindley) switch this to an unexported method on Checker. - t.check.completeInterface(pos, iface) + newTypeSet(t.check, pos, iface) return iface } @@ -685,7 +642,7 @@ func optype(typ Type) Type { // for a type parameter list of the form: // (type T interface { type T }). // See also issue #39680. - if a := t.Bound().allTypes; a != nil && a != typ { + if a := t.Bound().typeSet().types; a != nil && a != typ { // If we have a union with a single entry, ignore // any tilde because under(~t) == under(t). if u, _ := a.(*Union); u != nil && u.NumTerms() == 1 { diff --git a/src/go/types/typeset.go b/src/go/types/typeset.go new file mode 100644 index 00000000000..9ba04b97bfc --- /dev/null +++ b/src/go/types/typeset.go @@ -0,0 +1,70 @@ +// Copyright 2021 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 types + +import ( + "bytes" +) + +// topTypeSet may be used as type set for the empty interface. +var topTypeSet TypeSet + +// A TypeSet represents the type set of an interface. +type TypeSet struct { + // TODO(gri) consider using a set for the methods for faster lookup + methods []*Func // all methods of the interface; sorted by unique ID + types Type // typically a *Union; nil means no type restrictions +} + +func (s *TypeSet) String() string { + if s.IsTop() { + return "⊤" + } + + var buf bytes.Buffer + buf.WriteByte('{') + for i, m := range s.methods { + if i > 0 { + buf.WriteByte(';') + } + buf.WriteByte(' ') + buf.WriteString(m.String()) + } + if len(s.methods) > 0 && s.types != nil { + buf.WriteByte(';') + } + if s.types != nil { + buf.WriteByte(' ') + writeType(&buf, s.types, nil, nil) + } + + buf.WriteString(" }") // there was a least one method or type + return buf.String() +} + +// IsTop reports whether type set s is the top type set (corresponding to the empty interface). +func (s *TypeSet) IsTop() bool { return len(s.methods) == 0 && s.types == nil } + +// IsMethodSet reports whether the type set s is described by a single set of methods. +func (s *TypeSet) IsMethodSet() bool { return s.types == nil && !s.IsComparable() } + +// IsComparable reports whether each type in the set is comparable. +func (s *TypeSet) IsComparable() bool { + _, m := s.LookupMethod(nil, "==") + return m != nil +} + +// NumMethods returns the number of methods available. +func (s *TypeSet) NumMethods() int { return len(s.methods) } + +// Method returns the i'th method of type set s for 0 <= i < s.NumMethods(). +// The methods are ordered by their unique ID. +func (s *TypeSet) Method(i int) *Func { return s.methods[i] } + +// LookupMethod returns the index of and method with matching package and name, or (-1, nil). +func (s *TypeSet) LookupMethod(pkg *Package, name string) (int, *Func) { + // TODO(gri) s.methods is sorted - consider binary search + return lookupMethod(s.methods, pkg, name) +} diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go index 79b4f74ff3e..fb398de502a 100644 --- a/src/go/types/typestring.go +++ b/src/go/types/typestring.go @@ -190,7 +190,8 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { if gcCompatibilityMode { // print flattened interface // (useful to compare against gc-generated interfaces) - for i, m := range t.allMethods { + tset := t.typeSet() + for i, m := range tset.methods { if i > 0 { buf.WriteString("; ") } @@ -198,12 +199,12 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { writeSignature(buf, m.typ.(*Signature), qf, visited) empty = false } - if !empty && t.allTypes != nil { + if !empty && tset.types != nil { buf.WriteString("; ") } - if t.allTypes != nil { + if tset.types != nil { buf.WriteString("type ") - writeType(buf, t.allTypes, qf, visited) + writeType(buf, tset.types, qf, visited) } } else { // print explicit interface methods and embedded types @@ -226,7 +227,9 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { empty = false } } - if debug && (t.allMethods == nil || len(t.methods) > len(t.allMethods)) { + // print /* incomplete */ if needed to satisfy existing tests + // TODO(gri) get rid of this eventually + if debug && t.tset == nil { if !empty { buf.WriteByte(' ') } diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 249a3ac5c5c..070b0ade3e8 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -140,12 +140,12 @@ func (check *Checker) ordinaryType(pos positioner, typ Type) { // type-checking. check.later(func() { if t := asInterface(typ); t != nil { - check.completeInterface(pos.Pos(), t) // TODO(gri) is this the correct position? - if t.allTypes != nil { - check.softErrorf(pos, _Todo, "interface contains type constraints (%s)", t.allTypes) + tset := newTypeSet(check, pos.Pos(), t) // TODO(gri) is this the correct position? + if tset.types != nil { + check.softErrorf(pos, _Todo, "interface contains type constraints (%s)", tset.types) return } - if t._IsComparable() { + if tset.IsComparable() { check.softErrorf(pos, _Todo, "interface is (or embeds) comparable") } } diff --git a/src/go/types/unify.go b/src/go/types/unify.go index 7c58c6c5128..bc611db3479 100644 --- a/src/go/types/unify.go +++ b/src/go/types/unify.go @@ -8,7 +8,6 @@ package types import ( "bytes" - "go/token" "sort" ) @@ -361,16 +360,8 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool { // the same names and identical function types. Lower-case method names from // different packages are always different. The order of the methods is irrelevant. if y, ok := y.(*Interface); ok { - // If identical0 is called (indirectly) via an external API entry point - // (such as Identical, IdenticalIgnoreTags, etc.), check is nil. But in - // that case, interfaces are expected to be complete and lazy completion - // here is not needed. - if u.check != nil { - u.check.completeInterface(token.NoPos, x) - u.check.completeInterface(token.NoPos, y) - } - a := x.allMethods - b := y.allMethods + a := x.typeSet().methods + b := y.typeSet().methods if len(a) == len(b) { // Interface types are the only types where cycles can occur // that are not "terminated" via named types; and such cycles diff --git a/src/go/types/universe.go b/src/go/types/universe.go index d7feb2c609e..7ce401827e3 100644 --- a/src/go/types/universe.go +++ b/src/go/types/universe.go @@ -90,7 +90,7 @@ func defPredeclaredTypes() { res := NewVar(token.NoPos, nil, "", Typ[String]) sig := &Signature{results: NewTuple(res)} err := NewFunc(token.NoPos, nil, "Error", sig) - typ := &Named{underlying: NewInterfaceType([]*Func{err}, nil).Complete()} + typ := &Named{underlying: NewInterfaceType([]*Func{err}, nil)} sig.recv = NewVar(token.NoPos, nil, "", typ) def(NewTypeName(token.NoPos, nil, "error", typ)) } @@ -218,7 +218,7 @@ func defPredeclaredComparable() { // set up later to match the usual interface method assumptions. sig := new(Signature) eql := NewFunc(token.NoPos, nil, "==", sig) - iface := NewInterfaceType([]*Func{eql}, nil).Complete() + iface := NewInterfaceType([]*Func{eql}, nil) // set up the defined type for the interface obj := NewTypeName(token.NoPos, nil, "comparable", nil) From fce6290e0ac18ca2d5cc635adf4c3a77b375a49a Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 15 Jul 2021 23:18:59 -0400 Subject: [PATCH 696/940] [dev.typeparams] go/types: remove typeparams wrappers and aliases These wrappers and aliases were necessary when we had different versions of the API depending on the typeparams build constraint, but now they're just boilerplate. Remove them. Notably the documentation for types.Info is restored. Change-Id: I5363d1d5df47649c2641c03328dfba45b1456278 Reviewed-on: https://go-review.googlesource.com/c/go/+/334895 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/api.go | 100 +++++++++++++++++++- src/go/types/api_test.go | 123 +++++++++++++++++++++++++ src/go/types/api_typeparams.go | 48 ---------- src/go/types/api_typeparams_test.go | 136 ---------------------------- src/go/types/check.go | 4 +- src/go/types/decl.go | 2 +- src/go/types/index.go | 4 +- src/go/types/infer.go | 6 +- src/go/types/lookup.go | 4 +- src/go/types/methodset.go | 4 +- src/go/types/predicates.go | 8 +- src/go/types/sanitize.go | 4 +- src/go/types/signature.go | 4 +- src/go/types/sizeof_test.go | 2 +- src/go/types/subst.go | 16 ++-- src/go/types/type.go | 87 +++++++++--------- src/go/types/typestring.go | 6 +- src/go/types/unify.go | 6 +- 18 files changed, 302 insertions(+), 262 deletions(-) delete mode 100644 src/go/types/api_typeparams.go delete mode 100644 src/go/types/api_typeparams_test.go diff --git a/src/go/types/api.go b/src/go/types/api.go index 2bfbb8ce0cb..2815a6d0274 100644 --- a/src/go/types/api.go +++ b/src/go/types/api.go @@ -162,6 +162,102 @@ func srcimporter_setUsesCgo(conf *Config) { conf.go115UsesCgo = true } +// Info holds result type information for a type-checked package. +// Only the information for which a map is provided is collected. +// If the package has type errors, the collected information may +// be incomplete. +type Info struct { + // Types maps expressions to their types, and for constant + // expressions, also their values. Invalid expressions are + // omitted. + // + // For (possibly parenthesized) identifiers denoting built-in + // functions, the recorded signatures are call-site specific: + // if the call result is not a constant, the recorded type is + // an argument-specific signature. Otherwise, the recorded type + // is invalid. + // + // The Types map does not record the type of every identifier, + // only those that appear where an arbitrary expression is + // permitted. For instance, the identifier f in a selector + // expression x.f is found only in the Selections map, the + // identifier z in a variable declaration 'var z int' is found + // only in the Defs map, and identifiers denoting packages in + // qualified identifiers are collected in the Uses map. + Types map[ast.Expr]TypeAndValue + + // Inferred maps calls of parameterized functions that use + // type inference to the inferred type arguments and signature + // of the function called. The recorded "call" expression may be + // an *ast.CallExpr (as in f(x)), or an *ast.IndexExpr (s in f[T]). + Inferred map[ast.Expr]Inferred + + // Defs maps identifiers to the objects they define (including + // package names, dots "." of dot-imports, and blank "_" identifiers). + // For identifiers that do not denote objects (e.g., the package name + // in package clauses, or symbolic variables t in t := x.(type) of + // type switch headers), the corresponding objects are nil. + // + // For an embedded field, Defs returns the field *Var it defines. + // + // Invariant: Defs[id] == nil || Defs[id].Pos() == id.Pos() + Defs map[*ast.Ident]Object + + // Uses maps identifiers to the objects they denote. + // + // For an embedded field, Uses returns the *TypeName it denotes. + // + // Invariant: Uses[id].Pos() != id.Pos() + Uses map[*ast.Ident]Object + + // Implicits maps nodes to their implicitly declared objects, if any. + // The following node and object types may appear: + // + // node declared object + // + // *ast.ImportSpec *PkgName for imports without renames + // *ast.CaseClause type-specific *Var for each type switch case clause (incl. default) + // *ast.Field anonymous parameter *Var (incl. unnamed results) + // + Implicits map[ast.Node]Object + + // Selections maps selector expressions (excluding qualified identifiers) + // to their corresponding selections. + Selections map[*ast.SelectorExpr]*Selection + + // Scopes maps ast.Nodes to the scopes they define. Package scopes are not + // associated with a specific node but with all files belonging to a package. + // Thus, the package scope can be found in the type-checked Package object. + // Scopes nest, with the Universe scope being the outermost scope, enclosing + // the package scope, which contains (one or more) files scopes, which enclose + // function scopes which in turn enclose statement and function literal scopes. + // Note that even though package-level functions are declared in the package + // scope, the function scopes are embedded in the file scope of the file + // containing the function declaration. + // + // The following node types may appear in Scopes: + // + // *ast.File + // *ast.FuncType + // *ast.BlockStmt + // *ast.IfStmt + // *ast.SwitchStmt + // *ast.TypeSwitchStmt + // *ast.CaseClause + // *ast.CommClause + // *ast.ForStmt + // *ast.RangeStmt + // + Scopes map[ast.Node]*Scope + + // InitOrder is the list of package-level initializers in the order in which + // they must be executed. Initializers referring to variables related by an + // initialization dependency appear in topological order, the others appear + // in source order. Variables without an initialization expression do not + // appear in this list. + InitOrder []*Initializer +} + // The Info struct is found in api_notypeparams.go and api_typeparams.go. // TypeOf returns the type of expression e, or nil if not found. @@ -254,9 +350,9 @@ func (tv TypeAndValue) HasOk() bool { return tv.mode == commaok || tv.mode == mapindex } -// _Inferred reports the _Inferred type arguments and signature +// Inferred reports the Inferred type arguments and signature // for a parameterized function call that uses type inference. -type _Inferred struct { +type Inferred struct { TArgs []Type Sig *Signature } diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go index 6a7218d90f4..ef248781ccc 100644 --- a/src/go/types/api_test.go +++ b/src/go/types/api_test.go @@ -389,6 +389,129 @@ func TestTypesInfo(t *testing.T) { } } +func TestInferredInfo(t *testing.T) { + var tests = []struct { + src string + fun string + targs []string + sig string + }{ + {genericPkg + `p0; func f[T any](T); func _() { f(42) }`, + `f`, + []string{`int`}, + `func(int)`, + }, + {genericPkg + `p1; func f[T any](T) T; func _() { f('@') }`, + `f`, + []string{`rune`}, + `func(rune) rune`, + }, + {genericPkg + `p2; func f[T any](...T) T; func _() { f(0i) }`, + `f`, + []string{`complex128`}, + `func(...complex128) complex128`, + }, + {genericPkg + `p3; func f[A, B, C any](A, *B, []C); func _() { f(1.2, new(string), []byte{}) }`, + `f`, + []string{`float64`, `string`, `byte`}, + `func(float64, *string, []byte)`, + }, + {genericPkg + `p4; func f[A, B any](A, *B, ...[]B); func _() { f(1.2, new(byte)) }`, + `f`, + []string{`float64`, `byte`}, + `func(float64, *byte, ...[]byte)`, + }, + + {genericPkg + `s1; func f[T any, P interface{~*T}](x T); func _(x string) { f(x) }`, + `f`, + []string{`string`, `*string`}, + `func(x string)`, + }, + {genericPkg + `s2; func f[T any, P interface{~*T}](x []T); func _(x []int) { f(x) }`, + `f`, + []string{`int`, `*int`}, + `func(x []int)`, + }, + {genericPkg + `s3; type C[T any] interface{~chan<- T}; func f[T any, P C[T]](x []T); func _(x []int) { f(x) }`, + `f`, + []string{`int`, `chan<- int`}, + `func(x []int)`, + }, + {genericPkg + `s4; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T); func _(x []int) { f(x) }`, + `f`, + []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, + `func(x []int)`, + }, + + {genericPkg + `t1; func f[T any, P interface{~*T}]() T; func _() { _ = f[string] }`, + `f`, + []string{`string`, `*string`}, + `func() string`, + }, + {genericPkg + `t2; type C[T any] interface{~chan<- T}; func f[T any, P C[T]]() []T; func _() { _ = f[int] }`, + `f`, + []string{`int`, `chan<- int`}, + `func() []int`, + }, + {genericPkg + `t3; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T; func _() { _ = f[int] }`, + `f`, + []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, + `func() []int`, + }, + } + + for _, test := range tests { + info := Info{} + info.Inferred = make(map[ast.Expr]Inferred) + name, err := mayTypecheck(t, "InferredInfo", test.src, &info) + if err != nil { + t.Errorf("package %s: %v", name, err) + continue + } + + // look for inferred type arguments and signature + var targs []Type + var sig *Signature + for call, inf := range info.Inferred { + var fun ast.Expr + switch x := call.(type) { + case *ast.CallExpr: + fun = x.Fun + case *ast.IndexExpr: + fun = x.X + default: + panic(fmt.Sprintf("unexpected call expression type %T", call)) + } + if ExprString(fun) == test.fun { + targs = inf.TArgs + sig = inf.Sig + break + } + } + if targs == nil { + t.Errorf("package %s: no inferred information found for %s", name, test.fun) + continue + } + + // check that type arguments are correct + if len(targs) != len(test.targs) { + t.Errorf("package %s: got %d type arguments; want %d", name, len(targs), len(test.targs)) + continue + } + for i, targ := range targs { + if got := targ.String(); got != test.targs[i] { + t.Errorf("package %s, %d. type argument: got %s; want %s", name, i, got, test.targs[i]) + continue + } + } + + // check that signature is correct + if got := sig.String(); got != test.sig { + t.Errorf("package %s: got %s; want %s", name, got, test.sig) + } + } +} + func TestDefsInfo(t *testing.T) { var tests = []struct { src string diff --git a/src/go/types/api_typeparams.go b/src/go/types/api_typeparams.go deleted file mode 100644 index 864103df637..00000000000 --- a/src/go/types/api_typeparams.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2021 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 types - -import ( - "go/ast" -) - -type ( - Inferred = _Inferred - TypeParam = _TypeParam -) - -// NewTypeParam returns a new TypeParam. -func NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam { - return (*Checker)(nil).newTypeParam(obj, index, bound) -} - -func (s *Signature) TParams() []*TypeName { return s._TParams() } -func (s *Signature) SetTParams(tparams []*TypeName) { s._SetTParams(tparams) } - -func (t *Named) TParams() []*TypeName { return t._TParams() } -func (t *Named) TArgs() []Type { return t._TArgs() } -func (t *Named) SetTArgs(args []Type) { t._SetTArgs(args) } - -// Info is documented in api_notypeparams.go. -type Info struct { - Types map[ast.Expr]TypeAndValue - - // Inferred maps calls of parameterized functions that use type inference to - // the Inferred type arguments and signature of the function called. The - // recorded "call" expression may be an *ast.CallExpr (as in f(x)), or an - // *ast.IndexExpr (s in f[T]). - Inferred map[ast.Expr]_Inferred - - Defs map[*ast.Ident]Object - Uses map[*ast.Ident]Object - Implicits map[ast.Node]Object - Selections map[*ast.SelectorExpr]*Selection - Scopes map[ast.Node]*Scope - InitOrder []*Initializer -} - -func getInferred(info *Info) map[ast.Expr]_Inferred { - return info.Inferred -} diff --git a/src/go/types/api_typeparams_test.go b/src/go/types/api_typeparams_test.go deleted file mode 100644 index d9117b84129..00000000000 --- a/src/go/types/api_typeparams_test.go +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2021 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 types_test - -import ( - "fmt" - "go/ast" - "testing" - - . "go/types" -) - -func TestInferredInfo(t *testing.T) { - var tests = []struct { - src string - fun string - targs []string - sig string - }{ - {genericPkg + `p0; func f[T any](T); func _() { f(42) }`, - `f`, - []string{`int`}, - `func(int)`, - }, - {genericPkg + `p1; func f[T any](T) T; func _() { f('@') }`, - `f`, - []string{`rune`}, - `func(rune) rune`, - }, - {genericPkg + `p2; func f[T any](...T) T; func _() { f(0i) }`, - `f`, - []string{`complex128`}, - `func(...complex128) complex128`, - }, - {genericPkg + `p3; func f[A, B, C any](A, *B, []C); func _() { f(1.2, new(string), []byte{}) }`, - `f`, - []string{`float64`, `string`, `byte`}, - `func(float64, *string, []byte)`, - }, - {genericPkg + `p4; func f[A, B any](A, *B, ...[]B); func _() { f(1.2, new(byte)) }`, - `f`, - []string{`float64`, `byte`}, - `func(float64, *byte, ...[]byte)`, - }, - - {genericPkg + `s1; func f[T any, P interface{~*T}](x T); func _(x string) { f(x) }`, - `f`, - []string{`string`, `*string`}, - `func(x string)`, - }, - {genericPkg + `s2; func f[T any, P interface{~*T}](x []T); func _(x []int) { f(x) }`, - `f`, - []string{`int`, `*int`}, - `func(x []int)`, - }, - {genericPkg + `s3; type C[T any] interface{~chan<- T}; func f[T any, P C[T]](x []T); func _(x []int) { f(x) }`, - `f`, - []string{`int`, `chan<- int`}, - `func(x []int)`, - }, - {genericPkg + `s4; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T); func _(x []int) { f(x) }`, - `f`, - []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, - `func(x []int)`, - }, - - {genericPkg + `t1; func f[T any, P interface{~*T}]() T; func _() { _ = f[string] }`, - `f`, - []string{`string`, `*string`}, - `func() string`, - }, - {genericPkg + `t2; type C[T any] interface{~chan<- T}; func f[T any, P C[T]]() []T; func _() { _ = f[int] }`, - `f`, - []string{`int`, `chan<- int`}, - `func() []int`, - }, - {genericPkg + `t3; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T; func _() { _ = f[int] }`, - `f`, - []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, - `func() []int`, - }, - } - - for _, test := range tests { - info := Info{} - info.Inferred = make(map[ast.Expr]Inferred) - name, err := mayTypecheck(t, "InferredInfo", test.src, &info) - if err != nil { - t.Errorf("package %s: %v", name, err) - continue - } - - // look for inferred type arguments and signature - var targs []Type - var sig *Signature - for call, inf := range info.Inferred { - var fun ast.Expr - switch x := call.(type) { - case *ast.CallExpr: - fun = x.Fun - case *ast.IndexExpr: - fun = x.X - default: - panic(fmt.Sprintf("unexpected call expression type %T", call)) - } - if ExprString(fun) == test.fun { - targs = inf.TArgs - sig = inf.Sig - break - } - } - if targs == nil { - t.Errorf("package %s: no inferred information found for %s", name, test.fun) - continue - } - - // check that type arguments are correct - if len(targs) != len(test.targs) { - t.Errorf("package %s: got %d type arguments; want %d", name, len(targs), len(test.targs)) - continue - } - for i, targ := range targs { - if got := targ.String(); got != test.targs[i] { - t.Errorf("package %s, %d. type argument: got %s; want %s", name, i, got, test.targs[i]) - continue - } - } - - // check that signature is correct - if got := sig.String(); got != test.sig { - t.Errorf("package %s: got %s; want %s", name, got, test.sig) - } - } -} diff --git a/src/go/types/check.go b/src/go/types/check.go index 3e534de08a6..30aa8a9f0cb 100644 --- a/src/go/types/check.go +++ b/src/go/types/check.go @@ -412,8 +412,8 @@ func (check *Checker) recordCommaOkTypes(x ast.Expr, a [2]Type) { func (check *Checker) recordInferred(call ast.Expr, targs []Type, sig *Signature) { assert(call != nil) assert(sig != nil) - if m := getInferred(check.Info); m != nil { - m[call] = _Inferred{targs, sig} + if m := check.Info.Inferred; m != nil { + m[call] = Inferred{targs, sig} } } diff --git a/src/go/types/decl.go b/src/go/types/decl.go index 761418c4fb9..ac1b3815d22 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -740,7 +740,7 @@ func (check *Checker) collectTypeParams(list *ast.FieldList) (tparams []*TypeNam setBoundAt := func(at int, bound Type) { assert(IsInterface(bound)) - tparams[at].typ.(*_TypeParam).bound = bound + tparams[at].typ.(*TypeParam).bound = bound } index := 0 diff --git a/src/go/types/index.go b/src/go/types/index.go index 7c7aa382ff8..769626dcc2c 100644 --- a/src/go/types/index.go +++ b/src/go/types/index.go @@ -123,7 +123,7 @@ func (check *Checker) indexExpr(x *operand, expr *typeparams.IndexExpr) (isFuncI tkey = t.key e = t.elem nmaps++ - case *_TypeParam: + case *TypeParam: check.errorf(x, 0, "type of %s contains a type parameter - cannot index (implementation restriction)", x) case *instance: panic("unimplemented") @@ -246,7 +246,7 @@ func (check *Checker) sliceExpr(x *operand, e *ast.SliceExpr) { valid = true // x.typ doesn't change - case *Union, *_TypeParam: + case *Union, *TypeParam: check.errorf(x, 0, "generic slice expressions not yet implemented") x.mode = invalid return diff --git a/src/go/types/infer.go b/src/go/types/infer.go index ae53f68e48a..dda188ef10a 100644 --- a/src/go/types/infer.go +++ b/src/go/types/infer.go @@ -189,7 +189,7 @@ func (check *Checker) infer(posn positioner, tparams []*TypeName, targs []Type, // only parameter type it can possibly match against is a *TypeParam. // Thus, only consider untyped arguments for generic parameters that // are not of composite types and which don't have a type inferred yet. - if tpar, _ := par.typ.(*_TypeParam); tpar != nil && targs[tpar.index] == nil { + if tpar, _ := par.typ.(*TypeParam); tpar != nil && targs[tpar.index] == nil { arg := args[i] targ := Default(arg.typ) // The default type for an untyped nil is untyped nil. We must not @@ -333,7 +333,7 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { case *Named: return w.isParameterizedList(t.targs) - case *_TypeParam: + case *TypeParam: // t must be one of w.tparams return t.index < len(w.tparams) && w.tparams[t.index].typ == t @@ -382,7 +382,7 @@ func (check *Checker) inferB(tparams []*TypeName, targs []Type, report bool) (ty // Unify type parameters with their structural constraints, if any. for _, tpar := range tparams { - typ := tpar.typ.(*_TypeParam) + typ := tpar.typ.(*TypeParam) sbound := check.structuralType(typ.bound) if sbound != nil { if !u.unify(typ, sbound) { diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go index 4ce4b3217c9..cdd2f1bd517 100644 --- a/src/go/types/lookup.go +++ b/src/go/types/lookup.go @@ -107,7 +107,7 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack var next []embeddedType // embedded types found at current depth // look for (pkg, name) in all types at current depth - var tpar *_TypeParam // set if obj receiver is a type parameter + var tpar *TypeParam // set if obj receiver is a type parameter for _, e := range current { typ := e.typ @@ -196,7 +196,7 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack indirect = e.indirect } - case *_TypeParam: + case *TypeParam: if i, m := t.Bound().typeSet().LookupMethod(pkg, name); m != nil { assert(m.typ != nil) index = concat(e.index, i) diff --git a/src/go/types/methodset.go b/src/go/types/methodset.go index 71d634bf36e..53c0b71dfd2 100644 --- a/src/go/types/methodset.go +++ b/src/go/types/methodset.go @@ -130,7 +130,7 @@ func NewMethodSet(T Type) *MethodSet { // continue with underlying type, but only if it's not a type parameter // TODO(rFindley): should this use named.under()? Can there be a difference? typ = named.underlying - if _, ok := typ.(*_TypeParam); ok { + if _, ok := typ.(*TypeParam); ok { continue } } @@ -159,7 +159,7 @@ func NewMethodSet(T Type) *MethodSet { case *Interface: mset = mset.add(t.typeSet().methods, e.index, true, e.multiples) - case *_TypeParam: + case *TypeParam: mset = mset.add(t.Bound().typeSet().methods, e.index, true, e.multiples) } } diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index 7f6eee81209..2524ad0367e 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -10,7 +10,7 @@ package types // isNamed may be called with types that are not fully set up. func isNamed(typ Type) bool { switch typ.(type) { - case *Basic, *Named, *_TypeParam, *instance: + case *Basic, *Named, *TypeParam, *instance: return true } return false @@ -128,7 +128,7 @@ func comparable(T Type, seen map[Type]bool) bool { return t.underIs(func(t Type) bool { return comparable(t, seen) }) - case *_TypeParam: + case *TypeParam: return t.Bound().IsComparable() } return false @@ -356,7 +356,7 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { return x.obj == y.obj } - case *_TypeParam: + case *TypeParam: // nothing to do (x and y being equal is caught in the very beginning of this function) // case *instance: @@ -382,7 +382,7 @@ func (check *Checker) identicalTParams(x, y []*TypeName, cmpTags bool, p *ifaceP } for i, x := range x { y := y[i] - if !check.identical0(x.typ.(*_TypeParam).bound, y.typ.(*_TypeParam).bound, cmpTags, p) { + if !check.identical0(x.typ.(*TypeParam).bound, y.typ.(*TypeParam).bound, cmpTags, p) { return false } } diff --git a/src/go/types/sanitize.go b/src/go/types/sanitize.go index df09a6a38f6..62b91ef8c32 100644 --- a/src/go/types/sanitize.go +++ b/src/go/types/sanitize.go @@ -24,7 +24,7 @@ func sanitizeInfo(info *Info) { } } - inferred := getInferred(info) + inferred := info.Inferred for e, inf := range inferred { changed := false for i, targ := range inf.TArgs { @@ -147,7 +147,7 @@ func (s sanitizer) typ(typ Type) Type { s.typeList(t.targs) s.funcList(t.methods) - case *_TypeParam: + case *TypeParam: if bound := s.typ(t.bound); bound != t.bound { t.bound = bound } diff --git a/src/go/types/signature.go b/src/go/types/signature.go index 9be2cce752f..8048ba65194 100644 --- a/src/go/types/signature.go +++ b/src/go/types/signature.go @@ -70,7 +70,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast } smap := makeSubstMap(recvTParams, list) for i, tname := range sig.rparams { - bound := recvTParams[i].typ.(*_TypeParam).bound + bound := recvTParams[i].typ.(*TypeParam).bound // bound is (possibly) parameterized in the context of the // receiver type declaration. Substitute parameters for the // current context. @@ -78,7 +78,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast // (no bound == empty interface) if bound != nil { bound = check.subst(tname.pos, bound, smap) - tname.typ.(*_TypeParam).bound = bound + tname.typ.(*TypeParam).bound = bound } } } diff --git a/src/go/types/sizeof_test.go b/src/go/types/sizeof_test.go index 05a171f4989..8f5f42b4150 100644 --- a/src/go/types/sizeof_test.go +++ b/src/go/types/sizeof_test.go @@ -31,7 +31,7 @@ func TestSizeof(t *testing.T) { {Map{}, 16, 32}, {Chan{}, 12, 24}, {Named{}, 84, 160}, - {_TypeParam{}, 28, 48}, + {TypeParam{}, 28, 48}, {instance{}, 44, 88}, {top{}, 0, 0}, diff --git a/src/go/types/subst.go b/src/go/types/subst.go index 0e2e7f408ac..a4852ce86f9 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -22,21 +22,21 @@ type substMap struct { // TODO(gri) rewrite that code, get rid of this field, and make this // struct just the map (proj) targs []Type - proj map[*_TypeParam]Type + proj map[*TypeParam]Type } // makeSubstMap creates a new substitution map mapping tpars[i] to targs[i]. // If targs[i] is nil, tpars[i] is not substituted. func makeSubstMap(tpars []*TypeName, targs []Type) *substMap { assert(len(tpars) == len(targs)) - proj := make(map[*_TypeParam]Type, len(tpars)) + proj := make(map[*TypeParam]Type, len(tpars)) for i, tpar := range tpars { // We must expand type arguments otherwise *instance // types end up as components in composite types. // TODO(gri) explain why this causes problems, if it does targ := expand(targs[i]) // possibly nil targs[i] = targ - proj[tpar.typ.(*_TypeParam)] = targ + proj[tpar.typ.(*TypeParam)] = targ } return &substMap{targs, proj} } @@ -49,7 +49,7 @@ func (m *substMap) empty() bool { return len(m.proj) == 0 } -func (m *substMap) lookup(tpar *_TypeParam) Type { +func (m *substMap) lookup(tpar *TypeParam) Type { if t := m.proj[tpar]; t != nil { return t } @@ -128,7 +128,7 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist } // stop checking bounds after the first failure - if !check.satisfies(pos, targs[i], tname.typ.(*_TypeParam), smap) { + if !check.satisfies(pos, targs[i], tname.typ.(*TypeParam), smap) { break } } @@ -140,7 +140,7 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist // parameter tpar (after any of its type parameters have been substituted through smap). // A suitable error is reported if the result is false. // TODO(gri) This should be a method of interfaces or type sets. -func (check *Checker) satisfies(pos token.Pos, targ Type, tpar *_TypeParam, smap *substMap) bool { +func (check *Checker) satisfies(pos token.Pos, targ Type, tpar *TypeParam, smap *substMap) bool { iface := tpar.Bound() if iface.Empty() { return true // no type bound @@ -232,7 +232,7 @@ func (check *Checker) subst(pos token.Pos, typ Type, smap *substMap) Type { switch t := typ.(type) { case *Basic: return typ // nothing to do - case *_TypeParam: + case *TypeParam: return smap.lookup(t) } @@ -415,7 +415,7 @@ func (subst *subster) typ(typ Type) Type { return named - case *_TypeParam: + case *TypeParam: return subst.smap.lookup(t) case *instance: diff --git a/src/go/types/type.go b/src/go/types/type.go index 4dcc511b931..7445fa59abd 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -242,10 +242,10 @@ func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature { func (s *Signature) Recv() *Var { return s.recv } // _TParams returns the type parameters of signature s, or nil. -func (s *Signature) _TParams() []*TypeName { return s.tparams } +func (s *Signature) TParams() []*TypeName { return s.tparams } // _SetTParams sets the type parameters of signature s. -func (s *Signature) _SetTParams(tparams []*TypeName) { s.tparams = tparams } +func (s *Signature) SetTParams(tparams []*TypeName) { s.tparams = tparams } // Params returns the parameters of signature s, or nil. func (s *Signature) Params() *Tuple { return s.params } @@ -546,16 +546,16 @@ func (t *Named) _Orig() *Named { return t.orig } // _TParams returns the type parameters of the named type t, or nil. // The result is non-nil for an (originally) parameterized type even if it is instantiated. -func (t *Named) _TParams() []*TypeName { return t.expand().tparams } +func (t *Named) TParams() []*TypeName { return t.expand().tparams } // _SetTParams sets the type parameters of the named type t. -func (t *Named) _SetTParams(tparams []*TypeName) { t.expand().tparams = tparams } +func (t *Named) SetTParams(tparams []*TypeName) { t.expand().tparams = tparams } // _TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated. -func (t *Named) _TArgs() []Type { return t.targs } +func (t *Named) TArgs() []Type { return t.targs } // SetTArgs sets the type arguments of the named type t. -func (t *Named) _SetTArgs(args []Type) { t.targs = args } +func (t *Named) SetTArgs(args []Type) { t.targs = args } // NumMethods returns the number of explicit methods whose receiver is named type t. func (t *Named) NumMethods() int { return len(t.expand().methods) } @@ -591,8 +591,8 @@ var lastID uint32 // each call, starting with 1. It may be called concurrently. func nextID() uint64 { return uint64(atomic.AddUint32(&lastID, 1)) } -// A _TypeParam represents a type parameter type. -type _TypeParam struct { +// A TypeParam represents a type parameter type. +type TypeParam struct { check *Checker // for lazy type bound completion id uint64 // unique id, for debugging only obj *TypeName // corresponding type name @@ -600,7 +600,12 @@ type _TypeParam struct { bound Type // *Named or *Interface; underlying type is always *Interface } -func (check *Checker) newTypeParam(obj *TypeName, index int, bound Type) *_TypeParam { +// NewTypeParam returns a new TypeParam. +func NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam { + return (*Checker)(nil).newTypeParam(obj, index, bound) +} + +func (check *Checker) newTypeParam(obj *TypeName, index int, bound Type) *TypeParam { assert(bound != nil) // Always increment lastID, even if it is not used. @@ -610,14 +615,14 @@ func (check *Checker) newTypeParam(obj *TypeName, index int, bound Type) *_TypeP id = check.nextID } - typ := &_TypeParam{check: check, id: id, obj: obj, index: index, bound: bound} + typ := &TypeParam{check: check, id: id, obj: obj, index: index, bound: bound} if obj.typ == nil { obj.typ = typ } return typ } -func (t *_TypeParam) Bound() *Interface { +func (t *TypeParam) Bound() *Interface { iface := asInterface(t.bound) // use the type bound position if we have one pos := token.NoPos @@ -717,36 +722,36 @@ type top struct{} var theTop = &top{} // Type-specific implementations of Underlying. -func (t *Basic) Underlying() Type { return t } -func (t *Array) Underlying() Type { return t } -func (t *Slice) Underlying() Type { return t } -func (t *Struct) Underlying() Type { return t } -func (t *Pointer) Underlying() Type { return t } -func (t *Tuple) Underlying() Type { return t } -func (t *Signature) Underlying() Type { return t } -func (t *Interface) Underlying() Type { return t } -func (t *Map) Underlying() Type { return t } -func (t *Chan) Underlying() Type { return t } -func (t *Named) Underlying() Type { return t.expand().underlying } -func (t *_TypeParam) Underlying() Type { return t } -func (t *instance) Underlying() Type { return t } -func (t *top) Underlying() Type { return t } +func (t *Basic) Underlying() Type { return t } +func (t *Array) Underlying() Type { return t } +func (t *Slice) Underlying() Type { return t } +func (t *Struct) Underlying() Type { return t } +func (t *Pointer) Underlying() Type { return t } +func (t *Tuple) Underlying() Type { return t } +func (t *Signature) Underlying() Type { return t } +func (t *Interface) Underlying() Type { return t } +func (t *Map) Underlying() Type { return t } +func (t *Chan) Underlying() Type { return t } +func (t *Named) Underlying() Type { return t.expand().underlying } +func (t *TypeParam) Underlying() Type { return t } +func (t *instance) Underlying() Type { return t } +func (t *top) Underlying() Type { return t } // Type-specific implementations of String. -func (t *Basic) String() string { return TypeString(t, nil) } -func (t *Array) String() string { return TypeString(t, nil) } -func (t *Slice) String() string { return TypeString(t, nil) } -func (t *Struct) String() string { return TypeString(t, nil) } -func (t *Pointer) String() string { return TypeString(t, nil) } -func (t *Tuple) String() string { return TypeString(t, nil) } -func (t *Signature) String() string { return TypeString(t, nil) } -func (t *Interface) String() string { return TypeString(t, nil) } -func (t *Map) String() string { return TypeString(t, nil) } -func (t *Chan) String() string { return TypeString(t, nil) } -func (t *Named) String() string { return TypeString(t, nil) } -func (t *_TypeParam) String() string { return TypeString(t, nil) } -func (t *instance) String() string { return TypeString(t, nil) } -func (t *top) String() string { return TypeString(t, nil) } +func (t *Basic) String() string { return TypeString(t, nil) } +func (t *Array) String() string { return TypeString(t, nil) } +func (t *Slice) String() string { return TypeString(t, nil) } +func (t *Struct) String() string { return TypeString(t, nil) } +func (t *Pointer) String() string { return TypeString(t, nil) } +func (t *Tuple) String() string { return TypeString(t, nil) } +func (t *Signature) String() string { return TypeString(t, nil) } +func (t *Interface) String() string { return TypeString(t, nil) } +func (t *Map) String() string { return TypeString(t, nil) } +func (t *Chan) String() string { return TypeString(t, nil) } +func (t *Named) String() string { return TypeString(t, nil) } +func (t *TypeParam) String() string { return TypeString(t, nil) } +func (t *instance) String() string { return TypeString(t, nil) } +func (t *top) String() string { return TypeString(t, nil) } // under returns the true expanded underlying type. // If it doesn't exist, the result is Typ[Invalid]. @@ -827,7 +832,7 @@ func asNamed(t Type) *Named { return e } -func asTypeParam(t Type) *_TypeParam { - u, _ := under(t).(*_TypeParam) +func asTypeParam(t Type) *TypeParam { + u, _ := under(t).(*TypeParam) return u } diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go index fb398de502a..d234d86e61d 100644 --- a/src/go/types/typestring.go +++ b/src/go/types/typestring.go @@ -281,7 +281,7 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { writeTParamList(buf, t.TParams(), qf, visited) } - case *_TypeParam: + case *TypeParam: s := "?" if t.obj != nil { s = t.obj.name @@ -321,7 +321,7 @@ func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited for i, p := range list { // TODO(rFindley) support 'any' sugar here. var b Type = &emptyInterface - if t, _ := p.typ.(*_TypeParam); t != nil && t.bound != nil { + if t, _ := p.typ.(*TypeParam); t != nil && t.bound != nil { b = t.bound } if i > 0 { @@ -334,7 +334,7 @@ func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited } prev = b - if t, _ := p.typ.(*_TypeParam); t != nil { + if t, _ := p.typ.(*TypeParam); t != nil { writeType(buf, t, qf, visited) } else { buf.WriteString(p.name) diff --git a/src/go/types/unify.go b/src/go/types/unify.go index bc611db3479..43189d3b69a 100644 --- a/src/go/types/unify.go +++ b/src/go/types/unify.go @@ -99,7 +99,7 @@ func (d *tparamsList) init(tparams []*TypeName) { } if debug { for i, tpar := range tparams { - assert(i == tpar.typ.(*_TypeParam).index) + assert(i == tpar.typ.(*TypeParam).index) } } d.tparams = tparams @@ -147,7 +147,7 @@ func (u *unifier) join(i, j int) bool { // If typ is a type parameter of d, index returns the type parameter index. // Otherwise, the result is < 0. func (d *tparamsList) index(typ Type) int { - if t, ok := typ.(*_TypeParam); ok { + if t, ok := typ.(*TypeParam); ok { if i := t.index; i < len(d.tparams) && d.tparams[i].typ == t { return i } @@ -439,7 +439,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool { } } - case *_TypeParam: + case *TypeParam: // Two type parameters (which are not part of the type parameters of the // enclosing type as those are handled in the beginning of this function) // are identical if they originate in the same declaration. From b98b8b9b5be2ccbfc5aaf2a983fe5d439f91bc94 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 09:21:36 -0400 Subject: [PATCH 697/940] [dev.typeparams] go/types: remove unused *Checker arguments (cleanup) This is a straightforward port of CL 331512 to go/types. API usage in methodset.go was also updated. Change-Id: I6701265c9d2ae40eb9aa0ea5f00c98ce3516edab Reviewed-on: https://go-review.googlesource.com/c/go/+/335009 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/api.go | 4 ++-- src/go/types/builtins.go | 6 ++--- src/go/types/call.go | 4 ++-- src/go/types/conversions.go | 6 ++--- src/go/types/expr.go | 6 ++--- src/go/types/infer.go | 4 ++-- src/go/types/interface.go | 2 +- src/go/types/lookup.go | 45 +++++++++++++++---------------------- src/go/types/methodset.go | 7 +----- src/go/types/operand.go | 8 +++---- src/go/types/predicates.go | 40 ++++++++++++--------------------- src/go/types/stmt.go | 4 ++-- src/go/types/unify.go | 9 ++++---- 13 files changed, 59 insertions(+), 86 deletions(-) diff --git a/src/go/types/api.go b/src/go/types/api.go index 2815a6d0274..6c0ceb7b7c5 100644 --- a/src/go/types/api.go +++ b/src/go/types/api.go @@ -422,11 +422,11 @@ func Implements(V Type, T *Interface) bool { // Identical reports whether x and y are identical types. // Receivers of Signature types are ignored. func Identical(x, y Type) bool { - return (*Checker)(nil).identical(x, y) + return identical(x, y, true, nil) } // IdenticalIgnoreTags reports whether x and y are identical types if tags are ignored. // Receivers of Signature types are ignored. func IdenticalIgnoreTags(x, y Type) bool { - return (*Checker)(nil).identicalIgnoreTags(x, y) + return identical(x, y, false, nil) } diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index 5670790856a..e976e76cf1d 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -286,7 +286,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b } // both argument types must be identical - if !check.identical(x.typ, y.typ) { + if !Identical(x.typ, y.typ) { check.invalidArg(x, _InvalidComplex, "mismatched types %s and %s", x.typ, y.typ) return } @@ -351,7 +351,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b return } - if !check.identical(dst, src) { + if !Identical(dst, src) { check.invalidArg(x, _InvalidCopy, "arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src) return } @@ -644,7 +644,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b base := derefStructPtr(x.typ) sel := selx.Sel.Name - obj, index, indirect := check.lookupFieldOrMethod(base, false, check.pkg, sel) + obj, index, indirect := LookupFieldOrMethod(base, false, check.pkg, sel) switch obj.(type) { case nil: check.invalidArg(x, _MissingFieldOrMethod, "%s has no single field %s", base, sel) diff --git a/src/go/types/call.go b/src/go/types/call.go index cef5e9fc590..4e5b98a12e5 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -470,7 +470,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) { check.instantiatedOperand(x) - obj, index, indirect = check.lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel) + obj, index, indirect = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel) if obj == nil { switch { case index != nil: @@ -500,7 +500,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) { } else { changeCase = string(unicode.ToUpper(r)) + sel[1:] } - if obj, _, _ = check.lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, changeCase); obj != nil { + if obj, _, _ = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, changeCase); obj != nil { why += ", but does have " + changeCase } } diff --git a/src/go/types/conversions.go b/src/go/types/conversions.go index ad6d3eef102..a1fcdd4fd8d 100644 --- a/src/go/types/conversions.go +++ b/src/go/types/conversions.go @@ -94,7 +94,7 @@ func (x *operand) convertibleTo(check *Checker, T Type, reason *string) bool { V := x.typ Vu := under(V) Tu := under(T) - if check.identicalIgnoreTags(Vu, Tu) { + if IdenticalIgnoreTags(Vu, Tu) { return true } @@ -102,7 +102,7 @@ func (x *operand) convertibleTo(check *Checker, T Type, reason *string) bool { // have identical underlying types if tags are ignored" if V, ok := V.(*Pointer); ok { if T, ok := T.(*Pointer); ok { - if check.identicalIgnoreTags(under(V.base), under(T.base)) { + if IdenticalIgnoreTags(under(V.base), under(T.base)) { return true } } @@ -143,7 +143,7 @@ func (x *operand) convertibleTo(check *Checker, T Type, reason *string) bool { if s := asSlice(V); s != nil { if p := asPointer(T); p != nil { if a := asArray(p.Elem()); a != nil { - if check.identical(s.Elem(), a.Elem()) { + if Identical(s.Elem(), a.Elem()) { if check == nil || check.allowVersion(check.pkg, 1, 17) { return true } diff --git a/src/go/types/expr.go b/src/go/types/expr.go index c8adea45e29..edd7caf1c93 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -955,7 +955,7 @@ func (check *Checker) binary(x *operand, e ast.Expr, lhs, rhs ast.Expr, op token return } - if !check.identical(x.typ, y.typ) { + if !Identical(x.typ, y.typ) { // only report an error if we have valid types // (otherwise we had an error reported elsewhere already) if x.typ != Typ[Invalid] && y.typ != Typ[Invalid] { @@ -1281,7 +1281,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind { xkey := keyVal(x.val) if asInterface(utyp.key) != nil { for _, vtyp := range visited[xkey] { - if check.identical(vtyp, x.typ) { + if Identical(vtyp, x.typ) { duplicate = true break } @@ -1468,7 +1468,7 @@ func (check *Checker) typeAssertion(at positioner, x *operand, xtyp *Interface, } var msg string if wrongType != nil { - if check.identical(method.typ, wrongType.typ) { + if Identical(method.typ, wrongType.typ) { msg = fmt.Sprintf("missing method %s (%s has pointer receiver)", method.name, method.name) } else { msg = fmt.Sprintf("wrong type for method %s (have %s, want %s)", method.name, wrongType.typ, method.typ) diff --git a/src/go/types/infer.go b/src/go/types/infer.go index dda188ef10a..9faf7b75203 100644 --- a/src/go/types/infer.go +++ b/src/go/types/infer.go @@ -93,7 +93,7 @@ func (check *Checker) infer(posn positioner, tparams []*TypeName, targs []Type, // Unify parameter and argument types for generic parameters with typed arguments // and collect the indices of generic parameters with untyped arguments. // Terminology: generic parameter = function parameter with a type-parameterized type - u := newUnifier(check, false) + u := newUnifier(false) u.x.init(tparams) // Set the type arguments which we know already. @@ -369,7 +369,7 @@ func (check *Checker) inferB(tparams []*TypeName, targs []Type, report bool) (ty // Setup bidirectional unification between those structural bounds // and the corresponding type arguments (which may be nil!). - u := newUnifier(check, false) + u := newUnifier(false) u.x.init(tparams) u.y = u.x // type parameters between LHS and RHS of unification are identical diff --git a/src/go/types/interface.go b/src/go/types/interface.go index 3a4da569ab2..73fde3421a2 100644 --- a/src/go/types/interface.go +++ b/src/go/types/interface.go @@ -212,7 +212,7 @@ func newTypeSet(check *Checker, pos token.Pos, ityp *Interface) *TypeSet { } // check != nil check.later(func() { - if !check.allowVersion(m.pkg, 1, 14) || !check.identical(m.typ, other.Type()) { + if !check.allowVersion(m.pkg, 1, 14) || !Identical(m.typ, other.Type()) { check.errorf(atPos(pos), _DuplicateDecl, "duplicate method %s", m.name) check.errorf(atPos(mpos[other.(*Func)]), _DuplicateDecl, "\tother declaration of %s", m.name) // secondary error, \t indented } diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go index cdd2f1bd517..70e3b4281d7 100644 --- a/src/go/types/lookup.go +++ b/src/go/types/lookup.go @@ -8,6 +8,11 @@ package types import "go/token" +// Internal use of LookupFieldOrMethod: If the obj result is a method +// associated with a concrete (non-interface) type, the method's signature +// may not be fully set up. Call Checker.objDecl(obj, nil) before accessing +// the method's type. + // LookupFieldOrMethod looks up a field or method with given package and name // in T and returns the corresponding *Var or *Func, an index sequence, and a // bool indicating if there were any pointer indirections on the path to the @@ -35,19 +40,6 @@ import "go/token" // the method's formal receiver base type, nor was the receiver addressable. // func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) { - return (*Checker)(nil).lookupFieldOrMethod(T, addressable, pkg, name) -} - -// Internal use of Checker.lookupFieldOrMethod: If the obj result is a method -// associated with a concrete (non-interface) type, the method's signature -// may not be fully set up. Call Checker.objDecl(obj, nil) before accessing -// the method's type. -// TODO(gri) Now that we provide the *Checker, we can probably remove this -// caveat by calling Checker.objDecl from lookupFieldOrMethod. Investigate. - -// lookupFieldOrMethod is like the external version but completes interfaces -// as necessary. -func (check *Checker) lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) { // Methods cannot be associated to a named pointer type // (spec: "The type denoted by T is called the receiver base type; // it must not be a pointer or interface type and it must be declared @@ -57,7 +49,7 @@ func (check *Checker) lookupFieldOrMethod(T Type, addressable bool, pkg *Package // not have found it for T (see also issue 8590). if t := asNamed(T); t != nil { if p, _ := t.Underlying().(*Pointer); p != nil { - obj, index, indirect = check.rawLookupFieldOrMethod(p, false, pkg, name) + obj, index, indirect = lookupFieldOrMethod(p, false, pkg, name) if _, ok := obj.(*Func); ok { return nil, nil, false } @@ -65,7 +57,7 @@ func (check *Checker) lookupFieldOrMethod(T Type, addressable bool, pkg *Package } } - return check.rawLookupFieldOrMethod(T, addressable, pkg, name) + return lookupFieldOrMethod(T, addressable, pkg, name) } // TODO(gri) The named type consolidation and seen maps below must be @@ -73,10 +65,9 @@ func (check *Checker) lookupFieldOrMethod(T Type, addressable bool, pkg *Package // types always have only one representation (even when imported // indirectly via different packages.) -// rawLookupFieldOrMethod should only be called by lookupFieldOrMethod and missingMethod. -func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) { +// lookupFieldOrMethod should only be called by LookupFieldOrMethod and missingMethod. +func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) { // WARNING: The code in this function is extremely subtle - do not modify casually! - // This function and NewMethodSet should be kept in sync. if name == "_" { return // blank fields/methods are never found @@ -226,7 +217,7 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack return } - current = check.consolidateMultiples(next) + current = consolidateMultiples(next) } return nil, nil, false // not found @@ -243,7 +234,7 @@ type embeddedType struct { // consolidateMultiples collects multiple list entries with the same type // into a single entry marked as containing multiples. The result is the // consolidated list. -func (check *Checker) consolidateMultiples(list []embeddedType) []embeddedType { +func consolidateMultiples(list []embeddedType) []embeddedType { if len(list) <= 1 { return list // at most one entry - nothing to do } @@ -251,7 +242,7 @@ func (check *Checker) consolidateMultiples(list []embeddedType) []embeddedType { n := 0 // number of entries w/ unique type prev := make(map[Type]int) // index at which type was previously seen for _, e := range list { - if i, found := check.lookupType(prev, e.typ); found { + if i, found := lookupType(prev, e.typ); found { list[i].multiples = true // ignore this entry } else { @@ -263,14 +254,14 @@ func (check *Checker) consolidateMultiples(list []embeddedType) []embeddedType { return list[:n] } -func (check *Checker) lookupType(m map[Type]int, typ Type) (int, bool) { +func lookupType(m map[Type]int, typ Type) (int, bool) { // fast path: maybe the types are equal if i, found := m[typ]; found { return i, true } for t, i := range m { - if check.identical(t, typ) { + if Identical(t, typ) { return i, true } } @@ -336,7 +327,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // to see if they can be made to match. // TODO(gri) is this always correct? what about type bounds? // (Alternative is to rename/subst type parameters and compare.) - u := newUnifier(check, true) + u := newUnifier(true) u.x.init(ftyp.tparams) if !u.unify(ftyp, mtyp) { return m, f @@ -351,12 +342,12 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, Vn := asNamed(Vd) for _, m := range T.typeSet().methods { // TODO(gri) should this be calling lookupFieldOrMethod instead (and why not)? - obj, _, _ := check.rawLookupFieldOrMethod(V, false, m.pkg, m.name) + obj, _, _ := lookupFieldOrMethod(V, false, m.pkg, m.name) // Check if *V implements this method of T. if obj == nil { ptr := NewPointer(V) - obj, _, _ = check.rawLookupFieldOrMethod(ptr, false, m.pkg, m.name) + obj, _, _ = lookupFieldOrMethod(ptr, false, m.pkg, m.name) if obj != nil { return m, obj.(*Func) } @@ -412,7 +403,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // to see if they can be made to match. // TODO(gri) is this always correct? what about type bounds? // (Alternative is to rename/subst type parameters and compare.) - u := newUnifier(check, true) + u := newUnifier(true) u.x.init(ftyp.rparams) if !u.unify(ftyp, mtyp) { return m, f diff --git a/src/go/types/methodset.go b/src/go/types/methodset.go index 53c0b71dfd2..491917d6bcd 100644 --- a/src/go/types/methodset.go +++ b/src/go/types/methodset.go @@ -190,12 +190,7 @@ func NewMethodSet(T Type) *MethodSet { } } - // It's ok to call consolidateMultiples with a nil *Checker because - // MethodSets are not used internally (outside debug mode). When used - // externally, interfaces are expected to be completed and then we do - // not need a *Checker to complete them when (indirectly) calling - // Checker.identical via consolidateMultiples. - current = (*Checker)(nil).consolidateMultiples(next) + current = consolidateMultiples(next) } if len(base) == 0 { diff --git a/src/go/types/operand.go b/src/go/types/operand.go index 81dc66e800e..1d0f5b80b6c 100644 --- a/src/go/types/operand.go +++ b/src/go/types/operand.go @@ -240,7 +240,7 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er } // x's type is identical to T - if check.identical(V, T) { + if Identical(V, T) { return true, 0 } @@ -272,7 +272,7 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er // x's type V and T have identical underlying types // and at least one of V or T is not a named type - if check.identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) { + if Identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) { return true, 0 } @@ -281,7 +281,7 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er if m, wrongType := check.missingMethod(V, Ti, true); m != nil /* Implements(V, Ti) */ { if reason != nil { if wrongType != nil { - if check.identical(m.typ, wrongType.typ) { + if Identical(m.typ, wrongType.typ) { *reason = fmt.Sprintf("missing method %s (%s has pointer receiver)", m.name, m.name) } else { *reason = fmt.Sprintf("wrong type for method %s (have %s, want %s)", m.Name(), wrongType.typ, m.typ) @@ -300,7 +300,7 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er // type, x's type V and T have identical element types, // and at least one of V or T is not a named type if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv { - if Tc, ok := Tu.(*Chan); ok && check.identical(Vc.elem, Tc.elem) { + if Tc, ok := Tu.(*Chan); ok && Identical(Vc.elem, Tc.elem) { return !isNamed(V) || !isNamed(T), _InvalidChanAssign } } diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index 2524ad0367e..c3c168647da 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -147,18 +147,6 @@ func hasNil(typ Type) bool { return false } -// identical reports whether x and y are identical types. -// Receivers of Signature types are ignored. -func (check *Checker) identical(x, y Type) bool { - return check.identical0(x, y, true, nil) -} - -// identicalIgnoreTags reports whether x and y are identical types if tags are ignored. -// Receivers of Signature types are ignored. -func (check *Checker) identicalIgnoreTags(x, y Type) bool { - return check.identical0(x, y, false, nil) -} - // An ifacePair is a node in a stack of interface type pairs compared for identity. type ifacePair struct { x, y *Interface @@ -170,7 +158,7 @@ func (p *ifacePair) identical(q *ifacePair) bool { } // For changes to this code the corresponding changes should be made to unifier.nify. -func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { +func identical(x, y Type, cmpTags bool, p *ifacePair) bool { // types must be expanded for comparison x = expandf(x) y = expandf(y) @@ -194,13 +182,13 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { if y, ok := y.(*Array); ok { // If one or both array lengths are unknown (< 0) due to some error, // assume they are the same to avoid spurious follow-on errors. - return (x.len < 0 || y.len < 0 || x.len == y.len) && check.identical0(x.elem, y.elem, cmpTags, p) + return (x.len < 0 || y.len < 0 || x.len == y.len) && identical(x.elem, y.elem, cmpTags, p) } case *Slice: // Two slice types are identical if they have identical element types. if y, ok := y.(*Slice); ok { - return check.identical0(x.elem, y.elem, cmpTags, p) + return identical(x.elem, y.elem, cmpTags, p) } case *Struct: @@ -215,7 +203,7 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { if f.embedded != g.embedded || cmpTags && x.Tag(i) != y.Tag(i) || !f.sameId(g.pkg, g.name) || - !check.identical0(f.typ, g.typ, cmpTags, p) { + !identical(f.typ, g.typ, cmpTags, p) { return false } } @@ -226,7 +214,7 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { case *Pointer: // Two pointer types are identical if they have identical base types. if y, ok := y.(*Pointer); ok { - return check.identical0(x.base, y.base, cmpTags, p) + return identical(x.base, y.base, cmpTags, p) } case *Tuple: @@ -237,7 +225,7 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { if x != nil { for i, v := range x.vars { w := y.vars[i] - if !check.identical0(v.typ, w.typ, cmpTags, p) { + if !identical(v.typ, w.typ, cmpTags, p) { return false } } @@ -255,9 +243,9 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { // parameter names. if y, ok := y.(*Signature); ok { return x.variadic == y.variadic && - check.identicalTParams(x.tparams, y.tparams, cmpTags, p) && - check.identical0(x.params, y.params, cmpTags, p) && - check.identical0(x.results, y.results, cmpTags, p) + identicalTParams(x.tparams, y.tparams, cmpTags, p) && + identical(x.params, y.params, cmpTags, p) && + identical(x.results, y.results, cmpTags, p) } case *Union: @@ -325,7 +313,7 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { } for i, f := range a { g := b[i] - if f.Id() != g.Id() || !check.identical0(f.typ, g.typ, cmpTags, q) { + if f.Id() != g.Id() || !identical(f.typ, g.typ, cmpTags, q) { return false } } @@ -336,14 +324,14 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { case *Map: // Two map types are identical if they have identical key and value types. if y, ok := y.(*Map); ok { - return check.identical0(x.key, y.key, cmpTags, p) && check.identical0(x.elem, y.elem, cmpTags, p) + return identical(x.key, y.key, cmpTags, p) && identical(x.elem, y.elem, cmpTags, p) } case *Chan: // Two channel types are identical if they have identical value types // and the same direction. if y, ok := y.(*Chan); ok { - return x.dir == y.dir && check.identical0(x.elem, y.elem, cmpTags, p) + return x.dir == y.dir && identical(x.elem, y.elem, cmpTags, p) } case *Named: @@ -376,13 +364,13 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { return false } -func (check *Checker) identicalTParams(x, y []*TypeName, cmpTags bool, p *ifacePair) bool { +func identicalTParams(x, y []*TypeName, cmpTags bool, p *ifacePair) bool { if len(x) != len(y) { return false } for i, x := range x { y := y[i] - if !check.identical0(x.typ.(*TypeParam).bound, y.typ.(*TypeParam).bound, cmpTags, p) { + if !identical(x.typ.(*TypeParam).bound, y.typ.(*TypeParam).bound, cmpTags, p) { return false } } diff --git a/src/go/types/stmt.go b/src/go/types/stmt.go index afef8334900..53fccb0a640 100644 --- a/src/go/types/stmt.go +++ b/src/go/types/stmt.go @@ -265,7 +265,7 @@ L: // look for duplicate types for a given value // (quadratic algorithm, but these lists tend to be very short) for _, vt := range seen[val] { - if check.identical(v.typ, vt.typ) { + if Identical(v.typ, vt.typ) { check.errorf(&v, _DuplicateCase, "duplicate case %s in expression switch", &v) check.error(atPos(vt.pos), _DuplicateCase, "\tprevious case") // secondary error, \t indented continue L @@ -289,7 +289,7 @@ L: // look for duplicate types // (quadratic algorithm, but type switches tend to be reasonably small) for t, other := range seen { - if T == nil && t == nil || T != nil && t != nil && check.identical(T, t) { + if T == nil && t == nil || T != nil && t != nil && Identical(T, t) { // talk about "case" rather than "type" because of nil case Ts := "nil" if T != nil { diff --git a/src/go/types/unify.go b/src/go/types/unify.go index 43189d3b69a..762000db32c 100644 --- a/src/go/types/unify.go +++ b/src/go/types/unify.go @@ -8,6 +8,7 @@ package types import ( "bytes" + "fmt" "sort" ) @@ -37,7 +38,6 @@ import ( // and the respective types inferred for each type parameter. // A unifier is created by calling newUnifier. type unifier struct { - check *Checker exact bool x, y tparamsList // x and y must initialized via tparamsList.init types []Type // inferred types, shared by x and y @@ -48,8 +48,8 @@ type unifier struct { // exactly. If exact is not set, a named type's underlying type // is considered if unification would fail otherwise, and the // direction of channels is ignored. -func newUnifier(check *Checker, exact bool) *unifier { - u := &unifier{check: check, exact: exact} +func newUnifier(exact bool) *unifier { + u := &unifier{exact: exact} u.x.unifier = u u.y.unifier = u return u @@ -452,8 +452,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool { // avoid a crash in case of nil type default: - u.check.dump("### u.nify(%s, %s), u.x.tparams = %s", x, y, u.x.tparams) - unreachable() + panic(fmt.Sprintf("### u.nify(%s, %s), u.x.tparams = %s", x, y, u.x.tparams)) } return false From fe4f13404d553958c5b5889ce8b94144798d07bf Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 09:34:34 -0400 Subject: [PATCH 698/940] [dev.typeparams] go/types: move embedding positions from Checker to Interface This is a straightforward port of CL 331514 to go/types, with minor adjustments for the different position API. Change-Id: I714b3f1cd5a0e8d249912bb589d456885a87e167 Reviewed-on: https://go-review.googlesource.com/c/go/+/335030 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/check.go | 12 ++++----- src/go/types/interface.go | 50 ++++++++++++++----------------------- src/go/types/sizeof_test.go | 2 +- src/go/types/subst.go | 1 - src/go/types/type.go | 10 ++++---- 5 files changed, 30 insertions(+), 45 deletions(-) diff --git a/src/go/types/check.go b/src/go/types/check.go index 30aa8a9f0cb..4398475501c 100644 --- a/src/go/types/check.go +++ b/src/go/types/check.go @@ -85,12 +85,11 @@ type Checker struct { fset *token.FileSet pkg *Package *Info - version version // accepted language version - nextID uint64 // unique Id for type parameters (first valid Id is 1) - objMap map[Object]*declInfo // maps package-level objects and (non-interface) methods to declaration info - impMap map[importKey]*Package // maps (import path, source directory) to (complete or fake) package - posMap map[*Interface][]token.Pos // maps interface types to lists of embedded interface positions - typMap map[string]*Named // maps an instantiated named type hash to a *Named type + version version // accepted language version + nextID uint64 // unique Id for type parameters (first valid Id is 1) + objMap map[Object]*declInfo // maps package-level objects and (non-interface) methods to declaration info + impMap map[importKey]*Package // maps (import path, source directory) to (complete or fake) package + typMap map[string]*Named // maps an instantiated named type hash to a *Named type // pkgPathMap maps package names to the set of distinct import paths we've // seen for that name, anywhere in the import graph. It is used for @@ -193,7 +192,6 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch version: version, objMap: make(map[Object]*declInfo), impMap: make(map[importKey]*Package), - posMap: make(map[*Interface][]token.Pos), typMap: make(map[string]*Named), } } diff --git a/src/go/types/interface.go b/src/go/types/interface.go index 73fde3421a2..ccc95dd8416 100644 --- a/src/go/types/interface.go +++ b/src/go/types/interface.go @@ -16,11 +16,18 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d var tlist []ast.Expr var tname *ast.Ident // "type" name of first entry in a type list declaration + addEmbedded := func(pos token.Pos, typ Type) { + ityp.embeddeds = append(ityp.embeddeds, typ) + if ityp.embedPos == nil { + ityp.embedPos = new([]token.Pos) + } + *ityp.embedPos = append(*ityp.embedPos, pos) + } + for _, f := range iface.Methods.List { if len(f.Names) == 0 { // We have an embedded type; possibly a union of types. - ityp.embeddeds = append(ityp.embeddeds, parseUnion(check, flattenUnion(nil, f.Type))) - check.posMap[ityp] = append(check.posMap[ityp], f.Type.Pos()) + addEmbedded(f.Type.Pos(), parseUnion(check, flattenUnion(nil, f.Type))) continue } @@ -92,10 +99,9 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d // type constraints if tlist != nil { - ityp.embeddeds = append(ityp.embeddeds, parseUnion(check, tlist)) - // Types T in a type list are added as ~T expressions but we don't - // have the position of the '~'. Use the first type position instead. - check.posMap[ityp] = append(check.posMap[ityp], tlist[0].(*ast.UnaryExpr).X.Pos()) + // TODO(rfindley): this differs from types2 due to the use of Pos() below, + // which should actually be on the ~. Confirm that this position is correct. + addEmbedded(tlist[0].Pos(), parseUnion(check, tlist)) } // All methods and embedded elements for this interface are collected; @@ -110,7 +116,7 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d // sort for API stability sortMethods(ityp.methods) - sortTypes(ityp.embeddeds) + // (don't sort embeddeds: they must correspond to *embedPos entries) // Compute type set with a non-nil *Checker as soon as possible // to report any errors. Subsequent uses of type sets should be @@ -226,14 +232,13 @@ func newTypeSet(check *Checker, pos token.Pos, ityp *Interface) *TypeSet { // collect embedded elements var allTypes Type - var posList []token.Pos - if check != nil { - posList = check.posMap[ityp] - } for i, typ := range ityp.embeddeds { + // The embedding position is nil for imported interfaces + // and also for interface copies after substitution (but + // in that case we don't need to report errors again). var pos token.Pos // embedding position - if posList != nil { - pos = posList[i] + if ityp.embedPos != nil { + pos = (*ityp.embedPos)[i] } var types Type switch t := under(typ).(type) { @@ -268,6 +273,7 @@ func newTypeSet(check *Checker, pos token.Pos, ityp *Interface) *TypeSet { } allTypes = intersect(allTypes, types) } + ityp.embedPos = nil // not needed anymore (errors have been reported) // process todo's (this only happens if check == nil) for i := 0; i < len(todo); i += 2 { @@ -287,24 +293,6 @@ func newTypeSet(check *Checker, pos token.Pos, ityp *Interface) *TypeSet { return ityp.tset } -func sortTypes(list []Type) { - sort.Stable(byUniqueTypeName(list)) -} - -// byUniqueTypeName named type lists can be sorted by their unique type names. -type byUniqueTypeName []Type - -func (a byUniqueTypeName) Len() int { return len(a) } -func (a byUniqueTypeName) Less(i, j int) bool { return sortName(a[i]) < sortName(a[j]) } -func (a byUniqueTypeName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } - -func sortName(t Type) string { - if named := asNamed(t); named != nil { - return named.obj.Id() - } - return "" -} - func sortMethods(list []*Func) { sort.Sort(byUniqueMethodName(list)) } diff --git a/src/go/types/sizeof_test.go b/src/go/types/sizeof_test.go index 8f5f42b4150..b8f191ee867 100644 --- a/src/go/types/sizeof_test.go +++ b/src/go/types/sizeof_test.go @@ -27,7 +27,7 @@ func TestSizeof(t *testing.T) { {Tuple{}, 12, 24}, {Signature{}, 44, 88}, {Union{}, 24, 48}, - {Interface{}, 40, 80}, + {Interface{}, 44, 88}, {Map{}, 16, 32}, {Chan{}, 12, 24}, {Named{}, 84, 160}, diff --git a/src/go/types/subst.go b/src/go/types/subst.go index a4852ce86f9..41ffcd0d1e4 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -320,7 +320,6 @@ func (subst *subster) typ(typ Type) Type { if subst.check == nil { panic("internal error: cannot instantiate interfaces yet") } - subst.check.posMap[iface] = subst.check.posMap[t] // satisfy completeInterface requirement return iface } diff --git a/src/go/types/type.go b/src/go/types/type.go index 7445fa59abd..c1b307b642e 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -258,10 +258,11 @@ func (s *Signature) Variadic() bool { return s.variadic } // An Interface represents an interface type. type Interface struct { - obj Object // type name object defining this interface; or nil (for better error messages) - methods []*Func // ordered list of explicitly declared methods - embeddeds []Type // ordered list of explicitly embedded elements - complete bool // indicates that obj, methods, and embeddeds are set and type set can be computed + obj Object // type name object defining this interface; or nil (for better error messages) + methods []*Func // ordered list of explicitly declared methods + embeddeds []Type // ordered list of explicitly embedded elements + embedPos *[]token.Pos // positions of embedded elements; or nil (for error messages) - use pointer to save space + complete bool // indicates that obj, methods, and embeddeds are set and type set can be computed tset *TypeSet // type set described by this interface, computed lazily } @@ -326,7 +327,6 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface { // sort for API stability sortMethods(methods) - sortTypes(embeddeds) typ.methods = methods typ.embeddeds = embeddeds From 79955155e9a68ce47c50f0c77b7f41b10d093dab Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 09:39:05 -0400 Subject: [PATCH 699/940] [dev.typeparams] go/types: move newTypeSet function into typeset.go This is a straightforward port of CL 331515 to go/types. Change-Id: I05c687e7dd7a64a8a7815c4483ff7fbb06b37627 Reviewed-on: https://go-review.googlesource.com/c/go/+/335031 Trust: Robert Findley Run-TryBot: Robert Findley Reviewed-by: Robert Griesemer --- src/go/types/interface.go | 183 ------------------------------ src/go/types/typeset.go | 231 ++++++++++++++++++++++++++++++++++---- 2 files changed, 210 insertions(+), 204 deletions(-) diff --git a/src/go/types/interface.go b/src/go/types/interface.go index ccc95dd8416..fd7b55ab2f9 100644 --- a/src/go/types/interface.go +++ b/src/go/types/interface.go @@ -5,11 +5,9 @@ package types import ( - "fmt" "go/ast" "go/internal/typeparams" "go/token" - "sort" ) func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, def *Named) { @@ -131,184 +129,3 @@ func flattenUnion(list []ast.Expr, x ast.Expr) []ast.Expr { } return append(list, x) } - -// newTypeSet may be called with check == nil. -// TODO(gri) move this function into typeset.go eventually -func newTypeSet(check *Checker, pos token.Pos, ityp *Interface) *TypeSet { - if ityp.tset != nil { - return ityp.tset - } - - // If the interface is not fully set up yet, the type set will - // not be complete, which may lead to errors when using the the - // type set (e.g. missing method). Don't compute a partial type - // set (and don't store it!), so that we still compute the full - // type set eventually. Instead, return the top type set and - // let any follow-on errors play out. - // - // TODO(gri) Consider recording when this happens and reporting - // it as an error (but only if there were no other errors so to - // to not have unnecessary follow-on errors). - if !ityp.complete { - return &topTypeSet - } - - if check != nil && trace { - // Types don't generally have position information. - // If we don't have a valid pos provided, try to use - // one close enough. - if !pos.IsValid() && len(ityp.methods) > 0 { - pos = ityp.methods[0].pos - } - - check.trace(pos, "type set for %s", ityp) - check.indent++ - defer func() { - check.indent-- - check.trace(pos, "=> %s ", ityp.typeSet()) - }() - } - - // An infinitely expanding interface (due to a cycle) is detected - // elsewhere (Checker.validType), so here we simply assume we only - // have valid interfaces. Mark the interface as complete to avoid - // infinite recursion if the validType check occurs later for some - // reason. - ityp.tset = new(TypeSet) // TODO(gri) is this sufficient? - - // Methods of embedded interfaces are collected unchanged; i.e., the identity - // of a method I.m's Func Object of an interface I is the same as that of - // the method m in an interface that embeds interface I. On the other hand, - // if a method is embedded via multiple overlapping embedded interfaces, we - // don't provide a guarantee which "original m" got chosen for the embedding - // interface. See also issue #34421. - // - // If we don't care to provide this identity guarantee anymore, instead of - // reusing the original method in embeddings, we can clone the method's Func - // Object and give it the position of a corresponding embedded interface. Then - // we can get rid of the mpos map below and simply use the cloned method's - // position. - - var todo []*Func - var seen objset - var methods []*Func - mpos := make(map[*Func]token.Pos) // method specification or method embedding position, for good error messages - addMethod := func(pos token.Pos, m *Func, explicit bool) { - switch other := seen.insert(m); { - case other == nil: - methods = append(methods, m) - mpos[m] = pos - case explicit: - if check == nil { - panic(fmt.Sprintf("%v: duplicate method %s", m.pos, m.name)) - } - // check != nil - check.errorf(atPos(pos), _DuplicateDecl, "duplicate method %s", m.name) - check.errorf(atPos(mpos[other.(*Func)]), _DuplicateDecl, "\tother declaration of %s", m.name) // secondary error, \t indented - default: - // We have a duplicate method name in an embedded (not explicitly declared) method. - // Check method signatures after all types are computed (issue #33656). - // If we're pre-go1.14 (overlapping embeddings are not permitted), report that - // error here as well (even though we could do it eagerly) because it's the same - // error message. - if check == nil { - // check method signatures after all locally embedded interfaces are computed - todo = append(todo, m, other.(*Func)) - break - } - // check != nil - check.later(func() { - if !check.allowVersion(m.pkg, 1, 14) || !Identical(m.typ, other.Type()) { - check.errorf(atPos(pos), _DuplicateDecl, "duplicate method %s", m.name) - check.errorf(atPos(mpos[other.(*Func)]), _DuplicateDecl, "\tother declaration of %s", m.name) // secondary error, \t indented - } - }) - } - } - - for _, m := range ityp.methods { - addMethod(m.pos, m, true) - } - - // collect embedded elements - var allTypes Type - for i, typ := range ityp.embeddeds { - // The embedding position is nil for imported interfaces - // and also for interface copies after substitution (but - // in that case we don't need to report errors again). - var pos token.Pos // embedding position - if ityp.embedPos != nil { - pos = (*ityp.embedPos)[i] - } - var types Type - switch t := under(typ).(type) { - case *Interface: - tset := newTypeSet(check, pos, t) - for _, m := range tset.methods { - addMethod(pos, m, false) // use embedding position pos rather than m.pos - - } - types = tset.types - case *Union: - // TODO(gri) combine with default case once we have - // converted all tests to new notation and we - // can report an error when we don't have an - // interface before go1.18. - types = typ - case *TypeParam: - if check != nil && !check.allowVersion(check.pkg, 1, 18) { - check.errorf(atPos(pos), _InvalidIfaceEmbed, "%s is a type parameter, not an interface", typ) - continue - } - types = typ - default: - if typ == Typ[Invalid] { - continue - } - if check != nil && !check.allowVersion(check.pkg, 1, 18) { - check.errorf(atPos(pos), _InvalidIfaceEmbed, "%s is not an interface", typ) - continue - } - types = typ - } - allTypes = intersect(allTypes, types) - } - ityp.embedPos = nil // not needed anymore (errors have been reported) - - // process todo's (this only happens if check == nil) - for i := 0; i < len(todo); i += 2 { - m := todo[i] - other := todo[i+1] - if !Identical(m.typ, other.typ) { - panic(fmt.Sprintf("%v: duplicate method %s", m.pos, m.name)) - } - } - - if methods != nil { - sort.Sort(byUniqueMethodName(methods)) - ityp.tset.methods = methods - } - ityp.tset.types = allTypes - - return ityp.tset -} - -func sortMethods(list []*Func) { - sort.Sort(byUniqueMethodName(list)) -} - -func assertSortedMethods(list []*Func) { - if !debug { - panic("internal error: assertSortedMethods called outside debug mode") - } - if !sort.IsSorted(byUniqueMethodName(list)) { - panic("internal error: methods not sorted") - } -} - -// byUniqueMethodName method lists can be sorted by their unique method names. -type byUniqueMethodName []*Func - -func (a byUniqueMethodName) Len() int { return len(a) } -func (a byUniqueMethodName) Less(i, j int) bool { return a[i].Id() < a[j].Id() } -func (a byUniqueMethodName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } diff --git a/src/go/types/typeset.go b/src/go/types/typeset.go index 9ba04b97bfc..b349d4922c5 100644 --- a/src/go/types/typeset.go +++ b/src/go/types/typeset.go @@ -6,10 +6,13 @@ package types import ( "bytes" + "fmt" + "go/token" + "sort" ) -// topTypeSet may be used as type set for the empty interface. -var topTypeSet TypeSet +// ---------------------------------------------------------------------------- +// API // A TypeSet represents the type set of an interface. type TypeSet struct { @@ -18,6 +21,31 @@ type TypeSet struct { types Type // typically a *Union; nil means no type restrictions } +// IsTop reports whether type set s is the top type set (corresponding to the empty interface). +func (s *TypeSet) IsTop() bool { return len(s.methods) == 0 && s.types == nil } + +// IsMethodSet reports whether the type set s is described by a single set of methods. +func (s *TypeSet) IsMethodSet() bool { return s.types == nil && !s.IsComparable() } + +// IsComparable reports whether each type in the set is comparable. +func (s *TypeSet) IsComparable() bool { + _, m := s.LookupMethod(nil, "==") + return m != nil +} + +// NumMethods returns the number of methods available. +func (s *TypeSet) NumMethods() int { return len(s.methods) } + +// Method returns the i'th method of type set s for 0 <= i < s.NumMethods(). +// The methods are ordered by their unique ID. +func (s *TypeSet) Method(i int) *Func { return s.methods[i] } + +// LookupMethod returns the index of and method with matching package and name, or (-1, nil). +func (s *TypeSet) LookupMethod(pkg *Package, name string) (int, *Func) { + // TODO(gri) s.methods is sorted - consider binary search + return lookupMethod(s.methods, pkg, name) +} + func (s *TypeSet) String() string { if s.IsTop() { return "⊤" @@ -44,27 +72,188 @@ func (s *TypeSet) String() string { return buf.String() } -// IsTop reports whether type set s is the top type set (corresponding to the empty interface). -func (s *TypeSet) IsTop() bool { return len(s.methods) == 0 && s.types == nil } +// ---------------------------------------------------------------------------- +// Implementation -// IsMethodSet reports whether the type set s is described by a single set of methods. -func (s *TypeSet) IsMethodSet() bool { return s.types == nil && !s.IsComparable() } +// topTypeSet may be used as type set for the empty interface. +var topTypeSet TypeSet -// IsComparable reports whether each type in the set is comparable. -func (s *TypeSet) IsComparable() bool { - _, m := s.LookupMethod(nil, "==") - return m != nil +// newTypeSet may be called with check == nil. +func newTypeSet(check *Checker, pos token.Pos, ityp *Interface) *TypeSet { + if ityp.tset != nil { + return ityp.tset + } + + // If the interface is not fully set up yet, the type set will + // not be complete, which may lead to errors when using the the + // type set (e.g. missing method). Don't compute a partial type + // set (and don't store it!), so that we still compute the full + // type set eventually. Instead, return the top type set and + // let any follow-on errors play out. + // + // TODO(gri) Consider recording when this happens and reporting + // it as an error (but only if there were no other errors so to + // to not have unnecessary follow-on errors). + if !ityp.complete { + return &topTypeSet + } + + if check != nil && trace { + // Types don't generally have position information. + // If we don't have a valid pos provided, try to use + // one close enough. + if !pos.IsValid() && len(ityp.methods) > 0 { + pos = ityp.methods[0].pos + } + + check.trace(pos, "type set for %s", ityp) + check.indent++ + defer func() { + check.indent-- + check.trace(pos, "=> %s ", ityp.typeSet()) + }() + } + + // An infinitely expanding interface (due to a cycle) is detected + // elsewhere (Checker.validType), so here we simply assume we only + // have valid interfaces. Mark the interface as complete to avoid + // infinite recursion if the validType check occurs later for some + // reason. + ityp.tset = new(TypeSet) // TODO(gri) is this sufficient? + + // Methods of embedded interfaces are collected unchanged; i.e., the identity + // of a method I.m's Func Object of an interface I is the same as that of + // the method m in an interface that embeds interface I. On the other hand, + // if a method is embedded via multiple overlapping embedded interfaces, we + // don't provide a guarantee which "original m" got chosen for the embedding + // interface. See also issue #34421. + // + // If we don't care to provide this identity guarantee anymore, instead of + // reusing the original method in embeddings, we can clone the method's Func + // Object and give it the position of a corresponding embedded interface. Then + // we can get rid of the mpos map below and simply use the cloned method's + // position. + + var todo []*Func + var seen objset + var methods []*Func + mpos := make(map[*Func]token.Pos) // method specification or method embedding position, for good error messages + addMethod := func(pos token.Pos, m *Func, explicit bool) { + switch other := seen.insert(m); { + case other == nil: + methods = append(methods, m) + mpos[m] = pos + case explicit: + if check == nil { + panic(fmt.Sprintf("%v: duplicate method %s", m.pos, m.name)) + } + // check != nil + check.errorf(atPos(pos), _DuplicateDecl, "duplicate method %s", m.name) + check.errorf(atPos(mpos[other.(*Func)]), _DuplicateDecl, "\tother declaration of %s", m.name) // secondary error, \t indented + default: + // We have a duplicate method name in an embedded (not explicitly declared) method. + // Check method signatures after all types are computed (issue #33656). + // If we're pre-go1.14 (overlapping embeddings are not permitted), report that + // error here as well (even though we could do it eagerly) because it's the same + // error message. + if check == nil { + // check method signatures after all locally embedded interfaces are computed + todo = append(todo, m, other.(*Func)) + break + } + // check != nil + check.later(func() { + if !check.allowVersion(m.pkg, 1, 14) || !Identical(m.typ, other.Type()) { + check.errorf(atPos(pos), _DuplicateDecl, "duplicate method %s", m.name) + check.errorf(atPos(mpos[other.(*Func)]), _DuplicateDecl, "\tother declaration of %s", m.name) // secondary error, \t indented + } + }) + } + } + + for _, m := range ityp.methods { + addMethod(m.pos, m, true) + } + + // collect embedded elements + var allTypes Type + for i, typ := range ityp.embeddeds { + // The embedding position is nil for imported interfaces + // and also for interface copies after substitution (but + // in that case we don't need to report errors again). + var pos token.Pos // embedding position + if ityp.embedPos != nil { + pos = (*ityp.embedPos)[i] + } + var types Type + switch t := under(typ).(type) { + case *Interface: + tset := newTypeSet(check, pos, t) + for _, m := range tset.methods { + addMethod(pos, m, false) // use embedding position pos rather than m.pos + + } + types = tset.types + case *Union: + // TODO(gri) combine with default case once we have + // converted all tests to new notation and we + // can report an error when we don't have an + // interface before go1.18. + types = typ + case *TypeParam: + if check != nil && !check.allowVersion(check.pkg, 1, 18) { + check.errorf(atPos(pos), _InvalidIfaceEmbed, "%s is a type parameter, not an interface", typ) + continue + } + types = typ + default: + if typ == Typ[Invalid] { + continue + } + if check != nil && !check.allowVersion(check.pkg, 1, 18) { + check.errorf(atPos(pos), _InvalidIfaceEmbed, "%s is not an interface", typ) + continue + } + types = typ + } + allTypes = intersect(allTypes, types) + } + ityp.embedPos = nil // not needed anymore (errors have been reported) + + // process todo's (this only happens if check == nil) + for i := 0; i < len(todo); i += 2 { + m := todo[i] + other := todo[i+1] + if !Identical(m.typ, other.typ) { + panic(fmt.Sprintf("%v: duplicate method %s", m.pos, m.name)) + } + } + + if methods != nil { + sort.Sort(byUniqueMethodName(methods)) + ityp.tset.methods = methods + } + ityp.tset.types = allTypes + + return ityp.tset } -// NumMethods returns the number of methods available. -func (s *TypeSet) NumMethods() int { return len(s.methods) } - -// Method returns the i'th method of type set s for 0 <= i < s.NumMethods(). -// The methods are ordered by their unique ID. -func (s *TypeSet) Method(i int) *Func { return s.methods[i] } - -// LookupMethod returns the index of and method with matching package and name, or (-1, nil). -func (s *TypeSet) LookupMethod(pkg *Package, name string) (int, *Func) { - // TODO(gri) s.methods is sorted - consider binary search - return lookupMethod(s.methods, pkg, name) +func sortMethods(list []*Func) { + sort.Sort(byUniqueMethodName(list)) } + +func assertSortedMethods(list []*Func) { + if !debug { + panic("internal error: assertSortedMethods called outside debug mode") + } + if !sort.IsSorted(byUniqueMethodName(list)) { + panic("internal error: methods not sorted") + } +} + +// byUniqueMethodName method lists can be sorted by their unique method names. +type byUniqueMethodName []*Func + +func (a byUniqueMethodName) Len() int { return len(a) } +func (a byUniqueMethodName) Less(i, j int) bool { return a[i].Id() < a[j].Id() } +func (a byUniqueMethodName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } From 726ffce659a173951186097b26489570cff24fd3 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 09:44:08 -0400 Subject: [PATCH 700/940] [dev.typeparams] go/types: "comparable" must not be visible before Go 1.18 This is a straightforward port of CL 331517 to go/types. Change-Id: Id00761fd5dffb4d09e19f086d18ddc20f11528d0 Reviewed-on: https://go-review.googlesource.com/c/go/+/335032 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- .../types/testdata/fixedbugs/issue46090.go2 | 9 +++ src/go/types/typexpr.go | 2 +- src/go/types/universe.go | 64 +++++++------------ 3 files changed, 32 insertions(+), 43 deletions(-) create mode 100644 src/go/types/testdata/fixedbugs/issue46090.go2 diff --git a/src/go/types/testdata/fixedbugs/issue46090.go2 b/src/go/types/testdata/fixedbugs/issue46090.go2 new file mode 100644 index 00000000000..81b31974c8d --- /dev/null +++ b/src/go/types/testdata/fixedbugs/issue46090.go2 @@ -0,0 +1,9 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The predeclared type comparable is not visible before Go 1.18. + +package go1_17 + +type _ comparable // ERROR undeclared diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 070b0ade3e8..64a1b37cef9 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -27,7 +27,7 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, wantType bool) // Note that we cannot use check.lookup here because the returned scope // may be different from obj.Parent(). See also Scope.LookupParent doc. scope, obj := check.scope.LookupParent(e.Name, check.pos) - if obj == nil { + if obj == nil || obj == universeComparable && !check.allowVersion(check.pkg, 1, 18) { if e.Name == "_" { check.errorf(e, _InvalidBlank, "cannot use _ as value or type") } else { diff --git a/src/go/types/universe.go b/src/go/types/universe.go index 7ce401827e3..540b0ac1189 100644 --- a/src/go/types/universe.go +++ b/src/go/types/universe.go @@ -8,7 +8,6 @@ package types import ( "go/constant" - "go/internal/typeparams" "go/token" "strings" ) @@ -22,11 +21,12 @@ var Universe *Scope var Unsafe *Package var ( - universeIota *Const - universeByte *Basic // uint8 alias, but has name "byte" - universeRune *Basic // int32 alias, but has name "rune" - universeAny *Interface - universeError *Named + universeIota *Const + universeByte *Basic // uint8 alias, but has name "byte" + universeRune *Basic // int32 alias, but has name "rune" + universeAny *Interface + universeError *Named + universeComparable Object ) // Typ contains the predeclared *Basic types indexed by their @@ -79,21 +79,30 @@ func defPredeclaredTypes() { def(NewTypeName(token.NoPos, nil, t.name, t)) } - // any - // (Predeclared and entered into universe scope so we do all the - // usual checks; but removed again from scope later since it's - // only visible as constraint in a type parameter list.) + // type any = interface{} + // Entered into universe scope so we do all the usual checks; + // but removed again from scope later since it's only visible + // as constraint in a type parameter list. def(NewTypeName(token.NoPos, nil, "any", &emptyInterface)) - // Error has a nil package in its qualified name since it is in no package + // type error interface{ Error() string } { res := NewVar(token.NoPos, nil, "", Typ[String]) - sig := &Signature{results: NewTuple(res)} + sig := NewSignature(nil, nil, NewTuple(res), false) err := NewFunc(token.NoPos, nil, "Error", sig) typ := &Named{underlying: NewInterfaceType([]*Func{err}, nil)} sig.recv = NewVar(token.NoPos, nil, "", typ) def(NewTypeName(token.NoPos, nil, "error", typ)) } + + // type comparable interface{ ==() } + { + sig := NewSignature(nil, nil, nil, false) + eql := NewFunc(token.NoPos, nil, "==", sig) + typ := &Named{underlying: NewInterfaceType([]*Func{eql}, nil)} + sig.recv = NewVar(token.NoPos, nil, "", typ) + def(NewTypeName(token.NoPos, nil, "comparable", typ)) + } } var predeclaredConsts = [...]struct { @@ -202,33 +211,6 @@ func DefPredeclaredTestFuncs() { def(newBuiltin(_Trace)) } -func defPredeclaredComparable() { - // The "comparable" interface can be imagined as defined like - // - // type comparable interface { - // == () untyped bool - // != () untyped bool - // } - // - // == and != cannot be user-declared but we can declare - // a magic method == and check for its presence when needed. - - // Define interface { == () }. We don't care about the signature - // for == so leave it empty except for the receiver, which is - // set up later to match the usual interface method assumptions. - sig := new(Signature) - eql := NewFunc(token.NoPos, nil, "==", sig) - iface := NewInterfaceType([]*Func{eql}, nil) - - // set up the defined type for the interface - obj := NewTypeName(token.NoPos, nil, "comparable", nil) - named := NewNamed(obj, iface, nil) - obj.color_ = black - sig.recv = NewVar(token.NoPos, nil, "", named) // complete == signature - - def(obj) -} - func init() { Universe = NewScope(nil, token.NoPos, token.NoPos, "universe") Unsafe = NewPackage("unsafe", "unsafe") @@ -238,15 +220,13 @@ func init() { defPredeclaredConsts() defPredeclaredNil() defPredeclaredFuncs() - if typeparams.Enabled { - defPredeclaredComparable() - } universeIota = Universe.Lookup("iota").(*Const) universeByte = Universe.Lookup("byte").(*TypeName).typ.(*Basic) universeRune = Universe.Lookup("rune").(*TypeName).typ.(*Basic) universeAny = Universe.Lookup("any").(*TypeName).typ.(*Interface) universeError = Universe.Lookup("error").(*TypeName).typ.(*Named) + universeComparable = Universe.Lookup("comparable") // "any" is only visible as constraint in a type parameter list delete(Universe.elems, "any") From 5f50a6442e25c406bea7f2a967f2080f89b4e0f6 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 09:51:19 -0400 Subject: [PATCH 701/940] [dev.typeparams] go/internal/typeparams: remove the Enabled guard Type parameters are now always enabled. Users should guard against type checking generic code by using the types.Config.GoVersion field. This cleans up some differences with types2. Change-Id: Ie3e35a549e456a90a10d6a7e158ff58653cc1394 Reviewed-on: https://go-review.googlesource.com/c/go/+/335033 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/internal/typeparams/typeparams.go | 2 -- src/go/parser/error_test.go | 6 +----- src/go/parser/parser.go | 2 +- src/go/parser/resolver_test.go | 6 +----- src/go/parser/short_test.go | 6 ------ src/go/printer/printer_test.go | 4 ---- src/go/types/api_test.go | 9 --------- src/go/types/check_test.go | 14 ++------------ src/go/types/methodset_test.go | 7 ++----- src/go/types/typexpr.go | 7 ++----- 10 files changed, 9 insertions(+), 54 deletions(-) diff --git a/src/go/internal/typeparams/typeparams.go b/src/go/internal/typeparams/typeparams.go index e102b77ef84..3191654d4f8 100644 --- a/src/go/internal/typeparams/typeparams.go +++ b/src/go/internal/typeparams/typeparams.go @@ -10,8 +10,6 @@ import ( "go/token" ) -const Enabled = true - func PackIndexExpr(x ast.Expr, lbrack token.Pos, exprs []ast.Expr, rbrack token.Pos) ast.Expr { switch len(exprs) { case 0: diff --git a/src/go/parser/error_test.go b/src/go/parser/error_test.go index e22ab124510..f35ba0b5017 100644 --- a/src/go/parser/error_test.go +++ b/src/go/parser/error_test.go @@ -189,11 +189,7 @@ func TestErrors(t *testing.T) { t.Run(name, func(t *testing.T) { if !d.IsDir() && !strings.HasPrefix(name, ".") && (strings.HasSuffix(name, ".src") || strings.HasSuffix(name, ".go2")) { mode := DeclarationErrors | AllErrors - if strings.HasSuffix(name, ".go2") { - if !typeparams.Enabled { - return - } - } else { + if !strings.HasSuffix(name, ".go2") { mode |= typeparams.DisallowParsing } checkErrors(t, filepath.Join(testdata, name), nil, mode, true) diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go index d1082591710..bdc2ad308c8 100644 --- a/src/go/parser/parser.go +++ b/src/go/parser/parser.go @@ -77,7 +77,7 @@ func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode Mod } func (p *parser) parseTypeParams() bool { - return typeparams.Enabled && p.mode&typeparams.DisallowParsing == 0 + return p.mode&typeparams.DisallowParsing == 0 } // ---------------------------------------------------------------------------- diff --git a/src/go/parser/resolver_test.go b/src/go/parser/resolver_test.go index 625c009c914..0c06c592d5f 100644 --- a/src/go/parser/resolver_test.go +++ b/src/go/parser/resolver_test.go @@ -41,11 +41,7 @@ func TestResolution(t *testing.T) { path := filepath.Join(dir, fi.Name()) src := readFile(path) // panics on failure var mode Mode - if strings.HasSuffix(path, ".go2") { - if !typeparams.Enabled { - t.Skip("type params are not enabled") - } - } else { + if !strings.HasSuffix(path, ".go2") { mode |= typeparams.DisallowParsing } file, err := ParseFile(fset, path, src, mode) diff --git a/src/go/parser/short_test.go b/src/go/parser/short_test.go index 2467ccb4a77..bfc6f6714b9 100644 --- a/src/go/parser/short_test.go +++ b/src/go/parser/short_test.go @@ -133,9 +133,6 @@ func TestValid(t *testing.T) { } }) t.Run("tparams", func(t *testing.T) { - if !typeparams.Enabled { - t.Skip("type params are not enabled") - } for _, src := range valids { checkErrors(t, src, src, DeclarationErrors|AllErrors, false) } @@ -268,9 +265,6 @@ func TestInvalid(t *testing.T) { } }) t.Run("tparams", func(t *testing.T) { - if !typeparams.Enabled { - t.Skip("type params are not enabled") - } for _, src := range invalids { checkErrors(t, src, src, DeclarationErrors|AllErrors, true) } diff --git a/src/go/printer/printer_test.go b/src/go/printer/printer_test.go index 20c97b8c081..ff8be4ae97a 100644 --- a/src/go/printer/printer_test.go +++ b/src/go/printer/printer_test.go @@ -10,7 +10,6 @@ import ( "flag" "fmt" "go/ast" - "go/internal/typeparams" "go/parser" "go/token" "io" @@ -222,9 +221,6 @@ var data = []entry{ func TestFiles(t *testing.T) { t.Parallel() for _, e := range data { - if !typeparams.Enabled && e.mode&allowTypeParams != 0 { - continue - } source := filepath.Join(dataDir, e.source) golden := filepath.Join(dataDir, e.golden) mode := e.mode diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go index ef248781ccc..e6c209dda0d 100644 --- a/src/go/types/api_test.go +++ b/src/go/types/api_test.go @@ -353,9 +353,6 @@ func TestTypesInfo(t *testing.T) { } for _, test := range tests { - if strings.HasPrefix(test.src, genericPkg) && !typeparams.Enabled { - continue - } info := Info{Types: make(map[ast.Expr]TypeAndValue)} var name string if strings.HasPrefix(test.src, broken) { @@ -534,9 +531,6 @@ func TestDefsInfo(t *testing.T) { } for _, test := range tests { - if strings.HasPrefix(test.src, genericPkg) && !typeparams.Enabled { - continue - } info := Info{ Defs: make(map[*ast.Ident]Object), } @@ -582,9 +576,6 @@ func TestUsesInfo(t *testing.T) { } for _, test := range tests { - if strings.HasPrefix(test.src, genericPkg) && !typeparams.Enabled { - continue - } info := Info{ Uses: make(map[*ast.Ident]Object), } diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go index f0cfced97f2..692004facf1 100644 --- a/src/go/types/check_test.go +++ b/src/go/types/check_test.go @@ -207,10 +207,8 @@ func testFiles(t *testing.T, sizes Sizes, filenames []string, srcs [][]byte, man t.Fatal("no source files") } - if strings.HasSuffix(filenames[0], ".go2") && !typeparams.Enabled { - t.Skip("type params are not enabled") - } - if strings.HasSuffix(filenames[0], ".go1") && typeparams.Enabled { + if strings.HasSuffix(filenames[0], ".go1") { + // TODO(rfindley): re-enable this test by using GoVersion. t.Skip("type params are enabled") } @@ -356,14 +354,6 @@ func TestIndexRepresentability(t *testing.T) { testFiles(t, &StdSizes{4, 4}, []string{"index.go"}, [][]byte{[]byte(src)}, false, nil) } -func TestIssue46453(t *testing.T) { - if typeparams.Enabled { - t.Skip("type params are enabled") - } - const src = "package p\ntype _ comparable // ERROR \"undeclared name: comparable\"" - testFiles(t, nil, []string{"issue46453.go"}, [][]byte{[]byte(src)}, false, nil) -} - func TestCheck(t *testing.T) { DefPredeclaredTestFuncs(); testDirFiles(t, "testdata/check", false) } func TestExamples(t *testing.T) { testDirFiles(t, "testdata/examples", false) } func TestFixedbugs(t *testing.T) { testDirFiles(t, "testdata/fixedbugs", false) } diff --git a/src/go/types/methodset_test.go b/src/go/types/methodset_test.go index 4a373fa2c4f..566356ad6de 100644 --- a/src/go/types/methodset_test.go +++ b/src/go/types/methodset_test.go @@ -7,7 +7,6 @@ package types_test import ( "testing" - "go/internal/typeparams" . "go/types" ) @@ -101,9 +100,7 @@ func TestNewMethodSet(t *testing.T) { check(src, methods, false) } - if typeparams.Enabled { - for src, methods := range genericTests { - check(src, methods, true) - } + for src, methods := range genericTests { + check(src, methods, true) } } diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 64a1b37cef9..ea39473b510 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -263,11 +263,8 @@ func (check *Checker) typInternal(e0 ast.Expr, def *Named) (T Type) { case *ast.IndexExpr, *ast.MultiIndexExpr: ix := typeparams.UnpackIndexExpr(e) - if typeparams.Enabled { - return check.instantiatedType(ix, def) - } - check.errorf(e0, _NotAType, "%s is not a type", e0) - check.use(ix.X) + // TODO(rfindley): type instantiation should require go1.18 + return check.instantiatedType(ix, def) case *ast.ParenExpr: // Generic types must be instantiated before they can be used in any form. From 0f4198b5e287a655a6f2f67c9b5bdc758c9eae1e Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 10:27:17 -0400 Subject: [PATCH 702/940] [dev.typeparams] go/types: delay interface check for type bounds This is a port of CL 331690 to go/types. It diverges from that CL due to the different representation of Fields in the AST. Change-Id: I3ae9ac3a0172dc58ac748f28772d87b00db0732a Reviewed-on: https://go-review.googlesource.com/c/go/+/335034 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/decl.go | 58 ++++++++----------- .../types/testdata/fixedbugs/issue40789.go2 | 37 ++++++++++++ src/go/types/type.go | 6 +- 3 files changed, 65 insertions(+), 36 deletions(-) create mode 100644 src/go/types/testdata/fixedbugs/issue40789.go2 diff --git a/src/go/types/decl.go b/src/go/types/decl.go index ac1b3815d22..f0e7c5d5add 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -724,13 +724,8 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) { } -func (check *Checker) collectTypeParams(list *ast.FieldList) (tparams []*TypeName) { - // Type parameter lists should not be empty. The parser will - // complain but we still may get an incorrect AST: ignore it. - if list.NumFields() == 0 { - return - } - +func (check *Checker) collectTypeParams(list *ast.FieldList) []*TypeName { + var tparams []*TypeName // Declare type parameters up-front, with empty interface as type bound. // The scope of type parameters starts at the beginning of the type parameter // list (so we can have mutually recursive parameterized interfaces). @@ -738,46 +733,22 @@ func (check *Checker) collectTypeParams(list *ast.FieldList) (tparams []*TypeNam tparams = check.declareTypeParams(tparams, f.Names) } - setBoundAt := func(at int, bound Type) { - assert(IsInterface(bound)) - tparams[at].typ.(*TypeParam).bound = bound - } - index := 0 var bound Type for _, f := range list.List { if f.Type == nil { goto next } - - // The predeclared identifier "any" is visible only as a constraint - // in a type parameter list. Look for it before general constraint - // resolution. - if tident, _ := unparen(f.Type).(*ast.Ident); tident != nil && tident.Name == "any" && check.lookup("any") == nil { - bound = universeAny - } else { - bound = check.typ(f.Type) - } - - // type bound must be an interface - // TODO(gri) We should delay the interface check because - // we may not have a complete interface yet: - // type C(type T C) interface {} - // (issue #39724). - if _, ok := under(bound).(*Interface); ok { - // Otherwise, set the bound for each type parameter. - for i := range f.Names { - setBoundAt(index+i, bound) - } - } else if bound != Typ[Invalid] { - check.errorf(f.Type, _Todo, "%s is not an interface", bound) + bound = check.boundType(f.Type) + for i := range f.Names { + tparams[index+i].typ.(*TypeParam).bound = bound } next: index += len(f.Names) } - return + return tparams } func (check *Checker) declareTypeParams(tparams []*TypeName, names []*ast.Ident) []*TypeName { @@ -795,6 +766,23 @@ func (check *Checker) declareTypeParams(tparams []*TypeName, names []*ast.Ident) return tparams } +// boundType type-checks the type expression e and returns its type, or Typ[Invalid]. +// The type must be an interface, including the predeclared type "any". +func (check *Checker) boundType(e ast.Expr) Type { + // The predeclared identifier "any" is visible only as a type bound in a type parameter list. + if name, _ := unparen(e).(*ast.Ident); name != nil && name.Name == "any" && check.lookup("any") == nil { + return universeAny + } + + bound := check.typ(e) + check.later(func() { + if _, ok := under(bound).(*Interface); !ok && bound != Typ[Invalid] { + check.errorf(e, _Todo, "%s is not an interface", bound) + } + }) + return bound +} + func (check *Checker) collectMethods(obj *TypeName) { // get associated methods // (Checker.collectObjects only collects methods with non-blank names; diff --git a/src/go/types/testdata/fixedbugs/issue40789.go2 b/src/go/types/testdata/fixedbugs/issue40789.go2 new file mode 100644 index 00000000000..9eea4ad60a6 --- /dev/null +++ b/src/go/types/testdata/fixedbugs/issue40789.go2 @@ -0,0 +1,37 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "fmt" + +func main() { + m := map[string]int{ + "a": 6, + "b": 7, + } + fmt.Println(copyMap[map[string]int, string, int](m)) +} + +type Map[K comparable, V any] interface { + map[K] V +} + +func copyMap[M Map[K, V], K comparable, V any](m M) M { + m1 := make(M) + for k, v := range m { + m1[k] = v + } + return m1 +} + +// simpler test case from the same issue + +type A[X comparable] interface { + []X +} + +func f[B A[X], X comparable]() B { + return nil +} diff --git a/src/go/types/type.go b/src/go/types/type.go index c1b307b642e..03c15867746 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -623,7 +623,11 @@ func (check *Checker) newTypeParam(obj *TypeName, index int, bound Type) *TypePa } func (t *TypeParam) Bound() *Interface { - iface := asInterface(t.bound) + // we may not have an interface (error reported elsewhere) + iface, _ := under(t.bound).(*Interface) + if iface == nil { + return &emptyInterface + } // use the type bound position if we have one pos := token.NoPos if n, _ := t.bound.(*Named); n != nil { From de209e693a251c772a37e7deb274574d8b8759ce Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 10:33:59 -0400 Subject: [PATCH 703/940] [dev.typeparams] go/types: make Interface.obj a *TypeName This is a straightforward port of CL 332011 to go/types. Change-Id: I682791886c8496c52094f3688e36934afbd7a241 Reviewed-on: https://go-review.googlesource.com/c/go/+/335035 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/call.go | 7 +++---- src/go/types/sizeof_test.go | 2 +- src/go/types/type.go | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/go/types/call.go b/src/go/types/call.go index 4e5b98a12e5..bcd569e82f1 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -482,11 +482,10 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) { var why string if tpar := asTypeParam(x.typ); tpar != nil { // Type parameter bounds don't specify fields, so don't mention "field". - switch obj := tpar.Bound().obj.(type) { - case nil: + if tname := tpar.Bound().obj; tname != nil { + why = check.sprintf("interface %s has no method %s", tname.name, sel) + } else { why = check.sprintf("type bound for %s has no method %s", x.typ, sel) - case *TypeName: - why = check.sprintf("interface %s has no method %s", obj.name, sel) } } else { why = check.sprintf("type %s has no field or method %s", x.typ, sel) diff --git a/src/go/types/sizeof_test.go b/src/go/types/sizeof_test.go index b8f191ee867..8f5f42b4150 100644 --- a/src/go/types/sizeof_test.go +++ b/src/go/types/sizeof_test.go @@ -27,7 +27,7 @@ func TestSizeof(t *testing.T) { {Tuple{}, 12, 24}, {Signature{}, 44, 88}, {Union{}, 24, 48}, - {Interface{}, 44, 88}, + {Interface{}, 40, 80}, {Map{}, 16, 32}, {Chan{}, 12, 24}, {Named{}, 84, 160}, diff --git a/src/go/types/type.go b/src/go/types/type.go index 03c15867746..459ce9e72c1 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -258,7 +258,7 @@ func (s *Signature) Variadic() bool { return s.variadic } // An Interface represents an interface type. type Interface struct { - obj Object // type name object defining this interface; or nil (for better error messages) + obj *TypeName // type name object defining this interface; or nil (for better error messages) methods []*Func // ordered list of explicitly declared methods embeddeds []Type // ordered list of explicitly embedded elements embedPos *[]token.Pos // positions of embedded elements; or nil (for error messages) - use pointer to save space From 7c35f5c2fc5975cda9480a8549643f23fbb2ac7d Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 10:36:42 -0400 Subject: [PATCH 704/940] [dev.typeparams] go/types: rename newTypeSet -> computeTypeSet This is a port of CL 332089 to go/types. Change-Id: I39321eaee184c8204bd255b7770a0770ecb25fda Reviewed-on: https://go-review.googlesource.com/c/go/+/335036 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/interface.go | 2 +- src/go/types/type.go | 4 ++-- src/go/types/typeset.go | 6 +++--- src/go/types/typexpr.go | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/go/types/interface.go b/src/go/types/interface.go index fd7b55ab2f9..367fc794775 100644 --- a/src/go/types/interface.go +++ b/src/go/types/interface.go @@ -119,7 +119,7 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d // Compute type set with a non-nil *Checker as soon as possible // to report any errors. Subsequent uses of type sets should be // using this computed type set and won't need to pass in a *Checker. - check.later(func() { newTypeSet(check, iface.Pos(), ityp) }) + check.later(func() { computeTypeSet(check, iface.Pos(), ityp) }) } func flattenUnion(list []ast.Expr, x ast.Expr) []ast.Expr { diff --git a/src/go/types/type.go b/src/go/types/type.go index 459ce9e72c1..ce857d1c80e 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -268,7 +268,7 @@ type Interface struct { } // typeSet returns the type set for interface t. -func (t *Interface) typeSet() *TypeSet { return newTypeSet(nil, token.NoPos, t) } +func (t *Interface) typeSet() *TypeSet { return computeTypeSet(nil, token.NoPos, t) } // is reports whether interface t represents types that all satisfy f. func (t *Interface) is(f func(Type, bool) bool) bool { @@ -634,7 +634,7 @@ func (t *TypeParam) Bound() *Interface { pos = n.obj.pos } // TODO(rFindley) switch this to an unexported method on Checker. - newTypeSet(t.check, pos, iface) + computeTypeSet(t.check, pos, iface) return iface } diff --git a/src/go/types/typeset.go b/src/go/types/typeset.go index b349d4922c5..e979e90e6f5 100644 --- a/src/go/types/typeset.go +++ b/src/go/types/typeset.go @@ -78,8 +78,8 @@ func (s *TypeSet) String() string { // topTypeSet may be used as type set for the empty interface. var topTypeSet TypeSet -// newTypeSet may be called with check == nil. -func newTypeSet(check *Checker, pos token.Pos, ityp *Interface) *TypeSet { +// computeTypeSet may be called with check == nil. +func computeTypeSet(check *Checker, pos token.Pos, ityp *Interface) *TypeSet { if ityp.tset != nil { return ityp.tset } @@ -188,7 +188,7 @@ func newTypeSet(check *Checker, pos token.Pos, ityp *Interface) *TypeSet { var types Type switch t := under(typ).(type) { case *Interface: - tset := newTypeSet(check, pos, t) + tset := computeTypeSet(check, pos, t) for _, m := range tset.methods { addMethod(pos, m, false) // use embedding position pos rather than m.pos diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index ea39473b510..342317048bd 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -140,7 +140,7 @@ func (check *Checker) ordinaryType(pos positioner, typ Type) { // type-checking. check.later(func() { if t := asInterface(typ); t != nil { - tset := newTypeSet(check, pos.Pos(), t) // TODO(gri) is this the correct position? + tset := computeTypeSet(check, pos.Pos(), t) // TODO(gri) is this the correct position? if tset.types != nil { check.softErrorf(pos, _Todo, "interface contains type constraints (%s)", tset.types) return From b3e7f23a480513039c0aa6edac95a9718b02cab2 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 10:39:55 -0400 Subject: [PATCH 705/940] [dev.typeparams] go/types: move Struct type decl into struct.go (cleanup) This is a port of CL 332090 to go/types. Change-Id: Idc480374f5efe0e7f34f76f37ffd02a3aef59c67 Reviewed-on: https://go-review.googlesource.com/c/go/+/335037 Trust: Robert Findley Run-TryBot: Robert Findley Reviewed-by: Robert Griesemer --- src/go/types/struct.go | 46 ++++++++++++++++++++++++++++++++++++++++++ src/go/types/type.go | 39 ----------------------------------- 2 files changed, 46 insertions(+), 39 deletions(-) diff --git a/src/go/types/struct.go b/src/go/types/struct.go index 1fec9ea527c..d1fb813c147 100644 --- a/src/go/types/struct.go +++ b/src/go/types/struct.go @@ -10,6 +10,52 @@ import ( "strconv" ) +// ---------------------------------------------------------------------------- +// API + +// A Struct represents a struct type. +type Struct struct { + fields []*Var + tags []string // field tags; nil if there are no tags +} + +// NewStruct returns a new struct with the given fields and corresponding field tags. +// If a field with index i has a tag, tags[i] must be that tag, but len(tags) may be +// only as long as required to hold the tag with the largest index i. Consequently, +// if no field has a tag, tags may be nil. +func NewStruct(fields []*Var, tags []string) *Struct { + var fset objset + for _, f := range fields { + if f.name != "_" && fset.insert(f) != nil { + panic("multiple fields with the same name") + } + } + if len(tags) > len(fields) { + panic("more tags than fields") + } + return &Struct{fields: fields, tags: tags} +} + +// NumFields returns the number of fields in the struct (including blank and embedded fields). +func (s *Struct) NumFields() int { return len(s.fields) } + +// Field returns the i'th field for 0 <= i < NumFields(). +func (s *Struct) Field(i int) *Var { return s.fields[i] } + +// Tag returns the i'th field tag for 0 <= i < NumFields(). +func (s *Struct) Tag(i int) string { + if i < len(s.tags) { + return s.tags[i] + } + return "" +} + +func (t *Struct) Underlying() Type { return t } +func (t *Struct) String() string { return TypeString(t, nil) } + +// ---------------------------------------------------------------------------- +// Implementation + func (check *Checker) structType(styp *Struct, e *ast.StructType) { list := e.Fields if list == nil { diff --git a/src/go/types/type.go b/src/go/types/type.go index ce857d1c80e..6cd6c6b51f9 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -124,43 +124,6 @@ func NewSlice(elem Type) *Slice { return &Slice{elem: elem} } // Elem returns the element type of slice s. func (s *Slice) Elem() Type { return s.elem } -// A Struct represents a struct type. -type Struct struct { - fields []*Var - tags []string // field tags; nil if there are no tags -} - -// NewStruct returns a new struct with the given fields and corresponding field tags. -// If a field with index i has a tag, tags[i] must be that tag, but len(tags) may be -// only as long as required to hold the tag with the largest index i. Consequently, -// if no field has a tag, tags may be nil. -func NewStruct(fields []*Var, tags []string) *Struct { - var fset objset - for _, f := range fields { - if f.name != "_" && fset.insert(f) != nil { - panic("multiple fields with the same name") - } - } - if len(tags) > len(fields) { - panic("more tags than fields") - } - return &Struct{fields: fields, tags: tags} -} - -// NumFields returns the number of fields in the struct (including blank and embedded fields). -func (s *Struct) NumFields() int { return len(s.fields) } - -// Field returns the i'th field for 0 <= i < NumFields(). -func (s *Struct) Field(i int) *Var { return s.fields[i] } - -// Tag returns the i'th field tag for 0 <= i < NumFields(). -func (s *Struct) Tag(i int) string { - if i < len(s.tags) { - return s.tags[i] - } - return "" -} - // A Pointer represents a pointer type. type Pointer struct { base Type // element type @@ -729,7 +692,6 @@ var theTop = &top{} func (t *Basic) Underlying() Type { return t } func (t *Array) Underlying() Type { return t } func (t *Slice) Underlying() Type { return t } -func (t *Struct) Underlying() Type { return t } func (t *Pointer) Underlying() Type { return t } func (t *Tuple) Underlying() Type { return t } func (t *Signature) Underlying() Type { return t } @@ -745,7 +707,6 @@ func (t *top) Underlying() Type { return t } func (t *Basic) String() string { return TypeString(t, nil) } func (t *Array) String() string { return TypeString(t, nil) } func (t *Slice) String() string { return TypeString(t, nil) } -func (t *Struct) String() string { return TypeString(t, nil) } func (t *Pointer) String() string { return TypeString(t, nil) } func (t *Tuple) String() string { return TypeString(t, nil) } func (t *Signature) String() string { return TypeString(t, nil) } From e12d43866d3d68441cbbf858bca21ae20b1deeb9 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 10:43:26 -0400 Subject: [PATCH 706/940] [dev.typeparams] go/types: move Signature type decl into signature.go (cleanup) This is a port of CL 332091 to go/types. Notably types.Signature is missing APIs for RParams. This is left for a later CL, when the API is finalized. Change-Id: I70b664d656e8c1e32958a75e1d13eab5f3281bf9 Reviewed-on: https://go-review.googlesource.com/c/go/+/335038 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/signature.go | 65 +++++++++++++++++++++++++++++++++++++++ src/go/types/type.go | 58 ---------------------------------- 2 files changed, 65 insertions(+), 58 deletions(-) diff --git a/src/go/types/signature.go b/src/go/types/signature.go index 8048ba65194..665514587ee 100644 --- a/src/go/types/signature.go +++ b/src/go/types/signature.go @@ -11,6 +11,71 @@ import ( "go/token" ) +// ---------------------------------------------------------------------------- +// API + +// A Signature represents a (non-builtin) function or method type. +// The receiver is ignored when comparing signatures for identity. +type Signature struct { + // We need to keep the scope in Signature (rather than passing it around + // and store it in the Func Object) because when type-checking a function + // literal we call the general type checker which returns a general Type. + // We then unpack the *Signature and use the scope for the literal body. + rparams []*TypeName // receiver type parameters from left to right, or nil + tparams []*TypeName // type parameters from left to right, or nil + scope *Scope // function scope, present for package-local signatures + recv *Var // nil if not a method + params *Tuple // (incoming) parameters from left to right; or nil + results *Tuple // (outgoing) results from left to right; or nil + variadic bool // true if the last parameter's type is of the form ...T (or string, for append built-in only) +} + +// NewSignature returns a new function type for the given receiver, parameters, +// and results, either of which may be nil. If variadic is set, the function +// is variadic, it must have at least one parameter, and the last parameter +// must be of unnamed slice type. +func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature { + if variadic { + n := params.Len() + if n == 0 { + panic("types.NewSignature: variadic function must have at least one parameter") + } + if _, ok := params.At(n - 1).typ.(*Slice); !ok { + panic("types.NewSignature: variadic parameter must be of unnamed slice type") + } + } + return &Signature{recv: recv, params: params, results: results, variadic: variadic} +} + +// Recv returns the receiver of signature s (if a method), or nil if a +// function. It is ignored when comparing signatures for identity. +// +// For an abstract method, Recv returns the enclosing interface either +// as a *Named or an *Interface. Due to embedding, an interface may +// contain methods whose receiver type is a different interface. +func (s *Signature) Recv() *Var { return s.recv } + +// _TParams returns the type parameters of signature s, or nil. +func (s *Signature) TParams() []*TypeName { return s.tparams } + +// _SetTParams sets the type parameters of signature s. +func (s *Signature) SetTParams(tparams []*TypeName) { s.tparams = tparams } + +// Params returns the parameters of signature s, or nil. +func (s *Signature) Params() *Tuple { return s.params } + +// Results returns the results of signature s, or nil. +func (s *Signature) Results() *Tuple { return s.results } + +// Variadic reports whether the signature s is variadic. +func (s *Signature) Variadic() bool { return s.variadic } + +func (t *Signature) Underlying() Type { return t } +func (t *Signature) String() string { return TypeString(t, nil) } + +// ---------------------------------------------------------------------------- +// Implementation + // funcType type-checks a function or method type. func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast.FuncType) { check.openScope(ftyp, "function") diff --git a/src/go/types/type.go b/src/go/types/type.go index 6cd6c6b51f9..a4c47d17ea1 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -163,62 +163,6 @@ func (t *Tuple) Len() int { // At returns the i'th variable of tuple t. func (t *Tuple) At(i int) *Var { return t.vars[i] } -// A Signature represents a (non-builtin) function or method type. -// The receiver is ignored when comparing signatures for identity. -type Signature struct { - // We need to keep the scope in Signature (rather than passing it around - // and store it in the Func Object) because when type-checking a function - // literal we call the general type checker which returns a general Type. - // We then unpack the *Signature and use the scope for the literal body. - rparams []*TypeName // receiver type parameters from left to right, or nil - tparams []*TypeName // type parameters from left to right, or nil - scope *Scope // function scope, present for package-local signatures - recv *Var // nil if not a method - params *Tuple // (incoming) parameters from left to right; or nil - results *Tuple // (outgoing) results from left to right; or nil - variadic bool // true if the last parameter's type is of the form ...T (or string, for append built-in only) -} - -// NewSignature returns a new function type for the given receiver, parameters, -// and results, either of which may be nil. If variadic is set, the function -// is variadic, it must have at least one parameter, and the last parameter -// must be of unnamed slice type. -func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature { - if variadic { - n := params.Len() - if n == 0 { - panic("types.NewSignature: variadic function must have at least one parameter") - } - if _, ok := params.At(n - 1).typ.(*Slice); !ok { - panic("types.NewSignature: variadic parameter must be of unnamed slice type") - } - } - return &Signature{recv: recv, params: params, results: results, variadic: variadic} -} - -// Recv returns the receiver of signature s (if a method), or nil if a -// function. It is ignored when comparing signatures for identity. -// -// For an abstract method, Recv returns the enclosing interface either -// as a *Named or an *Interface. Due to embedding, an interface may -// contain methods whose receiver type is a different interface. -func (s *Signature) Recv() *Var { return s.recv } - -// _TParams returns the type parameters of signature s, or nil. -func (s *Signature) TParams() []*TypeName { return s.tparams } - -// _SetTParams sets the type parameters of signature s. -func (s *Signature) SetTParams(tparams []*TypeName) { s.tparams = tparams } - -// Params returns the parameters of signature s, or nil. -func (s *Signature) Params() *Tuple { return s.params } - -// Results returns the results of signature s, or nil. -func (s *Signature) Results() *Tuple { return s.results } - -// Variadic reports whether the signature s is variadic. -func (s *Signature) Variadic() bool { return s.variadic } - // An Interface represents an interface type. type Interface struct { obj *TypeName // type name object defining this interface; or nil (for better error messages) @@ -694,7 +638,6 @@ func (t *Array) Underlying() Type { return t } func (t *Slice) Underlying() Type { return t } func (t *Pointer) Underlying() Type { return t } func (t *Tuple) Underlying() Type { return t } -func (t *Signature) Underlying() Type { return t } func (t *Interface) Underlying() Type { return t } func (t *Map) Underlying() Type { return t } func (t *Chan) Underlying() Type { return t } @@ -709,7 +652,6 @@ func (t *Array) String() string { return TypeString(t, nil) } func (t *Slice) String() string { return TypeString(t, nil) } func (t *Pointer) String() string { return TypeString(t, nil) } func (t *Tuple) String() string { return TypeString(t, nil) } -func (t *Signature) String() string { return TypeString(t, nil) } func (t *Interface) String() string { return TypeString(t, nil) } func (t *Map) String() string { return TypeString(t, nil) } func (t *Chan) String() string { return TypeString(t, nil) } From 624d152db711cff77466b2049ae29377a110396a Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 10:45:51 -0400 Subject: [PATCH 707/940] [dev.typeparams] go/types: move Interface type decl into interface.go (cleanup) This is a port of CL 332092 to go/types. Change-Id: I9971c49570424368575108832eac0cd978eb3fe6 Reviewed-on: https://go-review.googlesource.com/c/go/+/335039 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/interface.go | 160 ++++++++++++++++++++++++++++++++++++++ src/go/types/type.go | 152 ------------------------------------ 2 files changed, 160 insertions(+), 152 deletions(-) diff --git a/src/go/types/interface.go b/src/go/types/interface.go index 367fc794775..91270cfcd37 100644 --- a/src/go/types/interface.go +++ b/src/go/types/interface.go @@ -10,6 +10,166 @@ import ( "go/token" ) +// ---------------------------------------------------------------------------- +// API + +// An Interface represents an interface type. +type Interface struct { + obj *TypeName // type name object defining this interface; or nil (for better error messages) + methods []*Func // ordered list of explicitly declared methods + embeddeds []Type // ordered list of explicitly embedded elements + embedPos *[]token.Pos // positions of embedded elements; or nil (for error messages) - use pointer to save space + complete bool // indicates that obj, methods, and embeddeds are set and type set can be computed + + tset *TypeSet // type set described by this interface, computed lazily +} + +// typeSet returns the type set for interface t. +func (t *Interface) typeSet() *TypeSet { return computeTypeSet(nil, token.NoPos, t) } + +// is reports whether interface t represents types that all satisfy f. +func (t *Interface) is(f func(Type, bool) bool) bool { + switch t := t.typeSet().types.(type) { + case nil, *top: + // TODO(gri) should settle on top or nil to represent this case + return false // we must have at least one type! (was bug) + case *Union: + return t.is(func(typ Type, tilde bool) bool { return f(typ, tilde) }) + default: + return f(t, false) + } +} + +// emptyInterface represents the empty (completed) interface +var emptyInterface = Interface{complete: true, tset: &topTypeSet} + +// NewInterface returns a new interface for the given methods and embedded types. +// NewInterface takes ownership of the provided methods and may modify their types +// by setting missing receivers. +// +// Deprecated: Use NewInterfaceType instead which allows arbitrary embedded types. +func NewInterface(methods []*Func, embeddeds []*Named) *Interface { + tnames := make([]Type, len(embeddeds)) + for i, t := range embeddeds { + tnames[i] = t + } + return NewInterfaceType(methods, tnames) +} + +// NewInterfaceType returns a new interface for the given methods and embedded types. +// NewInterfaceType takes ownership of the provided methods and may modify their types +// by setting missing receivers. +func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface { + if len(methods) == 0 && len(embeddeds) == 0 { + return &emptyInterface + } + + // set method receivers if necessary + typ := new(Interface) + for _, m := range methods { + if sig := m.typ.(*Signature); sig.recv == nil { + sig.recv = NewVar(m.pos, m.pkg, "", typ) + } + } + + // TODO(rfindley): this guard is not present in types2. Remove it? + // All embedded types should be interfaces; however, defined types + // may not yet be fully resolved. Only verify that non-defined types + // are interfaces. This matches the behavior of the code before the + // fix for #25301 (issue #25596). + for _, t := range embeddeds { + if _, ok := t.(*Named); !ok && !IsInterface(t) { + panic("embedded type is not an interface") + } + } + + // sort for API stability + sortMethods(methods) + + typ.methods = methods + typ.embeddeds = embeddeds + typ.complete = true + + return typ +} + +// NumExplicitMethods returns the number of explicitly declared methods of interface t. +func (t *Interface) NumExplicitMethods() int { return len(t.methods) } + +// ExplicitMethod returns the i'th explicitly declared method of interface t for 0 <= i < t.NumExplicitMethods(). +// The methods are ordered by their unique Id. +func (t *Interface) ExplicitMethod(i int) *Func { return t.methods[i] } + +// NumEmbeddeds returns the number of embedded types in interface t. +func (t *Interface) NumEmbeddeds() int { return len(t.embeddeds) } + +// Embedded returns the i'th embedded defined (*Named) type of interface t for 0 <= i < t.NumEmbeddeds(). +// The result is nil if the i'th embedded type is not a defined type. +// +// Deprecated: Use EmbeddedType which is not restricted to defined (*Named) types. +func (t *Interface) Embedded(i int) *Named { tname, _ := t.embeddeds[i].(*Named); return tname } + +// EmbeddedType returns the i'th embedded type of interface t for 0 <= i < t.NumEmbeddeds(). +func (t *Interface) EmbeddedType(i int) Type { return t.embeddeds[i] } + +// NumMethods returns the total number of methods of interface t. +func (t *Interface) NumMethods() int { return t.typeSet().NumMethods() } + +// Method returns the i'th method of interface t for 0 <= i < t.NumMethods(). +// The methods are ordered by their unique Id. +func (t *Interface) Method(i int) *Func { return t.typeSet().Method(i) } + +// Empty reports whether t is the empty interface. +func (t *Interface) Empty() bool { return t.typeSet().IsTop() } + +// IsComparable reports whether interface t is or embeds the predeclared interface "comparable". +func (t *Interface) IsComparable() bool { return t.typeSet().IsComparable() } + +// IsConstraint reports whether interface t is not just a method set. +func (t *Interface) IsConstraint() bool { return !t.typeSet().IsMethodSet() } + +// isSatisfiedBy reports whether interface t's type list is satisfied by the type typ. +// If the type list is empty (absent), typ trivially satisfies the interface. +// TODO(gri) This is not a great name. Eventually, we should have a more comprehensive +// "implements" predicate. +func (t *Interface) isSatisfiedBy(typ Type) bool { + t.Complete() + switch t := t.typeSet().types.(type) { + case nil: + return true // no type restrictions + case *Union: + r, _ := t.intersect(typ, false) + return r != nil + default: + return Identical(t, typ) + } +} + +// Complete computes the interface's type set. It must be called by users of +// NewInterfaceType and NewInterface after the interface's embedded types are +// fully defined and before using the interface type in any way other than to +// form other types. The interface must not contain duplicate methods or a +// panic occurs. Complete returns the receiver. +// +// Deprecated: Type sets are now computed lazily, on demand; this function +// is only here for backward-compatibility. It does not have to +// be called explicitly anymore. +func (t *Interface) Complete() *Interface { + // Some tests are still depending on the state change + // (string representation of an Interface not containing an + // /* incomplete */ marker) caused by the explicit Complete + // call, so we compute the type set eagerly here. + t.complete = true + t.typeSet() + return t +} + +func (t *Interface) Underlying() Type { return t } +func (t *Interface) String() string { return TypeString(t, nil) } + +// ---------------------------------------------------------------------------- +// Implementation + func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, def *Named) { var tlist []ast.Expr var tname *ast.Ident // "type" name of first entry in a type list declaration diff --git a/src/go/types/type.go b/src/go/types/type.go index a4c47d17ea1..2adc2fa3ca9 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -163,156 +163,6 @@ func (t *Tuple) Len() int { // At returns the i'th variable of tuple t. func (t *Tuple) At(i int) *Var { return t.vars[i] } -// An Interface represents an interface type. -type Interface struct { - obj *TypeName // type name object defining this interface; or nil (for better error messages) - methods []*Func // ordered list of explicitly declared methods - embeddeds []Type // ordered list of explicitly embedded elements - embedPos *[]token.Pos // positions of embedded elements; or nil (for error messages) - use pointer to save space - complete bool // indicates that obj, methods, and embeddeds are set and type set can be computed - - tset *TypeSet // type set described by this interface, computed lazily -} - -// typeSet returns the type set for interface t. -func (t *Interface) typeSet() *TypeSet { return computeTypeSet(nil, token.NoPos, t) } - -// is reports whether interface t represents types that all satisfy f. -func (t *Interface) is(f func(Type, bool) bool) bool { - switch t := t.typeSet().types.(type) { - case nil, *top: - // TODO(gri) should settle on top or nil to represent this case - return false // we must have at least one type! (was bug) - case *Union: - return t.is(func(typ Type, tilde bool) bool { return f(typ, tilde) }) - default: - return f(t, false) - } -} - -// emptyInterface represents the empty (completed) interface -var emptyInterface = Interface{complete: true, tset: &topTypeSet} - -// NewInterface returns a new interface for the given methods and embedded types. -// NewInterface takes ownership of the provided methods and may modify their types -// by setting missing receivers. -// -// Deprecated: Use NewInterfaceType instead which allows arbitrary embedded types. -func NewInterface(methods []*Func, embeddeds []*Named) *Interface { - tnames := make([]Type, len(embeddeds)) - for i, t := range embeddeds { - tnames[i] = t - } - return NewInterfaceType(methods, tnames) -} - -// NewInterfaceType returns a new interface for the given methods and embedded types. -// NewInterfaceType takes ownership of the provided methods and may modify their types -// by setting missing receivers. -func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface { - if len(methods) == 0 && len(embeddeds) == 0 { - return &emptyInterface - } - - // set method receivers if necessary - typ := new(Interface) - for _, m := range methods { - if sig := m.typ.(*Signature); sig.recv == nil { - sig.recv = NewVar(m.pos, m.pkg, "", typ) - } - } - - // All embedded types should be interfaces; however, defined types - // may not yet be fully resolved. Only verify that non-defined types - // are interfaces. This matches the behavior of the code before the - // fix for #25301 (issue #25596). - for _, t := range embeddeds { - if _, ok := t.(*Named); !ok && !IsInterface(t) { - panic("embedded type is not an interface") - } - } - - // sort for API stability - sortMethods(methods) - - typ.methods = methods - typ.embeddeds = embeddeds - typ.complete = true - - return typ -} - -// NumExplicitMethods returns the number of explicitly declared methods of interface t. -func (t *Interface) NumExplicitMethods() int { return len(t.methods) } - -// ExplicitMethod returns the i'th explicitly declared method of interface t for 0 <= i < t.NumExplicitMethods(). -// The methods are ordered by their unique Id. -func (t *Interface) ExplicitMethod(i int) *Func { return t.methods[i] } - -// NumEmbeddeds returns the number of embedded types in interface t. -func (t *Interface) NumEmbeddeds() int { return len(t.embeddeds) } - -// Embedded returns the i'th embedded defined (*Named) type of interface t for 0 <= i < t.NumEmbeddeds(). -// The result is nil if the i'th embedded type is not a defined type. -// -// Deprecated: Use EmbeddedType which is not restricted to defined (*Named) types. -func (t *Interface) Embedded(i int) *Named { tname, _ := t.embeddeds[i].(*Named); return tname } - -// EmbeddedType returns the i'th embedded type of interface t for 0 <= i < t.NumEmbeddeds(). -func (t *Interface) EmbeddedType(i int) Type { return t.embeddeds[i] } - -// NumMethods returns the total number of methods of interface t. -func (t *Interface) NumMethods() int { return t.typeSet().NumMethods() } - -// Method returns the i'th method of interface t for 0 <= i < t.NumMethods(). -// The methods are ordered by their unique Id. -func (t *Interface) Method(i int) *Func { return t.typeSet().Method(i) } - -// Empty reports whether t is the empty interface. -func (t *Interface) Empty() bool { return t.typeSet().IsTop() } - -// IsComparable reports whether interface t is or embeds the predeclared interface "comparable". -func (t *Interface) IsComparable() bool { return t.typeSet().IsComparable() } - -// IsConstraint reports whether interface t is not just a method set. -func (t *Interface) IsConstraint() bool { return !t.typeSet().IsMethodSet() } - -// isSatisfiedBy reports whether interface t's type list is satisfied by the type typ. -// If the type list is empty (absent), typ trivially satisfies the interface. -// TODO(gri) This is not a great name. Eventually, we should have a more comprehensive -// "implements" predicate. -func (t *Interface) isSatisfiedBy(typ Type) bool { - t.Complete() - switch t := t.typeSet().types.(type) { - case nil: - return true // no type restrictions - case *Union: - r, _ := t.intersect(typ, false) - return r != nil - default: - return Identical(t, typ) - } -} - -// Complete computes the interface's type set. It must be called by users of -// NewInterfaceType and NewInterface after the interface's embedded types are -// fully defined and before using the interface type in any way other than to -// form other types. The interface must not contain duplicate methods or a -// panic occurs. Complete returns the receiver. -// -// Deprecated: Type sets are now computed lazily, on demand; this function -// is only here for backward-compatibility. It does not have to -// be called explicitly anymore. -func (t *Interface) Complete() *Interface { - // Some tests are still depending on the state change - // (string representation of an Interface not containing an - // /* incomplete */ marker) caused by the explicit Complete - // call, so we compute the type set eagerly here. - t.complete = true - t.typeSet() - return t -} - // A Map represents a map type. type Map struct { key, elem Type @@ -638,7 +488,6 @@ func (t *Array) Underlying() Type { return t } func (t *Slice) Underlying() Type { return t } func (t *Pointer) Underlying() Type { return t } func (t *Tuple) Underlying() Type { return t } -func (t *Interface) Underlying() Type { return t } func (t *Map) Underlying() Type { return t } func (t *Chan) Underlying() Type { return t } func (t *Named) Underlying() Type { return t.expand().underlying } @@ -652,7 +501,6 @@ func (t *Array) String() string { return TypeString(t, nil) } func (t *Slice) String() string { return TypeString(t, nil) } func (t *Pointer) String() string { return TypeString(t, nil) } func (t *Tuple) String() string { return TypeString(t, nil) } -func (t *Interface) String() string { return TypeString(t, nil) } func (t *Map) String() string { return TypeString(t, nil) } func (t *Chan) String() string { return TypeString(t, nil) } func (t *Named) String() string { return TypeString(t, nil) } From 521828091c73e2af67bc2210b7c94cc54076f17b Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 10:59:53 -0400 Subject: [PATCH 708/940] [dev.typeparams] go/types: move (remaining) type decls into their own files (cleanup) This is a port of CL 332093 to go/types. A missing comment is added to named.go, and some TODOs were added to converge on the TypeParam API. Change-Id: I781a1d0d3fc6c11bb323123e954c106094d998ef Reviewed-on: https://go-review.googlesource.com/c/go/+/335040 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/array.go | 25 ++ src/go/types/basic.go | 82 +++++++ src/go/types/chan.go | 35 +++ src/go/types/instance.go | 58 +++++ src/go/types/map.go | 24 ++ src/go/types/named.go | 144 +++++++++++ src/go/types/pointer.go | 19 ++ src/go/types/slice.go | 19 ++ src/go/types/tuple.go | 36 +++ src/go/types/type.go | 486 ++------------------------------------ src/go/types/typeparam.go | 72 ++++++ 11 files changed, 532 insertions(+), 468 deletions(-) create mode 100644 src/go/types/array.go create mode 100644 src/go/types/basic.go create mode 100644 src/go/types/chan.go create mode 100644 src/go/types/instance.go create mode 100644 src/go/types/map.go create mode 100644 src/go/types/named.go create mode 100644 src/go/types/pointer.go create mode 100644 src/go/types/slice.go create mode 100644 src/go/types/tuple.go create mode 100644 src/go/types/typeparam.go diff --git a/src/go/types/array.go b/src/go/types/array.go new file mode 100644 index 00000000000..5b28474bb33 --- /dev/null +++ b/src/go/types/array.go @@ -0,0 +1,25 @@ +// Copyright 2011 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 types + +// An Array represents an array type. +type Array struct { + len int64 + elem Type +} + +// NewArray returns a new array type for the given element type and length. +// A negative length indicates an unknown length. +func NewArray(elem Type, len int64) *Array { return &Array{len: len, elem: elem} } + +// Len returns the length of array a. +// A negative result indicates an unknown length. +func (a *Array) Len() int64 { return a.len } + +// Elem returns element type of array a. +func (a *Array) Elem() Type { return a.elem } + +func (t *Array) Underlying() Type { return t } +func (t *Array) String() string { return TypeString(t, nil) } diff --git a/src/go/types/basic.go b/src/go/types/basic.go new file mode 100644 index 00000000000..215923f6573 --- /dev/null +++ b/src/go/types/basic.go @@ -0,0 +1,82 @@ +// Copyright 2011 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 types + +// BasicKind describes the kind of basic type. +type BasicKind int + +const ( + Invalid BasicKind = iota // type is invalid + + // predeclared types + Bool + Int + Int8 + Int16 + Int32 + Int64 + Uint + Uint8 + Uint16 + Uint32 + Uint64 + Uintptr + Float32 + Float64 + Complex64 + Complex128 + String + UnsafePointer + + // types for untyped values + UntypedBool + UntypedInt + UntypedRune + UntypedFloat + UntypedComplex + UntypedString + UntypedNil + + // aliases + Byte = Uint8 + Rune = Int32 +) + +// BasicInfo is a set of flags describing properties of a basic type. +type BasicInfo int + +// Properties of basic types. +const ( + IsBoolean BasicInfo = 1 << iota + IsInteger + IsUnsigned + IsFloat + IsComplex + IsString + IsUntyped + + IsOrdered = IsInteger | IsFloat | IsString + IsNumeric = IsInteger | IsFloat | IsComplex + IsConstType = IsBoolean | IsNumeric | IsString +) + +// A Basic represents a basic type. +type Basic struct { + kind BasicKind + info BasicInfo + name string +} + +// Kind returns the kind of basic type b. +func (b *Basic) Kind() BasicKind { return b.kind } + +// Info returns information about properties of basic type b. +func (b *Basic) Info() BasicInfo { return b.info } + +// Name returns the name of basic type b. +func (b *Basic) Name() string { return b.name } + +func (t *Basic) Underlying() Type { return t } +func (t *Basic) String() string { return TypeString(t, nil) } diff --git a/src/go/types/chan.go b/src/go/types/chan.go new file mode 100644 index 00000000000..1f7b72be309 --- /dev/null +++ b/src/go/types/chan.go @@ -0,0 +1,35 @@ +// Copyright 2011 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 types + +// A Chan represents a channel type. +type Chan struct { + dir ChanDir + elem Type +} + +// A ChanDir value indicates a channel direction. +type ChanDir int + +// The direction of a channel is indicated by one of these constants. +const ( + SendRecv ChanDir = iota + SendOnly + RecvOnly +) + +// NewChan returns a new channel type for the given direction and element type. +func NewChan(dir ChanDir, elem Type) *Chan { + return &Chan{dir: dir, elem: elem} +} + +// Dir returns the direction of channel c. +func (c *Chan) Dir() ChanDir { return c.dir } + +// Elem returns the element type of channel c. +func (c *Chan) Elem() Type { return c.elem } + +func (t *Chan) Underlying() Type { return t } +func (t *Chan) String() string { return TypeString(t, nil) } diff --git a/src/go/types/instance.go b/src/go/types/instance.go new file mode 100644 index 00000000000..c57a9470601 --- /dev/null +++ b/src/go/types/instance.go @@ -0,0 +1,58 @@ +// Copyright 2011 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 types + +import "go/token" + +// An instance represents an instantiated generic type syntactically +// (without expanding the instantiation). Type instances appear only +// during type-checking and are replaced by their fully instantiated +// (expanded) types before the end of type-checking. +type instance struct { + check *Checker // for lazy instantiation + pos token.Pos // position of type instantiation; for error reporting only + base *Named // parameterized type to be instantiated + targs []Type // type arguments + poslist []token.Pos // position of each targ; for error reporting only + value Type // base(targs...) after instantiation or Typ[Invalid]; nil if not yet set +} + +// expand returns the instantiated (= expanded) type of t. +// The result is either an instantiated *Named type, or +// Typ[Invalid] if there was an error. +func (t *instance) expand() Type { + v := t.value + if v == nil { + v = t.check.instantiate(t.pos, t.base, t.targs, t.poslist) + if v == nil { + v = Typ[Invalid] + } + t.value = v + } + // After instantiation we must have an invalid or a *Named type. + if debug && v != Typ[Invalid] { + _ = v.(*Named) + } + return v +} + +// expand expands a type instance into its instantiated +// type and leaves all other types alone. expand does +// not recurse. +func expand(typ Type) Type { + if t, _ := typ.(*instance); t != nil { + return t.expand() + } + return typ +} + +// expandf is set to expand. +// Call expandf when calling expand causes compile-time cycle error. +var expandf func(Type) Type + +func init() { expandf = expand } + +func (t *instance) Underlying() Type { return t } +func (t *instance) String() string { return TypeString(t, nil) } diff --git a/src/go/types/map.go b/src/go/types/map.go new file mode 100644 index 00000000000..01e13b214e9 --- /dev/null +++ b/src/go/types/map.go @@ -0,0 +1,24 @@ +// Copyright 2011 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 types + +// A Map represents a map type. +type Map struct { + key, elem Type +} + +// NewMap returns a new map for the given key and element types. +func NewMap(key, elem Type) *Map { + return &Map{key: key, elem: elem} +} + +// Key returns the key type of map m. +func (m *Map) Key() Type { return m.key } + +// Elem returns the element type of map m. +func (m *Map) Elem() Type { return m.elem } + +func (t *Map) Underlying() Type { return t } +func (t *Map) String() string { return TypeString(t, nil) } diff --git a/src/go/types/named.go b/src/go/types/named.go new file mode 100644 index 00000000000..8f2e8706a19 --- /dev/null +++ b/src/go/types/named.go @@ -0,0 +1,144 @@ +// Copyright 2011 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 types + +import "sync" + +// TODO(rfindley) Clean up Named struct below; specifically the fromRHS field (can we use underlying?). + +// A Named represents a named (defined) type. +type Named struct { + check *Checker // for Named.under implementation; nilled once under has been called + info typeInfo // for cycle detection + obj *TypeName // corresponding declared object + orig *Named // original, uninstantiated type + fromRHS Type // type (on RHS of declaration) this *Named type is derived of (for cycle reporting) + underlying Type // possibly a *Named during setup; never a *Named once set up completely + tparams []*TypeName // type parameters, or nil + targs []Type // type arguments (after instantiation), or nil + methods []*Func // methods declared for this type (not the method set of this type); signatures are type-checked lazily + + resolve func(*Named) ([]*TypeName, Type, []*Func) + once sync.Once +} + +// NewNamed returns a new named type for the given type name, underlying type, and associated methods. +// If the given type name obj doesn't have a type yet, its type is set to the returned named type. +// The underlying type must not be a *Named. +func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named { + if _, ok := underlying.(*Named); ok { + panic("types.NewNamed: underlying type must not be *Named") + } + return (*Checker)(nil).newNamed(obj, nil, underlying, nil, methods) +} + +func (t *Named) expand() *Named { + if t.resolve == nil { + return t + } + + t.once.Do(func() { + // TODO(mdempsky): Since we're passing t to resolve anyway + // (necessary because types2 expects the receiver type for methods + // on defined interface types to be the Named rather than the + // underlying Interface), maybe it should just handle calling + // SetTParams, SetUnderlying, and AddMethod instead? Those + // methods would need to support reentrant calls though. It would + // also make the API more future-proof towards further extensions + // (like SetTParams). + + tparams, underlying, methods := t.resolve(t) + + switch underlying.(type) { + case nil, *Named: + panic("invalid underlying type") + } + + t.tparams = tparams + t.underlying = underlying + t.methods = methods + }) + return t +} + +// newNamed is like NewNamed but with a *Checker receiver and additional orig argument. +func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams []*TypeName, methods []*Func) *Named { + typ := &Named{check: check, obj: obj, orig: orig, fromRHS: underlying, underlying: underlying, tparams: tparams, methods: methods} + if typ.orig == nil { + typ.orig = typ + } + if obj.typ == nil { + obj.typ = typ + } + // Ensure that typ is always expanded, at which point the check field can be + // nilled out. + // + // Note that currently we cannot nil out check inside typ.under(), because + // it's possible that typ is expanded multiple times. + // + // TODO(rFindley): clean this up so that under is the only function mutating + // named types. + if check != nil { + check.later(func() { + switch typ.under().(type) { + case *Named, *instance: + panic("internal error: unexpanded underlying type") + } + typ.check = nil + }) + } + return typ +} + +// Obj returns the type name for the named type t. +func (t *Named) Obj() *TypeName { return t.obj } + +// _Orig returns the original generic type an instantiated type is derived from. +// If t is not an instantiated type, the result is t. +func (t *Named) _Orig() *Named { return t.orig } + +// TODO(gri) Come up with a better representation and API to distinguish +// between parameterized instantiated and non-instantiated types. + +// _TParams returns the type parameters of the named type t, or nil. +// The result is non-nil for an (originally) parameterized type even if it is instantiated. +func (t *Named) TParams() []*TypeName { return t.expand().tparams } + +// _SetTParams sets the type parameters of the named type t. +func (t *Named) SetTParams(tparams []*TypeName) { t.expand().tparams = tparams } + +// _TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated. +func (t *Named) TArgs() []Type { return t.targs } + +// SetTArgs sets the type arguments of the named type t. +func (t *Named) SetTArgs(args []Type) { t.targs = args } + +// NumMethods returns the number of explicit methods whose receiver is named type t. +func (t *Named) NumMethods() int { return len(t.expand().methods) } + +// Method returns the i'th method of named type t for 0 <= i < t.NumMethods(). +func (t *Named) Method(i int) *Func { return t.expand().methods[i] } + +// SetUnderlying sets the underlying type and marks t as complete. +func (t *Named) SetUnderlying(underlying Type) { + if underlying == nil { + panic("types.Named.SetUnderlying: underlying type must not be nil") + } + if _, ok := underlying.(*Named); ok { + panic("types.Named.SetUnderlying: underlying type must not be *Named") + } + t.expand().underlying = underlying +} + +// AddMethod adds method m unless it is already in the method list. +func (t *Named) AddMethod(m *Func) { + t.expand() + if i, _ := lookupMethod(t.methods, m.pkg, m.name); i < 0 { + t.methods = append(t.methods, m) + } +} + +func (t *Named) Underlying() Type { return t.expand().underlying } +func (t *Named) String() string { return TypeString(t, nil) } diff --git a/src/go/types/pointer.go b/src/go/types/pointer.go new file mode 100644 index 00000000000..6352ee57e2c --- /dev/null +++ b/src/go/types/pointer.go @@ -0,0 +1,19 @@ +// Copyright 2011 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 types + +// A Pointer represents a pointer type. +type Pointer struct { + base Type // element type +} + +// NewPointer returns a new pointer type for the given element (base) type. +func NewPointer(elem Type) *Pointer { return &Pointer{base: elem} } + +// Elem returns the element type for the given pointer p. +func (p *Pointer) Elem() Type { return p.base } + +func (t *Pointer) Underlying() Type { return t } +func (t *Pointer) String() string { return TypeString(t, nil) } diff --git a/src/go/types/slice.go b/src/go/types/slice.go new file mode 100644 index 00000000000..debdd81586c --- /dev/null +++ b/src/go/types/slice.go @@ -0,0 +1,19 @@ +// Copyright 2011 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 types + +// A Slice represents a slice type. +type Slice struct { + elem Type +} + +// NewSlice returns a new slice type for the given element type. +func NewSlice(elem Type) *Slice { return &Slice{elem: elem} } + +// Elem returns the element type of slice s. +func (s *Slice) Elem() Type { return s.elem } + +func (t *Slice) Underlying() Type { return t } +func (t *Slice) String() string { return TypeString(t, nil) } diff --git a/src/go/types/tuple.go b/src/go/types/tuple.go new file mode 100644 index 00000000000..16d28bc9a6f --- /dev/null +++ b/src/go/types/tuple.go @@ -0,0 +1,36 @@ +// Copyright 2011 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 types + +// A Tuple represents an ordered list of variables; a nil *Tuple is a valid (empty) tuple. +// Tuples are used as components of signatures and to represent the type of multiple +// assignments; they are not first class types of Go. +type Tuple struct { + vars []*Var +} + +// NewTuple returns a new tuple for the given variables. +func NewTuple(x ...*Var) *Tuple { + if len(x) > 0 { + return &Tuple{vars: x} + } + // TODO(gri) Don't represent empty tuples with a (*Tuple)(nil) pointer; + // it's too subtle and causes problems. + return nil +} + +// Len returns the number variables of tuple t. +func (t *Tuple) Len() int { + if t != nil { + return len(t.vars) + } + return 0 +} + +// At returns the i'th variable of tuple t. +func (t *Tuple) At(i int) *Var { return t.vars[i] } + +func (t *Tuple) Underlying() Type { return t } +func (t *Tuple) String() string { return TypeString(t, nil) } diff --git a/src/go/types/type.go b/src/go/types/type.go index 2adc2fa3ca9..662dd859f09 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -4,12 +4,6 @@ package types -import ( - "go/token" - "sync" - "sync/atomic" -) - // A Type represents a type of Go. // All types implement the Type interface. type Type interface { @@ -22,379 +16,31 @@ type Type interface { String() string } -// BasicKind describes the kind of basic type. -type BasicKind int +// top represents the top of the type lattice. +// It is the underlying type of a type parameter that +// can be satisfied by any type (ignoring methods), +// because its type constraint contains no restrictions +// besides methods. +type top struct{} -const ( - Invalid BasicKind = iota // type is invalid +// theTop is the singleton top type. +var theTop = &top{} - // predeclared types - Bool - Int - Int8 - Int16 - Int32 - Int64 - Uint - Uint8 - Uint16 - Uint32 - Uint64 - Uintptr - Float32 - Float64 - Complex64 - Complex128 - String - UnsafePointer +func (t *top) Underlying() Type { return t } +func (t *top) String() string { return TypeString(t, nil) } - // types for untyped values - UntypedBool - UntypedInt - UntypedRune - UntypedFloat - UntypedComplex - UntypedString - UntypedNil - - // aliases - Byte = Uint8 - Rune = Int32 -) - -// BasicInfo is a set of flags describing properties of a basic type. -type BasicInfo int - -// Properties of basic types. -const ( - IsBoolean BasicInfo = 1 << iota - IsInteger - IsUnsigned - IsFloat - IsComplex - IsString - IsUntyped - - IsOrdered = IsInteger | IsFloat | IsString - IsNumeric = IsInteger | IsFloat | IsComplex - IsConstType = IsBoolean | IsNumeric | IsString -) - -// A Basic represents a basic type. -type Basic struct { - kind BasicKind - info BasicInfo - name string -} - -// Kind returns the kind of basic type b. -func (b *Basic) Kind() BasicKind { return b.kind } - -// Info returns information about properties of basic type b. -func (b *Basic) Info() BasicInfo { return b.info } - -// Name returns the name of basic type b. -func (b *Basic) Name() string { return b.name } - -// An Array represents an array type. -type Array struct { - len int64 - elem Type -} - -// NewArray returns a new array type for the given element type and length. -// A negative length indicates an unknown length. -func NewArray(elem Type, len int64) *Array { return &Array{len: len, elem: elem} } - -// Len returns the length of array a. -// A negative result indicates an unknown length. -func (a *Array) Len() int64 { return a.len } - -// Elem returns element type of array a. -func (a *Array) Elem() Type { return a.elem } - -// A Slice represents a slice type. -type Slice struct { - elem Type -} - -// NewSlice returns a new slice type for the given element type. -func NewSlice(elem Type) *Slice { return &Slice{elem: elem} } - -// Elem returns the element type of slice s. -func (s *Slice) Elem() Type { return s.elem } - -// A Pointer represents a pointer type. -type Pointer struct { - base Type // element type -} - -// NewPointer returns a new pointer type for the given element (base) type. -func NewPointer(elem Type) *Pointer { return &Pointer{base: elem} } - -// Elem returns the element type for the given pointer p. -func (p *Pointer) Elem() Type { return p.base } - -// A Tuple represents an ordered list of variables; a nil *Tuple is a valid (empty) tuple. -// Tuples are used as components of signatures and to represent the type of multiple -// assignments; they are not first class types of Go. -type Tuple struct { - vars []*Var -} - -// NewTuple returns a new tuple for the given variables. -func NewTuple(x ...*Var) *Tuple { - if len(x) > 0 { - return &Tuple{vars: x} +// under returns the true expanded underlying type. +// If it doesn't exist, the result is Typ[Invalid]. +// under must only be called when a type is known +// to be fully set up. +func under(t Type) Type { + // TODO(gri) is this correct for *Union? + if n := asNamed(t); n != nil { + return n.under() } - // TODO(gri) Don't represent empty tuples with a (*Tuple)(nil) pointer; - // it's too subtle and causes problems. - return nil -} - -// Len returns the number variables of tuple t. -func (t *Tuple) Len() int { - if t != nil { - return len(t.vars) - } - return 0 -} - -// At returns the i'th variable of tuple t. -func (t *Tuple) At(i int) *Var { return t.vars[i] } - -// A Map represents a map type. -type Map struct { - key, elem Type -} - -// NewMap returns a new map for the given key and element types. -func NewMap(key, elem Type) *Map { - return &Map{key: key, elem: elem} -} - -// Key returns the key type of map m. -func (m *Map) Key() Type { return m.key } - -// Elem returns the element type of map m. -func (m *Map) Elem() Type { return m.elem } - -// A Chan represents a channel type. -type Chan struct { - dir ChanDir - elem Type -} - -// A ChanDir value indicates a channel direction. -type ChanDir int - -// The direction of a channel is indicated by one of these constants. -const ( - SendRecv ChanDir = iota - SendOnly - RecvOnly -) - -// NewChan returns a new channel type for the given direction and element type. -func NewChan(dir ChanDir, elem Type) *Chan { - return &Chan{dir: dir, elem: elem} -} - -// Dir returns the direction of channel c. -func (c *Chan) Dir() ChanDir { return c.dir } - -// Elem returns the element type of channel c. -func (c *Chan) Elem() Type { return c.elem } - -// TODO(rfindley) Clean up Named struct below; specifically the fromRHS field (can we use underlying?). - -// A Named represents a named (defined) type. -type Named struct { - check *Checker // for Named.under implementation; nilled once under has been called - info typeInfo // for cycle detection - obj *TypeName // corresponding declared object - orig *Named // original, uninstantiated type - fromRHS Type // type (on RHS of declaration) this *Named type is derived of (for cycle reporting) - underlying Type // possibly a *Named during setup; never a *Named once set up completely - tparams []*TypeName // type parameters, or nil - targs []Type // type arguments (after instantiation), or nil - methods []*Func // methods declared for this type (not the method set of this type); signatures are type-checked lazily - - resolve func(*Named) ([]*TypeName, Type, []*Func) - once sync.Once -} - -// NewNamed returns a new named type for the given type name, underlying type, and associated methods. -// If the given type name obj doesn't have a type yet, its type is set to the returned named type. -// The underlying type must not be a *Named. -func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named { - if _, ok := underlying.(*Named); ok { - panic("types.NewNamed: underlying type must not be *Named") - } - return (*Checker)(nil).newNamed(obj, nil, underlying, nil, methods) -} - -func (t *Named) expand() *Named { - if t.resolve == nil { - return t - } - - t.once.Do(func() { - // TODO(mdempsky): Since we're passing t to resolve anyway - // (necessary because types2 expects the receiver type for methods - // on defined interface types to be the Named rather than the - // underlying Interface), maybe it should just handle calling - // SetTParams, SetUnderlying, and AddMethod instead? Those - // methods would need to support reentrant calls though. It would - // also make the API more future-proof towards further extensions - // (like SetTParams). - - tparams, underlying, methods := t.resolve(t) - - switch underlying.(type) { - case nil, *Named: - panic("invalid underlying type") - } - - t.tparams = tparams - t.underlying = underlying - t.methods = methods - }) return t } -func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams []*TypeName, methods []*Func) *Named { - typ := &Named{check: check, obj: obj, orig: orig, fromRHS: underlying, underlying: underlying, tparams: tparams, methods: methods} - if typ.orig == nil { - typ.orig = typ - } - if obj.typ == nil { - obj.typ = typ - } - // Ensure that typ is always expanded, at which point the check field can be - // nilled out. - // - // Note that currently we cannot nil out check inside typ.under(), because - // it's possible that typ is expanded multiple times. - // - // TODO(rFindley): clean this up so that under is the only function mutating - // named types. - if check != nil { - check.later(func() { - switch typ.under().(type) { - case *Named, *instance: - panic("internal error: unexpanded underlying type") - } - typ.check = nil - }) - } - return typ -} - -// Obj returns the type name for the named type t. -func (t *Named) Obj() *TypeName { return t.obj } - -// _Orig returns the original generic type an instantiated type is derived from. -// If t is not an instantiated type, the result is t. -func (t *Named) _Orig() *Named { return t.orig } - -// TODO(gri) Come up with a better representation and API to distinguish -// between parameterized instantiated and non-instantiated types. - -// _TParams returns the type parameters of the named type t, or nil. -// The result is non-nil for an (originally) parameterized type even if it is instantiated. -func (t *Named) TParams() []*TypeName { return t.expand().tparams } - -// _SetTParams sets the type parameters of the named type t. -func (t *Named) SetTParams(tparams []*TypeName) { t.expand().tparams = tparams } - -// _TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated. -func (t *Named) TArgs() []Type { return t.targs } - -// SetTArgs sets the type arguments of the named type t. -func (t *Named) SetTArgs(args []Type) { t.targs = args } - -// NumMethods returns the number of explicit methods whose receiver is named type t. -func (t *Named) NumMethods() int { return len(t.expand().methods) } - -// Method returns the i'th method of named type t for 0 <= i < t.NumMethods(). -func (t *Named) Method(i int) *Func { return t.expand().methods[i] } - -// SetUnderlying sets the underlying type and marks t as complete. -func (t *Named) SetUnderlying(underlying Type) { - if underlying == nil { - panic("types.Named.SetUnderlying: underlying type must not be nil") - } - if _, ok := underlying.(*Named); ok { - panic("types.Named.SetUnderlying: underlying type must not be *Named") - } - t.expand().underlying = underlying -} - -// AddMethod adds method m unless it is already in the method list. -func (t *Named) AddMethod(m *Func) { - t.expand() - if i, _ := lookupMethod(t.methods, m.pkg, m.name); i < 0 { - t.methods = append(t.methods, m) - } -} - -// Note: This is a uint32 rather than a uint64 because the -// respective 64 bit atomic instructions are not available -// on all platforms. -var lastID uint32 - -// nextID returns a value increasing monotonically by 1 with -// each call, starting with 1. It may be called concurrently. -func nextID() uint64 { return uint64(atomic.AddUint32(&lastID, 1)) } - -// A TypeParam represents a type parameter type. -type TypeParam struct { - check *Checker // for lazy type bound completion - id uint64 // unique id, for debugging only - obj *TypeName // corresponding type name - index int // type parameter index in source order, starting at 0 - bound Type // *Named or *Interface; underlying type is always *Interface -} - -// NewTypeParam returns a new TypeParam. -func NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam { - return (*Checker)(nil).newTypeParam(obj, index, bound) -} - -func (check *Checker) newTypeParam(obj *TypeName, index int, bound Type) *TypeParam { - assert(bound != nil) - - // Always increment lastID, even if it is not used. - id := nextID() - if check != nil { - check.nextID++ - id = check.nextID - } - - typ := &TypeParam{check: check, id: id, obj: obj, index: index, bound: bound} - if obj.typ == nil { - obj.typ = typ - } - return typ -} - -func (t *TypeParam) Bound() *Interface { - // we may not have an interface (error reported elsewhere) - iface, _ := under(t.bound).(*Interface) - if iface == nil { - return &emptyInterface - } - // use the type bound position if we have one - pos := token.NoPos - if n, _ := t.bound.(*Named); n != nil { - pos = n.obj.pos - } - // TODO(rFindley) switch this to an unexported method on Checker. - computeTypeSet(t.check, pos, iface) - return iface -} - // optype returns a type's operational type. Except for type parameters, // the operational type is the same as the underlying type (as returned // by under). For Type parameters, the operational type is determined @@ -424,102 +70,6 @@ func optype(typ Type) Type { return under(typ) } -// An instance represents an instantiated generic type syntactically -// (without expanding the instantiation). Type instances appear only -// during type-checking and are replaced by their fully instantiated -// (expanded) types before the end of type-checking. -type instance struct { - check *Checker // for lazy instantiation - pos token.Pos // position of type instantiation; for error reporting only - base *Named // parameterized type to be instantiated - targs []Type // type arguments - poslist []token.Pos // position of each targ; for error reporting only - value Type // base(targs...) after instantiation or Typ[Invalid]; nil if not yet set -} - -// expand returns the instantiated (= expanded) type of t. -// The result is either an instantiated *Named type, or -// Typ[Invalid] if there was an error. -func (t *instance) expand() Type { - v := t.value - if v == nil { - v = t.check.instantiate(t.pos, t.base, t.targs, t.poslist) - if v == nil { - v = Typ[Invalid] - } - t.value = v - } - // After instantiation we must have an invalid or a *Named type. - if debug && v != Typ[Invalid] { - _ = v.(*Named) - } - return v -} - -// expand expands a type instance into its instantiated -// type and leaves all other types alone. expand does -// not recurse. -func expand(typ Type) Type { - if t, _ := typ.(*instance); t != nil { - return t.expand() - } - return typ -} - -// expandf is set to expand. -// Call expandf when calling expand causes compile-time cycle error. -var expandf func(Type) Type - -func init() { expandf = expand } - -// top represents the top of the type lattice. -// It is the underlying type of a type parameter that -// can be satisfied by any type (ignoring methods), -// because its type constraint contains no restrictions -// besides methods. -type top struct{} - -// theTop is the singleton top type. -var theTop = &top{} - -// Type-specific implementations of Underlying. -func (t *Basic) Underlying() Type { return t } -func (t *Array) Underlying() Type { return t } -func (t *Slice) Underlying() Type { return t } -func (t *Pointer) Underlying() Type { return t } -func (t *Tuple) Underlying() Type { return t } -func (t *Map) Underlying() Type { return t } -func (t *Chan) Underlying() Type { return t } -func (t *Named) Underlying() Type { return t.expand().underlying } -func (t *TypeParam) Underlying() Type { return t } -func (t *instance) Underlying() Type { return t } -func (t *top) Underlying() Type { return t } - -// Type-specific implementations of String. -func (t *Basic) String() string { return TypeString(t, nil) } -func (t *Array) String() string { return TypeString(t, nil) } -func (t *Slice) String() string { return TypeString(t, nil) } -func (t *Pointer) String() string { return TypeString(t, nil) } -func (t *Tuple) String() string { return TypeString(t, nil) } -func (t *Map) String() string { return TypeString(t, nil) } -func (t *Chan) String() string { return TypeString(t, nil) } -func (t *Named) String() string { return TypeString(t, nil) } -func (t *TypeParam) String() string { return TypeString(t, nil) } -func (t *instance) String() string { return TypeString(t, nil) } -func (t *top) String() string { return TypeString(t, nil) } - -// under returns the true expanded underlying type. -// If it doesn't exist, the result is Typ[Invalid]. -// under must only be called when a type is known -// to be fully set up. -func under(t Type) Type { - // TODO(gri) is this correct for *Union? - if n := asNamed(t); n != nil { - return n.under() - } - return t -} - // Converters // // A converter must only be called when a type is diff --git a/src/go/types/typeparam.go b/src/go/types/typeparam.go new file mode 100644 index 00000000000..e1345088555 --- /dev/null +++ b/src/go/types/typeparam.go @@ -0,0 +1,72 @@ +// Copyright 2011 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 types + +import ( + "go/token" + "sync/atomic" +) + +// Note: This is a uint32 rather than a uint64 because the +// respective 64 bit atomic instructions are not available +// on all platforms. +var lastID uint32 + +// nextID returns a value increasing monotonically by 1 with +// each call, starting with 1. It may be called concurrently. +func nextID() uint64 { return uint64(atomic.AddUint32(&lastID, 1)) } + +// A TypeParam represents a type parameter type. +type TypeParam struct { + check *Checker // for lazy type bound completion + id uint64 // unique id, for debugging only + obj *TypeName // corresponding type name + index int // type parameter index in source order, starting at 0 + bound Type // *Named or *Interface; underlying type is always *Interface +} + +// NewTypeParam returns a new TypeParam. +func NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam { + return (*Checker)(nil).newTypeParam(obj, index, bound) +} + +// TODO(rfindley): this is factored slightly differently in types2. +func (check *Checker) newTypeParam(obj *TypeName, index int, bound Type) *TypeParam { + assert(bound != nil) + + // Always increment lastID, even if it is not used. + id := nextID() + if check != nil { + check.nextID++ + id = check.nextID + } + + typ := &TypeParam{check: check, id: id, obj: obj, index: index, bound: bound} + if obj.typ == nil { + obj.typ = typ + } + return typ +} + +// TODO(rfindley): types2 to has Index and SetID. Should we add them here? + +func (t *TypeParam) Bound() *Interface { + // we may not have an interface (error reported elsewhere) + iface, _ := under(t.bound).(*Interface) + if iface == nil { + return &emptyInterface + } + // use the type bound position if we have one + pos := token.NoPos + if n, _ := t.bound.(*Named); n != nil { + pos = n.obj.pos + } + // TODO(rFindley) switch this to an unexported method on Checker. + computeTypeSet(t.check, pos, iface) + return iface +} + +func (t *TypeParam) Underlying() Type { return t } +func (t *TypeParam) String() string { return TypeString(t, nil) } From c4cd76fbbbf0f8b89fee70783103b0c3abb68756 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 12:45:35 -0400 Subject: [PATCH 709/940] [dev.typeparams] go/types: disallow "free" type parameter as RHS of a type declaration This is a port of CL 332411 to go/types. methodset_test.go is similarly updated. Change-Id: I332b1837a954acc9d3b7e0e2ad2bec3425f088f7 Reviewed-on: https://go-review.googlesource.com/c/go/+/335109 Reviewed-by: Robert Griesemer Run-TryBot: Robert Findley TryBot-Result: Go Bot Trust: Robert Findley --- src/go/types/decl.go | 70 ++++++++++--------- src/go/types/methodset_test.go | 5 +- src/go/types/testdata/examples/types.go2 | 48 ++++++++----- .../types/testdata/fixedbugs/issue45639.go2 | 12 ++++ src/go/types/unify.go | 15 ++-- 5 files changed, 92 insertions(+), 58 deletions(-) create mode 100644 src/go/types/testdata/fixedbugs/issue45639.go2 diff --git a/src/go/types/decl.go b/src/go/types/decl.go index f0e7c5d5add..921530595a3 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -680,48 +680,52 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) { alias = false } + // alias declaration if alias { - // type alias declaration if !check.allowVersion(check.pkg, 1, 9) { check.errorf(atPos(tdecl.Assign), _BadDecl, "type aliases requires go1.9 or later") } obj.typ = Typ[Invalid] obj.typ = check.anyType(tdecl.Type) - - } else { - // defined type declaration - - named := check.newNamed(obj, nil, nil, nil, nil) - def.setUnderlying(named) - - if tparams := typeparams.Get(tdecl); tparams != nil { - check.openScope(tdecl, "type parameters") - defer check.closeScope() - named.tparams = check.collectTypeParams(tparams) - } - - // determine underlying type of named - named.fromRHS = check.definedType(tdecl.Type, named) - - // The underlying type of named may be itself a named type that is - // incomplete: - // - // type ( - // A B - // B *C - // C A - // ) - // - // The type of C is the (named) type of A which is incomplete, - // and which has as its underlying type the named type B. - // Determine the (final, unnamed) underlying type by resolving - // any forward chain. - // TODO(gri) Investigate if we can just use named.fromRHS here - // and rely on lazy computation of the underlying type. - named.underlying = under(named) + return } + // type definition or generic type declaration + named := check.newNamed(obj, nil, nil, nil, nil) + def.setUnderlying(named) + + if tparams := typeparams.Get(tdecl); tparams != nil { + check.openScope(tdecl, "type parameters") + defer check.closeScope() + named.tparams = check.collectTypeParams(tparams) + } + + // determine underlying type of named + named.fromRHS = check.definedType(tdecl.Type, named) + + // The underlying type of named may be itself a named type that is + // incomplete: + // + // type ( + // A B + // B *C + // C A + // ) + // + // The type of C is the (named) type of A which is incomplete, + // and which has as its underlying type the named type B. + // Determine the (final, unnamed) underlying type by resolving + // any forward chain. + // TODO(gri) Investigate if we can just use named.fromRHS here + // and rely on lazy computation of the underlying type. + named.underlying = under(named) + + // If the RHS is a type parameter, it must be from this type declaration. + if tpar, _ := named.underlying.(*TypeParam); tpar != nil && tparamIndex(named.tparams, tpar) < 0 { + check.errorf(tdecl.Type, _Todo, "cannot use function type parameter %s as RHS in type declaration", tpar) + named.underlying = Typ[Invalid] + } } func (check *Checker) collectTypeParams(list *ast.FieldList) []*TypeName { diff --git a/src/go/types/methodset_test.go b/src/go/types/methodset_test.go index 566356ad6de..5b29b2f0fea 100644 --- a/src/go/types/methodset_test.go +++ b/src/go/types/methodset_test.go @@ -50,8 +50,9 @@ func TestNewMethodSet(t *testing.T) { "type C interface{ f() }; func g[T C]() { var a T; _ = a }": {{"f", []int{0}, true}}, "type C interface{ f() }; func g[T C]() { var a struct{T}; _ = a }": {{"f", []int{0, 0}, true}}, - // Issue #45639. - "type C interface{ f() }; func g[T C]() { type Y T; var a Y; _ = a }": {}, + // Issue #45639: We don't allow this anymore. Keep this code in case we + // decide to revisit this decision. + // "type C interface{ f() }; func g[T C]() { type Y T; var a Y; _ = a }": {}, } check := func(src string, methods []method, generic bool) { diff --git a/src/go/types/testdata/examples/types.go2 b/src/go/types/testdata/examples/types.go2 index 8cdd7f2fd27..a7544f79ea0 100644 --- a/src/go/types/testdata/examples/types.go2 +++ b/src/go/types/testdata/examples/types.go2 @@ -161,30 +161,40 @@ type _ struct { * /* ERROR List redeclared */ List[int] } +// Issue #45639: We don't allow this anymore. Keep this code +// in case we decide to revisit this decision. +// // It's possible to declare local types whose underlying types // are type parameters. As with ordinary type definitions, the // types underlying properties are "inherited" but the methods // are not. -func _[T interface{ m(); ~int }]() { - type L T - var x L +//func _[T interface{ m(); ~int }]() { +// type L T +// var x L +// +// // m is not defined on L (it is not "inherited" from +// // its underlying type). +// x.m /* ERROR x.m undefined */ () +// +// // But the properties of T, such that as that it supports +// // the operations of the types given by its type bound, +// // are also the properties of L. +// x++ +// _ = x - x +// +// // On the other hand, if we define a local alias for T, +// // that alias stands for T as expected. +// type A = T +// var y A +// y.m() +// _ = y < 0 +//} - // m is not defined on L (it is not "inherited" from - // its underlying type). - x.m /* ERROR x.m undefined */ () - - // But the properties of T, such that as that it supports - // the operations of the types given by its type bound, - // are also the properties of L. - x++ - _ = x - x - - // On the other hand, if we define a local alias for T, - // that alias stands for T as expected. - type A = T - var y A - y.m() - _ = y < 0 +// It is not permitted to declare a local type whose underlying +// type is a type parameters not declared by that type declaration. +func _[T any]() { + type _ T // ERROR cannot use function type parameter T as RHS in type declaration + type _ [_ any] T // ERROR cannot use function type parameter T as RHS in type declaration } // As a special case, an explicit type argument may be omitted diff --git a/src/go/types/testdata/fixedbugs/issue45639.go2 b/src/go/types/testdata/fixedbugs/issue45639.go2 new file mode 100644 index 00000000000..441fb4cb346 --- /dev/null +++ b/src/go/types/testdata/fixedbugs/issue45639.go2 @@ -0,0 +1,12 @@ +// Copyright 2021 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 + +// It is not permitted to declare a local type whose underlying +// type is a type parameters not declared by that type declaration. +func _[T any]() { + type _ T // ERROR cannot use function type parameter T as RHS in type declaration + type _ [_ any] T // ERROR cannot use function type parameter T as RHS in type declaration +} diff --git a/src/go/types/unify.go b/src/go/types/unify.go index 762000db32c..84c8ae718f0 100644 --- a/src/go/types/unify.go +++ b/src/go/types/unify.go @@ -147,10 +147,17 @@ func (u *unifier) join(i, j int) bool { // If typ is a type parameter of d, index returns the type parameter index. // Otherwise, the result is < 0. func (d *tparamsList) index(typ Type) int { - if t, ok := typ.(*TypeParam); ok { - if i := t.index; i < len(d.tparams) && d.tparams[i].typ == t { - return i - } + if tpar, ok := typ.(*TypeParam); ok { + return tparamIndex(d.tparams, tpar) + } + return -1 +} + +// If tpar is a type parameter in list, tparamIndex returns the type parameter index. +// Otherwise, the result is < 0. tpar must not be nil. +func tparamIndex(list []*TypeName, tpar *TypeParam) int { + if i := tpar.index; i < len(list) && list[i].typ == tpar { + return i } return -1 } From e9836fe31897ef6e8a5c82c3f8fc8c2b31a3bea3 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 12:54:37 -0400 Subject: [PATCH 710/940] [dev.typeparams] go/types: clean up index expr implementation for type parameters This is a port of CL 332553 to go/types. The "expr" variable is renamed to "e" in Checker.indexExpr to be consistent with types2. Change-Id: I7905bebf2e8dab47256361362b16becf7596cf95 Reviewed-on: https://go-review.googlesource.com/c/go/+/335110 Reviewed-by: Robert Griesemer Run-TryBot: Robert Findley TryBot-Result: Go Bot Trust: Robert Findley --- src/go/types/index.go | 145 +++++++++--------- src/go/types/testdata/check/typeparams.go2 | 17 +- .../types/testdata/fixedbugs/issue45635.go2 | 5 +- src/go/types/typeparam.go | 7 + src/go/types/typeset.go | 15 ++ src/go/types/typestring.go | 2 +- src/go/types/union.go | 2 +- 7 files changed, 106 insertions(+), 87 deletions(-) diff --git a/src/go/types/index.go b/src/go/types/index.go index 769626dcc2c..036752c7340 100644 --- a/src/go/types/index.go +++ b/src/go/types/index.go @@ -15,18 +15,18 @@ import ( // If e is a valid function instantiation, indexExpr returns true. // In that case x represents the uninstantiated function value and // it is the caller's responsibility to instantiate the function. -func (check *Checker) indexExpr(x *operand, expr *typeparams.IndexExpr) (isFuncInst bool) { - check.exprOrType(x, expr.X) +func (check *Checker) indexExpr(x *operand, e *typeparams.IndexExpr) (isFuncInst bool) { + check.exprOrType(x, e.X) switch x.mode { case invalid: - check.use(expr.Indices...) + check.use(e.Indices...) return false case typexpr: // type instantiation x.mode = invalid - x.typ = check.varType(expr.Orig) + x.typ = check.varType(e.Orig) if x.typ != Typ[Invalid] { x.mode = typexpr } @@ -41,7 +41,7 @@ func (check *Checker) indexExpr(x *operand, expr *typeparams.IndexExpr) (isFuncI valid := false length := int64(-1) // valid if >= 0 - switch typ := optype(x.typ).(type) { + switch typ := under(x.typ).(type) { case *Basic: if isString(typ) { valid = true @@ -77,10 +77,10 @@ func (check *Checker) indexExpr(x *operand, expr *typeparams.IndexExpr) (isFuncI x.typ = typ.elem case *Map: - index := check.singleIndex(expr) + index := check.singleIndex(e) if index == nil { x.mode = invalid - return + return false } var key operand check.expr(&key, index) @@ -88,88 +88,81 @@ func (check *Checker) indexExpr(x *operand, expr *typeparams.IndexExpr) (isFuncI // ok to continue even if indexing failed - map element type is known x.mode = mapindex x.typ = typ.elem - x.expr = expr.Orig - return + x.expr = e.Orig + return false - case *Union: - // A union type can be indexed if all of the union's terms - // support indexing and have the same index and element - // type. Special rules apply for maps in the union type. - var tkey, telem Type // key is for map types only - nmaps := 0 // number of map types in union type - if typ.underIs(func(t Type) bool { - var e Type - switch t := t.(type) { + case *TypeParam: + // TODO(gri) report detailed failure cause for better error messages + var tkey, telem Type // tkey != nil if we have maps + if typ.underIs(func(u Type) bool { + var key, elem Type + alen := int64(-1) // valid if >= 0 + switch t := u.(type) { case *Basic: - if isString(t) { - e = universeByte - } - case *Array: - e = t.elem - case *Pointer: - if t := asArray(t.base); t != nil { - e = t.elem - } - case *Slice: - e = t.elem - case *Map: - // If there are multiple maps in the union type, - // they must have identical key types. - // TODO(gri) We may be able to relax this rule - // but it becomes complicated very quickly. - if tkey != nil && !Identical(t.key, tkey) { + if !isString(t) { return false } - tkey = t.key - e = t.elem - nmaps++ - case *TypeParam: - check.errorf(x, 0, "type of %s contains a type parameter - cannot index (implementation restriction)", x) - case *instance: - panic("unimplemented") - } - if e == nil || telem != nil && !Identical(e, telem) { + elem = universeByte + case *Array: + elem = t.elem + alen = t.len + case *Pointer: + a, _ := under(t.base).(*Array) + if a == nil { + return false + } + elem = a.elem + alen = a.len + case *Slice: + elem = t.elem + case *Map: + key = t.key + elem = t.elem + default: return false } - telem = e + assert(elem != nil) + if telem == nil { + // first type + tkey, telem = key, elem + length = alen + } else { + // all map keys must be identical (incl. all nil) + if !Identical(key, tkey) { + return false + } + // all element types must be identical + if !Identical(elem, telem) { + return false + } + tkey, telem = key, elem + // track the minimal length for arrays + if alen >= 0 && alen < length { + length = alen + } + } return true }) { - // If there are maps, the index expression must be assignable - // to the map key type (as for simple map index expressions). - if nmaps > 0 { - index := check.singleIndex(expr) + // For maps, the index expression must be assignable to the map key type. + if tkey != nil { + index := check.singleIndex(e) if index == nil { x.mode = invalid - return + return false } var key operand check.expr(&key, index) check.assignment(&key, tkey, "map index") // ok to continue even if indexing failed - map element type is known - - // If there are only maps, we are done. - if nmaps == typ.NumTerms() { - x.mode = mapindex - x.typ = telem - x.expr = expr.Orig - return - } - - // Otherwise we have mix of maps and other types. For - // now we require that the map key be an integer type. - // TODO(gri) This is probably not good enough. - valid = isInteger(tkey) - // avoid 2nd indexing error if indexing failed above - if !valid && key.mode == invalid { - x.mode = invalid - return - } - x.mode = value // map index expressions are not addressable - } else { - // no maps - valid = true - x.mode = variable + x.mode = mapindex + x.typ = telem + x.expr = e + return false } + + // no maps + valid = true + x.mode = variable x.typ = telem } } @@ -177,13 +170,13 @@ func (check *Checker) indexExpr(x *operand, expr *typeparams.IndexExpr) (isFuncI if !valid { check.invalidOp(x, _NonIndexableOperand, "cannot index %s", x) x.mode = invalid - return + return false } - index := check.singleIndex(expr) + index := check.singleIndex(e) if index == nil { x.mode = invalid - return + return false } // In pathological (invalid) cases (e.g.: type T1 [][[]T1{}[0][0]]T0) diff --git a/src/go/types/testdata/check/typeparams.go2 b/src/go/types/testdata/check/typeparams.go2 index 5b4361d2791..b832e6b760c 100644 --- a/src/go/types/testdata/check/typeparams.go2 +++ b/src/go/types/testdata/check/typeparams.go2 @@ -98,18 +98,23 @@ func _[T any] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } func _[T interface{ ~int }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } func _[T interface{ ~string }] (x T, i int) { _ = x[i] } func _[T interface{ ~[]int }] (x T, i int) { _ = x[i] } -func _[T interface{ ~[10]int | ~*[20]int | ~map[int]int }] (x T, i int) { _ = x[i] } +func _[T interface{ ~[10]int | ~*[20]int | ~map[int]int }] (x T, i int) { _ = x /* ERROR cannot index */ [i] } // map and non-map types func _[T interface{ ~string | ~[]byte }] (x T, i int) { _ = x[i] } func _[T interface{ ~[]int | ~[1]rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } func _[T interface{ ~string | ~[]rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } -// indexing with various combinations of map types in type lists (see issue #42616) -func _[T interface{ ~[]E | ~map[int]E }, E any](x T, i int) { _ = x[i] } +// indexing with various combinations of map types in type sets (see issue #42616) +func _[T interface{ ~[]E | ~map[int]E }, E any](x T, i int) { _ = x /* ERROR cannot index */ [i] } // map and non-map types func _[T interface{ ~[]E }, E any](x T, i int) { _ = &x[i] } func _[T interface{ ~map[int]E }, E any](x T, i int) { _, _ = x[i] } // comma-ok permitted -func _[T interface{ ~[]E | ~map[int]E }, E any](x T, i int) { _ = &x /* ERROR cannot take address */ [i] } -func _[T interface{ ~[]E | ~map[int]E | ~map[uint]E }, E any](x T, i int) { _ = x /* ERROR cannot index */ [i] } // different map element types -func _[T interface{ ~[]E | ~map[string]E }, E any](x T, i int) { _ = x[i /* ERROR cannot use i */ ] } +func _[T interface{ ~map[int]E }, E any](x T, i int) { _ = &x /* ERROR cannot take address */ [i] } +func _[T interface{ ~map[int]E | ~map[uint]E }, E any](x T, i int) { _ = x /* ERROR cannot index */ [i] } // different map element types +func _[T interface{ ~[]E | ~map[string]E }, E any](x T, i int) { _ = x /* ERROR cannot index */ [i] } // map and non-map types + +// indexing with various combinations of array and other types in type sets +func _[T interface{ [10]int }](x T, i int) { _ = x[i]; _ = x[9]; _ = x[10 /* ERROR out of bounds */ ] } +func _[T interface{ [10]byte | string }](x T, i int) { _ = x[i]; _ = x[9]; _ = x[10 /* ERROR out of bounds */ ] } +func _[T interface{ [10]int | *[20]int | []int }](x T, i int) { _ = x[i]; _ = x[9]; _ = x[10 /* ERROR out of bounds */ ] } // slicing // TODO(gri) implement this diff --git a/src/go/types/testdata/fixedbugs/issue45635.go2 b/src/go/types/testdata/fixedbugs/issue45635.go2 index c6784e12fda..fc50797b17c 100644 --- a/src/go/types/testdata/fixedbugs/issue45635.go2 +++ b/src/go/types/testdata/fixedbugs/issue45635.go2 @@ -13,7 +13,7 @@ type N[T any] struct{} var _ N [] // ERROR expected type argument list type I interface { - ~map[int]int | ~[]int + ~[]int } func _[T I](i, j int) { @@ -27,6 +27,5 @@ func _[T I](i, j int) { _ = s[i, j /* ERROR "more than one index" */ ] var t T - // TODO(rFindley) Fix the duplicate error below. - _ = t[i, j /* ERROR "more than one index" */ /* ERROR "more than one index" */ ] + _ = t[i, j /* ERROR "more than one index" */ ] } diff --git a/src/go/types/typeparam.go b/src/go/types/typeparam.go index e1345088555..92b048f2478 100644 --- a/src/go/types/typeparam.go +++ b/src/go/types/typeparam.go @@ -70,3 +70,10 @@ func (t *TypeParam) Bound() *Interface { func (t *TypeParam) Underlying() Type { return t } func (t *TypeParam) String() string { return TypeString(t, nil) } + +// ---------------------------------------------------------------------------- +// Implementation + +func (t *TypeParam) underIs(f func(Type) bool) bool { + return t.Bound().typeSet().underIs(f) +} diff --git a/src/go/types/typeset.go b/src/go/types/typeset.go index e979e90e6f5..3fe48892fe9 100644 --- a/src/go/types/typeset.go +++ b/src/go/types/typeset.go @@ -75,6 +75,21 @@ func (s *TypeSet) String() string { // ---------------------------------------------------------------------------- // Implementation +// underIs reports whether f returned true for the underlying types of the +// enumerable types in the type set s. If the type set comprises all types +// f is called once with the top type; if the type set is empty, the result +// is false. +func (s *TypeSet) underIs(f func(Type) bool) bool { + switch t := s.types.(type) { + case nil: + return f(theTop) + default: + return f(t) + case *Union: + return t.underIs(f) + } +} + // topTypeSet may be used as type set for the empty interface. var topTypeSet TypeSet diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go index d234d86e61d..aef5e2013bd 100644 --- a/src/go/types/typestring.go +++ b/src/go/types/typestring.go @@ -165,7 +165,7 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { } for i, e := range t.types { if i > 0 { - buf.WriteString("|") + buf.WriteByte('|') } if t.tilde[i] { buf.WriteByte('~') diff --git a/src/go/types/union.go b/src/go/types/union.go index 690b734d76d..7c69ec7b108 100644 --- a/src/go/types/union.go +++ b/src/go/types/union.go @@ -60,7 +60,7 @@ func (u *Union) is(f func(Type, bool) bool) bool { return true } -// is reports whether f returned true for the underlying types of all terms of u. +// underIs reports whether f returned true for the underlying types of all terms of u. func (u *Union) underIs(f func(Type) bool) bool { if u.IsEmpty() { return false From df778e6fd9a8ad4f50f734f08b8d07d4ce597c02 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 13:03:06 -0400 Subject: [PATCH 711/940] [dev.typeparams] go/types: replace optype() with under() in various cases (cleanup) This is a port of CL 332555 to go/types. Change-Id: I9b26bba8b605f5bbbd8f0f81fd6651a4a3ff4b57 Reviewed-on: https://go-review.googlesource.com/c/go/+/335111 Reviewed-by: Robert Griesemer Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot --- src/go/types/builtins.go | 8 +++++--- src/go/types/expr.go | 6 +++--- src/go/types/index.go | 6 +++--- src/go/types/predicates.go | 17 ++++++++--------- src/go/types/testdata/check/typeparams.go2 | 2 +- src/go/types/typeset.go | 1 + 6 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index e976e76cf1d..9b2a75458cb 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -337,13 +337,15 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b return } var src Type - switch t := optype(y.typ).(type) { + switch t := under(y.typ).(type) { case *Basic: if isString(y.typ) { src = universeByte } case *Slice: src = t.elem + case *TypeParam: + check.error(x, _Todo, "copy on generic operands not yet implemented") } if dst == nil || src == nil { @@ -464,12 +466,12 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b var valid func(t Type) bool valid = func(t Type) bool { var m int - switch t := optype(t).(type) { + switch t := under(t).(type) { case *Slice: m = 2 case *Map, *Chan: m = 1 - case *Union: + case *TypeParam: return t.underIs(valid) default: return false diff --git a/src/go/types/expr.go b/src/go/types/expr.go index edd7caf1c93..46f6e334631 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -622,7 +622,7 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const return x.typ, nil, 0 } - switch t := optype(target).(type) { + switch t := under(target).(type) { case *Basic: if x.mode == constant_ { v, code := check.representation(x, t) @@ -661,7 +661,7 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const default: return nil, nil, _InvalidUntypedConversion } - case *Union: + case *TypeParam: ok := t.underIs(func(t Type) bool { target, _, _ := check.implicitTypeAndValue(x, t) return target != nil @@ -1151,7 +1151,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind { goto Error } - switch utyp := optype(base).(type) { + switch utyp := under(base).(type) { case *Struct: if len(e.Elts) == 0 { break diff --git a/src/go/types/index.go b/src/go/types/index.go index 036752c7340..b2a5a2e9488 100644 --- a/src/go/types/index.go +++ b/src/go/types/index.go @@ -199,7 +199,7 @@ func (check *Checker) sliceExpr(x *operand, e *ast.SliceExpr) { valid := false length := int64(-1) // valid if >= 0 - switch typ := optype(x.typ).(type) { + switch typ := under(x.typ).(type) { case *Basic: if isString(typ) { if e.Slice3 { @@ -239,8 +239,8 @@ func (check *Checker) sliceExpr(x *operand, e *ast.SliceExpr) { valid = true // x.typ doesn't change - case *Union, *TypeParam: - check.errorf(x, 0, "generic slice expressions not yet implemented") + case *TypeParam: + check.errorf(x, _Todo, "generic slice expressions not yet implemented") x.mode = invalid return } diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index c3c168647da..c9be1218394 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -25,10 +25,10 @@ func isGeneric(typ Type) bool { } func is(typ Type, what BasicInfo) bool { - switch t := optype(typ).(type) { + switch t := under(typ).(type) { case *Basic: return t.info&what != 0 - case *Union: + case *TypeParam: return t.underIs(func(typ Type) bool { return is(typ, what) }) } return false @@ -97,18 +97,19 @@ func comparable(T Type, seen map[Type]bool) bool { seen[T] = true // If T is a type parameter not constrained by any type - // list (i.e., it's operational type is the top type), + // (i.e., it's operational type is the top type), // T is comparable if it has the == method. Otherwise, // the operational type "wins". For instance // // interface{ comparable; type []byte } // // is not comparable because []byte is not comparable. + // TODO(gri) this code is not 100% correct (see comment for TypeSet.IsComparable) if t := asTypeParam(T); t != nil && optype(t) == theTop { return t.Bound().IsComparable() } - switch t := optype(T).(type) { + switch t := under(T).(type) { case *Basic: // assume invalid types to be comparable // to avoid follow-up errors @@ -124,24 +125,22 @@ func comparable(T Type, seen map[Type]bool) bool { return true case *Array: return comparable(t.elem, seen) - case *Union: + case *TypeParam: return t.underIs(func(t Type) bool { return comparable(t, seen) }) - case *TypeParam: - return t.Bound().IsComparable() } return false } // hasNil reports whether a type includes the nil value. func hasNil(typ Type) bool { - switch t := optype(typ).(type) { + switch t := under(typ).(type) { case *Basic: return t.kind == UnsafePointer case *Slice, *Pointer, *Signature, *Interface, *Map, *Chan: return true - case *Union: + case *TypeParam: return t.underIs(hasNil) } return false diff --git a/src/go/types/testdata/check/typeparams.go2 b/src/go/types/testdata/check/typeparams.go2 index b832e6b760c..0e3795724b3 100644 --- a/src/go/types/testdata/check/typeparams.go2 +++ b/src/go/types/testdata/check/typeparams.go2 @@ -119,7 +119,7 @@ func _[T interface{ [10]int | *[20]int | []int }](x T, i int) { _ = x[i]; _ = x[ // slicing // TODO(gri) implement this -func _[T interface{ ~string }] (x T, i, j, k int) { _ = x /* ERROR invalid operation */ [i:j:k] } +func _[T interface{ ~string }] (x T, i, j, k int) { _ = x /* ERROR generic slice expressions not yet implemented */ [i:j:k] } // len/cap built-ins diff --git a/src/go/types/typeset.go b/src/go/types/typeset.go index 3fe48892fe9..d8fe42f7d08 100644 --- a/src/go/types/typeset.go +++ b/src/go/types/typeset.go @@ -28,6 +28,7 @@ func (s *TypeSet) IsTop() bool { return len(s.methods) == 0 && s.types == nil } func (s *TypeSet) IsMethodSet() bool { return s.types == nil && !s.IsComparable() } // IsComparable reports whether each type in the set is comparable. +// TODO(gri) this is not correct - there may be s.types values containing non-comparable types func (s *TypeSet) IsComparable() bool { _, m := s.LookupMethod(nil, "==") return m != nil From 650fc2117aaffbc4d596dc35cc88400ba11b2f25 Mon Sep 17 00:00:00 2001 From: mehradsadeghi <2012.linkinpark@gmail.com> Date: Fri, 16 Jul 2021 21:25:28 +0000 Subject: [PATCH 712/940] text/scanner: use Go convention in Position doc comment Change-Id: Ib872f139af7bfb0a75cc21dace5358fe8fcf2cf0 GitHub-Last-Rev: 8fd5ab01fab3bc1d7701092f31071d07ab79acc5 GitHub-Pull-Request: golang/go#47250 Reviewed-on: https://go-review.googlesource.com/c/go/+/335149 Reviewed-by: Robert Griesemer Reviewed-by: Ian Lance Taylor Trust: Robert Griesemer --- src/text/scanner/scanner.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/text/scanner/scanner.go b/src/text/scanner/scanner.go index e0847a72396..c5fc4ff93b9 100644 --- a/src/text/scanner/scanner.go +++ b/src/text/scanner/scanner.go @@ -23,7 +23,7 @@ import ( "unicode/utf8" ) -// A source position is represented by a Position value. +// Position is a value that represents a source position. // A position is valid if Line > 0. type Position struct { Filename string // filename, if any From a66190eceeea63aab0b5410ae3222454e5e0cd96 Mon Sep 17 00:00:00 2001 From: nimelehin Date: Fri, 16 Jul 2021 20:41:21 +0000 Subject: [PATCH 713/940] test/bench/go1: fix size for RegexpMatchMedium_32 Change-Id: Idc67abb95248bc010820a89dd6096a2da334e723 GitHub-Last-Rev: ae9014b011efb2692f853888c1860920d1acc3cb GitHub-Pull-Request: golang/go#47254 Reviewed-on: https://go-review.googlesource.com/c/go/+/335189 Reviewed-by: Rob Pike Run-TryBot: Rob Pike TryBot-Result: Go Bot Trust: Alberto Donizetti --- test/bench/go1/regexp_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/bench/go1/regexp_test.go b/test/bench/go1/regexp_test.go index 3ce9f3a2c67..dd1034fde5d 100644 --- a/test/bench/go1/regexp_test.go +++ b/test/bench/go1/regexp_test.go @@ -53,7 +53,7 @@ func BenchmarkRegexpMatchEasy0_32(b *testing.B) { benchmark(b, easy0, 32<<0) } func BenchmarkRegexpMatchEasy0_1K(b *testing.B) { benchmark(b, easy0, 1<<10) } func BenchmarkRegexpMatchEasy1_32(b *testing.B) { benchmark(b, easy1, 32<<0) } func BenchmarkRegexpMatchEasy1_1K(b *testing.B) { benchmark(b, easy1, 1<<10) } -func BenchmarkRegexpMatchMedium_32(b *testing.B) { benchmark(b, medium, 1<<0) } +func BenchmarkRegexpMatchMedium_32(b *testing.B) { benchmark(b, medium, 32<<0) } func BenchmarkRegexpMatchMedium_1K(b *testing.B) { benchmark(b, medium, 1<<10) } func BenchmarkRegexpMatchHard_32(b *testing.B) { benchmark(b, hard, 32<<0) } func BenchmarkRegexpMatchHard_1K(b *testing.B) { benchmark(b, hard, 1<<10) } From 9b85985d36a7cc7117e9c14bc1d2632844a5a818 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Fri, 9 Jul 2021 16:27:22 -0700 Subject: [PATCH 714/940] [dev.typeparams] Separate out gcshape types that are instantiated types Distinguish the gcshape of all top-level instantiated type from normal concrete types, even if they have the exact same underlying "shape", because in a function instantiation, any method call on this type arg will be a generic method call (requiring a dictionary), rather than a direct method call on the underlying type (no dictionary). So, we add the instshape prefix to the gcshape name for instantiated types, and we make it a defined type with that name. Change-Id: I33056269d24f3451a2632a5ce6a481108f533c9c Reviewed-on: https://go-review.googlesource.com/c/go/+/335169 Trust: Dan Scales Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/noder/stencil.go | 28 ++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index f4935fe22a4..7eac8573c96 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -729,11 +729,37 @@ func gcshapeType(t *types.Type) (*types.Type, string) { // Call CallSize so type sizes and field offsets are available. types.CalcSize(t) + + instType := t.Sym() != nil && t.IsFullyInstantiated() + if instType { + // We distinguish the gcshape of all top-level instantiated type from + // normal concrete types, even if they have the exact same underlying + // "shape", because in a function instantiation, any method call on + // this type arg will be a generic method call (requiring a + // dictionary), rather than a direct method call on the underlying + // type (no dictionary). So, we add the instshape prefix to the + // normal gcshape name, and will make it a defined type with that + // name below. + buf.WriteString("instshape-") + } fl = accumGcshape(fl, buf, t, nil) + // TODO: Should gcshapes be in a global package, so we don't have to // duplicate in each package? Or at least in the specified source package // of a function/method instantiation? gcshape := types.NewStruct(types.LocalPkg, fl) + gcname := buf.String() + if instType { + // Lookup or create type with name 'gcname' (with instshape prefix). + newsym := t.Sym().Pkg.Lookup(gcname) + if newsym.Def != nil { + gcshape = newsym.Def.Type() + } else { + newt := typecheck.NewIncompleteNamedType(t.Pos(), newsym) + newt.SetUnderlying(gcshape.Underlying()) + gcshape = newt + } + } assert(gcshape.Size() == t.Size()) return gcshape, buf.String() } @@ -764,7 +790,7 @@ func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth // Testing out gcshapeType() and gcshapeName() for i, t := range targs { gct, gcs := gcshapeType(t) - fmt.Printf("targ %d: %v %v\n", i, gct, gcs) + fmt.Printf("targ %d: %v %v %v\n", i, gcs, gct, gct.Underlying()) } } // If instantiation doesn't exist yet, create it and add From 49402bee36fd3d5cee9f4b2d2e1e8560ead0203b Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Thu, 15 Jul 2021 16:29:36 -0400 Subject: [PATCH 715/940] cmd/{compile,link}: fix bug in map.zero handling In CL 326211 a change was made to switch "go.map.zero" symbols from non-pkg DUPOK symbols to hashed symbols. The intent of this change was ensure that in cases where there are multiple competing go.map.zero symbols feeding into a link, the largest map.zero symbol is selected. The change was buggy, however, and resulted in duplicate symbols in the final binary (see bug cited below for details). This duplication was relatively benign for linux/ELF, but causes duplicate definition errors on Windows. This patch switches "go.map.zero" symbols back from hashed symbols to non-pkg DUPOK symbols, and updates the relevant code in the loader to ensure that we do the right thing when there are multiple competing DUPOK symbols with different sizes. Fixes #47185. Change-Id: I8aeb910c65827f5380144d07646006ba553c9251 Reviewed-on: https://go-review.googlesource.com/c/go/+/334930 Trust: Than McIntosh Run-TryBot: Than McIntosh TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/cmd/compile/internal/gc/obj.go | 2 +- src/cmd/link/internal/loader/loader.go | 9 +++ test/fixedbugs/issue47185.dir/bad/bad.go | 72 ++++++++++++++++++++++++ test/fixedbugs/issue47185.dir/main.go | 28 +++++++++ test/fixedbugs/issue47185.go | 11 ++++ 5 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue47185.dir/bad/bad.go create mode 100644 test/fixedbugs/issue47185.dir/main.go create mode 100644 test/fixedbugs/issue47185.go diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go index 55a0ab7da79..474d718525f 100644 --- a/src/cmd/compile/internal/gc/obj.go +++ b/src/cmd/compile/internal/gc/obj.go @@ -148,7 +148,7 @@ func dumpdata() { if reflectdata.ZeroSize > 0 { zero := base.PkgLinksym("go.map", "zero", obj.ABI0) objw.Global(zero, int32(reflectdata.ZeroSize), obj.DUPOK|obj.RODATA) - zero.Set(obj.AttrContentAddressable, true) + zero.Set(obj.AttrStatic, true) } staticdata.WriteFuncSyms() diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go index efca824d981..9d5319c3120 100644 --- a/src/cmd/link/internal/loader/loader.go +++ b/src/cmd/link/internal/loader/loader.go @@ -459,6 +459,15 @@ func (st *loadState) addSym(name string, ver int, r *oReader, li uint32, kind in if l.flags&FlagStrictDups != 0 { l.checkdup(name, r, li, oldi) } + // Fix for issue #47185 -- given two dupok symbols with + // different sizes, favor symbol with larger size. See + // also issue #46653. + szdup := l.SymSize(oldi) + sz := int64(r.Sym(li).Siz()) + if szdup < sz { + // new symbol overwrites old symbol. + l.objSyms[oldi] = objSym{r.objidx, li} + } return oldi } oldr, oldli := l.toLocal(oldi) diff --git a/test/fixedbugs/issue47185.dir/bad/bad.go b/test/fixedbugs/issue47185.dir/bad/bad.go new file mode 100644 index 00000000000..1aa4fbb9095 --- /dev/null +++ b/test/fixedbugs/issue47185.dir/bad/bad.go @@ -0,0 +1,72 @@ +// Copyright 2021 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 a + +// Note that the use of CGO here is solely to trigger external +// linking, since that is required to trigger that bad behavior +// in this bug. + +// #include +import "C" + +func Bad() { + m := make(map[int64]A) + a := m[0] + if len(a.B.C1.D2.E2.F1) != 0 || + len(a.B.C1.D2.E2.F2) != 0 || + len(a.B.C1.D2.E2.F3) != 0 || + len(a.B.C1.D2.E2.F4) != 0 || + len(a.B.C1.D2.E2.F5) != 0 || + len(a.B.C1.D2.E2.F6) != 0 || + len(a.B.C1.D2.E2.F7) != 0 || + len(a.B.C1.D2.E2.F8) != 0 || + len(a.B.C1.D2.E2.F9) != 0 || + len(a.B.C1.D2.E2.F10) != 0 || + len(a.B.C1.D2.E2.F11) != 0 || + len(a.B.C1.D2.E2.F16) != 0 { + panic("bad") + } + C.malloc(100) +} + +type A struct { + B +} + +type B struct { + C1 C + C2 C +} + +type C struct { + D1 D + D2 D +} + +type D struct { + E1 E + E2 E + E3 E + E4 E +} + +type E struct { + F1 string + F2 string + F3 string + F4 string + F5 string + F6 string + F7 string + F8 string + F9 string + F10 string + F11 string + F12 string + F13 string + F14 string + F15 string + F16 string +} diff --git a/test/fixedbugs/issue47185.dir/main.go b/test/fixedbugs/issue47185.dir/main.go new file mode 100644 index 00000000000..7b46e55d8b5 --- /dev/null +++ b/test/fixedbugs/issue47185.dir/main.go @@ -0,0 +1,28 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + bad "issue47185.dir/bad" +) + +func main() { + another() + bad.Bad() +} + +func another() L { + m := make(map[string]L) + return m[""] +} + +type L struct { + A Data + B Data +} + +type Data struct { + F1 [22][]string +} diff --git a/test/fixedbugs/issue47185.go b/test/fixedbugs/issue47185.go new file mode 100644 index 00000000000..9c921b86984 --- /dev/null +++ b/test/fixedbugs/issue47185.go @@ -0,0 +1,11 @@ +// +build cgo +// runindir + +// Copyright 2021 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. + +// Another test to verify compiler and linker handling of multiple +// competing map.zero symbol definitions. + +package ignored From 76b39959f4edc8b877506fe7cfe674ceaf64a627 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 13:15:24 -0400 Subject: [PATCH 716/940] [dev.typeparams] go/types: don't permit method calls on ptr to type parameter receivers This is a port of CL 332609 to go/types. Change-Id: I3482ea1b97bc7101b987ef312cd6cade80a5843f Reviewed-on: https://go-review.googlesource.com/c/go/+/335112 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/lookup.go | 10 ++++++---- src/go/types/testdata/check/issues.go2 | 10 ++++------ .../types/testdata/fixedbugs/issue47031.go2 | 20 +++++++++++++++++++ src/go/types/type.go | 12 +++++------ 4 files changed, 36 insertions(+), 16 deletions(-) create mode 100644 src/go/types/testdata/fixedbugs/issue47031.go2 diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go index 70e3b4281d7..304ae6e3c90 100644 --- a/src/go/types/lookup.go +++ b/src/go/types/lookup.go @@ -75,10 +75,12 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o typ, isPtr := deref(T) - // *typ where typ is an interface has no methods. - // Be cautious: typ may be nil (issue 39634, crash #3). - if typ == nil || isPtr && IsInterface(typ) { - return + // *typ where typ is an interface or type parameter has no methods. + switch under(typ).(type) { + case *Interface, *TypeParam: + if isPtr { + return + } } // Start with typ as single entry at shallowest depth. diff --git a/src/go/types/testdata/check/issues.go2 b/src/go/types/testdata/check/issues.go2 index c655fb99a4f..607da1df19e 100644 --- a/src/go/types/testdata/check/issues.go2 +++ b/src/go/types/testdata/check/issues.go2 @@ -24,22 +24,20 @@ func _() { eql[io.Reader](nil, nil) } -// If we have a receiver of pointer type (below: *T) we must ignore -// the pointer in the implementation of the method lookup because -// the type bound of T is an interface and pointer to interface types -// have no methods and then the lookup would fail. +// If we have a receiver of pointer to type parameter type (below: *T) +// we don't have any methods, like for interfaces. type C[T any] interface { m() } // using type bound C func _[T C[T]](x *T) { - x.m() + x.m /* ERROR x\.m undefined */ () } // using an interface literal as bound func _[T interface{ m() }](x *T) { - x.m() + x.m /* ERROR x\.m undefined */ () } // In a generic function body all method calls will be pointer method calls. diff --git a/src/go/types/testdata/fixedbugs/issue47031.go2 b/src/go/types/testdata/fixedbugs/issue47031.go2 new file mode 100644 index 00000000000..b184f9b5b7d --- /dev/null +++ b/src/go/types/testdata/fixedbugs/issue47031.go2 @@ -0,0 +1,20 @@ +// Copyright 2021 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 + +type Mer interface { M() } + +func F[T Mer](p *T) { + p.M /* ERROR p\.M undefined */ () +} + +type MyMer int + +func (MyMer) M() {} + +func _() { + F(new(MyMer)) + F[Mer](nil) +} diff --git a/src/go/types/type.go b/src/go/types/type.go index 662dd859f09..0a6fff0dcab 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -113,11 +113,6 @@ func asSignature(t Type) *Signature { return op } -func asInterface(t Type) *Interface { - op, _ := optype(t).(*Interface) - return op -} - func asMap(t Type) *Map { op, _ := optype(t).(*Map) return op @@ -128,10 +123,15 @@ func asChan(t Type) *Chan { return op } -// If the argument to asNamed and asTypeParam is of the respective types +// If the argument to asInterface, asNamed, or asTypeParam is of the respective type // (possibly after expanding an instance type), these methods return that type. // Otherwise the result is nil. +func asInterface(t Type) *Interface { + op, _ := optype(t).(*Interface) + return op +} + func asNamed(t Type) *Named { e, _ := expand(t).(*Named) return e From ccf95f17dd87683d915f7b11d88530b5f8f8efa2 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 13:27:57 -0400 Subject: [PATCH 717/940] [dev.typeparams] go/types: support local defined types This is a port of CL 327170 to go/types. Tests were not ported; they can be added later. Change-Id: Ic9fd681ac06dd187c1715efaf882b11353bc395a Reviewed-on: https://go-review.googlesource.com/c/go/+/335113 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/subst.go | 5 +++++ src/go/types/typestring.go | 36 ++++++++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/go/types/subst.go b/src/go/types/subst.go index 41ffcd0d1e4..d8388a948b8 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -428,14 +428,19 @@ func (subst *subster) typ(typ Type) Type { return typ } +var instanceHashing = 0 + // TODO(gri) Eventually, this should be more sophisticated. // It won't work correctly for locally declared types. func instantiatedHash(typ *Named, targs []Type) string { + assert(instanceHashing == 0) + instanceHashing++ var buf bytes.Buffer writeTypeName(&buf, typ.obj, nil) buf.WriteByte('[') writeTypeList(&buf, targs, nil, nil) buf.WriteByte(']') + instanceHashing-- // With respect to the represented type, whether a // type is fully expanded or stored as instance diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go index aef5e2013bd..f348d185c55 100644 --- a/src/go/types/typestring.go +++ b/src/go/types/typestring.go @@ -348,17 +348,33 @@ func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited } func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) { - s := "" - if obj != nil { - if obj.pkg != nil { - writePackage(buf, obj.pkg, qf) - } - // TODO(gri): function-local named types should be displayed - // differently from named types at package level to avoid - // ambiguity. - s = obj.name + if obj == nil { + buf.WriteString("") + return + } + if obj.pkg != nil { + writePackage(buf, obj.pkg, qf) + } + buf.WriteString(obj.name) + + if instanceHashing != 0 { + // For local defined types, use the (original!) TypeName's position + // to disambiguate. This is overkill, and could probably instead + // just be the pointer value (if we assume a non-moving GC) or + // a unique ID (like cmd/compile uses). But this works for now, + // and is convenient for debugging. + + // TODO(mdempsky): I still don't fully understand why typ.orig.orig + // can differ from typ.orig, or whether looping more than twice is + // ever necessary. + typ := obj.typ.(*Named) + for typ.orig != typ { + typ = typ.orig + } + if orig := typ.obj; orig.pkg != nil && orig.parent != orig.pkg.scope { + fmt.Fprintf(buf, "@%q", orig.pos) + } } - buf.WriteString(s) } func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visited []Type) { From c7c13ae4323f9f1d658625a9a774525789ee4d71 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 14:20:18 -0400 Subject: [PATCH 718/940] [dev.typeparams] go/types: use scope numbers to identify local types This is a port of CL 333192 to go/types. Change-Id: I12fd6b682d40c4d30b9ac0e87c463843cf5030d2 Reviewed-on: https://go-review.googlesource.com/c/go/+/335114 Trust: Robert Findley Run-TryBot: Robert Findley Reviewed-by: Robert Griesemer --- src/go/types/instance.go | 2 +- src/go/types/scope.go | 4 +++- src/go/types/sizeof_test.go | 2 +- src/go/types/subst.go | 2 -- src/go/types/typestring.go | 29 +++++++++++++++++------------ src/go/types/universe.go | 12 ++++++++---- 6 files changed, 30 insertions(+), 21 deletions(-) diff --git a/src/go/types/instance.go b/src/go/types/instance.go index c57a9470601..99771104bf8 100644 --- a/src/go/types/instance.go +++ b/src/go/types/instance.go @@ -16,7 +16,7 @@ type instance struct { base *Named // parameterized type to be instantiated targs []Type // type arguments poslist []token.Pos // position of each targ; for error reporting only - value Type // base(targs...) after instantiation or Typ[Invalid]; nil if not yet set + value Type // base[targs...] after instantiation or Typ[Invalid]; nil if not yet set } // expand returns the instantiated (= expanded) type of t. diff --git a/src/go/types/scope.go b/src/go/types/scope.go index fa6e0ecb8ff..010727eb722 100644 --- a/src/go/types/scope.go +++ b/src/go/types/scope.go @@ -23,6 +23,7 @@ import ( type Scope struct { parent *Scope children []*Scope + number int // parent.children[number-1] is this scope; 0 if there is no parent elems map[string]Object // lazily allocated pos, end token.Pos // scope extent; may be invalid comment string // for debugging only @@ -32,10 +33,11 @@ type Scope struct { // NewScope returns a new, empty scope contained in the given parent // scope, if any. The comment is for debugging only. func NewScope(parent *Scope, pos, end token.Pos, comment string) *Scope { - s := &Scope{parent, nil, nil, pos, end, comment, false} + s := &Scope{parent, nil, 0, nil, pos, end, comment, false} // don't add children to Universe scope! if parent != nil && parent != Universe { parent.children = append(parent.children, s) + s.number = len(parent.children) } return s } diff --git a/src/go/types/sizeof_test.go b/src/go/types/sizeof_test.go index 8f5f42b4150..d03e1ea0cb3 100644 --- a/src/go/types/sizeof_test.go +++ b/src/go/types/sizeof_test.go @@ -46,7 +46,7 @@ func TestSizeof(t *testing.T) { {Nil{}, 40, 72}, // Misc - {Scope{}, 40, 80}, + {Scope{}, 44, 88}, {Package{}, 40, 80}, {TypeSet{}, 20, 40}, } diff --git a/src/go/types/subst.go b/src/go/types/subst.go index d8388a948b8..4809b8c47a3 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -430,8 +430,6 @@ func (subst *subster) typ(typ Type) Type { var instanceHashing = 0 -// TODO(gri) Eventually, this should be more sophisticated. -// It won't work correctly for locally declared types. func instantiatedHash(typ *Named, targs []Type) string { assert(instanceHashing == 0) instanceHashing++ diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go index f348d185c55..4e73030613c 100644 --- a/src/go/types/typestring.go +++ b/src/go/types/typestring.go @@ -358,22 +358,27 @@ func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) { buf.WriteString(obj.name) if instanceHashing != 0 { - // For local defined types, use the (original!) TypeName's position - // to disambiguate. This is overkill, and could probably instead - // just be the pointer value (if we assume a non-moving GC) or - // a unique ID (like cmd/compile uses). But this works for now, - // and is convenient for debugging. - - // TODO(mdempsky): I still don't fully understand why typ.orig.orig - // can differ from typ.orig, or whether looping more than twice is - // ever necessary. + // For local defined types, use the (original!) TypeName's scope + // numbers to disambiguate. typ := obj.typ.(*Named) + // TODO(gri) Figure out why typ.orig != typ.orig.orig sometimes + // and whether the loop can iterate more than twice. + // (It seems somehow connected to instance types.) for typ.orig != typ { typ = typ.orig } - if orig := typ.obj; orig.pkg != nil && orig.parent != orig.pkg.scope { - fmt.Fprintf(buf, "@%q", orig.pos) - } + writeScopeNumbers(buf, typ.obj.parent) + } +} + +// writeScopeNumbers writes the number sequence for this scope to buf +// in the form ".i.j.k" where i, j, k, etc. stand for scope numbers. +// If a scope is nil or has no parent (such as a package scope), nothing +// is written. +func writeScopeNumbers(buf *bytes.Buffer, s *Scope) { + if s != nil && s.number > 0 { + writeScopeNumbers(buf, s.parent) + fmt.Fprintf(buf, ".%d", s.number) } } diff --git a/src/go/types/universe.go b/src/go/types/universe.go index 540b0ac1189..7c1e29b856c 100644 --- a/src/go/types/universe.go +++ b/src/go/types/universe.go @@ -87,21 +87,25 @@ func defPredeclaredTypes() { // type error interface{ Error() string } { + obj := NewTypeName(token.NoPos, nil, "error", nil) + obj.setColor(black) res := NewVar(token.NoPos, nil, "", Typ[String]) sig := NewSignature(nil, nil, NewTuple(res), false) err := NewFunc(token.NoPos, nil, "Error", sig) - typ := &Named{underlying: NewInterfaceType([]*Func{err}, nil)} + typ := NewNamed(obj, NewInterfaceType([]*Func{err}, nil), nil) sig.recv = NewVar(token.NoPos, nil, "", typ) - def(NewTypeName(token.NoPos, nil, "error", typ)) + def(obj) } // type comparable interface{ ==() } { + obj := NewTypeName(token.NoPos, nil, "comparable", nil) + obj.setColor(black) sig := NewSignature(nil, nil, nil, false) eql := NewFunc(token.NoPos, nil, "==", sig) - typ := &Named{underlying: NewInterfaceType([]*Func{eql}, nil)} + typ := NewNamed(obj, NewInterfaceType([]*Func{eql}, nil), nil) sig.recv = NewVar(token.NoPos, nil, "", typ) - def(NewTypeName(token.NoPos, nil, "comparable", typ)) + def(obj) } } From 43ad1ffa990358e60130ca9395210315e59e059a Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 14:30:15 -0400 Subject: [PATCH 719/940] [dev.typeparams] go/types: recursive substitution must terminate (bug fix) This is a port of CL 333383 to go/types. Change-Id: I7ff68116cbe63337dbcc834c473a2a5588274e36 Reviewed-on: https://go-review.googlesource.com/c/go/+/335115 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/api_test.go | 23 +++++++++++++++++++++++ src/go/types/subst.go | 38 ++++++++++++++++++++++---------------- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go index e6c209dda0d..9ca24db1de6 100644 --- a/src/go/types/api_test.go +++ b/src/go/types/api_test.go @@ -1817,3 +1817,26 @@ func f(x T) T { return foo.F(x) } } } } + +func TestInstantiate(t *testing.T) { + // eventually we like more tests but this is a start + const src = genericPkg + "p; type T[P any] *T[P]" + pkg, err := pkgFor(".", src, nil) + if err != nil { + t.Fatal(err) + } + + // type T should have one type parameter + T := pkg.Scope().Lookup("T").Type().(*Named) + if n := len(T.TParams()); n != 1 { + t.Fatalf("expected 1 type parameter; found %d", n) + } + + // instantiation should succeed (no endless recursion) + res := Instantiate(token.NoPos, T, []Type{Typ[Int]}) + + // instantiated type should point to itself + if res.Underlying().(*Pointer).Elem() != res { + t.Fatalf("unexpected result type: %s", res) + } +} diff --git a/src/go/types/subst.go b/src/go/types/subst.go index 4809b8c47a3..64146be27eb 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -237,15 +237,27 @@ func (check *Checker) subst(pos token.Pos, typ Type, smap *substMap) Type { } // general case - subst := subster{check, pos, make(map[Type]Type), smap} + var subst subster + subst.pos = pos + subst.smap = smap + if check != nil { + subst.check = check + subst.typMap = check.typMap + } else { + // If we don't have a *Checker and its global type map, + // use a local version. Besides avoiding duplicate work, + // the type map prevents infinite recursive substitution + // for recursive types (example: type T[P any] *T[P]). + subst.typMap = make(map[string]*Named) + } return subst.typ(typ) } type subster struct { - check *Checker - pos token.Pos - cache map[Type]Type - smap *substMap + pos token.Pos + smap *substMap + check *Checker // nil if called via Instantiate + typMap map[string]*Named } func (subst *subster) typ(typ Type) Type { @@ -390,22 +402,16 @@ func (subst *subster) typ(typ Type) Type { // before creating a new named type, check if we have this one already h := instantiatedHash(t, newTargs) dump(">>> new type hash: %s", h) - if subst.check != nil { - if named, found := subst.check.typMap[h]; found { - dump(">>> found %s", named) - subst.cache[t] = named - return named - } + if named, found := subst.typMap[h]; found { + dump(">>> found %s", named) + return named } - // create a new named type and populate caches to avoid endless recursion + // create a new named type and populate typMap to avoid endless recursion tname := NewTypeName(subst.pos, t.obj.pkg, t.obj.name, nil) named := subst.check.newNamed(tname, t, t.Underlying(), t.TParams(), t.methods) // method signatures are updated lazily named.targs = newTargs - if subst.check != nil { - subst.check.typMap[h] = named - } - subst.cache[t] = named + subst.typMap[h] = named // do the substitution dump(">>> subst %s with %s (new: %s)", t.underlying, subst.smap, newTargs) From b96f1b94191f7a404599e61b8cdd8ac010805545 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 14:43:30 -0400 Subject: [PATCH 720/940] [dev.typeparams] go/types: add some missing APIs for the importer This is a partial port of CL 319930, containing only changes to go/types. Importer changes will be made in a separate CL. The TypeParams APIs are left unexported for now; they will be exported when they are needed. Change-Id: I74bd246d4c174cb38f8360d921c733fa03900eab Reviewed-on: https://go-review.googlesource.com/c/go/+/335143 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/api_test.go | 12 ++++++------ src/go/types/signature.go | 7 +++++-- src/go/types/typeparam.go | 13 ++++++++++++- src/go/types/typestring.go | 7 +++++++ 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go index 9ca24db1de6..0a91f139fe0 100644 --- a/src/go/types/api_test.go +++ b/src/go/types/api_test.go @@ -331,16 +331,16 @@ func TestTypesInfo(t *testing.T) { {broken + `x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string][-1]int`}, // parameterized functions - {genericPkg + `p0; func f[T any](T); var _ = f[int]`, `f`, `func[T₁ interface{}](T₁)`}, + {genericPkg + `p0; func f[T any](T); var _ = f[int]`, `f`, `func[generic_p0.T₁ interface{}](generic_p0.T₁)`}, {genericPkg + `p1; func f[T any](T); var _ = f[int]`, `f[int]`, `func(int)`}, - {genericPkg + `p2; func f[T any](T); func _() { f(42) }`, `f`, `func[T₁ interface{}](T₁)`}, + {genericPkg + `p2; func f[T any](T); func _() { f(42) }`, `f`, `func[generic_p2.T₁ interface{}](generic_p2.T₁)`}, {genericPkg + `p3; func f[T any](T); func _() { f(42) }`, `f(42)`, `()`}, // type parameters {genericPkg + `t0; type t[] int; var _ t`, `t`, `generic_t0.t`}, // t[] is a syntax error that is ignored in this test in favor of t - {genericPkg + `t1; type t[P any] int; var _ t[int]`, `t`, `generic_t1.t[P₁ interface{}]`}, - {genericPkg + `t2; type t[P interface{}] int; var _ t[int]`, `t`, `generic_t2.t[P₁ interface{}]`}, - {genericPkg + `t3; type t[P, Q interface{}] int; var _ t[int, int]`, `t`, `generic_t3.t[P₁, Q₂ interface{}]`}, + {genericPkg + `t1; type t[P any] int; var _ t[int]`, `t`, `generic_t1.t[generic_t1.P₁ interface{}]`}, + {genericPkg + `t2; type t[P interface{}] int; var _ t[int]`, `t`, `generic_t2.t[generic_t2.P₁ interface{}]`}, + {genericPkg + `t3; type t[P, Q interface{}] int; var _ t[int, int]`, `t`, `generic_t3.t[generic_t3.P₁, generic_t3.Q₂ interface{}]`}, // TODO (rFindley): compare with types2, which resolves the type broken_t4.t[P₁, Q₂ interface{m()}] here {broken + `t4; type t[P, Q interface{ m() }] int; var _ t[int, int]`, `t`, `broken_t4.t`}, @@ -349,7 +349,7 @@ func TestTypesInfo(t *testing.T) { {genericPkg + `g0; type t[P any] int; var x struct{ f t[int] }; var _ = x.f`, `x.f`, `generic_g0.t[int]`}, // issue 45096 - {genericPkg + `issue45096; func _[T interface{ ~int8 | ~int16 | ~int32 }](x T) { _ = x < 0 }`, `0`, `T₁`}, + {genericPkg + `issue45096; func _[T interface{ ~int8 | ~int16 | ~int32 }](x T) { _ = x < 0 }`, `0`, `generic_issue45096.T₁`}, } for _, test := range tests { diff --git a/src/go/types/signature.go b/src/go/types/signature.go index 665514587ee..85a735120f4 100644 --- a/src/go/types/signature.go +++ b/src/go/types/signature.go @@ -55,12 +55,15 @@ func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature { // contain methods whose receiver type is a different interface. func (s *Signature) Recv() *Var { return s.recv } -// _TParams returns the type parameters of signature s, or nil. +// TParams returns the type parameters of signature s, or nil. func (s *Signature) TParams() []*TypeName { return s.tparams } -// _SetTParams sets the type parameters of signature s. +// SetTParams sets the type parameters of signature s. func (s *Signature) SetTParams(tparams []*TypeName) { s.tparams = tparams } +// SetRParams sets the receiver type params of signature s. +func (s *Signature) SetRParams(rparams []*TypeName) { s.rparams = rparams } + // Params returns the parameters of signature s, or nil. func (s *Signature) Params() *Tuple { return s.params } diff --git a/src/go/types/typeparam.go b/src/go/types/typeparam.go index 92b048f2478..89ac3ecf38f 100644 --- a/src/go/types/typeparam.go +++ b/src/go/types/typeparam.go @@ -50,7 +50,18 @@ func (check *Checker) newTypeParam(obj *TypeName, index int, bound Type) *TypePa return typ } -// TODO(rfindley): types2 to has Index and SetID. Should we add them here? +// TODO(rfindley): remove or export these placeholder APIs. + +// Index returns the index of the type param within its param list. +func (t *TypeParam) _Index() int { + return t.index +} + +// SetId sets the unique id of a type param. Should only be used for type params +// in imported generic types. +func (t *TypeParam) _SetId(id uint64) { + t.id = id +} func (t *TypeParam) Bound() *Interface { // we may not have an interface (error reported elsewhere) diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go index 4e73030613c..cba678588a9 100644 --- a/src/go/types/typestring.go +++ b/src/go/types/typestring.go @@ -284,6 +284,13 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { case *TypeParam: s := "?" if t.obj != nil { + // Optionally write out package for typeparams (like Named). + // TODO(rfindley): this is required for import/export, so + // we maybe need a separate function that won't be changed + // for debugging purposes. + if t.obj.pkg != nil { + writePackage(buf, t.obj.pkg, qf) + } s = t.obj.name } buf.WriteString(s + subscript(t.id)) From 22a38ba5caa49fb7d494b09fedef90afb674cd77 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 14:54:21 -0400 Subject: [PATCH 721/940] [dev.typeparams] go/types: remove unnecessary guard from NewInterfaceType This is a partial port of CL 322609, containing only changes to go/types. Importer changes will be made in a separate CL. Change-Id: I50af3c1ed5e949bb28a3462d717c0eb29a5f31ab Reviewed-on: https://go-review.googlesource.com/c/go/+/335144 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/interface.go | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/go/types/interface.go b/src/go/types/interface.go index 91270cfcd37..686dd7a786d 100644 --- a/src/go/types/interface.go +++ b/src/go/types/interface.go @@ -72,17 +72,6 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface { } } - // TODO(rfindley): this guard is not present in types2. Remove it? - // All embedded types should be interfaces; however, defined types - // may not yet be fully resolved. Only verify that non-defined types - // are interfaces. This matches the behavior of the code before the - // fix for #25301 (issue #25596). - for _, t := range embeddeds { - if _, ok := t.(*Named); !ok && !IsInterface(t) { - panic("embedded type is not an interface") - } - } - // sort for API stability sortMethods(methods) From 9e147c55b7a08b487efff3a87a27ed8c463cf347 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 19:01:16 -0400 Subject: [PATCH 722/940] [dev.typeparams] go/types: update TypeParam APIs to match types2 This is a partial port of CL 323029, consisting only of changes to go/types. Changes to the importer will be made in a separate CL. Change-Id: I3b300f5e8f4df36c2c87e3f164705cd3c36218ac Reviewed-on: https://go-review.googlesource.com/c/go/+/335145 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/builtins.go | 8 +++++--- src/go/types/decl.go | 2 +- src/go/types/type.go | 12 +++++++----- src/go/types/typeparam.go | 19 +++++++++---------- 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index 9b2a75458cb..2573bac69ec 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -783,9 +783,11 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { return nil } - // construct a suitable new type parameter - tpar := NewTypeName(token.NoPos, nil /* = Universe pkg */, "", nil) - ptyp := check.newTypeParam(tpar, 0, &emptyInterface) // assigns type to tpar as a side-effect + // Construct a suitable new type parameter for the sum type. The + // type param is placed in the current package so export/import + // works as expected. + tpar := NewTypeName(token.NoPos, check.pkg, "", nil) + ptyp := check.NewTypeParam(tpar, 0, &emptyInterface) // assigns type to tpar as a side-effect tsum := newUnion(rtypes, tildes) ptyp.bound = &Interface{complete: true, tset: &TypeSet{types: tsum}} diff --git a/src/go/types/decl.go b/src/go/types/decl.go index 921530595a3..d68070d0498 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -758,7 +758,7 @@ func (check *Checker) collectTypeParams(list *ast.FieldList) []*TypeName { func (check *Checker) declareTypeParams(tparams []*TypeName, names []*ast.Ident) []*TypeName { for _, name := range names { tpar := NewTypeName(name.Pos(), check.pkg, name.Name, nil) - check.newTypeParam(tpar, len(tparams), &emptyInterface) // assigns type to tpar as a side-effect + check.NewTypeParam(tpar, len(tparams), &emptyInterface) // assigns type to tpar as a side-effect check.declare(check.scope, name, tpar, check.scope.pos) // TODO(gri) check scope position tparams = append(tparams, tpar) } diff --git a/src/go/types/type.go b/src/go/types/type.go index 0a6fff0dcab..e0498fece26 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -41,11 +41,13 @@ func under(t Type) Type { return t } -// optype returns a type's operational type. Except for type parameters, -// the operational type is the same as the underlying type (as returned -// by under). For Type parameters, the operational type is determined -// by the corresponding type constraint. The result may be the top type, -// but it is never the incoming type parameter. +// optype returns a type's operational type. Except for +// type parameters, the operational type is the same +// as the underlying type (as returned by under). For +// Type parameters, the operational type is determined +// by the corresponding type bound's type list. The +// result may be the bottom or top type, but it is never +// the incoming type parameter. func optype(typ Type) Type { if t := asTypeParam(typ); t != nil { // If the optype is typ, return the top type as we have diff --git a/src/go/types/typeparam.go b/src/go/types/typeparam.go index 89ac3ecf38f..e42c24f8cbe 100644 --- a/src/go/types/typeparam.go +++ b/src/go/types/typeparam.go @@ -27,22 +27,14 @@ type TypeParam struct { bound Type // *Named or *Interface; underlying type is always *Interface } -// NewTypeParam returns a new TypeParam. -func NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam { - return (*Checker)(nil).newTypeParam(obj, index, bound) -} - -// TODO(rfindley): this is factored slightly differently in types2. -func (check *Checker) newTypeParam(obj *TypeName, index int, bound Type) *TypeParam { - assert(bound != nil) - +// NewTypeParam returns a new TypeParam. bound can be nil (and set later). +func (check *Checker) NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam { // Always increment lastID, even if it is not used. id := nextID() if check != nil { check.nextID++ id = check.nextID } - typ := &TypeParam{check: check, id: id, obj: obj, index: index, bound: bound} if obj.typ == nil { obj.typ = typ @@ -79,6 +71,13 @@ func (t *TypeParam) Bound() *Interface { return iface } +func (t *TypeParam) _SetBound(bound Type) { + if bound == nil { + panic("internal error: bound must not be nil") + } + t.bound = bound +} + func (t *TypeParam) Underlying() Type { return t } func (t *TypeParam) String() string { return TypeString(t, nil) } From 41ff0aac13fd0537702a7f28091a841bef233548 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 19:49:43 -0400 Subject: [PATCH 723/940] [dev.typeparams] go/types: replace types2.Instantiate with Checker.Instantiate This is a partial port of CL 333569 containing just changes to go/types. Changes to the importer wil be made in a separate CL. Change-Id: I9383e260b76402875ca6eb23c4478a6a3e8c1f0d Reviewed-on: https://go-review.googlesource.com/c/go/+/335071 Trust: Robert Findley Run-TryBot: Robert Findley Reviewed-by: Robert Griesemer TryBot-Result: Go Bot --- src/go/types/api_test.go | 4 ++- src/go/types/call.go | 4 +-- src/go/types/instance.go | 3 +- src/go/types/instantiate.go | 64 ++++--------------------------------- src/go/types/sizeof_test.go | 2 +- src/go/types/subst.go | 54 +++++++++++++++++++++---------- src/go/types/typexpr.go | 2 ++ 7 files changed, 53 insertions(+), 80 deletions(-) diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go index 0a91f139fe0..444cb440872 100644 --- a/src/go/types/api_test.go +++ b/src/go/types/api_test.go @@ -1833,7 +1833,9 @@ func TestInstantiate(t *testing.T) { } // instantiation should succeed (no endless recursion) - res := Instantiate(token.NoPos, T, []Type{Typ[Int]}) + // even with a nil *Checker + var check *Checker + res := check.Instantiate(token.NoPos, T, []Type{Typ[Int]}, nil, false) // instantiated type should point to itself if res.Underlying().(*Pointer).Elem() != res { diff --git a/src/go/types/call.go b/src/go/types/call.go index bcd569e82f1..9453b53c3a2 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -60,7 +60,7 @@ func (check *Checker) funcInst(x *operand, ix *typeparams.IndexExpr) { } // instantiate function signature - res := check.instantiate(x.Pos(), sig, targs, poslist).(*Signature) + res := check.Instantiate(x.Pos(), sig, targs, poslist, true).(*Signature) assert(res.tparams == nil) // signature is not generic anymore if inferred { check.recordInferred(ix.Orig, targs, res) @@ -333,7 +333,7 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, targs []Type } // compute result signature - rsig = check.instantiate(call.Pos(), sig, targs, nil).(*Signature) + rsig = check.Instantiate(call.Pos(), sig, targs, nil, true).(*Signature) assert(rsig.tparams == nil) // signature is not generic anymore check.recordInferred(call, targs, rsig) diff --git a/src/go/types/instance.go b/src/go/types/instance.go index 99771104bf8..143ba693a6e 100644 --- a/src/go/types/instance.go +++ b/src/go/types/instance.go @@ -16,6 +16,7 @@ type instance struct { base *Named // parameterized type to be instantiated targs []Type // type arguments poslist []token.Pos // position of each targ; for error reporting only + verify bool // if set, constraint satisfaction is verified value Type // base[targs...] after instantiation or Typ[Invalid]; nil if not yet set } @@ -25,7 +26,7 @@ type instance struct { func (t *instance) expand() Type { v := t.value if v == nil { - v = t.check.instantiate(t.pos, t.base, t.targs, t.poslist) + v = t.check.Instantiate(t.pos, t.base, t.targs, t.poslist, t.verify) if v == nil { v = Typ[Invalid] } diff --git a/src/go/types/instantiate.go b/src/go/types/instantiate.go index 1c15ac199ce..61b90553268 100644 --- a/src/go/types/instantiate.go +++ b/src/go/types/instantiate.go @@ -9,71 +9,19 @@ import ( "go/token" ) -// Instantiate instantiates the type typ with the given type arguments. -// typ must be a *Named or a *Signature type, it must be generic, and -// its number of type parameters must match the number of provided type -// arguments. The result is a new, instantiated (not generic) type of -// the same kind (either a *Named or a *Signature). The type arguments -// are not checked against the constraints of the type parameters. -// Any methods attached to a *Named are simply copied; they are not -// instantiated. -func Instantiate(pos token.Pos, typ Type, targs []Type) (res Type) { - // TODO(gri) This code is basically identical to the prolog - // in Checker.instantiate. Factor. - var tparams []*TypeName - switch t := typ.(type) { - case *Named: - tparams = t.TParams() - case *Signature: - tparams = t.tparams - defer func() { - // If we had an unexpected failure somewhere don't panic below when - // asserting res.(*Signature). Check for *Signature in case Typ[Invalid] - // is returned. - if _, ok := res.(*Signature); !ok { - return - } - // If the signature doesn't use its type parameters, subst - // will not make a copy. In that case, make a copy now (so - // we can set tparams to nil w/o causing side-effects). - if t == res { - copy := *t - res = © - } - // After instantiating a generic signature, it is not generic - // anymore; we need to set tparams to nil. - res.(*Signature).tparams = nil - }() - - default: - panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) - } - - // the number of supplied types must match the number of type parameters - if len(targs) != len(tparams) { - panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, len(targs), len(tparams))) - } - - if len(tparams) == 0 { - return typ // nothing to do (minor optimization) - } - - smap := makeSubstMap(tparams, targs) - return (*Checker)(nil).subst(pos, typ, smap) -} - // InstantiateLazy is like Instantiate, but avoids actually // instantiating the type until needed. -func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type) (res Type) { +func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type, verify bool) (res Type) { base := asNamed(typ) if base == nil { panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) } return &instance{ - check: check, - pos: pos, - base: base, - targs: targs, + check: check, + pos: pos, + base: base, + targs: targs, + verify: verify, } } diff --git a/src/go/types/sizeof_test.go b/src/go/types/sizeof_test.go index d03e1ea0cb3..8c18de8675d 100644 --- a/src/go/types/sizeof_test.go +++ b/src/go/types/sizeof_test.go @@ -32,7 +32,7 @@ func TestSizeof(t *testing.T) { {Chan{}, 12, 24}, {Named{}, 84, 160}, {TypeParam{}, 28, 48}, - {instance{}, 44, 88}, + {instance{}, 48, 96}, {top{}, 0, 0}, // Objects diff --git a/src/go/types/subst.go b/src/go/types/subst.go index 64146be27eb..d367369158c 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -56,8 +56,24 @@ func (m *substMap) lookup(tpar *TypeParam) Type { return tpar } -func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist []token.Pos) (res Type) { - if trace { +// Instantiate instantiates the type typ with the given type arguments +// targs. To check type constraint satisfaction, verify must be set. +// pos and posList correspond to the instantiation and type argument +// positions respectively; posList may be nil or shorter than the number +// of type arguments provided. +// typ must be a *Named or a *Signature type, and its number of type +// parameters must match the number of provided type arguments. +// The receiver (check) may be nil if and only if verify is not set. +// The result is a new, instantiated (not generic) type of the same kind +// (either a *Named or a *Signature). +// Any methods attached to a *Named are simply copied; they are not +// instantiated. +func (check *Checker) Instantiate(pos token.Pos, typ Type, targs []Type, posList []token.Pos, verify bool) (res Type) { + if verify && check == nil { + panic("cannot have nil receiver if verify is set") + } + + if check != nil && trace { check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs)) check.indent++ defer func() { @@ -73,7 +89,7 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist }() } - assert(len(poslist) <= len(targs)) + assert(len(posList) <= len(targs)) // TODO(gri) What is better here: work with TypeParams, or work with TypeNames? var tparams []*TypeName @@ -100,17 +116,19 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist // anymore; we need to set tparams to nil. res.(*Signature).tparams = nil }() - default: - check.dump("%v: cannot instantiate %v", pos, typ) - unreachable() // only defined types and (defined) functions can be generic + // only types and functions can be generic + panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) } // the number of supplied types must match the number of type parameters if len(targs) != len(tparams) { // TODO(gri) provide better error message - check.errorf(atPos(pos), _Todo, "got %d arguments but %d type parameters", len(targs), len(tparams)) - return Typ[Invalid] + if check != nil { + check.errorf(atPos(pos), _Todo, "got %d arguments but %d type parameters", len(targs), len(tparams)) + return Typ[Invalid] + } + panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, len(targs), len(tparams))) } if len(tparams) == 0 { @@ -120,16 +138,18 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist smap := makeSubstMap(tparams, targs) // check bounds - for i, tname := range tparams { - // best position for error reporting - pos := pos - if i < len(poslist) { - pos = poslist[i] - } + if verify { + for i, tname := range tparams { + // best position for error reporting + pos := pos + if i < len(posList) { + pos = posList[i] + } - // stop checking bounds after the first failure - if !check.satisfies(pos, targs[i], tname.typ.(*TypeParam), smap) { - break + // stop checking bounds after the first failure + if !check.satisfies(pos, targs[i], tname.typ.(*TypeParam), smap) { + break + } } } diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 342317048bd..e93c50a087c 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -413,12 +413,14 @@ func (check *Checker) instantiatedType(ix *typeparams.IndexExpr, def *Named) Typ // create a new type instance rather than instantiate the type // TODO(gri) should do argument number check here rather than // when instantiating the type? + // TODO(gri) use InstantiateLazy here (cleanup) typ := new(instance) def.setUnderlying(typ) typ.check = check typ.pos = ix.X.Pos() typ.base = base + typ.verify = true // evaluate arguments (always) typ.targs = check.typeList(ix.Indices) From 4a72be87b354e7ae641ccebfb57242ee24c8d7f4 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 19:52:46 -0400 Subject: [PATCH 724/940] [dev.typeparams] go/types: move instantiation code to instantiate.go (cleanup) This is a port of CL 333589 to go/types. Change-Id: Ib9fb1b09e10c400e62d20b55ff0558f3a92fc0eb Reviewed-on: https://go-review.googlesource.com/c/go/+/335072 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/instantiate.go | 185 +++++++++++++++++++++++++++++++++++ src/go/types/subst.go | 186 +----------------------------------- 2 files changed, 186 insertions(+), 185 deletions(-) diff --git a/src/go/types/instantiate.go b/src/go/types/instantiate.go index 61b90553268..55e34ca0c1c 100644 --- a/src/go/types/instantiate.go +++ b/src/go/types/instantiate.go @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// This file implements instantiation of generic types +// through substitution of type parameters by type arguments. + package types import ( @@ -9,6 +12,106 @@ import ( "go/token" ) +// Instantiate instantiates the type typ with the given type arguments +// targs. To check type constraint satisfaction, verify must be set. +// pos and posList correspond to the instantiation and type argument +// positions respectively; posList may be nil or shorter than the number +// of type arguments provided. +// typ must be a *Named or a *Signature type, and its number of type +// parameters must match the number of provided type arguments. +// The receiver (check) may be nil if and only if verify is not set. +// The result is a new, instantiated (not generic) type of the same kind +// (either a *Named or a *Signature). +// Any methods attached to a *Named are simply copied; they are not +// instantiated. +func (check *Checker) Instantiate(pos token.Pos, typ Type, targs []Type, posList []token.Pos, verify bool) (res Type) { + if verify && check == nil { + panic("cannot have nil receiver if verify is set") + } + + if check != nil && trace { + check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs)) + check.indent++ + defer func() { + check.indent-- + var under Type + if res != nil { + // Calling under() here may lead to endless instantiations. + // Test case: type T[P any] T[P] + // TODO(gri) investigate if that's a bug or to be expected. + under = res.Underlying() + } + check.trace(pos, "=> %s (under = %s)", res, under) + }() + } + + assert(len(posList) <= len(targs)) + + // TODO(gri) What is better here: work with TypeParams, or work with TypeNames? + var tparams []*TypeName + switch t := typ.(type) { + case *Named: + tparams = t.TParams() + case *Signature: + tparams = t.tparams + defer func() { + // If we had an unexpected failure somewhere don't panic below when + // asserting res.(*Signature). Check for *Signature in case Typ[Invalid] + // is returned. + if _, ok := res.(*Signature); !ok { + return + } + // If the signature doesn't use its type parameters, subst + // will not make a copy. In that case, make a copy now (so + // we can set tparams to nil w/o causing side-effects). + if t == res { + copy := *t + res = © + } + // After instantiating a generic signature, it is not generic + // anymore; we need to set tparams to nil. + res.(*Signature).tparams = nil + }() + default: + // only types and functions can be generic + panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) + } + + // the number of supplied types must match the number of type parameters + if len(targs) != len(tparams) { + // TODO(gri) provide better error message + if check != nil { + check.errorf(atPos(pos), _Todo, "got %d arguments but %d type parameters", len(targs), len(tparams)) + return Typ[Invalid] + } + panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, len(targs), len(tparams))) + } + + if len(tparams) == 0 { + return typ // nothing to do (minor optimization) + } + + smap := makeSubstMap(tparams, targs) + + // check bounds + if verify { + for i, tname := range tparams { + // best position for error reporting + pos := pos + if i < len(posList) { + pos = posList[i] + } + + // stop checking bounds after the first failure + if !check.satisfies(pos, targs[i], tname.typ.(*TypeParam), smap) { + break + } + } + } + + return check.subst(pos, typ, smap) +} + // InstantiateLazy is like Instantiate, but avoids actually // instantiating the type until needed. func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type, verify bool) (res Type) { @@ -25,3 +128,85 @@ func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type, ver verify: verify, } } + +// satisfies reports whether the type argument targ satisfies the constraint of type parameter +// parameter tpar (after any of its type parameters have been substituted through smap). +// A suitable error is reported if the result is false. +// TODO(gri) This should be a method of interfaces or type sets. +func (check *Checker) satisfies(pos token.Pos, targ Type, tpar *TypeParam, smap *substMap) bool { + iface := tpar.Bound() + if iface.Empty() { + return true // no type bound + } + + // The type parameter bound is parameterized with the same type parameters + // as the instantiated type; before we can use it for bounds checking we + // need to instantiate it with the type arguments with which we instantiate + // the parameterized type. + iface = check.subst(pos, iface, smap).(*Interface) + + // targ must implement iface (methods) + // - check only if we have methods + if iface.NumMethods() > 0 { + // If the type argument is a pointer to a type parameter, the type argument's + // method set is empty. + // TODO(gri) is this what we want? (spec question) + if base, isPtr := deref(targ); isPtr && asTypeParam(base) != nil { + check.errorf(atPos(pos), 0, "%s has no methods", targ) + return false + } + if m, wrong := check.missingMethod(targ, iface, true); m != nil { + // TODO(gri) needs to print updated name to avoid major confusion in error message! + // (print warning for now) + // Old warning: + // check.softErrorf(pos, "%s does not satisfy %s (warning: name not updated) = %s (missing method %s)", targ, tpar.bound, iface, m) + if m.name == "==" { + // We don't want to report "missing method ==". + check.softErrorf(atPos(pos), 0, "%s does not satisfy comparable", targ) + } else if wrong != nil { + // TODO(gri) This can still report uninstantiated types which makes the error message + // more difficult to read then necessary. + // TODO(rFindley) should this use parentheses rather than ':' for qualification? + check.softErrorf(atPos(pos), _Todo, + "%s does not satisfy %s: wrong method signature\n\tgot %s\n\twant %s", + targ, tpar.bound, wrong, m, + ) + } else { + check.softErrorf(atPos(pos), 0, "%s does not satisfy %s (missing method %s)", targ, tpar.bound, m.name) + } + return false + } + } + + // targ's underlying type must also be one of the interface types listed, if any + if iface.typeSet().types == nil { + return true // nothing to do + } + + // If targ is itself a type parameter, each of its possible types, but at least one, must be in the + // list of iface types (i.e., the targ type list must be a non-empty subset of the iface types). + if targ := asTypeParam(targ); targ != nil { + targBound := targ.Bound() + if targBound.typeSet().types == nil { + check.softErrorf(atPos(pos), _Todo, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ) + return false + } + return iface.is(func(typ Type, tilde bool) bool { + // TODO(gri) incorporate tilde information! + if !iface.isSatisfiedBy(typ) { + // TODO(gri) match this error message with the one below (or vice versa) + check.softErrorf(atPos(pos), 0, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, typ, iface.typeSet().types) + return false + } + return true + }) + } + + // Otherwise, targ's type or underlying type must also be one of the interface types listed, if any. + if !iface.isSatisfiedBy(targ) { + check.softErrorf(atPos(pos), _Todo, "%s does not satisfy %s (%s not found in %s)", targ, tpar.bound, targ, iface.typeSet().types) + return false + } + + return true +} diff --git a/src/go/types/subst.go b/src/go/types/subst.go index d367369158c..ec85a6bfc49 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -2,9 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// This file implements instantiation of generic types -// through substitution of type parameters by actual -// types. +// This file implements type parameter substitution. package types @@ -56,188 +54,6 @@ func (m *substMap) lookup(tpar *TypeParam) Type { return tpar } -// Instantiate instantiates the type typ with the given type arguments -// targs. To check type constraint satisfaction, verify must be set. -// pos and posList correspond to the instantiation and type argument -// positions respectively; posList may be nil or shorter than the number -// of type arguments provided. -// typ must be a *Named or a *Signature type, and its number of type -// parameters must match the number of provided type arguments. -// The receiver (check) may be nil if and only if verify is not set. -// The result is a new, instantiated (not generic) type of the same kind -// (either a *Named or a *Signature). -// Any methods attached to a *Named are simply copied; they are not -// instantiated. -func (check *Checker) Instantiate(pos token.Pos, typ Type, targs []Type, posList []token.Pos, verify bool) (res Type) { - if verify && check == nil { - panic("cannot have nil receiver if verify is set") - } - - if check != nil && trace { - check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs)) - check.indent++ - defer func() { - check.indent-- - var under Type - if res != nil { - // Calling under() here may lead to endless instantiations. - // Test case: type T[P any] T[P] - // TODO(gri) investigate if that's a bug or to be expected. - under = res.Underlying() - } - check.trace(pos, "=> %s (under = %s)", res, under) - }() - } - - assert(len(posList) <= len(targs)) - - // TODO(gri) What is better here: work with TypeParams, or work with TypeNames? - var tparams []*TypeName - switch t := typ.(type) { - case *Named: - tparams = t.TParams() - case *Signature: - tparams = t.tparams - defer func() { - // If we had an unexpected failure somewhere don't panic below when - // asserting res.(*Signature). Check for *Signature in case Typ[Invalid] - // is returned. - if _, ok := res.(*Signature); !ok { - return - } - // If the signature doesn't use its type parameters, subst - // will not make a copy. In that case, make a copy now (so - // we can set tparams to nil w/o causing side-effects). - if t == res { - copy := *t - res = © - } - // After instantiating a generic signature, it is not generic - // anymore; we need to set tparams to nil. - res.(*Signature).tparams = nil - }() - default: - // only types and functions can be generic - panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) - } - - // the number of supplied types must match the number of type parameters - if len(targs) != len(tparams) { - // TODO(gri) provide better error message - if check != nil { - check.errorf(atPos(pos), _Todo, "got %d arguments but %d type parameters", len(targs), len(tparams)) - return Typ[Invalid] - } - panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, len(targs), len(tparams))) - } - - if len(tparams) == 0 { - return typ // nothing to do (minor optimization) - } - - smap := makeSubstMap(tparams, targs) - - // check bounds - if verify { - for i, tname := range tparams { - // best position for error reporting - pos := pos - if i < len(posList) { - pos = posList[i] - } - - // stop checking bounds after the first failure - if !check.satisfies(pos, targs[i], tname.typ.(*TypeParam), smap) { - break - } - } - } - - return check.subst(pos, typ, smap) -} - -// satisfies reports whether the type argument targ satisfies the constraint of type parameter -// parameter tpar (after any of its type parameters have been substituted through smap). -// A suitable error is reported if the result is false. -// TODO(gri) This should be a method of interfaces or type sets. -func (check *Checker) satisfies(pos token.Pos, targ Type, tpar *TypeParam, smap *substMap) bool { - iface := tpar.Bound() - if iface.Empty() { - return true // no type bound - } - - // The type parameter bound is parameterized with the same type parameters - // as the instantiated type; before we can use it for bounds checking we - // need to instantiate it with the type arguments with which we instantiate - // the parameterized type. - iface = check.subst(pos, iface, smap).(*Interface) - - // targ must implement iface (methods) - // - check only if we have methods - if iface.NumMethods() > 0 { - // If the type argument is a pointer to a type parameter, the type argument's - // method set is empty. - // TODO(gri) is this what we want? (spec question) - if base, isPtr := deref(targ); isPtr && asTypeParam(base) != nil { - check.errorf(atPos(pos), 0, "%s has no methods", targ) - return false - } - if m, wrong := check.missingMethod(targ, iface, true); m != nil { - // TODO(gri) needs to print updated name to avoid major confusion in error message! - // (print warning for now) - // Old warning: - // check.softErrorf(pos, "%s does not satisfy %s (warning: name not updated) = %s (missing method %s)", targ, tpar.bound, iface, m) - if m.name == "==" { - // We don't want to report "missing method ==". - check.softErrorf(atPos(pos), 0, "%s does not satisfy comparable", targ) - } else if wrong != nil { - // TODO(gri) This can still report uninstantiated types which makes the error message - // more difficult to read then necessary. - // TODO(rFindley) should this use parentheses rather than ':' for qualification? - check.softErrorf(atPos(pos), _Todo, - "%s does not satisfy %s: wrong method signature\n\tgot %s\n\twant %s", - targ, tpar.bound, wrong, m, - ) - } else { - check.softErrorf(atPos(pos), 0, "%s does not satisfy %s (missing method %s)", targ, tpar.bound, m.name) - } - return false - } - } - - // targ's underlying type must also be one of the interface types listed, if any - if iface.typeSet().types == nil { - return true // nothing to do - } - - // If targ is itself a type parameter, each of its possible types, but at least one, must be in the - // list of iface types (i.e., the targ type list must be a non-empty subset of the iface types). - if targ := asTypeParam(targ); targ != nil { - targBound := targ.Bound() - if targBound.typeSet().types == nil { - check.softErrorf(atPos(pos), _Todo, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ) - return false - } - return iface.is(func(typ Type, tilde bool) bool { - // TODO(gri) incorporate tilde information! - if !iface.isSatisfiedBy(typ) { - // TODO(gri) match this error message with the one below (or vice versa) - check.softErrorf(atPos(pos), 0, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, typ, iface.typeSet().types) - return false - } - return true - }) - } - - // Otherwise, targ's type or underlying type must also be one of the interface types listed, if any. - if !iface.isSatisfiedBy(targ) { - check.softErrorf(atPos(pos), _Todo, "%s does not satisfy %s (%s not found in %s)", targ, tpar.bound, targ, iface.typeSet().types) - return false - } - - return true -} - // subst returns the type typ with its type parameters tpars replaced by // the corresponding type arguments targs, recursively. // subst is functional in the sense that it doesn't modify the incoming From 22f39ba208189413440671c63baca7173d1d4774 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 19:58:59 -0400 Subject: [PATCH 725/940] [dev.typeparams] go/types: use InstantiateLazy to create instance types (cleanup) This is a port of CL 333669 to go/types, adjusted for the position and IndexExpr APIs, and excluding the noder changes. Change-Id: I3ac4bbf271947c3cf80ab04c462a91657316f4fe Reviewed-on: https://go-review.googlesource.com/c/go/+/335073 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/instance.go | 4 ++-- src/go/types/instantiate.go | 16 +++++++------ src/go/types/typexpr.go | 45 +++++++++++++------------------------ 3 files changed, 27 insertions(+), 38 deletions(-) diff --git a/src/go/types/instance.go b/src/go/types/instance.go index 143ba693a6e..25f1442881d 100644 --- a/src/go/types/instance.go +++ b/src/go/types/instance.go @@ -15,7 +15,7 @@ type instance struct { pos token.Pos // position of type instantiation; for error reporting only base *Named // parameterized type to be instantiated targs []Type // type arguments - poslist []token.Pos // position of each targ; for error reporting only + posList []token.Pos // position of each targ; for error reporting only verify bool // if set, constraint satisfaction is verified value Type // base[targs...] after instantiation or Typ[Invalid]; nil if not yet set } @@ -26,7 +26,7 @@ type instance struct { func (t *instance) expand() Type { v := t.value if v == nil { - v = t.check.Instantiate(t.pos, t.base, t.targs, t.poslist, t.verify) + v = t.check.Instantiate(t.pos, t.base, t.targs, t.posList, t.verify) if v == nil { v = Typ[Invalid] } diff --git a/src/go/types/instantiate.go b/src/go/types/instantiate.go index 55e34ca0c1c..99ffb9e6048 100644 --- a/src/go/types/instantiate.go +++ b/src/go/types/instantiate.go @@ -113,19 +113,21 @@ func (check *Checker) Instantiate(pos token.Pos, typ Type, targs []Type, posList } // InstantiateLazy is like Instantiate, but avoids actually -// instantiating the type until needed. -func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type, verify bool) (res Type) { +// instantiating the type until needed. typ must be a *Named +// type. +func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type, posList []token.Pos, verify bool) Type { base := asNamed(typ) if base == nil { panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) } return &instance{ - check: check, - pos: pos, - base: base, - targs: targs, - verify: verify, + check: check, + pos: pos, + base: base, + targs: targs, + posList: posList, + verify: verify, } } diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index e93c50a087c..9a9fe32cb38 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -264,7 +264,7 @@ func (check *Checker) typInternal(e0 ast.Expr, def *Named) (T Type) { case *ast.IndexExpr, *ast.MultiIndexExpr: ix := typeparams.UnpackIndexExpr(e) // TODO(rfindley): type instantiation should require go1.18 - return check.instantiatedType(ix, def) + return check.instantiatedType(ix.X, ix.Indices, def) case *ast.ParenExpr: // Generic types must be instantiated before they can be used in any form. @@ -400,45 +400,32 @@ func (check *Checker) typeOrNil(e ast.Expr) Type { return Typ[Invalid] } -func (check *Checker) instantiatedType(ix *typeparams.IndexExpr, def *Named) Type { - b := check.genericType(ix.X, true) // TODO(gri) what about cycles? - if b == Typ[Invalid] { - return b // error already reported - } - base := asNamed(b) - if base == nil { - unreachable() // should have been caught by genericType +func (check *Checker) instantiatedType(x ast.Expr, targsx []ast.Expr, def *Named) Type { + base := check.genericType(x, true) + if base == Typ[Invalid] { + return base // error already reported } - // create a new type instance rather than instantiate the type - // TODO(gri) should do argument number check here rather than - // when instantiating the type? - // TODO(gri) use InstantiateLazy here (cleanup) - typ := new(instance) - def.setUnderlying(typ) - - typ.check = check - typ.pos = ix.X.Pos() - typ.base = base - typ.verify = true - - // evaluate arguments (always) - typ.targs = check.typeList(ix.Indices) - if typ.targs == nil { + // evaluate arguments + targs := check.typeList(targsx) + if targs == nil { def.setUnderlying(Typ[Invalid]) // avoid later errors due to lazy instantiation return Typ[Invalid] } - // determine argument positions (for error reporting) - typ.poslist = make([]token.Pos, len(ix.Indices)) - for i, arg := range ix.Indices { - typ.poslist[i] = arg.Pos() + // determine argument positions + posList := make([]token.Pos, len(targs)) + for i, arg := range targsx { + posList[i] = arg.Pos() } + typ := check.InstantiateLazy(x.Pos(), base, targs, posList, true) + def.setUnderlying(typ) + // make sure we check instantiation works at least once // and that the resulting type is valid check.later(func() { - t := typ.expand() + t := typ.(*instance).expand() check.validType(t, nil) }) From 796ac6d5f24f725794a3620d767d30c52f232a60 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 20:07:01 -0400 Subject: [PATCH 726/940] [dev.typeparams] go/types: move methods on *Named into named.go This is a port of CL 333671 to go/types. Change-Id: Ic2f66b49f1db68fb93d5095131733e99a37b9cbf Reviewed-on: https://go-review.googlesource.com/c/go/+/335074 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/decl.go | 96 ----------------------------------------- src/go/types/named.go | 99 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 96 deletions(-) diff --git a/src/go/types/decl.go b/src/go/types/decl.go index d68070d0498..8fae59ffe81 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -569,102 +569,6 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) { check.initVars(lhs, []ast.Expr{init}, token.NoPos) } -// under returns the expanded underlying type of n0; possibly by following -// forward chains of named types. If an underlying type is found, resolve -// the chain by setting the underlying type for each defined type in the -// chain before returning it. If no underlying type is found or a cycle -// is detected, the result is Typ[Invalid]. If a cycle is detected and -// n0.check != nil, the cycle is reported. -func (n0 *Named) under() Type { - u := n0.Underlying() - - if u == Typ[Invalid] { - return u - } - - // If the underlying type of a defined type is not a defined - // (incl. instance) type, then that is the desired underlying - // type. - switch u.(type) { - case nil: - return Typ[Invalid] - default: - // common case - return u - case *Named, *instance: - // handled below - } - - if n0.check == nil { - panic("internal error: Named.check == nil but type is incomplete") - } - - // Invariant: after this point n0 as well as any named types in its - // underlying chain should be set up when this function exits. - check := n0.check - - // If we can't expand u at this point, it is invalid. - n := asNamed(u) - if n == nil { - n0.underlying = Typ[Invalid] - return n0.underlying - } - - // Otherwise, follow the forward chain. - seen := map[*Named]int{n0: 0} - path := []Object{n0.obj} - for { - u = n.Underlying() - if u == nil { - u = Typ[Invalid] - break - } - var n1 *Named - switch u1 := u.(type) { - case *Named: - n1 = u1 - case *instance: - n1, _ = u1.expand().(*Named) - if n1 == nil { - u = Typ[Invalid] - } - } - if n1 == nil { - break // end of chain - } - - seen[n] = len(seen) - path = append(path, n.obj) - n = n1 - - if i, ok := seen[n]; ok { - // cycle - check.cycleError(path[i:]) - u = Typ[Invalid] - break - } - } - - for n := range seen { - // We should never have to update the underlying type of an imported type; - // those underlying types should have been resolved during the import. - // Also, doing so would lead to a race condition (was issue #31749). - // Do this check always, not just in debug mode (it's cheap). - if n.obj.pkg != check.pkg { - panic("internal error: imported type with unresolved underlying type") - } - n.underlying = u - } - - return u -} - -func (n *Named) setUnderlying(typ Type) { - if n != nil { - n.underlying = typ - } -} - func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) { assert(obj.typ == nil) diff --git a/src/go/types/named.go b/src/go/types/named.go index 8f2e8706a19..4511f395e08 100644 --- a/src/go/types/named.go +++ b/src/go/types/named.go @@ -142,3 +142,102 @@ func (t *Named) AddMethod(m *Func) { func (t *Named) Underlying() Type { return t.expand().underlying } func (t *Named) String() string { return TypeString(t, nil) } + +// ---------------------------------------------------------------------------- +// Implementation + +// under returns the expanded underlying type of n0; possibly by following +// forward chains of named types. If an underlying type is found, resolve +// the chain by setting the underlying type for each defined type in the +// chain before returning it. If no underlying type is found or a cycle +// is detected, the result is Typ[Invalid]. If a cycle is detected and +// n0.check != nil, the cycle is reported. +func (n0 *Named) under() Type { + u := n0.Underlying() + + if u == Typ[Invalid] { + return u + } + + // If the underlying type of a defined type is not a defined + // (incl. instance) type, then that is the desired underlying + // type. + switch u.(type) { + case nil: + return Typ[Invalid] + default: + // common case + return u + case *Named, *instance: + // handled below + } + + if n0.check == nil { + panic("internal error: Named.check == nil but type is incomplete") + } + + // Invariant: after this point n0 as well as any named types in its + // underlying chain should be set up when this function exits. + check := n0.check + + // If we can't expand u at this point, it is invalid. + n := asNamed(u) + if n == nil { + n0.underlying = Typ[Invalid] + return n0.underlying + } + + // Otherwise, follow the forward chain. + seen := map[*Named]int{n0: 0} + path := []Object{n0.obj} + for { + u = n.Underlying() + if u == nil { + u = Typ[Invalid] + break + } + var n1 *Named + switch u1 := u.(type) { + case *Named: + n1 = u1 + case *instance: + n1, _ = u1.expand().(*Named) + if n1 == nil { + u = Typ[Invalid] + } + } + if n1 == nil { + break // end of chain + } + + seen[n] = len(seen) + path = append(path, n.obj) + n = n1 + + if i, ok := seen[n]; ok { + // cycle + check.cycleError(path[i:]) + u = Typ[Invalid] + break + } + } + + for n := range seen { + // We should never have to update the underlying type of an imported type; + // those underlying types should have been resolved during the import. + // Also, doing so would lead to a race condition (was issue #31749). + // Do this check always, not just in debug mode (it's cheap). + if n.obj.pkg != check.pkg { + panic("internal error: imported type with unresolved underlying type") + } + n.underlying = u + } + + return u +} + +func (n *Named) setUnderlying(typ Type) { + if n != nil { + n.underlying = typ + } +} From d6d7f8458e9e4360d7b0a4e42c5c850ae27bac8d Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 20:16:27 -0400 Subject: [PATCH 727/940] [dev.typeparams] go/types: implement <-ch where ch is of type parameter type This is a port of CL 333709 to go/types, adjusted for the different error API. Fixes #43671 Change-Id: Ifd340149bfbcabe401cec74398cb83f2ae812e51 Reviewed-on: https://go-review.googlesource.com/c/go/+/335075 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/expr.go | 36 +++++++++--- .../types/testdata/fixedbugs/issue43671.go2 | 58 +++++++++++++++++++ 2 files changed, 85 insertions(+), 9 deletions(-) create mode 100644 src/go/types/testdata/fixedbugs/issue43671.go2 diff --git a/src/go/types/expr.go b/src/go/types/expr.go index 46f6e334631..751a3608900 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -144,6 +144,14 @@ var op2str2 = [...]string{ token.SHL: "shift", } +func underIs(typ Type, f func(Type) bool) bool { + u := under(typ) + if tpar, _ := u.(*TypeParam); tpar != nil { + return tpar.underIs(f) + } + return f(u) +} + // The unary expression e may be nil. It's passed in for better error messages only. func (check *Checker) unary(x *operand, e *ast.UnaryExpr) { check.expr(x, e.X) @@ -164,19 +172,29 @@ func (check *Checker) unary(x *operand, e *ast.UnaryExpr) { return case token.ARROW: - typ := asChan(x.typ) - if typ == nil { - check.invalidOp(x, _InvalidReceive, "cannot receive from non-channel %s", x) - x.mode = invalid - return - } - if typ.dir == SendOnly { - check.invalidOp(x, _InvalidReceive, "cannot receive from send-only channel %s", x) + var elem Type + if !underIs(x.typ, func(u Type) bool { + ch, _ := u.(*Chan) + if ch == nil { + check.invalidOp(x, _InvalidReceive, "cannot receive from non-channel %s", x) + return false + } + if ch.dir == SendOnly { + check.invalidOp(x, _InvalidReceive, "cannot receive from send-only channel %s", x) + return false + } + if elem != nil && !Identical(ch.elem, elem) { + check.invalidOp(x, _Todo, "channels of %s must have the same element type", x) + return false + } + elem = ch.elem + return true + }) { x.mode = invalid return } x.mode = commaok - x.typ = typ.elem + x.typ = elem check.hasCallOrRecv = true return } diff --git a/src/go/types/testdata/fixedbugs/issue43671.go2 b/src/go/types/testdata/fixedbugs/issue43671.go2 new file mode 100644 index 00000000000..6cc3801cc96 --- /dev/null +++ b/src/go/types/testdata/fixedbugs/issue43671.go2 @@ -0,0 +1,58 @@ +// Copyright 2021 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 + +type C0 interface{ int } +type C1 interface{ chan int } +type C2 interface{ chan int | <-chan int } +type C3 interface{ chan int | chan float32 } +type C4 interface{ chan int | chan<- int } +type C5[T any] interface{ ~chan T | <-chan T } + +func _[T any](ch T) { + <-ch // ERROR cannot receive from non-channel +} + +func _[T C0](ch T) { + <-ch // ERROR cannot receive from non-channel +} + +func _[T C1](ch T) { + <-ch +} + +func _[T C2](ch T) { + <-ch +} + +func _[T C3](ch T) { + <-ch // ERROR channels of ch .* must have the same element type +} + +func _[T C4](ch T) { + <-ch // ERROR cannot receive from send-only channel +} + +func _[T C5[X], X any](ch T, x X) { + x = <-ch +} + +// test case from issue, slightly modified +type RecvChan[T any] interface { + ~chan T | ~<-chan T +} + +func _[T any, C RecvChan[T]](ch C) T { + return <-ch +} + +func f[T any, C interface{ chan T }](ch C) T { + return <-ch +} + +func _(ch chan int) { + var x int = f(ch) // test constraint type inference for this case + _ = x +} From 19b4142f240172d525f81d1b4efb5679f147b474 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 20:22:59 -0400 Subject: [PATCH 728/940] [dev.typeparams] go/types: implement ch <- x where ch is of type parameter type This is a port of CL 333712 to go/types, adjusted for the different error reporting API and to position errors on the arrows. Fixes #43671 Change-Id: I7d2de249e86d272c89a046f60e632e75848ff865 Reviewed-on: https://go-review.googlesource.com/c/go/+/335076 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/stmt.go | 36 ++++++++++------- .../types/testdata/fixedbugs/issue47115.go2 | 40 +++++++++++++++++++ 2 files changed, 62 insertions(+), 14 deletions(-) create mode 100644 src/go/types/testdata/fixedbugs/issue47115.go2 diff --git a/src/go/types/stmt.go b/src/go/types/stmt.go index 53fccb0a640..0f0a2e4d9fd 100644 --- a/src/go/types/stmt.go +++ b/src/go/types/stmt.go @@ -361,25 +361,33 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) { check.errorf(&x, code, "%s %s", &x, msg) case *ast.SendStmt: - var ch, x operand + var ch, val operand check.expr(&ch, s.Chan) - check.expr(&x, s.Value) - if ch.mode == invalid || x.mode == invalid { + check.expr(&val, s.Value) + if ch.mode == invalid || val.mode == invalid { return } - - tch := asChan(ch.typ) - if tch == nil { - check.invalidOp(inNode(s, s.Arrow), _InvalidSend, "cannot send to non-chan type %s", ch.typ) + var elem Type + if !underIs(ch.typ, func(u Type) bool { + uch, _ := u.(*Chan) + if uch == nil { + check.invalidOp(inNode(s, s.Arrow), _InvalidSend, "cannot send to non-channel %s", &ch) + return false + } + if uch.dir == RecvOnly { + check.invalidOp(inNode(s, s.Arrow), _InvalidSend, "cannot send to receive-only channel %s", &ch) + return false + } + if elem != nil && !Identical(uch.elem, elem) { + check.invalidOp(inNode(s, s.Arrow), _Todo, "channels of %s must have the same element type", &ch) + return false + } + elem = uch.elem + return true + }) { return } - - if tch.dir == RecvOnly { - check.invalidOp(inNode(s, s.Arrow), _InvalidSend, "cannot send to receive-only type %s", tch) - return - } - - check.assignment(&x, tch.elem, "send") + check.assignment(&val, elem, "send") case *ast.IncDecStmt: var op token.Token diff --git a/src/go/types/testdata/fixedbugs/issue47115.go2 b/src/go/types/testdata/fixedbugs/issue47115.go2 new file mode 100644 index 00000000000..6694219b549 --- /dev/null +++ b/src/go/types/testdata/fixedbugs/issue47115.go2 @@ -0,0 +1,40 @@ +// Copyright 2021 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 + +type C0 interface{ int } +type C1 interface{ chan int } +type C2 interface{ chan int | <-chan int } +type C3 interface{ chan int | chan float32 } +type C4 interface{ chan int | chan<- int } +type C5[T any] interface{ ~chan T | chan<- T } + +func _[T any](ch T) { + ch <- /* ERROR cannot send to non-channel */ 0 +} + +func _[T C0](ch T) { + ch <- /* ERROR cannot send to non-channel */ 0 +} + +func _[T C1](ch T) { + ch <- 0 +} + +func _[T C2](ch T) { + ch <-/* ERROR cannot send to receive-only channel */ 0 +} + +func _[T C3](ch T) { + ch <- /* ERROR channels of ch .* must have the same element type */ 0 +} + +func _[T C4](ch T) { + ch <- 0 +} + +func _[T C5[X], X any](ch T, x X) { + ch <- x +} From cf7e66b7d4c74f45a767068c926ff74c76231f5f Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 20:30:45 -0400 Subject: [PATCH 729/940] [dev.typeparams] go/types: implement close(ch) where ch is of type parameter type This is a port of CL 333713 to go/types. Change-Id: I517f52592f65cc76e11a12d9148b20c12d9e3e81 Reviewed-on: https://go-review.googlesource.com/c/go/+/335077 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/builtins.go | 22 ++++++---- src/go/types/testdata/check/builtins.go2 | 55 ++++++++++++++++++++---- src/go/types/testdata/check/builtins.src | 2 +- src/go/types/type.go | 10 ----- 4 files changed, 61 insertions(+), 28 deletions(-) diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index 2573bac69ec..c8348f42591 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -217,19 +217,23 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b case _Close: // close(c) - c := asChan(x.typ) - if c == nil { - check.invalidArg(x, _InvalidClose, "%s is not a channel", x) + if !underIs(x.typ, func(u Type) bool { + uch, _ := u.(*Chan) + if uch == nil { + check.invalidOp(x, _InvalidClose, "cannot close non-channel %s", x) + return false + } + if uch.dir == RecvOnly { + check.invalidOp(x, _InvalidClose, "cannot close receive-only channel %s", x) + return false + } + return true + }) { return } - if c.dir == RecvOnly { - check.invalidArg(x, _InvalidClose, "%s must not be a receive-only channel", x) - return - } - x.mode = novalue if check.Types != nil { - check.recordBuiltinType(call.Fun, makeSig(nil, c)) + check.recordBuiltinType(call.Fun, makeSig(nil, x.typ)) } case _Complex: diff --git a/src/go/types/testdata/check/builtins.go2 b/src/go/types/testdata/check/builtins.go2 index 5bb67efec9d..71295bf4342 100644 --- a/src/go/types/testdata/check/builtins.go2 +++ b/src/go/types/testdata/check/builtins.go2 @@ -6,6 +6,45 @@ package builtins +// close + +type C0 interface{ int } +type C1 interface{ chan int } +type C2 interface{ chan int | <-chan int } +type C3 interface{ chan int | chan float32 } +type C4 interface{ chan int | chan<- int } +type C5[T any] interface{ ~chan T | chan<- T } + +func _[T any](ch T) { + close(ch /* ERROR cannot close non-channel */) +} + +func _[T C0](ch T) { + close(ch /* ERROR cannot close non-channel */) +} + +func _[T C1](ch T) { + close(ch) +} + +func _[T C2](ch T) { + close(ch /* ERROR cannot close receive-only channel */) +} + +func _[T C3](ch T) { + close(ch) +} + +func _[T C4](ch T) { + close(ch) +} + +func _[T C5[X], X any](ch T) { + close(ch) +} + +// make + type Bmc interface { ~map[rune]string | ~chan int } @@ -22,31 +61,31 @@ type Bss interface { ~[]int | ~[]string } -func _[T any] () { - _ = make(T /* ERROR invalid argument */ ) - _ = make(T /* ERROR invalid argument */ , 10) - _ = make(T /* ERROR invalid argument */ , 10, 20) +func _[T any]() { + _ = make(T /* ERROR invalid argument */) + _ = make(T /* ERROR invalid argument */, 10) + _ = make(T /* ERROR invalid argument */, 10, 20) } -func _[T Bmc] () { +func _[T Bmc]() { _ = make(T) _ = make(T, 10) _ = make /* ERROR expects 1 or 2 arguments */ (T, 10, 20) } -func _[T Bms] () { +func _[T Bms]() { _ = make /* ERROR expects 2 arguments */ (T) _ = make(T, 10) _ = make /* ERROR expects 2 arguments */ (T, 10, 20) } -func _[T Bcs] () { +func _[T Bcs]() { _ = make /* ERROR expects 2 arguments */ (T) _ = make(T, 10) _ = make /* ERROR expects 2 arguments */ (T, 10, 20) } -func _[T Bss] () { +func _[T Bss]() { _ = make /* ERROR expects 2 or 3 arguments */ (T) _ = make(T, 10) _ = make(T, 10, 20) diff --git a/src/go/types/testdata/check/builtins.src b/src/go/types/testdata/check/builtins.src index 37075289140..7fd6a4b0329 100644 --- a/src/go/types/testdata/check/builtins.src +++ b/src/go/types/testdata/check/builtins.src @@ -144,7 +144,7 @@ func close1() { var r <-chan int close() // ERROR not enough arguments close(1, 2) // ERROR too many arguments - close(42 /* ERROR not a channel */) + close(42 /* ERROR cannot close non-channel */) close(r /* ERROR receive-only channel */) close(c) _ = close /* ERROR used as value */ (c) diff --git a/src/go/types/type.go b/src/go/types/type.go index e0498fece26..bbb7100ef4f 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -105,11 +105,6 @@ func asPointer(t Type) *Pointer { return op } -func asTuple(t Type) *Tuple { - op, _ := optype(t).(*Tuple) - return op -} - func asSignature(t Type) *Signature { op, _ := optype(t).(*Signature) return op @@ -120,11 +115,6 @@ func asMap(t Type) *Map { return op } -func asChan(t Type) *Chan { - op, _ := optype(t).(*Chan) - return op -} - // If the argument to asInterface, asNamed, or asTypeParam is of the respective type // (possibly after expanding an instance type), these methods return that type. // Otherwise the result is nil. From b3d91e3a24f95a6a5906dab28c3392a542ccc81c Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 20:34:00 -0400 Subject: [PATCH 730/940] [dev.typeparams] go/types: implement delete(m, k) where m is of type parameter type This is a port of CL 333729 to go/types. Change-Id: I8682f549a7a15124b1b338f8c73e83a57d138368 Reviewed-on: https://go-review.googlesource.com/c/go/+/335078 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/builtins.go | 27 +++++++++++++---- src/go/types/testdata/check/builtins.go2 | 37 ++++++++++++++++++++++++ src/go/types/type.go | 5 ---- 3 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index c8348f42591..eb3503fd6b5 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -369,25 +369,40 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b x.typ = Typ[Int] case _Delete: - // delete(m, k) - m := asMap(x.typ) - if m == nil { - check.invalidArg(x, _InvalidDelete, "%s is not a map", x) + // delete(map_, key) + // map_ must be a map type or a type parameter describing map types. + // The key cannot be a type parameter for now. + map_ := x.typ + var key Type + if !underIs(map_, func(u Type) bool { + map_, _ := u.(*Map) + if map_ == nil { + check.invalidArg(x, _InvalidDelete, "%s is not a map", x) + return false + } + if key != nil && !Identical(map_.key, key) { + check.invalidArg(x, _Todo, "maps of %s must have identical key types", x) + return false + } + key = map_.key + return true + }) { return } + arg(x, 1) // k if x.mode == invalid { return } - check.assignment(x, m.key, "argument to delete") + check.assignment(x, key, "argument to delete") if x.mode == invalid { return } x.mode = novalue if check.Types != nil { - check.recordBuiltinType(call.Fun, makeSig(nil, m, m.key)) + check.recordBuiltinType(call.Fun, makeSig(nil, map_, key)) } case _Imag, _Real: diff --git a/src/go/types/testdata/check/builtins.go2 b/src/go/types/testdata/check/builtins.go2 index 71295bf4342..8fe6d7b332e 100644 --- a/src/go/types/testdata/check/builtins.go2 +++ b/src/go/types/testdata/check/builtins.go2 @@ -43,6 +43,43 @@ func _[T C5[X], X any](ch T) { close(ch) } +// delete + +type M0 interface{ int } +type M1 interface{ map[string]int } +type M2 interface { map[string]int | map[string]float64 } +type M3 interface{ map[string]int | map[rune]int } +type M4[K comparable, V any] interface{ map[K]V | map[rune]V } + +func _[T any](m T) { + delete(m /* ERROR not a map */, "foo") +} + +func _[T M0](m T) { + delete(m /* ERROR not a map */, "foo") +} + +func _[T M1](m T) { + delete(m, "foo") +} + +func _[T M2](m T) { + delete(m, "foo") + delete(m, 0 /* ERROR cannot use .* as string */) +} + +func _[T M3](m T) { + delete(m /* ERROR must have identical key types */, "foo") +} + +func _[T M4[rune, V], V any](m T) { + delete(m, 'k') +} + +func _[T M4[K, V], K comparable, V any](m T) { + delete(m /* ERROR must have identical key types */, "foo") +} + // make type Bmc interface { diff --git a/src/go/types/type.go b/src/go/types/type.go index bbb7100ef4f..b575b11e4e1 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -110,11 +110,6 @@ func asSignature(t Type) *Signature { return op } -func asMap(t Type) *Map { - op, _ := optype(t).(*Map) - return op -} - // If the argument to asInterface, asNamed, or asTypeParam is of the respective type // (possibly after expanding an instance type), these methods return that type. // Otherwise the result is nil. From baeabf3b366fad1eae113f8334451906dac61c0d Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 20:40:58 -0400 Subject: [PATCH 731/940] [dev.typeparams] go/types: cleanups around receiver type checks This is a port of CL 333770 to go/types, adjusted for the error reporting API and to not support compiler error messages. An error message changed (to 'invalid receiver type' from just 'invalid receiver'), so a test had to be adjusted. Change-Id: I166e8831d8c9f98ebfb0270fe5221586fc112825 Reviewed-on: https://go-review.googlesource.com/c/go/+/335079 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/signature.go | 34 ++++++++++++------- src/go/types/testdata/examples/methods.go2 | 17 ++++++++++ .../types/testdata/fixedbugs/issue28251.src | 2 +- 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/go/types/signature.go b/src/go/types/signature.go index 85a735120f4..da01ec801a5 100644 --- a/src/go/types/signature.go +++ b/src/go/types/signature.go @@ -199,30 +199,40 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast // spec: "The receiver type must be of the form T or *T where T is a type name." // (ignore invalid types - error was reported before) - if t := rtyp; t != Typ[Invalid] { + if rtyp != Typ[Invalid] { var err string - if T := asNamed(t); T != nil { + switch T := rtyp.(type) { + case *Named: // spec: "The type denoted by T is called the receiver base type; it must not // be a pointer or interface type and it must be declared in the same package // as the method." if T.obj.pkg != check.pkg { err = "type not defined in this package" } else { - switch u := optype(T).(type) { - case *Basic: - // unsafe.Pointer is treated like a regular pointer - if u.kind == UnsafePointer { - err = "unsafe.Pointer" + // The underlying type of a receiver base type can be a type parameter; + // e.g. for methods with a generic receiver T[P] with type T[P any] P. + underIs(T, func(u Type) bool { + switch u := u.(type) { + case *Basic: + // unsafe.Pointer is treated like a regular pointer + if u.kind == UnsafePointer { + err = "unsafe.Pointer" + return false + } + case *Pointer, *Interface: + err = "pointer or interface type" + return false } - case *Pointer, *Interface: - err = "pointer or interface type" - } + return true + }) } - } else { + case *Basic: err = "basic or unnamed type" + default: + check.errorf(recv, _InvalidRecv, "invalid receiver type %s", recv.typ) } if err != "" { - check.errorf(recv, _InvalidRecv, "invalid receiver %s (%s)", recv.typ, err) + check.errorf(recv, _InvalidRecv, "invalid receiver type %s (%s)", recv.typ, err) // ok to continue } } diff --git a/src/go/types/testdata/examples/methods.go2 b/src/go/types/testdata/examples/methods.go2 index 76c6539e1b7..4e87041e547 100644 --- a/src/go/types/testdata/examples/methods.go2 +++ b/src/go/types/testdata/examples/methods.go2 @@ -6,6 +6,8 @@ package p +import "unsafe" + // Parameterized types may have methods. type T1[A any] struct{ a A } @@ -94,3 +96,18 @@ func (_ T2[_, _, _]) _() int { return 42 } type T0 struct{} func (T0) _() {} func (T1[A]) _() {} + +// A generic receiver type may constrain its type parameter such +// that it must be a pointer type. Such receiver types are not +// permitted. +type T3a[P interface{ ~int | ~string | ~float64 }] P + +func (T3a[_]) m() {} // this is ok + +type T3b[P interface{ ~unsafe.Pointer }] P + +func (T3b /* ERROR invalid receiver */ [_]) m() {} + +type T3c[P interface{ *int | *string }] P + +func (T3c /* ERROR invalid receiver */ [_]) m() {} diff --git a/src/go/types/testdata/fixedbugs/issue28251.src b/src/go/types/testdata/fixedbugs/issue28251.src index cd79e0e8b5d..ef5e61df47f 100644 --- a/src/go/types/testdata/fixedbugs/issue28251.src +++ b/src/go/types/testdata/fixedbugs/issue28251.src @@ -60,6 +60,6 @@ type ( T11 = T ) -func (T9 /* ERROR invalid receiver \*\*T */ ) m9() {} +func (T9 /* ERROR invalid receiver type \*\*T */ ) m9() {} func _() { (T{}).m9 /* ERROR has no field or method m9 */ () } func _() { (&T{}).m9 /* ERROR has no field or method m9 */ () } From 62f6f130fe1c6cbe9d2c1ea5160e83fb1cfa208a Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 20:46:39 -0400 Subject: [PATCH 732/940] [dev.typeparams] go/types: interface identity must consider full type set This is a port of CL 333889 to go/types. Change-Id: I66cefb81a33f4677efc18c1ca923ded374a87f12 Reviewed-on: https://go-review.googlesource.com/c/go/+/335080 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/predicates.go | 17 +++++++++++++---- src/go/types/unify.go | 12 ++++++++---- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index c9be1218394..ea2bed720a1 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -270,12 +270,21 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { } case *Interface: + // Two interface types are identical if they describe the same type sets. + // With the existing implementation restriction, this simplifies to: + // // Two interface types are identical if they have the same set of methods with - // the same names and identical function types. Lower-case method names from - // different packages are always different. The order of the methods is irrelevant. + // the same names and identical function types, and if any type restrictions + // are the same. Lower-case method names from different packages are always + // different. The order of the methods is irrelevant. if y, ok := y.(*Interface); ok { - a := x.typeSet().methods - b := y.typeSet().methods + xset := x.typeSet() + yset := y.typeSet() + if !Identical(xset.types, yset.types) { + return false + } + a := xset.methods + b := yset.methods if len(a) == len(b) { // Interface types are the only types where cycles can occur // that are not "terminated" via named types; and such cycles diff --git a/src/go/types/unify.go b/src/go/types/unify.go index 84c8ae718f0..da57e533cc8 100644 --- a/src/go/types/unify.go +++ b/src/go/types/unify.go @@ -359,16 +359,20 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool { } case *Union: - // This should not happen with the current internal use of union types. - panic("type inference across union types not implemented") + panic("unimplemented: unification with type sets described by types") case *Interface: // Two interface types are identical if they have the same set of methods with // the same names and identical function types. Lower-case method names from // different packages are always different. The order of the methods is irrelevant. if y, ok := y.(*Interface); ok { - a := x.typeSet().methods - b := y.typeSet().methods + xset := x.typeSet() + yset := y.typeSet() + if !Identical(xset.types, yset.types) { + return false + } + a := xset.methods + b := yset.methods if len(a) == len(b) { // Interface types are the only types where cycles can occur // that are not "terminated" via named types; and such cycles From 82f875d735fd07957a2224d2c73c677ddfdeef0d Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 20:50:18 -0400 Subject: [PATCH 733/940] [dev.typeparams] go/types: fix generic type indirection This is a port of CL 333890 to go/types. Change-Id: I8ee20f405dad98083bb5e91636044d132a95d909 Reviewed-on: https://go-review.googlesource.com/c/go/+/335081 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/expr.go | 21 ++++++++++---- src/go/types/testdata/examples/operations.go2 | 29 +++++++++++++++++++ 2 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 src/go/types/testdata/examples/operations.go2 diff --git a/src/go/types/expr.go b/src/go/types/expr.go index 751a3608900..b55f51185fd 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -1400,13 +1400,24 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind { case typexpr: x.typ = &Pointer{base: x.typ} default: - if typ := asPointer(x.typ); typ != nil { - x.mode = variable - x.typ = typ.base - } else { - check.invalidOp(x, _InvalidIndirection, "cannot indirect %s", x) + var base Type + if !underIs(x.typ, func(u Type) bool { + p, _ := u.(*Pointer) + if p == nil { + check.invalidOp(x, _InvalidIndirection, "cannot indirect %s", x) + return false + } + if base != nil && !Identical(p.base, base) { + check.invalidOp(x, _Todo, "pointers of %s must have identical base types", x) + return false + } + base = p.base + return true + }) { goto Error } + x.mode = variable + x.typ = base } case *ast.UnaryExpr: diff --git a/src/go/types/testdata/examples/operations.go2 b/src/go/types/testdata/examples/operations.go2 new file mode 100644 index 00000000000..18e4d6080c5 --- /dev/null +++ b/src/go/types/testdata/examples/operations.go2 @@ -0,0 +1,29 @@ +// Copyright 2021 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 + +// indirection + +func _[P any](p P) { + _ = *p // ERROR cannot indirect p +} + +func _[P interface{ int }](p P) { + _ = *p // ERROR cannot indirect p +} + +func _[P interface{ *int }](p P) { + _ = *p +} + +func _[P interface{ *int | *string }](p P) { + _ = *p // ERROR must have identical base types +} + +type intPtr *int + +func _[P interface{ *int | intPtr } ](p P) { + var _ int = *p +} From 7e714f448eaf2c489c32bfff5c00f5f5ad6ea289 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 20:57:10 -0400 Subject: [PATCH 734/940] [dev.typeparams] go/types: embedding stand-alone type parameters is not permitted This is a port of CL 334151 to go/types. Fixes #47127 Change-Id: I57d69c498d2649a9e1657559e4c0271333096c88 Reviewed-on: https://go-review.googlesource.com/c/go/+/335082 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/testdata/check/issues.go2 | 2 +- src/go/types/testdata/check/tinference.go2 | 42 ++++++++++--------- .../types/testdata/fixedbugs/issue39634.go2 | 7 ++-- .../types/testdata/fixedbugs/issue39680.go2 | 4 ++ .../types/testdata/fixedbugs/issue39948.go2 | 10 +---- .../types/testdata/fixedbugs/issue47127.go2 | 37 ++++++++++++++++ src/go/types/typeset.go | 8 ++-- src/go/types/union.go | 11 +++-- 8 files changed, 81 insertions(+), 40 deletions(-) create mode 100644 src/go/types/testdata/fixedbugs/issue47127.go2 diff --git a/src/go/types/testdata/check/issues.go2 b/src/go/types/testdata/check/issues.go2 index 607da1df19e..c57f0023034 100644 --- a/src/go/types/testdata/check/issues.go2 +++ b/src/go/types/testdata/check/issues.go2 @@ -239,7 +239,7 @@ func _[T interface{ ~func() }](f T) { type sliceOf[E any] interface{ ~[]E } -func append[T interface{}, S sliceOf[T], T2 interface{ T }](s S, t ...T2) S +func append[T interface{}, S sliceOf[T], T2 interface{}](s S, t ...T2) S var f func() var cancelSlice []context.CancelFunc diff --git a/src/go/types/testdata/check/tinference.go2 b/src/go/types/testdata/check/tinference.go2 index 7ed358e0784..44e8dc00595 100644 --- a/src/go/types/testdata/check/tinference.go2 +++ b/src/go/types/testdata/check/tinference.go2 @@ -11,19 +11,20 @@ type any interface{} // TODO(rFindley) the below partially applied function types should probably // not be permitted (spec question). -func f0[A any, B interface{~C}, C interface{~D}, D interface{~A}](A, B, C, D) -func _() { - f := f0[string] - f("a", "b", "c", "d") - f0("a", "b", "c", "d") -} - -func f1[A any, B interface{~A}](A, B) -func _() { - f := f1[int] - f(int(0), int(0)) - f1(int(0), int(0)) -} +// Embedding stand-alone type parameters is not permitted for now. Disabled. +// func f0[A any, B interface{~C}, C interface{~D}, D interface{~A}](A, B, C, D) +// func _() { +// f := f0[string] +// f("a", "b", "c", "d") +// f0("a", "b", "c", "d") +// } +// +// func f1[A any, B interface{~A}](A, B) +// func _() { +// f := f1[int] +// f(int(0), int(0)) +// f1(int(0), int(0)) +// } func f2[A any, B interface{~[]A}](A, B) func _() { @@ -32,13 +33,14 @@ func _() { f2(byte(0), []byte{}) } -func f3[A any, B interface{~C}, C interface{~*A}](A, B, C) -func _() { - f := f3[int] - var x int - f(x, &x, &x) - f3(x, &x, &x) -} +// Embedding stand-alone type parameters is not permitted for now. Disabled. +// func f3[A any, B interface{~C}, C interface{~*A}](A, B, C) +// func _() { +// f := f3[int] +// var x int +// f(x, &x, &x) +// f3(x, &x, &x) +// } func f4[A any, B interface{~[]C}, C interface{~*A}](A, B, C) func _() { diff --git a/src/go/types/testdata/fixedbugs/issue39634.go2 b/src/go/types/testdata/fixedbugs/issue39634.go2 index 2a1367373f5..aec404e294b 100644 --- a/src/go/types/testdata/fixedbugs/issue39634.go2 +++ b/src/go/types/testdata/fixedbugs/issue39634.go2 @@ -31,9 +31,10 @@ type x7[A any] struct{ foo7 } func main7() { var _ foo7 = x7[int]{} } // crash 8 -type foo8[A any] interface { ~A } -func bar8[A foo8[A]](a A) {} -func main8() {} +// Embedding stand-alone type parameters is not permitted for now. Disabled. +// type foo8[A any] interface { ~A } +// func bar8[A foo8[A]](a A) {} +// func main8() {} // crash 9 type foo9[A any] interface { foo9 /* ERROR illegal cycle */ [A] } diff --git a/src/go/types/testdata/fixedbugs/issue39680.go2 b/src/go/types/testdata/fixedbugs/issue39680.go2 index 01eadd2dbf9..e56bc354758 100644 --- a/src/go/types/testdata/fixedbugs/issue39680.go2 +++ b/src/go/types/testdata/fixedbugs/issue39680.go2 @@ -4,6 +4,9 @@ package p +// Embedding stand-alone type parameters is not permitted for now. Disabled. + +/* import "fmt" // Minimal test case. @@ -25,3 +28,4 @@ func Print[T constr[T]](s []T) { func f() { Print([]string{"Hello, ", "playground\n"}) } +*/ diff --git a/src/go/types/testdata/fixedbugs/issue39948.go2 b/src/go/types/testdata/fixedbugs/issue39948.go2 index d83084b52a7..e38e57268d6 100644 --- a/src/go/types/testdata/fixedbugs/issue39948.go2 +++ b/src/go/types/testdata/fixedbugs/issue39948.go2 @@ -2,14 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// TODO(rfindley) Eventually, once we disallow type lists, we need to -// adjust this code: for 1.17 we don't accept type parameters, -// and for 1.18 this code is valid. -// Leaving for now so we can see that existing errors -// are being reported. - -package go1_17 // don't permit non-interface elements in interfaces +package p type T[P any] interface{ - P // ERROR P is a type parameter, not an interface + P // ERROR cannot embed a type parameter } diff --git a/src/go/types/testdata/fixedbugs/issue47127.go2 b/src/go/types/testdata/fixedbugs/issue47127.go2 new file mode 100644 index 00000000000..387c946957c --- /dev/null +++ b/src/go/types/testdata/fixedbugs/issue47127.go2 @@ -0,0 +1,37 @@ +// Copyright 2021 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. + +// Embedding of stand-alone type parameters is not permitted. + +package p + +type ( + _[P any] interface{ *P | []P | chan P | map[string]P } + _[P any] interface{ P /* ERROR "cannot embed a type parameter" */ } + _[P any] interface{ ~P /* ERROR "cannot embed a type parameter" */ } + _[P any] interface{ int | P /* ERROR "cannot embed a type parameter" */ } + _[P any] interface{ int | ~P /* ERROR "cannot embed a type parameter" */ } +) + +func _[P any]() { + type ( + _[P any] interface{ *P | []P | chan P | map[string]P } + _[P any] interface{ P /* ERROR "cannot embed a type parameter" */ } + _[P any] interface{ ~P /* ERROR "cannot embed a type parameter" */ } + _[P any] interface{ int | P /* ERROR "cannot embed a type parameter" */ } + _[P any] interface{ int | ~P /* ERROR "cannot embed a type parameter" */ } + + _ interface{ *P | []P | chan P | map[string]P } + _ interface{ P /* ERROR "cannot embed a type parameter" */ } + _ interface{ ~P /* ERROR "cannot embed a type parameter" */ } + _ interface{ int | P /* ERROR "cannot embed a type parameter" */ } + _ interface{ int | ~P /* ERROR "cannot embed a type parameter" */ } + ) +} + +func _[P any, Q interface{ *P | []P | chan P | map[string]P }]() +func _[P any, Q interface{ P /* ERROR "cannot embed a type parameter" */ }]() +func _[P any, Q interface{ ~P /* ERROR "cannot embed a type parameter" */ }]() +func _[P any, Q interface{ int | P /* ERROR "cannot embed a type parameter" */ }]() +func _[P any, Q interface{ int | ~P /* ERROR "cannot embed a type parameter" */ }]() diff --git a/src/go/types/typeset.go b/src/go/types/typeset.go index d8fe42f7d08..3df2f1235f5 100644 --- a/src/go/types/typeset.go +++ b/src/go/types/typeset.go @@ -217,11 +217,9 @@ func computeTypeSet(check *Checker, pos token.Pos, ityp *Interface) *TypeSet { // interface before go1.18. types = typ case *TypeParam: - if check != nil && !check.allowVersion(check.pkg, 1, 18) { - check.errorf(atPos(pos), _InvalidIfaceEmbed, "%s is a type parameter, not an interface", typ) - continue - } - types = typ + // Embedding stand-alone type parameters is not permitted for now. + // This case is handled during union parsing. + unreachable() default: if typ == Typ[Invalid] { continue diff --git a/src/go/types/union.go b/src/go/types/union.go index 7c69ec7b108..556be46bf6a 100644 --- a/src/go/types/union.go +++ b/src/go/types/union.go @@ -131,13 +131,18 @@ func parseUnion(check *Checker, tlist []ast.Expr) Type { return newUnion(types, tilde) } -func parseTilde(check *Checker, x ast.Expr) (Type, bool) { - tilde := false +func parseTilde(check *Checker, x ast.Expr) (typ Type, tilde bool) { if op, _ := x.(*ast.UnaryExpr); op != nil && op.Op == token.TILDE { x = op.X tilde = true } - return check.anyType(x), tilde + typ = check.anyType(x) + // embedding stand-alone type parameters is not permitted (issue #47127). + if _, ok := under(typ).(*TypeParam); ok { + check.error(x, _Todo, "cannot embed a type parameter") + typ = Typ[Invalid] + } + return } // intersect computes the intersection of the types x and y, From 6bf2667d4ef7dee76d308c0ac7acd0d409213b8a Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Mon, 19 Jul 2021 10:58:40 -0400 Subject: [PATCH 735/940] [dev.typeparams] go/types: more consistent handling of predeclared "any" This is a port of CL 334911 to go/types. Change-Id: I2cafdc76cb4d06ba82188c530f35952c1f77d292 Reviewed-on: https://go-review.googlesource.com/c/go/+/335569 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/decl.go | 5 +++-- src/go/types/object_test.go | 2 +- src/go/types/testdata/check/typeparams.go2 | 8 +++---- src/go/types/typexpr.go | 15 +++++++++++-- src/go/types/universe.go | 26 +++++++++------------- 5 files changed, 31 insertions(+), 25 deletions(-) diff --git a/src/go/types/decl.go b/src/go/types/decl.go index 8fae59ffe81..e38124f077a 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -678,8 +678,9 @@ func (check *Checker) declareTypeParams(tparams []*TypeName, names []*ast.Ident) // The type must be an interface, including the predeclared type "any". func (check *Checker) boundType(e ast.Expr) Type { // The predeclared identifier "any" is visible only as a type bound in a type parameter list. - if name, _ := unparen(e).(*ast.Ident); name != nil && name.Name == "any" && check.lookup("any") == nil { - return universeAny + // If we allow "any" for general use, this if-statement can be removed (issue #33232). + if name, _ := unparen(e).(*ast.Ident); name != nil && name.Name == "any" && check.lookup("any") == universeAny { + return universeAny.Type() } bound := check.typ(e) diff --git a/src/go/types/object_test.go b/src/go/types/object_test.go index 2b6057bd934..0ff8fdd6fa6 100644 --- a/src/go/types/object_test.go +++ b/src/go/types/object_test.go @@ -22,7 +22,7 @@ func TestIsAlias(t *testing.T) { check(Unsafe.Scope().Lookup("Pointer").(*TypeName), false) for _, name := range Universe.Names() { if obj, _ := Universe.Lookup(name).(*TypeName); obj != nil { - check(obj, name == "byte" || name == "rune") + check(obj, name == "any" || name == "byte" || name == "rune") } } diff --git a/src/go/types/testdata/check/typeparams.go2 b/src/go/types/testdata/check/typeparams.go2 index 0e3795724b3..b03725ff2aa 100644 --- a/src/go/types/testdata/check/typeparams.go2 +++ b/src/go/types/testdata/check/typeparams.go2 @@ -6,11 +6,11 @@ package p // import "io" // for type assertion tests -// The predeclared identifier "any" is only visible as a constraint +// The predeclared identifier "any" can only be used as a constraint // in a type parameter list. -var _ any // ERROR undeclared -func _[_ any /* ok here */ , _ interface{any /* ERROR undeclared */ }](any /* ERROR undeclared */ ) { - var _ any /* ERROR undeclared */ +var _ any // ERROR cannot use any outside constraint position +func _[_ any /* ok here */ , _ interface{any /* ERROR constraint */ }](any /* ERROR constraint */ ) { + var _ any /* ERROR constraint */ } func identity[T any](x T) T { return x } diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 9a9fe32cb38..f2c4762a6b3 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -27,13 +27,24 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, wantType bool) // Note that we cannot use check.lookup here because the returned scope // may be different from obj.Parent(). See also Scope.LookupParent doc. scope, obj := check.scope.LookupParent(e.Name, check.pos) - if obj == nil || obj == universeComparable && !check.allowVersion(check.pkg, 1, 18) { + switch obj { + case nil: if e.Name == "_" { - check.errorf(e, _InvalidBlank, "cannot use _ as value or type") + check.error(e, _InvalidBlank, "cannot use _ as value or type") } else { check.errorf(e, _UndeclaredName, "undeclared name: %s", e.Name) } return + case universeAny, universeComparable: + if !check.allowVersion(check.pkg, 1, 18) { + check.errorf(e, _UndeclaredName, "undeclared name: %s (requires version go1.18 or later)", e.Name) + return + } + // If we allow "any" for general use, this if-statement can be removed (issue #33232). + if obj == universeAny { + check.error(e, _Todo, "cannot use any outside constraint position") + return + } } check.recordUse(e, obj) diff --git a/src/go/types/universe.go b/src/go/types/universe.go index 7c1e29b856c..59952bc6427 100644 --- a/src/go/types/universe.go +++ b/src/go/types/universe.go @@ -21,11 +21,11 @@ var Universe *Scope var Unsafe *Package var ( - universeIota *Const - universeByte *Basic // uint8 alias, but has name "byte" - universeRune *Basic // int32 alias, but has name "rune" - universeAny *Interface - universeError *Named + universeIota Object + universeByte Type // uint8 alias, but has name "byte" + universeRune Type // int32 alias, but has name "rune" + universeAny Object + universeError Type universeComparable Object ) @@ -80,9 +80,6 @@ func defPredeclaredTypes() { } // type any = interface{} - // Entered into universe scope so we do all the usual checks; - // but removed again from scope later since it's only visible - // as constraint in a type parameter list. def(NewTypeName(token.NoPos, nil, "any", &emptyInterface)) // type error interface{ Error() string } @@ -225,15 +222,12 @@ func init() { defPredeclaredNil() defPredeclaredFuncs() - universeIota = Universe.Lookup("iota").(*Const) - universeByte = Universe.Lookup("byte").(*TypeName).typ.(*Basic) - universeRune = Universe.Lookup("rune").(*TypeName).typ.(*Basic) - universeAny = Universe.Lookup("any").(*TypeName).typ.(*Interface) - universeError = Universe.Lookup("error").(*TypeName).typ.(*Named) + universeIota = Universe.Lookup("iota") + universeByte = Universe.Lookup("byte").Type() + universeRune = Universe.Lookup("rune").Type() + universeAny = Universe.Lookup("any") + universeError = Universe.Lookup("error").Type() universeComparable = Universe.Lookup("comparable") - - // "any" is only visible as constraint in a type parameter list - delete(Universe.elems, "any") } // Objects with names containing blanks are internal and not entered into From 6298cfe6724e3ca24dedd3f62b2b358aafe17276 Mon Sep 17 00:00:00 2001 From: Leonard Wang Date: Sun, 11 Jul 2021 11:46:26 +0800 Subject: [PATCH 736/940] cmd/compile: fix typo in fatal message of builtinCall Change-Id: I523d5fd810b82154a204670d46fc250a0fc66791 Reviewed-on: https://go-review.googlesource.com/c/go/+/333849 Reviewed-by: Ian Lance Taylor Reviewed-by: Matthew Dempsky Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot --- src/cmd/compile/internal/typecheck/iimport.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index a5ddbb5a74c..37f5a7bba0a 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -1540,7 +1540,7 @@ func (r *importReader) exprsOrNil() (a, b ir.Node) { func builtinCall(pos src.XPos, op ir.Op) *ir.CallExpr { if go117ExportTypes { // These should all be encoded as direct ops, not OCALL. - base.Fatalf("builtinCall should not be invoked when types are included in inport/export") + base.Fatalf("builtinCall should not be invoked when types are included in import/export") } return ir.NewCallExpr(pos, ir.OCALL, ir.NewIdent(base.Pos, types.BuiltinPkg.Lookup(ir.OpNames[op])), nil) } From c6d3d0b0ad10926fc1952deda913d139ed608cb3 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 11 Jun 2021 12:40:42 -0400 Subject: [PATCH 737/940] [dev.typeparams] go/types: fix the type parameter index in applyTypeFunc We should preserve type parameter indices when transforming them using applyTypeFunc. Change-Id: Ib75f5cf1a146bd7e6850368fa954c1affcba3ad1 Reviewed-on: https://go-review.googlesource.com/c/go/+/327269 Trust: Robert Findley Run-TryBot: Robert Findley Reviewed-by: Robert Griesemer TryBot-Result: Go Bot --- src/cmd/compile/internal/types2/builtins.go | 2 +- src/go/types/builtins.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index 1f7eb23cdf0..14be24e2514 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -802,7 +802,7 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { // type param is placed in the current package so export/import // works as expected. tpar := NewTypeName(nopos, check.pkg, "", nil) - ptyp := check.NewTypeParam(tpar, 0, &emptyInterface) // assigns type to tpar as a side-effect + ptyp := check.NewTypeParam(tpar, tp.index, &emptyInterface) // assigns type to tpar as a side-effect tsum := newUnion(rtypes, tildes) ptyp.bound = &Interface{complete: true, tset: &TypeSet{types: tsum}} diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index eb3503fd6b5..2edf9011654 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -806,7 +806,7 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { // type param is placed in the current package so export/import // works as expected. tpar := NewTypeName(token.NoPos, check.pkg, "", nil) - ptyp := check.NewTypeParam(tpar, 0, &emptyInterface) // assigns type to tpar as a side-effect + ptyp := check.NewTypeParam(tpar, tp.index, &emptyInterface) // assigns type to tpar as a side-effect tsum := newUnion(rtypes, tildes) ptyp.bound = &Interface{complete: true, tset: &TypeSet{types: tsum}} From 404127c30f3f66eb234da2dc1a78e6eea0ef4ee0 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 14 Jul 2021 18:52:44 -0400 Subject: [PATCH 738/940] cmd/compile: fix off-by-one error in traceback argument counting For traceback argument printing, we want to print at most 10 words, then print "..." if there are still more args and/or fields. The current code has off-by-one error that for 11 non-aggregate typed args, it prints the first 10 but without the "...". Also, for aggregate-typed args, in some cases it may print an extra "..." when there is actually no more fields. The problem for this is that visitType return false (meaning not to continue visiting) if it reaches the limit anywhere during the recursive visit. It doesn't distinguish whether it has printed anything for the current arg. If it reaches the limit before it prints anything, it means that we're visiting the extra arg/field, so the caller should print "..." and stop. If it prints something then reaches the limit, however, the caller should keep going, and only print "..." at the next iteration when there is actually an extra arg/field. This CL does so. Fixes #47159. Change-Id: I93fc25b73ada2b5a98df780c45e5b0c9565dc2fc Reviewed-on: https://go-review.googlesource.com/c/go/+/334710 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/cmd/compile/internal/ssagen/ssa.go | 43 +++--- src/runtime/traceback_test.go | 179 ++++++++++++++++++++++++- 2 files changed, 190 insertions(+), 32 deletions(-) diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index f1dc56e7297..a5cb0857b31 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -6598,6 +6598,7 @@ func EmitArgInfo(f *ir.Func, abiInfo *abi.ABIParamResultInfo) *obj.LSym { x := base.Ctxt.Lookup(fmt.Sprintf("%s.arginfo%d", f.LSym.Name, f.ABI)) PtrSize := int64(types.PtrSize) + uintptrTyp := types.Types[types.TUINTPTR] isAggregate := func(t *types.Type) bool { return t.IsStruct() || t.IsArray() || t.IsComplex() || t.IsInterface() || t.IsString() || t.IsSlice() @@ -6641,12 +6642,8 @@ func EmitArgInfo(f *ir.Func, abiInfo *abi.ABIParamResultInfo) *obj.LSym { n := 0 writebyte := func(o uint8) { wOff = objw.Uint8(x, wOff, o) } - // Write one non-aggrgate arg/field/element if there is room. - // Returns whether to continue. - write1 := func(sz, offset int64) bool { - if n >= limit { - return false - } + // Write one non-aggrgate arg/field/element. + write1 := func(sz, offset int64) { if offset >= _special { writebyte(_offsetTooLarge) } else { @@ -6654,7 +6651,6 @@ func EmitArgInfo(f *ir.Func, abiInfo *abi.ABIParamResultInfo) *obj.LSym { writebyte(uint8(sz)) } n++ - return true } // Visit t recursively and write it out. @@ -6662,10 +6658,12 @@ func EmitArgInfo(f *ir.Func, abiInfo *abi.ABIParamResultInfo) *obj.LSym { var visitType func(baseOffset int64, t *types.Type, depth int) bool visitType = func(baseOffset int64, t *types.Type, depth int) bool { if n >= limit { + writebyte(_dotdotdot) return false } if !isAggregate(t) { - return write1(t.Size(), baseOffset) + write1(t.Size(), baseOffset) + return true } writebyte(_startAgg) depth++ @@ -6675,58 +6673,47 @@ func EmitArgInfo(f *ir.Func, abiInfo *abi.ABIParamResultInfo) *obj.LSym { n++ return true } - var r bool switch { case t.IsInterface(), t.IsString(): - r = write1(PtrSize, baseOffset) && - write1(PtrSize, baseOffset+PtrSize) + _ = visitType(baseOffset, uintptrTyp, depth) && + visitType(baseOffset+PtrSize, uintptrTyp, depth) case t.IsSlice(): - r = write1(PtrSize, baseOffset) && - write1(PtrSize, baseOffset+PtrSize) && - write1(PtrSize, baseOffset+PtrSize*2) + _ = visitType(baseOffset, uintptrTyp, depth) && + visitType(baseOffset+PtrSize, uintptrTyp, depth) && + visitType(baseOffset+PtrSize*2, uintptrTyp, depth) case t.IsComplex(): - r = write1(t.Size()/2, baseOffset) && - write1(t.Size()/2, baseOffset+t.Size()/2) + _ = visitType(baseOffset, types.FloatForComplex(t), depth) && + visitType(baseOffset+t.Size()/2, types.FloatForComplex(t), depth) case t.IsArray(): - r = true if t.NumElem() == 0 { n++ // {} counts as a component break } for i := int64(0); i < t.NumElem(); i++ { if !visitType(baseOffset, t.Elem(), depth) { - r = false break } baseOffset += t.Elem().Size() } case t.IsStruct(): - r = true if t.NumFields() == 0 { n++ // {} counts as a component break } for _, field := range t.Fields().Slice() { if !visitType(baseOffset+field.Offset, field.Type, depth) { - r = false break } } } - if !r { - writebyte(_dotdotdot) - } writebyte(_endAgg) - return r + return true } - c := true for _, a := range abiInfo.InParams() { - if !c { - writebyte(_dotdotdot) + if !visitType(a.FrameOffset(abiInfo), a.Type, 0) { break } - c = visitType(a.FrameOffset(abiInfo), a.Type, 0) } writebyte(_endSeq) if wOff > maxLen { diff --git a/src/runtime/traceback_test.go b/src/runtime/traceback_test.go index 2a0497e9a90..83b86a7e909 100644 --- a/src/runtime/traceback_test.go +++ b/src/runtime/traceback_test.go @@ -19,8 +19,8 @@ func TestTracebackArgs(t *testing.T) { }{ // simple ints { - func() int { return testTracebackArgs1(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) }, - "testTracebackArgs1(0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, ...)", + func() int { return testTracebackArgs1(1, 2, 3, 4, 5) }, + "testTracebackArgs1(0x1, 0x2, 0x3, 0x4, 0x5)", }, // some aggregates { @@ -53,6 +53,58 @@ func TestTracebackArgs(t *testing.T) { }, "testTracebackArgs5(0x0, {0x1, {}, {{}, {}}}, {}, {}, {}, {}, {}, ...)", }, + + // edge cases for ... + // no ... for 10 args + { + func() int { return testTracebackArgs6a(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) }, + "testTracebackArgs6a(0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa)", + }, + // has ... for 11 args + { + func() int { return testTracebackArgs6b(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) }, + "testTracebackArgs6b(0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, ...)", + }, + // no ... for aggregates with 10 words + { + func() int { return testTracebackArgs7a([10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) }, + "testTracebackArgs7a({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa})", + }, + // has ... for aggregates with 11 words + { + func() int { return testTracebackArgs7b([11]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}) }, + "testTracebackArgs7b({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, ...})", + }, + // no ... for aggregates, but with more args + { + func() int { return testTracebackArgs7c([10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 11) }, + "testTracebackArgs7c({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa}, ...)", + }, + // has ... for aggregates and also for more args + { + func() int { return testTracebackArgs7d([11]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 12) }, + "testTracebackArgs7d({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, ...}, ...)", + }, + // nested aggregates, no ... + { + func() int { return testTracebackArgs8a(testArgsType8a{1, 2, 3, 4, 5, 6, 7, 8, [2]int{9, 10}}) }, + "testTracebackArgs8a({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, {0x9, 0xa}})", + }, + // nested aggregates, ... in inner but not outer + { + func() int { return testTracebackArgs8b(testArgsType8b{1, 2, 3, 4, 5, 6, 7, 8, [3]int{9, 10, 11}}) }, + "testTracebackArgs8b({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, {0x9, 0xa, ...}})", + }, + // nested aggregates, ... in outer but not inner + { + func() int { return testTracebackArgs8c(testArgsType8c{1, 2, 3, 4, 5, 6, 7, 8, [2]int{9, 10}, 11}) }, + "testTracebackArgs8c({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, {0x9, 0xa}, ...})", + }, + // nested aggregates, ... in both inner and outer + { + func() int { return testTracebackArgs8d(testArgsType8d{1, 2, 3, 4, 5, 6, 7, 8, [3]int{9, 10, 11}, 12}) }, + "testTracebackArgs8d({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, {0x9, 0xa, ...}, ...})", + }, } for _, test := range tests { n := test.fn() @@ -64,11 +116,11 @@ func TestTracebackArgs(t *testing.T) { } //go:noinline -func testTracebackArgs1(a, b, c, d, e, f, g, h, i, j, k, l int) int { +func testTracebackArgs1(a, b, c, d, e int) int { n := runtime.Stack(testTracebackArgsBuf[:], false) if a < 0 { // use in-reg args to keep them alive - return a + b + c + d + e + f + g + h + i + j + k + l + return a + b + c + d + e } return n } @@ -119,3 +171,122 @@ func testTracebackArgs5(a bool, x struct { } return n } + +//go:noinline +func testTracebackArgs6a(a, b, c, d, e, f, g, h, i, j int) int { + n := runtime.Stack(testTracebackArgsBuf[:], false) + if a < 0 { + // use in-reg args to keep them alive + return a + b + c + d + e + f + g + h + i + j + } + return n +} + +//go:noinline +func testTracebackArgs6b(a, b, c, d, e, f, g, h, i, j, k int) int { + n := runtime.Stack(testTracebackArgsBuf[:], false) + if a < 0 { + // use in-reg args to keep them alive + return a + b + c + d + e + f + g + h + i + j + k + } + return n +} + +//go:noinline +func testTracebackArgs7a(a [10]int) int { + n := runtime.Stack(testTracebackArgsBuf[:], false) + if a[0] < 0 { + // use in-reg args to keep them alive + return a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9] + } + return n +} + +//go:noinline +func testTracebackArgs7b(a [11]int) int { + n := runtime.Stack(testTracebackArgsBuf[:], false) + if a[0] < 0 { + // use in-reg args to keep them alive + return a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9] + a[10] + } + return n +} + +//go:noinline +func testTracebackArgs7c(a [10]int, b int) int { + n := runtime.Stack(testTracebackArgsBuf[:], false) + if a[0] < 0 { + // use in-reg args to keep them alive + return a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9] + b + } + return n +} + +//go:noinline +func testTracebackArgs7d(a [11]int, b int) int { + n := runtime.Stack(testTracebackArgsBuf[:], false) + if a[0] < 0 { + // use in-reg args to keep them alive + return a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9] + a[10] + b + } + return n +} + +type testArgsType8a struct { + a, b, c, d, e, f, g, h int + i [2]int +} +type testArgsType8b struct { + a, b, c, d, e, f, g, h int + i [3]int +} +type testArgsType8c struct { + a, b, c, d, e, f, g, h int + i [2]int + j int +} +type testArgsType8d struct { + a, b, c, d, e, f, g, h int + i [3]int + j int +} + +//go:noinline +func testTracebackArgs8a(a testArgsType8a) int { + n := runtime.Stack(testTracebackArgsBuf[:], false) + if a.a < 0 { + // use in-reg args to keep them alive + return a.b + a.c + a.d + a.e + a.f + a.g + a.h + a.i[0] + a.i[1] + } + return n +} + +//go:noinline +func testTracebackArgs8b(a testArgsType8b) int { + n := runtime.Stack(testTracebackArgsBuf[:], false) + if a.a < 0 { + // use in-reg args to keep them alive + return a.b + a.c + a.d + a.e + a.f + a.g + a.h + a.i[0] + a.i[1] + a.i[2] + } + return n +} + +//go:noinline +func testTracebackArgs8c(a testArgsType8c) int { + n := runtime.Stack(testTracebackArgsBuf[:], false) + if a.a < 0 { + // use in-reg args to keep them alive + return a.b + a.c + a.d + a.e + a.f + a.g + a.h + a.i[0] + a.i[1] + a.j + } + return n +} + +//go:noinline +func testTracebackArgs8d(a testArgsType8d) int { + n := runtime.Stack(testTracebackArgsBuf[:], false) + if a.a < 0 { + // use in-reg args to keep them alive + return a.b + a.c + a.d + a.e + a.f + a.g + a.h + a.i[0] + a.i[1] + a.i[2] + a.j + } + return n +} From 1d91551b7326383343c7c143a8ac299d0a685289 Mon Sep 17 00:00:00 2001 From: helloPiers Date: Mon, 19 Jul 2021 20:08:50 +0000 Subject: [PATCH 739/940] time: correct typo in documentation for UnixMicro Fixes #47283. Change-Id: Ibdc35433d22be3caa70197b6a95c66999812a16a GitHub-Last-Rev: 75962b029467a5e26e1ee78a38bf01c954445ea1 GitHub-Pull-Request: golang/go#47284 Reviewed-on: https://go-review.googlesource.com/c/go/+/335549 Reviewed-by: Ian Lance Taylor Trust: Than McIntosh --- src/time/time.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/time/time.go b/src/time/time.go index 1cf1e2bbf61..4ecc3d82dcc 100644 --- a/src/time/time.go +++ b/src/time/time.go @@ -1334,7 +1334,7 @@ func UnixMilli(msec int64) Time { } // UnixMicro returns the local Time corresponding to the given Unix time, -// usec milliseconds since January 1, 1970 UTC. +// usec microseconds since January 1, 1970 UTC. func UnixMicro(usec int64) Time { return Unix(usec/1e6, (usec%1e6)*1e3) } From c8f4e6152d5f0b767a8177b7d09884cf2279d8e6 Mon Sep 17 00:00:00 2001 From: Piers Date: Mon, 19 Jul 2021 20:11:29 +0000 Subject: [PATCH 740/940] spec: correct example comment in Conversions from slice to array Fixes #47280 Change-Id: I78a8d235949b4878c7f075ac4ca37700e7e6c31c GitHub-Last-Rev: 067f96eeb2c918eb4f775c428edc945c75af44d8 GitHub-Pull-Request: golang/go#47282 Reviewed-on: https://go-review.googlesource.com/c/go/+/335470 Reviewed-by: Robert Griesemer Trust: Robert Griesemer Trust: Than McIntosh --- doc/go_spec.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index ad21ffb1b88..df256f0f0ee 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -4334,7 +4334,7 @@ s4 := (*[4]byte)(s) // panics: len([4]byte) > len(s) var t []string t0 := (*[0]string)(t) // t0 == nil -t1 := (*[1]string)(t) // panics: len([1]string) > len(s) +t1 := (*[1]string)(t) // panics: len([1]string) > len(t)

Constant expressions

From d568e6e075e6434635268d3caf55963f4e564579 Mon Sep 17 00:00:00 2001 From: Benny Siegert Date: Tue, 20 Jul 2021 09:36:08 -0400 Subject: [PATCH 741/940] runtime/debug: skip TestPanicOnFault on netbsd/arm This test has been failing since the builder was updated to NetBSD 9. While the issue is under investigation, skip the test so that we do not miss other breakage. Update issue #45026 Change-Id: Id083901c517f3f88e6b4bc2b51208f65170d47a6 Reviewed-on: https://go-review.googlesource.com/c/go/+/335909 Reviewed-by: Than McIntosh Reviewed-by: Keith Randall Trust: Benny Siegert Run-TryBot: Benny Siegert TryBot-Result: Go Bot --- src/runtime/debug/panic_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/runtime/debug/panic_test.go b/src/runtime/debug/panic_test.go index b93631e1d83..65f9555f376 100644 --- a/src/runtime/debug/panic_test.go +++ b/src/runtime/debug/panic_test.go @@ -24,6 +24,9 @@ func TestPanicOnFault(t *testing.T) { if runtime.GOOS == "ios" { t.Skip("iOS doesn't provide fault addresses") } + if runtime.GOOS == "netbsd" && runtime.GOARCH == "arm" { + t.Skip("netbsd-arm doesn't provide fault address (golang.org/issue/45026)") + } m, err := syscall.Mmap(-1, 0, 0x1000, syscall.PROT_READ /* Note: no PROT_WRITE */, syscall.MAP_SHARED|syscall.MAP_ANON) if err != nil { t.Fatalf("can't map anonymous memory: %s", err) From 9e26569293c13974d210fd588ebfd29b857d8525 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 18 Jul 2021 13:58:13 -0700 Subject: [PATCH 742/940] cmd/go: don't add C compiler ID to hash for standard library No test because a real test requires installing two different compilers. For #40042 For #47251 Change-Id: Iefddd67830d242a119378b7ce20be481904806e4 Reviewed-on: https://go-review.googlesource.com/c/go/+/335409 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills Reviewed-by: Jay Conrod --- src/cmd/go/go_test.go | 32 ++++++++++++++++++++++++++++++++ src/cmd/go/internal/work/exec.go | 11 +++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index c0c86ab9f58..6ce276537ba 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -2848,3 +2848,35 @@ func TestExecInDeletedDir(t *testing.T) { // `go version` should not fail tg.run("version") } + +// A missing C compiler should not force the net package to be stale. +// Issue 47215. +func TestMissingCC(t *testing.T) { + if !canCgo { + t.Skip("test is only meaningful on systems with cgo") + } + cc := os.Getenv("CC") + if cc == "" { + cc = "gcc" + } + if filepath.IsAbs(cc) { + t.Skipf(`"CC" (%s) is an absolute path`, cc) + } + _, err := exec.LookPath(cc) + if err != nil { + t.Skipf(`"CC" (%s) not on PATH`, cc) + } + + tg := testgo(t) + defer tg.cleanup() + netStale, _ := tg.isStale("net") + if netStale { + t.Skip(`skipping test because "net" package is currently stale`) + } + + tg.setenv("PATH", "") // No C compiler on PATH. + netStale, _ = tg.isStale("net") + if netStale { + t.Error(`clearing "PATH" causes "net" to be stale`) + } +} diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index b506b836561..5a225fb9f1f 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -252,8 +252,15 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID { ccExe := b.ccExe() fmt.Fprintf(h, "CC=%q %q %q %q\n", ccExe, cppflags, cflags, ldflags) - if ccID, err := b.gccToolID(ccExe[0], "c"); err == nil { - fmt.Fprintf(h, "CC ID=%q\n", ccID) + // Include the C compiler tool ID so that if the C + // compiler changes we rebuild the package. + // But don't do that for standard library packages like net, + // so that the prebuilt .a files from a Go binary install + // don't need to be rebuilt with the local compiler. + if !p.Standard { + if ccID, err := b.gccToolID(ccExe[0], "c"); err == nil { + fmt.Fprintf(h, "CC ID=%q\n", ccID) + } } if len(p.CXXFiles)+len(p.SwigCXXFiles) > 0 { cxxExe := b.cxxExe() From 6a931673f0b655e7ca538826af21a54d3f958070 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 20 Jul 2021 13:28:12 -0700 Subject: [PATCH 743/940] [dev.typeparams] cmd/compile: add base.Assertf{,At} functions We have almost 200 uses of the "assert" helper functions in noder and typecheck. Clearly the tiny bit of extra convenience of writing a one-line assertion rather than an if+panic is helpful, so we might as well add functions for this to base itself so that it's easier to write more informative error messages. Change-Id: I06e2db2f0455af063937b25a53ca42f9413cf496 Reviewed-on: https://go-review.googlesource.com/c/go/+/336050 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/base/print.go | 21 +++++++++++++++++++++ src/cmd/compile/internal/noder/stencil.go | 4 +--- src/cmd/compile/internal/typecheck/subr.go | 4 +--- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/cmd/compile/internal/base/print.go b/src/cmd/compile/internal/base/print.go index b095fd704da..4afe2eb9eea 100644 --- a/src/cmd/compile/internal/base/print.go +++ b/src/cmd/compile/internal/base/print.go @@ -233,6 +233,27 @@ func FatalfAt(pos src.XPos, format string, args ...interface{}) { ErrorExit() } +// Assert reports "assertion failed" with Fatalf, unless b is true. +func Assert(b bool) { + if !b { + Fatalf("assertion failed") + } +} + +// Assertf reports a fatal error with Fatalf, unless b is true. +func Assertf(b bool, format string, args ...interface{}) { + if !b { + Fatalf(format, args...) + } +} + +// AssertfAt reports a fatal error with FatalfAt, unless b is true. +func AssertfAt(b bool, pos src.XPos, format string, args ...interface{}) { + if !b { + FatalfAt(pos, format, args...) + } +} + // hcrash crashes the compiler when -h is set, to find out where a message is generated. func hcrash() { if Flag.LowerH != 0 { diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 7eac8573c96..72ecd80cf5d 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -23,9 +23,7 @@ import ( ) func assert(p bool) { - if !p { - panic("assertion failed") - } + base.Assert(p) } // Temporary - for outputting information on derived types, dictionaries, sub-dictionaries. diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index d9e6612dfc3..a795524b2bc 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -981,9 +981,7 @@ func MakeDictName(gf *types.Sym, targs []*types.Type, hasBrackets bool) *types.S } func assert(p bool) { - if !p { - panic("assertion failed") - } + base.Assert(p) } // General type substituter, for replacing typeparams with type args. From d5f6ba943c4e8f39d1bd20c79f4e9274ad10c103 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Sat, 17 Jul 2021 00:15:07 +0700 Subject: [PATCH 744/940] [dev.typeparams] test: add regression test for go/defer wrapper CL 330330 moved logic for wrapping go/defer from order to esacpe analysis. It introduced a bug involves go/defer statement with ABI0 functions. Consider this following code: package p //go:cgo_unsafe_args func g(*int) (r1 struct{}) { return } func f() { defer g(new(int)) } g is a cgo-like generated function with ABI0. While compiling g, we set the offset per ABI0. The function f is rewritten into: func f() { _0, _1 := g, new(int) defer func() { _0(_1) }() } The temporary _0 hold function value with the same type as g, but with class PAUTO. Thus ssagen/ssa.go:state.call cannot handle it and use ABIDefault to set the offset, causes the offset of r1 changed CL 330332 intended to optimize code generated for wrapping function, by rewriting the wrapper function into: func f() { _0 := new(int) defer func() { g(_0) }() } So it fixed the bug unintentionally. This CL add regression test for this bug, and also add a comment to explain while not wrapping declared function is important. Updates #47227 Change-Id: I75c83d1d9cc7fd4699e6b218a295d0c0a10ef471 Reviewed-on: https://go-review.googlesource.com/c/go/+/334882 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/escape/call.go | 2 ++ test/fixedbugs/issue47227.go | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 test/fixedbugs/issue47227.go diff --git a/src/cmd/compile/internal/escape/call.go b/src/cmd/compile/internal/escape/call.go index 9e5abed5914..65c76d6870b 100644 --- a/src/cmd/compile/internal/escape/call.go +++ b/src/cmd/compile/internal/escape/call.go @@ -320,6 +320,8 @@ func (e *escape) rewriteArgument(argp *ir.Node, init *ir.Nodes, call ir.Node, fn return case ir.ONAME: if arg.(*ir.Name).Class == ir.PFUNC { + // TODO(cuonglm): figure it why this is necessary, we should not depend on this to make + // ABI analyze works correctly (see #47227 and discussion in CL 334882). return } } diff --git a/test/fixedbugs/issue47227.go b/test/fixedbugs/issue47227.go new file mode 100644 index 00000000000..a14efc9a689 --- /dev/null +++ b/test/fixedbugs/issue47227.go @@ -0,0 +1,23 @@ +// run fake-arg-to-force-use-of-go-run + +// Copyright 2021 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 cgo +// +build cgo + +package main + +// void f(int *p) { *p = 0x12345678; } +import "C" + +func main() { + var x C.int + func() { + defer C.f(&x) + }() + if x != 0x12345678 { + panic("FAIL") + } +} From 897970688b326f7baa8ad8e3330fb552d94b0014 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 20 Jul 2021 16:52:37 -0700 Subject: [PATCH 745/940] [dev.typeparams] cmd/compile: cleanup unified IR file format a little This CL makes two changes: 1. It moves object symbols and code tags into a new "relocName" relocation, which should eventually allow getting rid of objStub. 2. It moves the type parameter data into the relocObjDict relocation, so everything related to writing out dictionaries is contained there. Change-Id: If0f7ff7d9384e8664957c3180bf6f20e97bcff6e Reviewed-on: https://go-review.googlesource.com/c/go/+/336051 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/noder/linker.go | 31 +++------ src/cmd/compile/internal/noder/reader.go | 79 +++++++++++----------- src/cmd/compile/internal/noder/reader2.go | 43 ++++++------ src/cmd/compile/internal/noder/reloc.go | 1 + src/cmd/compile/internal/noder/sync.go | 1 + src/cmd/compile/internal/noder/unified.go | 4 +- src/cmd/compile/internal/noder/writer.go | 81 +++++++++++++---------- 7 files changed, 124 insertions(+), 116 deletions(-) diff --git a/src/cmd/compile/internal/noder/linker.go b/src/cmd/compile/internal/noder/linker.go index eefb5083e50..2bc7f7c608e 100644 --- a/src/cmd/compile/internal/noder/linker.go +++ b/src/cmd/compile/internal/noder/linker.go @@ -110,7 +110,7 @@ func (l *linker) relocPkg(pr *pkgReader, idx int) int { } func (l *linker) relocObj(pr *pkgReader, idx int) int { - path, name, tag, _ := pr.peekObj(idx) + path, name, tag := pr.peekObj(idx) sym := types.NewPkg(path, "").Lookup(name) if newidx, ok := l.decls[sym]; ok { @@ -127,7 +127,7 @@ func (l *linker) relocObj(pr *pkgReader, idx int) int { pr = pri.pr idx = pri.idx - path2, name2, tag2, _ := pr.peekObj(idx) + path2, name2, tag2 := pr.peekObj(idx) sym2 := types.NewPkg(path2, "").Lookup(name2) assert(sym == sym2) assert(tag2 != objStub) @@ -135,13 +135,16 @@ func (l *linker) relocObj(pr *pkgReader, idx int) int { w := l.pw.newEncoderRaw(relocObj) wext := l.pw.newEncoderRaw(relocObjExt) + wname := l.pw.newEncoderRaw(relocName) wdict := l.pw.newEncoderRaw(relocObjDict) l.decls[sym] = w.idx assert(wext.idx == w.idx) + assert(wname.idx == w.idx) assert(wdict.idx == w.idx) l.relocCommon(pr, &w, relocObj, idx) + l.relocCommon(pr, &wname, relocName, idx) l.relocCommon(pr, &wdict, relocObjDict, idx) var obj *ir.Name @@ -279,33 +282,15 @@ func (pr *pkgDecoder) peekPkgPath(idx int) string { return path } -func (pr *pkgDecoder) peekObj(idx int) (string, string, codeObj, []int) { - r := pr.newDecoder(relocObj, idx, syncObject1) +func (pr *pkgDecoder) peekObj(idx int) (string, string, codeObj) { + r := pr.newDecoder(relocName, idx, syncObject1) r.sync(syncSym) r.sync(syncPkg) path := pr.peekPkgPath(r.reloc(relocPkg)) name := r.string() assert(name != "") - r.sync(syncTypeParamBounds) - r.len() // implicits - bounds := make([]int, r.len()) - for i := range bounds { - r.sync(syncType) - if r.bool() { - r.len() - } else { - r.reloc(relocType) - } - - // TODO(mdempsky): This result now needs to include the 'derived' - // bool too, but none of the callers currently depend on it - // anyway. Either fix it to be meaningful, or just get rid of it - // altogether. - bounds[i] = -1 - } - tag := codeObj(r.code(syncCodeObj)) - return path, name, tag, bounds + return path, name, tag } diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index de708769bab..44d1c4f28be 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -534,18 +534,10 @@ func (r *reader) obj() ir.Node { } func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node { - r := pr.newReader(relocObj, idx, syncObject1) - r.ext = pr.newReader(relocObjExt, idx, syncObject1) + rname := pr.newReader(relocName, idx, syncObject1) + _, sym := rname.qualifiedIdent() + tag := codeObj(rname.code(syncCodeObj)) - _, sym := r.qualifiedIdent() - - dict := &readerDict{} - r.dict = dict - r.ext.dict = dict - - r.typeParamBounds(sym, implicits, explicits) - - tag := codeObj(r.code(syncCodeObj)) if tag == objStub { assert(!sym.IsBlank()) switch sym.Pkg { @@ -556,30 +548,19 @@ func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node return pri.pr.objIdx(pri.idx, nil, explicits) } if haveLegacyImports { - assert(!r.hasTypeParams()) + assert(len(explicits) == 0) return typecheck.Resolve(ir.NewIdent(src.NoXPos, sym)) } base.Fatalf("unresolved stub: %v", sym) } - { - rdict := pr.newReader(relocObjDict, idx, syncObject1) - r.dict.derived = make([]derivedInfo, rdict.len()) - r.dict.derivedTypes = make([]*types.Type, len(r.dict.derived)) - for i := range r.dict.derived { - r.dict.derived[i] = derivedInfo{rdict.reloc(relocType), rdict.bool()} - } - r.dict.funcs = make([]objInfo, rdict.len()) - r.dict.funcsObj = make([]ir.Node, len(r.dict.funcs)) - for i := range r.dict.funcs { - objIdx := rdict.reloc(relocObj) - targs := make([]typeInfo, rdict.len()) - for j := range targs { - targs[j] = rdict.typInfo() - } - r.dict.funcs[i] = objInfo{idx: objIdx, explicits: targs} - } - } + dict := pr.objDictIdx(sym, idx, implicits, explicits) + + r := pr.newReader(relocObj, idx, syncObject1) + r.ext = pr.newReader(relocObjExt, idx, syncObject1) + + r.dict = dict + r.ext.dict = dict sym = r.mangle(sym) if !sym.IsBlank() && sym.Def != nil { @@ -692,8 +673,10 @@ func (r *reader) mangle(sym *types.Sym) *types.Sym { return sym.Pkg.Lookup(buf.String()) } -func (r *reader) typeParamBounds(sym *types.Sym, implicits, explicits []*types.Type) { - r.sync(syncTypeParamBounds) +func (pr *pkgReader) objDictIdx(sym *types.Sym, idx int, implicits, explicits []*types.Type) *readerDict { + r := pr.newReader(relocObjDict, idx, syncObject1) + + var dict readerDict nimplicits := r.len() nexplicits := r.len() @@ -702,12 +685,11 @@ func (r *reader) typeParamBounds(sym *types.Sym, implicits, explicits []*types.T base.Fatalf("%v has %v+%v params, but instantiated with %v+%v args", sym, nimplicits, nexplicits, len(implicits), len(explicits)) } - r.dict.targs = append(implicits[:nimplicits:nimplicits], explicits...) - r.dict.implicits = nimplicits + dict.targs = append(implicits[:nimplicits:nimplicits], explicits...) + dict.implicits = nimplicits // For stenciling, we can just skip over the type parameters. - - for range r.dict.targs[r.dict.implicits:] { + for range dict.targs[dict.implicits:] { // Skip past bounds without actually evaluating them. r.sync(syncType) if r.bool() { @@ -716,6 +698,25 @@ func (r *reader) typeParamBounds(sym *types.Sym, implicits, explicits []*types.T r.reloc(relocType) } } + + dict.derived = make([]derivedInfo, r.len()) + dict.derivedTypes = make([]*types.Type, len(dict.derived)) + for i := range dict.derived { + dict.derived[i] = derivedInfo{r.reloc(relocType), r.bool()} + } + + dict.funcs = make([]objInfo, r.len()) + dict.funcsObj = make([]ir.Node, len(dict.funcs)) + for i := range dict.funcs { + objIdx := r.reloc(relocObj) + targs := make([]typeInfo, r.len()) + for j := range targs { + targs[j] = r.typInfo() + } + dict.funcs[i] = objInfo{idx: objIdx, explicits: targs} + } + + return &dict } func (r *reader) typeParamNames() { @@ -790,7 +791,11 @@ func (r *reader) selector() (origPkg *types.Pkg, sym *types.Sym) { } func (r *reader) hasTypeParams() bool { - return r.dict != nil && len(r.dict.targs) != 0 + return r.dict.hasTypeParams() +} + +func (dict *readerDict) hasTypeParams() bool { + return dict != nil && len(dict.targs) != 0 } // @@@ Compiler extensions diff --git a/src/cmd/compile/internal/noder/reader2.go b/src/cmd/compile/internal/noder/reader2.go index a2339145fa5..297fa59439a 100644 --- a/src/cmd/compile/internal/noder/reader2.go +++ b/src/cmd/compile/internal/noder/reader2.go @@ -358,29 +358,22 @@ func (r *reader2) obj() (types2.Object, []types2.Type) { } func (pr *pkgReader2) objIdx(idx int) (*types2.Package, string) { - r := pr.newReader(relocObj, idx, syncObject1) - r.dict = &reader2Dict{} + rname := pr.newReader(relocName, idx, syncObject1) - objPkg, objName := r.qualifiedIdent() + objPkg, objName := rname.qualifiedIdent() assert(objName != "") - r.typeParamBounds() - tag := codeObj(r.code(syncCodeObj)) + tag := codeObj(rname.code(syncCodeObj)) if tag == objStub { assert(objPkg == nil) return objPkg, objName } - { - rdict := r.p.newReader(relocObjDict, idx, syncObject1) - r.dict.derived = make([]derivedInfo, rdict.len()) - r.dict.derivedTypes = make([]types2.Type, len(r.dict.derived)) - for i := range r.dict.derived { - r.dict.derived[i] = derivedInfo{rdict.reloc(relocType), rdict.bool()} - } - // function references follow, but reader2 doesn't need those - } + dict := pr.objDictIdx(idx) + + r := pr.newReader(relocObj, idx, syncObject1) + r.dict = dict objPkg.Scope().InsertLazy(objName, func() types2.Object { switch tag { @@ -439,17 +432,29 @@ func (r *reader2) value() (types2.Type, constant.Value) { return r.typ(), r.rawValue() } -func (r *reader2) typeParamBounds() { - r.sync(syncTypeParamBounds) +func (pr *pkgReader2) objDictIdx(idx int) *reader2Dict { + r := pr.newReader(relocObjDict, idx, syncObject1) + + var dict reader2Dict if implicits := r.len(); implicits != 0 { base.Fatalf("unexpected object with %v implicit type parameter(s)", implicits) } - r.dict.bounds = make([]typeInfo, r.len()) - for i := range r.dict.bounds { - r.dict.bounds[i] = r.typInfo() + dict.bounds = make([]typeInfo, r.len()) + for i := range dict.bounds { + dict.bounds[i] = r.typInfo() } + + dict.derived = make([]derivedInfo, r.len()) + dict.derivedTypes = make([]types2.Type, len(dict.derived)) + for i := range dict.derived { + dict.derived[i] = derivedInfo{r.reloc(relocType), r.bool()} + } + + // function references follow, but reader2 doesn't need those + + return &dict } func (r *reader2) typeParamNames() []*types2.TypeName { diff --git a/src/cmd/compile/internal/noder/reloc.go b/src/cmd/compile/internal/noder/reloc.go index 4eb6bcdb1c0..669a6182e62 100644 --- a/src/cmd/compile/internal/noder/reloc.go +++ b/src/cmd/compile/internal/noder/reloc.go @@ -31,6 +31,7 @@ const ( relocMeta relocPosBase relocPkg + relocName relocType relocObj relocObjExt diff --git a/src/cmd/compile/internal/noder/sync.go b/src/cmd/compile/internal/noder/sync.go index aef98dbd788..7af558f8b20 100644 --- a/src/cmd/compile/internal/noder/sync.go +++ b/src/cmd/compile/internal/noder/sync.go @@ -183,4 +183,5 @@ const ( syncTypeParamNames syncTypeParamBounds syncImplicitTypes + syncObjectName ) diff --git a/src/cmd/compile/internal/noder/unified.go b/src/cmd/compile/internal/noder/unified.go index e8c203ae463..9f80ca000de 100644 --- a/src/cmd/compile/internal/noder/unified.go +++ b/src/cmd/compile/internal/noder/unified.go @@ -263,7 +263,7 @@ func readPackage(pr *pkgReader, importpkg *types.Pkg) { idx := r.reloc(relocObj) assert(r.len() == 0) - path, name, code, _ := r.p.peekObj(idx) + path, name, code := r.p.peekObj(idx) if code != objStub { objReader[types.NewPkg(path, "").Lookup(name)] = pkgReaderIndex{pr, idx, nil} } @@ -298,7 +298,7 @@ func writeNewExport(out io.Writer) { idx := r.reloc(relocObj) assert(r.len() == 0) - xpath, xname, xtag, _ := pr.peekObj(idx) + xpath, xname, xtag := pr.peekObj(idx) assert(xpath == pr.pkgPath) assert(xtag != objStub) diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go index 48884056f32..bf60246d64b 100644 --- a/src/cmd/compile/internal/noder/writer.go +++ b/src/cmd/compile/internal/noder/writer.go @@ -505,60 +505,45 @@ func (pw *pkgWriter) objIdx(obj types2.Object) int { w := pw.newWriter(relocObj, syncObject1) w.ext = pw.newWriter(relocObjExt, syncObject1) + wname := pw.newWriter(relocName, syncObject1) wdict := pw.newWriter(relocObjDict, syncObject1) pw.globalsIdx[obj] = w.idx // break cycles assert(w.ext.idx == w.idx) + assert(wname.idx == w.idx) assert(wdict.idx == w.idx) w.dict = dict w.ext.dict = dict - // Ident goes first so importer can avoid unnecessary work if - // they've already resolved this object. - w.qualifiedIdent(obj) - - w.typeParamBounds(objTypeParams(obj)) - - w.doObj(obj) - + code := w.doObj(obj) w.flush() w.ext.flush() - // Done writing out the object description; write out the list of - // derived types and instantiated functions found along the way. - wdict.len(len(dict.derived)) - for _, typ := range dict.derived { - wdict.reloc(relocType, typ.idx) - wdict.bool(typ.needed) - } - wdict.len(len(dict.funcs)) - for _, fn := range dict.funcs { - wdict.reloc(relocObj, fn.idx) - wdict.len(len(fn.explicits)) - for _, targ := range fn.explicits { - wdict.typInfo(targ) - } - } + wname.qualifiedIdent(obj) + wname.code(code) + wname.flush() + + wdict.objDict(obj, w.dict) wdict.flush() return w.idx } -func (w *writer) doObj(obj types2.Object) { +func (w *writer) doObj(obj types2.Object) codeObj { if obj.Pkg() != w.p.curpkg { - w.code(objStub) - return + return objStub } switch obj := obj.(type) { default: w.p.unexpected("object", obj) + panic("unreachable") case *types2.Const: - w.code(objConst) w.pos(obj) w.value(obj.Type(), obj.Val()) + return objConst case *types2.Func: decl, ok := w.p.funDecls[obj] @@ -584,28 +569,26 @@ func (w *writer) doObj(obj types2.Object) { sig = types2.NewSignature(nil, types2.NewTuple(params...), sig.Results(), sig.Variadic()) } - w.code(objFunc) w.pos(obj) w.typeParamNames(sig.TParams()) w.signature(sig) w.pos(decl) w.ext.funcExt(obj) + return objFunc case *types2.TypeName: decl, ok := w.p.typDecls[obj] assert(ok) if obj.IsAlias() { - w.code(objAlias) w.pos(obj) w.typ(obj.Type()) - break + return objAlias } named := obj.Type().(*types2.Named) assert(named.TArgs() == nil) - w.code(objType) w.pos(obj) w.typeParamNames(named.TParams()) w.ext.typeExt(obj) @@ -616,11 +599,13 @@ func (w *writer) doObj(obj types2.Object) { w.method(named.Method(i)) } + return objType + case *types2.Var: - w.code(objVar) w.pos(obj) w.typ(obj.Type()) w.ext.varExt(obj) + return objVar } } @@ -638,15 +623,41 @@ func (w *writer) value(typ types2.Type, val constant.Value) { w.rawValue(val) } -func (w *writer) typeParamBounds(tparams []*types2.TypeName) { - w.sync(syncTypeParamBounds) +// objDict writes the dictionary needed for reading the given object. +func (w *writer) objDict(obj types2.Object, dict *writerDict) { + // TODO(mdempsky): Split objDict into multiple entries? reader.go + // doesn't care about the type parameter bounds, and reader2.go + // doesn't care about referenced functions. - w.len(len(w.dict.implicits)) + w.dict = dict // TODO(mdempsky): This is a bit sketchy. + w.len(len(dict.implicits)) + + tparams := objTypeParams(obj) w.len(len(tparams)) for _, tparam := range tparams { w.typ(tparam.Type().(*types2.TypeParam).Bound()) } + + nderived := len(dict.derived) + w.len(nderived) + for _, typ := range dict.derived { + w.reloc(relocType, typ.idx) + w.bool(typ.needed) + } + + nfuncs := len(dict.funcs) + w.len(nfuncs) + for _, fn := range dict.funcs { + w.reloc(relocObj, fn.idx) + w.len(len(fn.explicits)) + for _, targ := range fn.explicits { + w.typInfo(targ) + } + } + + assert(len(dict.derived) == nderived) + assert(len(dict.funcs) == nfuncs) } func (w *writer) typeParamNames(tparams []*types2.TypeName) { From 48c88f1b1bac1ef4fc81246a7f31933f8f922706 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 14 Jul 2021 14:46:09 -0700 Subject: [PATCH 746/940] reflect: add Value.CanConvert For #395 For #46746 Change-Id: I4bfc094cf1cecd27ce48e31f92384cf470f371a6 Reviewed-on: https://go-review.googlesource.com/c/go/+/334669 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Keith Randall Reviewed-by: Joe Tsai --- api/go1.17.txt | 1 + doc/go1.17.html | 12 ++++++++++++ src/reflect/all_test.go | 9 +++++++++ src/reflect/value.go | 20 ++++++++++++++++++++ 4 files changed, 42 insertions(+) diff --git a/api/go1.17.txt b/api/go1.17.txt index 3d0a464fec5..48505381f1e 100644 --- a/api/go1.17.txt +++ b/api/go1.17.txt @@ -80,6 +80,7 @@ pkg net/url, method (Values) Has(string) bool pkg reflect, func VisibleFields(Type) []StructField pkg reflect, method (Method) IsExported() bool pkg reflect, method (StructField) IsExported() bool +pkg reflect, method (Value) CanConvert(Type) bool pkg runtime/cgo (darwin-amd64-cgo), func NewHandle(interface{}) Handle pkg runtime/cgo (darwin-amd64-cgo), method (Handle) Delete() pkg runtime/cgo (darwin-amd64-cgo), method (Handle) Value() interface{} diff --git a/doc/go1.17.html b/doc/go1.17.html index b31006fe656..7739d1c62e0 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -989,6 +989,18 @@ func Foo() bool {
reflect
+

+ The new + Value.CanConvert + method reports whether a value can be converted to a type. + This may be used to avoid a panic when converting a slice to an + array pointer type if the slice is too short. + Previously it was sufficient to use + Type.ConvertibleTo + for this, but the newly permitted conversion from slice to array + pointer type can panic even if the types are convertible. +

+

The new StructField.IsExported diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 0db5e132172..eac27e886f2 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -4304,6 +4304,9 @@ func TestConvert(t *testing.T) { // vout1 represents the in value converted to the in type. v1 := tt.in + if !v1.CanConvert(t1) { + t.Errorf("ValueOf(%T(%[1]v)).CanConvert(%s) = false, want true", tt.in.Interface(), t1) + } vout1 := v1.Convert(t1) out1 := vout1.Interface() if vout1.Type() != tt.in.Type() || !DeepEqual(out1, tt.in.Interface()) { @@ -4311,6 +4314,9 @@ func TestConvert(t *testing.T) { } // vout2 represents the in value converted to the out type. + if !v1.CanConvert(t2) { + t.Errorf("ValueOf(%T(%[1]v)).CanConvert(%s) = false, want true", tt.in.Interface(), t2) + } vout2 := v1.Convert(t2) out2 := vout2.Interface() if vout2.Type() != tt.out.Type() || !DeepEqual(out2, tt.out.Interface()) { @@ -4371,6 +4377,9 @@ func TestConvertPanic(t *testing.T) { if !v.Type().ConvertibleTo(pt) { t.Errorf("[]byte should be convertible to *[8]byte") } + if v.CanConvert(pt) { + t.Errorf("slice with length 4 should not be convertible to *[8]byte") + } shouldPanic("reflect: cannot convert slice with length 4 to pointer to array with length 8", func() { _ = v.Convert(pt) }) diff --git a/src/reflect/value.go b/src/reflect/value.go index 9dce251ac57..6f878eba5b0 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -2811,6 +2811,26 @@ func (v Value) Convert(t Type) Value { return op(v, t) } +// CanConvert reports whether the value v can be converted to type t. +// If v.CanConvert(t) returns true then v.Convert(t) will not panic. +func (v Value) CanConvert(t Type) bool { + vt := v.Type() + if !vt.ConvertibleTo(t) { + return false + } + // Currently the only conversion that is OK in terms of type + // but that can panic depending on the value is converting + // from slice to pointer-to-array. + if vt.Kind() == Slice && t.Kind() == Ptr && t.Elem().Kind() == Array { + n := t.Elem().Len() + h := (*unsafeheader.Slice)(v.ptr) + if n > h.Len { + return false + } + } + return true +} + // convertOp returns the function to convert a value of type src // to a value of type dst. If the conversion is illegal, convertOp returns nil. func convertOp(dst, src *rtype) func(Value, Type) Value { From 3e48c0381fd1beb78e993e940c3b46ca9898ce6d Mon Sep 17 00:00:00 2001 From: wdvxdr Date: Wed, 21 Jul 2021 11:59:45 +0800 Subject: [PATCH 747/940] reflect: add missing copyright header Change-Id: I5a2f7203f83be02b03aa7be5fe386e485bf68ca3 Reviewed-on: https://go-review.googlesource.com/c/go/+/336189 Reviewed-by: Ian Lance Taylor Trust: Robert Findley --- src/reflect/visiblefields.go | 4 ++++ src/reflect/visiblefields_test.go | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/reflect/visiblefields.go b/src/reflect/visiblefields.go index c068979dcc8..1a2b53570be 100644 --- a/src/reflect/visiblefields.go +++ b/src/reflect/visiblefields.go @@ -1,3 +1,7 @@ +// Copyright 2021 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 reflect // VisibleFields returns all the visible fields in t, which must be a diff --git a/src/reflect/visiblefields_test.go b/src/reflect/visiblefields_test.go index 2688b63091a..915bbee867c 100644 --- a/src/reflect/visiblefields_test.go +++ b/src/reflect/visiblefields_test.go @@ -1,3 +1,7 @@ +// Copyright 2021 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 reflect_test import ( From a7a17f0ca86d252dc1ef20b5852c352ade5f8610 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Wed, 9 Jun 2021 19:30:16 -0700 Subject: [PATCH 748/940] [dev.typeparams] cmd/compile: introduce named gcshape types Still 1-1 with real types, but now with their own names! Shape types are implicitly convertible to (and convertible from) the types they represent. Change-Id: I0133a8d8fbeb369380574b075a32b3c987e314d5 Reviewed-on: https://go-review.googlesource.com/c/go/+/335170 Run-TryBot: Keith Randall Trust: Keith Randall Trust: Dan Scales Reviewed-by: Dan Scales --- src/cmd/compile/internal/noder/stencil.go | 150 +++++++++++++++++- src/cmd/compile/internal/noder/types.go | 2 +- .../compile/internal/reflectdata/reflect.go | 33 +++- src/cmd/compile/internal/typecheck/subr.go | 104 +++++++++--- src/cmd/compile/internal/types/identity.go | 9 ++ src/cmd/compile/internal/types/type.go | 46 ++++++ src/cmd/internal/obj/objfile.go | 5 + 7 files changed, 317 insertions(+), 32 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 72ecd80cf5d..905ea0c88c1 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -128,6 +128,7 @@ func (g *irgen) stencil() { // call. call.Args.Prepend(inst.X.(*ir.SelectorExpr).X) } + // Add dictionary to argument list. call.Args.Prepend(dictValue) // Transform the Call now, which changes OCALL @@ -486,6 +487,10 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { func (g *irgen) instantiateMethods() { for i := 0; i < len(g.instTypeList); i++ { typ := g.instTypeList[i] + if typ.HasShape() { + // Shape types should not have any methods. + continue + } // Mark runtime type as needed, since this ensures that the // compiler puts out the needed DWARF symbols, when this // instantiated type has a different package from the local @@ -781,7 +786,12 @@ func checkFetchBody(nameNode *ir.Name) { // cached, then it calls genericSubst to create the new instantiation. func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth bool) *ir.Func { checkFetchBody(nameNode) - sym := typecheck.MakeInstName(nameNode.Sym(), targs, isMeth) + + // Convert type arguments to their shape, so we can reduce the number + // of instantiations we have to generate. + shapes := typecheck.ShapifyList(targs) + + sym := typecheck.MakeInstName(nameNode.Sym(), shapes, isMeth) info := g.instInfoMap[sym] if info == nil { if false { @@ -802,7 +812,7 @@ func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth dictEntryMap: make(map[ir.Node]int), } // genericSubst fills in info.dictParam and info.dictEntryMap. - st := g.genericSubst(sym, nameNode, targs, isMeth, info) + st := g.genericSubst(sym, nameNode, shapes, targs, isMeth, info) info.fun = st g.instInfoMap[sym] = info // This ensures that the linker drops duplicates of this instantiation. @@ -824,6 +834,18 @@ type subster struct { newf *ir.Func // Func node for the new stenciled function ts typecheck.Tsubster info *instInfo // Place to put extra info in the instantiation + + // Which type parameter the shape type came from. + shape2param map[*types.Type]*types.Type + + // unshapeify maps from shape types to the concrete types they represent. + // TODO: remove when we no longer need it. + unshapify typecheck.Tsubster + concretify typecheck.Tsubster + + // TODO: some sort of map from to index in the + // dictionary where a *runtime.itab for the corresponding pair resides. } // genericSubst returns a new function with name newsym. The function is an @@ -832,7 +854,7 @@ type subster struct { // function type where the receiver becomes the first parameter. Otherwise the // instantiated method would still need to be transformed by later compiler // phases. genericSubst fills in info.dictParam and info.dictEntryMap. -func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*types.Type, isMethod bool, info *instInfo) *ir.Func { +func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, shapes, targs []*types.Type, isMethod bool, info *instInfo) *ir.Func { var tparams []*types.Type if isMethod { // Get the type params from the method receiver (after skipping @@ -847,6 +869,11 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*type tparams[i] = f.Type } } + for i := range targs { + if targs[i].HasShape() { + base.Fatalf("generiSubst shape %s %+v %+v\n", newsym.Name, shapes[i], targs[i]) + } + } gf := nameNode.Func // Pos of the instantiated function is same as the generic function newf := ir.NewFunc(gf.Pos()) @@ -860,6 +887,7 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*type // depend on ir.CurFunc being set. ir.CurFunc = newf + assert(len(tparams) == len(shapes)) assert(len(tparams) == len(targs)) subst := &subster{ @@ -869,9 +897,26 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*type info: info, ts: typecheck.Tsubster{ Tparams: tparams, + Targs: shapes, + Vars: make(map[*ir.Name]*ir.Name), + }, + shape2param: map[*types.Type]*types.Type{}, + unshapify: typecheck.Tsubster{ + Tparams: shapes, Targs: targs, Vars: make(map[*ir.Name]*ir.Name), }, + concretify: typecheck.Tsubster{ + Tparams: tparams, + Targs: targs, + Vars: make(map[*ir.Name]*ir.Name), + }, + } + for i := range shapes { + if !shapes[i].IsShape() { + panic("must be a shape type") + } + subst.shape2param[shapes[i]] = tparams[i] } newf.Dcl = make([]*ir.Name, 0, len(gf.Dcl)+1) @@ -919,16 +964,25 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*type newf.Body = subst.list(gf.Body) // Add code to check that the dictionary is correct. - newf.Body.Prepend(g.checkDictionary(dictionaryName, targs)...) + // TODO: must go away when we move to many->1 shape to concrete mapping. + newf.Body.Prepend(subst.checkDictionary(dictionaryName, targs)...) ir.CurFunc = savef // Add any new, fully instantiated types seen during the substitution to // g.instTypeList. g.instTypeList = append(g.instTypeList, subst.ts.InstTypeList...) + g.instTypeList = append(g.instTypeList, subst.unshapify.InstTypeList...) + g.instTypeList = append(g.instTypeList, subst.concretify.InstTypeList...) return newf } +func (subst *subster) unshapifyTyp(t *types.Type) *types.Type { + res := subst.unshapify.Typ(t) + types.CheckSize(res) + return res +} + // localvar creates a new name node for the specified local variable and enters it // in subst.vars. It substitutes type arguments for type parameters in the type of // name as needed. @@ -950,7 +1004,7 @@ func (subst *subster) localvar(name *ir.Name) *ir.Name { // checkDictionary returns code that does runtime consistency checks // between the dictionary and the types it should contain. -func (g *irgen) checkDictionary(name *ir.Name, targs []*types.Type) (code []ir.Node) { +func (subst *subster) checkDictionary(name *ir.Name, targs []*types.Type) (code []ir.Node) { if false { return // checking turned off } @@ -965,6 +1019,13 @@ func (g *irgen) checkDictionary(name *ir.Name, targs []*types.Type) (code []ir.N // Check that each type entry in the dictionary is correct. for i, t := range targs { + if t.HasShape() { + // Check the concrete type, not the shape type. + // TODO: can this happen? + //t = subst.unshapify.Typ(t) + base.Fatalf("shape type in dictionary %s %+v\n", name.Sym().Name, t) + continue + } want := reflectdata.TypePtr(t) typed(types.Types[types.TUINTPTR], want) deref := ir.NewStarExpr(pos, d) @@ -1144,11 +1205,36 @@ func (subst *subster) node(n ir.Node) ir.Node { // will be transformed to an ODOTMETH or ODOTINTER node if // we find in the OCALL case below that the method value // is actually called. - transformDot(m.(*ir.SelectorExpr), false) + mse := m.(*ir.SelectorExpr) + if src := mse.X.Type(); src.IsShape() { + // The only dot on a shape type value are methods. + if mse.X.Op() == ir.OTYPE { + // Method expression T.M + // Fall back from shape type to concrete type. + src = subst.unshapifyTyp(src) + mse.X = ir.TypeNode(src) + } else { + // Implement x.M as a conversion-to-bound-interface + // 1) convert x to the bound interface + // 2) call M on that interface + dst := subst.concretify.Typ(subst.shape2param[src].Bound()) + // Mark that we use the methods of this concrete type. + // Otherwise the linker deadcode-eliminates them :( + reflectdata.MarkTypeUsedInInterface(subst.unshapifyTyp(src), subst.newf.Sym().Linksym()) + ix := subst.findDictType(subst.shape2param[src]) + assert(ix >= 0) + mse.X = subst.convertUsingDictionary(m.Pos(), mse.X, dst, subst.shape2param[src], ix) + } + } + transformDot(mse, false) + if mse.Op() == ir.OMETHEXPR && mse.X.Type().HasShape() { + mse.X = ir.TypeNodeAt(mse.X.Pos(), subst.unshapifyTyp(mse.X.Type())) + } m.SetTypecheck(1) case ir.OCALL: call := m.(*ir.CallExpr) + convcheck := false switch call.X.Op() { case ir.OTYPE: // Transform the conversion, now that we know the @@ -1170,7 +1256,9 @@ func (subst *subster) node(n ir.Node) ir.Node { // transform the call. call.X.(*ir.SelectorExpr).SetOp(ir.OXDOT) transformDot(call.X.(*ir.SelectorExpr), true) + call.X.SetType(subst.unshapifyTyp(call.X.Type())) transformCall(call) + convcheck = true case ir.ODOT, ir.ODOTPTR: // An OXDOT for a generic receiver was resolved to @@ -1178,6 +1266,7 @@ func (subst *subster) node(n ir.Node) ir.Node { // value. Transform the call to that function, now // that the OXDOT was resolved. transformCall(call) + convcheck = true case ir.ONAME: name := call.X.Name() @@ -1190,15 +1279,24 @@ func (subst *subster) node(n ir.Node) ir.Node { default: base.FatalfAt(call.Pos(), "Unexpected builtin op") } + switch m.Op() { + case ir.OAPPEND: + // Append needs to pass a concrete type to the runtime. + // TODO: there's no way to record a dictionary-loaded type for walk to use here + m.SetType(subst.unshapifyTyp(m.Type())) + } + } else { // This is the case of a function value that was a // type parameter (implied to be a function via a // structural constraint) which is now resolved. transformCall(call) + convcheck = true } case ir.OCLOSURE: transformCall(call) + convcheck = true case ir.OFUNCINST: // A call with an OFUNCINST will get transformed @@ -1208,6 +1306,16 @@ func (subst *subster) node(n ir.Node) ir.Node { default: base.FatalfAt(call.Pos(), fmt.Sprintf("Unexpected op with CALL during stenciling: %v", call.X.Op())) } + if convcheck { + for i, arg := range x.(*ir.CallExpr).Args { + if arg.Type().HasTParam() && arg.Op() != ir.OCONVIFACE && + call.Args[i].Op() == ir.OCONVIFACE { + ix := subst.findDictType(arg.Type()) + assert(ix >= 0) + call.Args[i] = subst.convertUsingDictionary(arg.Pos(), call.Args[i].(*ir.ConvExpr).X, call.Args[i].Type(), arg.Type(), ix) + } + } + } case ir.OCLOSURE: // We're going to create a new closure from scratch, so clear m @@ -1281,6 +1389,29 @@ func (subst *subster) node(n ir.Node) ir.Node { m.Y = subst.convertUsingDictionary(m.Y.Pos(), m.Y, i, x.X.Type(), ix) } } + + case ir.ONEW: + // New needs to pass a concrete type to the runtime. + // Or maybe it doesn't? We could use a shape type. + // TODO: need to modify m.X? I don't think any downstream passes use it. + m.SetType(subst.unshapifyTyp(m.Type())) + + case ir.OPTRLIT: + m := m.(*ir.AddrExpr) + // Walk uses the type of the argument of ptrlit. Also could be a shape type? + m.X.SetType(subst.unshapifyTyp(m.X.Type())) + + case ir.OMETHEXPR: + se := m.(*ir.SelectorExpr) + se.X = ir.TypeNodeAt(se.X.Pos(), subst.unshapifyTyp(se.X.Type())) + case ir.OFUNCINST: + inst := m.(*ir.InstExpr) + targs2 := make([]ir.Node, len(inst.Targs)) + for i, n := range inst.Targs { + targs2[i] = ir.TypeNodeAt(n.Pos(), subst.unshapifyTyp(n.Type())) + // TODO: need an ir.Name node? + } + inst.Targs = targs2 } return m } @@ -1414,6 +1545,13 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) base.Fatalf("%s should have type arguments", gf.Sym().Name) } + // Enforce that only concrete types can make it to here. + for _, t := range targs { + if t.IsShape() { + panic(fmt.Sprintf("shape %+v in dictionary for %s", t, gf.Sym().Name)) + } + } + // Get a symbol representing the dictionary. sym := typecheck.MakeDictName(gf.Sym(), targs, isMeth) diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go index c18ae3a1fc3..d073526adaf 100644 --- a/src/cmd/compile/internal/noder/types.go +++ b/src/cmd/compile/internal/noder/types.go @@ -327,7 +327,7 @@ func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) { methods[i].Nname = meth } ntyp.Methods().Set(methods) - if !ntyp.HasTParam() { + if !ntyp.HasTParam() && !ntyp.HasShape() { // Generate all the methods for a new fully-instantiated type. g.instTypeList = append(g.instTypeList, ntyp) } diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index b20fc8cccc9..2236c7f1cff 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -302,6 +302,9 @@ func MapIterType(t *types.Type) *types.Type { // methods returns the methods of the non-interface type t, sorted by name. // Generates stub functions as needed. func methods(t *types.Type) []*typeSig { + if t.HasShape() { + return nil + } // method type mt := types.ReceiverBaseType(t) @@ -1215,6 +1218,7 @@ func NeedRuntimeType(t *types.Type) { if t.HasTParam() { // Generic types don't have a runtime type descriptor (but will // have a dictionary) + // TODO: also shape type here? return } if _, ok := signatset[t]; !ok { @@ -1276,6 +1280,9 @@ func writeITab(lsym *obj.LSym, typ, iface *types.Type) { for _, m := range methods(typ) { if m.name == sigs[0].Sym { entries = append(entries, m.isym) + if m.isym == nil { + panic("NO ISYM") + } sigs = sigs[1:] if len(sigs) == 0 { break @@ -1764,6 +1771,17 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy // an embedded field) which is an interface method. // TODO: check that we do the right thing when method is an interface method. generic = true + + targs := rcvr.RParams() + if rcvr.IsPtr() { + targs = rcvr.Elem().RParams() + } + // TODO: why do shape-instantiated types exist? + for _, t := range targs { + if t.HasShape() { + base.Fatalf("method on type instantiated with shapes targ:%+v rcvr:%+v", t, rcvr) + } + } } newnam := ir.MethodSym(rcvr, method.Sym) lsym := newnam.Linksym() @@ -1881,9 +1899,13 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy } args = append(args, ir.ParamNames(tfn.Type())...) - // TODO: Once we enter the gcshape world, we'll need a way to look up - // the stenciled implementation to use for this concrete type. Essentially, - // erase the concrete types and replace them with gc shape representatives. + // Target method uses shaped names. + targs2 := make([]*types.Type, len(targs)) + for i, t := range targs { + targs2[i] = typecheck.Shaped[t] + } + targs = targs2 + sym := typecheck.MakeInstName(ir.MethodSym(methodrcvr, method.Sym), targs, true) if sym.Def == nil { // Currently we make sure that we have all the instantiations @@ -1975,6 +1997,11 @@ func getDictionary(gf *types.Sym, targs []*types.Type) ir.Node { if len(targs) == 0 { base.Fatalf("%s should have type arguments", gf.Name) } + for _, t := range targs { + if t.HasShape() { + base.Fatalf("dictionary for %s should only use concrete types: %+v", gf.Name, t) + } + } sym := typecheck.MakeDictName(gf, targs, true) diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index a795524b2bc..c6ffa175f1f 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -353,9 +353,10 @@ func Assignop(src, dst *types.Type) (ir.Op, string) { return ir.OCONVNOP, "" } - // 2. src and dst have identical underlying types - // and either src or dst is not a named type or - // both are empty interface types. + // 2. src and dst have identical underlying types and + // a. either src or dst is not a named type, or + // b. both are empty interface types, or + // c. at least one is a gcshape type. // For assignable but different non-empty interface types, // we want to recompute the itab. Recomputing the itab ensures // that itabs are unique (thus an interface with a compile-time @@ -372,12 +373,23 @@ func Assignop(src, dst *types.Type) (ir.Op, string) { // which need to have their itab updated. return ir.OCONVNOP, "" } + if src.IsShape() || dst.IsShape() { + // Conversion between a shape type and one of the types + // it represents also needs no conversion. + return ir.OCONVNOP, "" + } } // 3. dst is an interface type and src implements dst. if dst.IsInterface() && src.Kind() != types.TNIL { var missing, have *types.Field var ptr int + if src.IsShape() { + // Shape types implement things they have already + // been typechecked to implement, even if they + // don't have the methods for them. + return ir.OCONVIFACE, "" + } if implements(src, dst, &missing, &have, &ptr) { return ir.OCONVIFACE, "" } @@ -898,8 +910,8 @@ func makeGenericName(name string, targs []*types.Type, hasBrackets bool) string hasTParam := false for _, targ := range targs { if hasTParam { - assert(targ.HasTParam()) - } else if targ.HasTParam() { + assert(targ.HasTParam() || targ.HasShape()) + } else if targ.HasTParam() || targ.HasShape() { hasTParam = true } } @@ -1002,14 +1014,14 @@ type Tsubster struct { // result is t; otherwise the result is a new type. It deals with recursive types // by using TFORW types and finding partially or fully created types via sym.Def. func (ts *Tsubster) Typ(t *types.Type) *types.Type { - if !t.HasTParam() && t.Kind() != types.TFUNC { + if !t.HasTParam() && !t.HasShape() && t.Kind() != types.TFUNC { // Note: function types need to be copied regardless, as the // types of closures may contain declarations that need // to be copied. See #45738. return t } - if t.IsTypeParam() { + if t.IsTypeParam() || t.IsShape() { for i, tp := range ts.Tparams { if tp == t { return ts.Targs[i] @@ -1038,6 +1050,7 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type { var newsym *types.Sym var neededTargs []*types.Type + var targsChanged bool var forw *types.Type if t.Sym() != nil { @@ -1046,6 +1059,9 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type { neededTargs = make([]*types.Type, len(t.RParams())) for i, rparam := range t.RParams() { neededTargs[i] = ts.Typ(rparam) + if !types.Identical(neededTargs[i], rparam) { + targsChanged = true + } } // For a named (defined) type, we have to change the name of the // type as well. We do this first, so we can look up if we've @@ -1074,7 +1090,7 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type { switch t.Kind() { case types.TTYPEPARAM: - if t.Sym() == newsym { + if t.Sym() == newsym && !targsChanged { // The substitution did not change the type. return t } @@ -1086,26 +1102,26 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type { case types.TARRAY: elem := t.Elem() newelem := ts.Typ(elem) - if newelem != elem { + if newelem != elem || targsChanged { newt = types.NewArray(newelem, t.NumElem()) } case types.TPTR: elem := t.Elem() newelem := ts.Typ(elem) - if newelem != elem { + if newelem != elem || targsChanged { newt = types.NewPtr(newelem) } case types.TSLICE: elem := t.Elem() newelem := ts.Typ(elem) - if newelem != elem { + if newelem != elem || targsChanged { newt = types.NewSlice(newelem) } case types.TSTRUCT: - newt = ts.tstruct(t, false) + newt = ts.tstruct(t, targsChanged) if newt == t { newt = nil } @@ -1114,7 +1130,7 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type { newrecvs := ts.tstruct(t.Recvs(), false) newparams := ts.tstruct(t.Params(), false) newresults := ts.tstruct(t.Results(), false) - if newrecvs != t.Recvs() || newparams != t.Params() || newresults != t.Results() { + if newrecvs != t.Recvs() || newparams != t.Params() || newresults != t.Results() || targsChanged { // If any types have changed, then the all the fields of // of recv, params, and results must be copied, because they have // offset fields that are dependent, and so must have an @@ -1144,14 +1160,14 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type { case types.TMAP: newkey := ts.Typ(t.Key()) newval := ts.Typ(t.Elem()) - if newkey != t.Key() || newval != t.Elem() { + if newkey != t.Key() || newval != t.Elem() || targsChanged { newt = types.NewMap(newkey, newval) } case types.TCHAN: elem := t.Elem() newelem := ts.Typ(elem) - if newelem != elem { + if newelem != elem || targsChanged { newt = types.NewChan(newelem, t.ChanDir()) if !newt.HasTParam() { // TODO(danscales): not sure why I have to do this @@ -1167,7 +1183,7 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type { } case types.TINT, types.TINT8, types.TINT16, types.TINT32, types.TINT64, types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, - types.TUINTPTR, types.TBOOL, types.TSTRING: + types.TUINTPTR, types.TBOOL, types.TSTRING, types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128: newt = t.Underlying() } if newt == nil { @@ -1177,15 +1193,17 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type { return t } - if t.Sym() == nil { - // Not a named type, so there was no forwarding type and there are - // no methods to substitute. + if t.Sym() == nil && t.Kind() != types.TINTER { + // Not a named type or interface type, so there was no forwarding type + // and there are no methods to substitute. assert(t.Methods().Len() == 0) return newt } - forw.SetUnderlying(newt) - newt = forw + if forw != nil { + forw.SetUnderlying(newt) + newt = forw + } if t.Kind() != types.TINTER && t.Methods().Len() > 0 { // Fill in the method info for the new type. @@ -1207,7 +1225,7 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type { newfields[i].Nname = nname } newt.Methods().Set(newfields) - if !newt.HasTParam() { + if !newt.HasTParam() && !newt.HasShape() { // Generate all the methods for a new fully-instantiated type. ts.InstTypeList = append(ts.InstTypeList, newt) } @@ -1305,3 +1323,45 @@ func (ts *Tsubster) tinter(t *types.Type) *types.Type { func genericTypeName(sym *types.Sym) string { return sym.Name[0:strings.Index(sym.Name, "[")] } + +// Shapify takes a concrete type and returns a GCshape type that can +// be used in place of the input type and still generate identical code. +// TODO: this could take the generic function and base its decisions +// on how that generic function uses this type argument. For instance, +// if it doesn't use it as a function argument/return value, then +// we don't need to distinguish int64 and float64 (because they only +// differ in how they get passed as arguments). For now, we only +// unify two different types if they are identical in every possible way. +func Shapify(t *types.Type) *types.Type { + if t.IsShape() { + return t // TODO: is this right? + } + if s := Shaped[t]; s != nil { + return s //TODO: keep? + } + + // For now, there is a 1-1 mapping between regular types and shape types. + sym := Lookup(fmt.Sprintf(".shape%d", snum)) + snum++ + name := ir.NewDeclNameAt(t.Pos(), ir.OTYPE, sym) + s := types.NewNamed(name) + s.SetUnderlying(t.Underlying()) + s.SetIsShape(true) + name.SetType(s) + name.SetTypecheck(1) + // TODO: add methods to s that the bound has? + Shaped[t] = s + return s +} + +var snum int + +var Shaped = map[*types.Type]*types.Type{} + +func ShapifyList(targs []*types.Type) []*types.Type { + r := make([]*types.Type, len(targs)) + for i, t := range targs { + r[i] = Shapify(t) + } + return r +} diff --git a/src/cmd/compile/internal/types/identity.go b/src/cmd/compile/internal/types/identity.go index dde9f518568..0a78092f078 100644 --- a/src/cmd/compile/internal/types/identity.go +++ b/src/cmd/compile/internal/types/identity.go @@ -29,6 +29,14 @@ func identical(t1, t2 *Type, cmpTags bool, assumedEqual map[typePair]struct{}) b return false } if t1.sym != nil || t2.sym != nil { + if t1.HasShape() || t2.HasShape() { + switch t1.kind { + case TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64, TUINT64, TINT, TUINT, TUINTPTR, TCOMPLEX64, TCOMPLEX128, TFLOAT32, TFLOAT64, TBOOL, TSTRING, TUNSAFEPTR: + return true + } + // fall through to unnamed type comparison for complex types. + goto cont + } // Special case: we keep byte/uint8 and rune/int32 // separate for error messages. Treat them as equal. switch t1.kind { @@ -40,6 +48,7 @@ func identical(t1, t2 *Type, cmpTags bool, assumedEqual map[typePair]struct{}) b return false } } +cont: // Any cyclic type must go through a named type, and if one is // named, it is only identical to the other if they are the diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index 28312111adb..e6ae0e7bc1a 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -210,6 +210,7 @@ const ( typeDeferwidth // width computation has been deferred and type is on deferredTypeStack typeRecur typeHasTParam // there is a typeparam somewhere in the type (generic function or type) + typeIsShape // represents a set of closely related types, for generics ) func (t *Type) NotInHeap() bool { return t.flags&typeNotInHeap != 0 } @@ -218,12 +219,14 @@ func (t *Type) Noalg() bool { return t.flags&typeNoalg != 0 } func (t *Type) Deferwidth() bool { return t.flags&typeDeferwidth != 0 } func (t *Type) Recur() bool { return t.flags&typeRecur != 0 } func (t *Type) HasTParam() bool { return t.flags&typeHasTParam != 0 } +func (t *Type) IsShape() bool { return t.flags&typeIsShape != 0 } func (t *Type) SetNotInHeap(b bool) { t.flags.set(typeNotInHeap, b) } func (t *Type) SetBroke(b bool) { t.flags.set(typeBroke, b) } func (t *Type) SetNoalg(b bool) { t.flags.set(typeNoalg, b) } func (t *Type) SetDeferwidth(b bool) { t.flags.set(typeDeferwidth, b) } func (t *Type) SetRecur(b bool) { t.flags.set(typeRecur, b) } +func (t *Type) SetIsShape(b bool) { t.flags.set(typeIsShape, b) } // Generic types should never have alg functions. func (t *Type) SetHasTParam(b bool) { t.flags.set(typeHasTParam, b); t.flags.set(typeNoalg, b) } @@ -2147,3 +2150,46 @@ var ( ) var SimType [NTYPE]Kind + +// Reports whether t has a shape type anywere. +func (t *Type) HasShape() bool { + return t.HasShape1(map[*Type]bool{}) +} +func (t *Type) HasShape1(visited map[*Type]bool) bool { + if t.IsShape() { + return true + } + if visited[t] { + return false + } + visited[t] = true + if t.Sym() != nil { + for _, u := range t.RParams() { + if u.HasShape1(visited) { + return true + } + } + } + switch t.Kind() { + case TPTR, TARRAY, TSLICE, TCHAN: + return t.Elem().HasShape1(visited) + case TMAP: + return t.Elem().HasShape1(visited) || t.Key().HasShape1(visited) + case TSTRUCT: + for _, f := range t.FieldSlice() { + if f.Type.HasShape1(visited) { + return true + } + } + case TFUNC: + for _, a := range RecvsParamsResults { + for _, f := range a(t).FieldSlice() { + if f.Type.HasShape1(visited) { + return true + } + } + } + // TODO: TINTER - check methods? + } + return false +} diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go index 24fb5a19dec..01466ea7360 100644 --- a/src/cmd/internal/obj/objfile.go +++ b/src/cmd/internal/obj/objfile.go @@ -452,6 +452,11 @@ func (w *writer) contentHash(s *LSym) goobj.HashType { binary.LittleEndian.PutUint64(tmp[6:14], uint64(r.Add)) h.Write(tmp[:]) rs := r.Sym + if rs == nil { + fmt.Printf("symbol: %s\n", s) + fmt.Printf("relocation: %#v\n", r) + panic("nil symbol target in relocation") + } switch rs.PkgIdx { case goobj.PkgIdxHashed64: h.Write([]byte{0}) From 73af5f718f6012c0a76cabd43c91505d5a80c169 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 19 Jul 2021 16:49:32 -0700 Subject: [PATCH 749/940] [dev.typeparams] cmd/compile: disable failing generic tests We'll have to revisit eventually, but disabling for now. Change-Id: Ic34cfe451939d61884079bb125b9290db1e05e47 Reviewed-on: https://go-review.googlesource.com/c/go/+/335829 Run-TryBot: Keith Randall Trust: Keith Randall Trust: Dan Scales Reviewed-by: Dan Scales --- test/run.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/run.go b/test/run.go index ce0d645985e..6e0c12d46b3 100644 --- a/test/run.go +++ b/test/run.go @@ -2173,6 +2173,11 @@ var g3Failures = setOf( "typeparam/nested.go", // -G=3 doesn't support function-local types with generics "typeparam/mdempsky/4.go", // -G=3 can't export functions with labeled breaks in loops + + "typeparam/cons.go", // causes an unreachable method + "typeparam/dictionaryCapture.go", // segv, dictionary access failure? + "typeparam/issue44688.go", // interface conversion fails due to missing method + "typeparam/mdempsky/14.go", // interface comparison failure ) var unifiedFailures = setOf( From 2fe4b14795fe20fa3ba8efbe92b88f2d564509d2 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 20 Jul 2021 12:55:51 -0700 Subject: [PATCH 750/940] [dev.typeparams] cmd/compile: ensure methods of generic types survive linker pruning Calling MarkTypeUsedInInterface before inlining is problematic (when using the containing function as the reference source), because we end up attaching a relocation to the original function, which is then deadcode removed because all instances of it were inlined. (All other current uses of MarkTypeUsedInInterface happen after inlining, so they don't have this problem.) Instead, attach the relocation to the dictionary in which the type appears. This should always work, because if the dictionary is ever deadcode eliminated, then the type can never be put in an interface, which means we indeed don't need its methods. This CL is a bit overkill, as not *all* types in the dictionary need this mark, but it is sufficient for now. Change-Id: I2d39456691f1c3df8efe3bddc3b9017e0ef37a7f Reviewed-on: https://go-review.googlesource.com/c/go/+/336012 Trust: Keith Randall Trust: Dan Scales Reviewed-by: Dan Scales --- src/cmd/compile/internal/noder/stencil.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 905ea0c88c1..9e0f1982622 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -566,7 +566,6 @@ const UINTSTRING = "u8" // XX fix for 32-bit arch // buf. fieldSym is the sym of the field associated with type t, if it is in a // struct. fieldSym could be used to have special naming for blank fields, etc. func accumGcshape(fl []*types.Field, buf *bytes.Buffer, t *types.Type, fieldSym *types.Sym) []*types.Field { - // t.Kind() is already the kind of the underlying type, so no need to // reference t.Underlying() to reference the underlying type. assert(t.Kind() == t.Underlying().Kind()) @@ -1220,7 +1219,6 @@ func (subst *subster) node(n ir.Node) ir.Node { dst := subst.concretify.Typ(subst.shape2param[src].Bound()) // Mark that we use the methods of this concrete type. // Otherwise the linker deadcode-eliminates them :( - reflectdata.MarkTypeUsedInInterface(subst.unshapifyTyp(src), subst.newf.Sym().Linksym()) ix := subst.findDictType(subst.shape2param[src]) assert(ix >= 0) mse.X = subst.convertUsingDictionary(m.Pos(), mse.X, dst, subst.shape2param[src], ix) @@ -1566,6 +1564,11 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) infoPrint(" * %v\n", t) s := reflectdata.TypeLinksym(t) off = objw.SymPtr(lsym, off, s, 0) + // Ensure that methods on t don't get deadcode eliminated + // by the linker. + // TODO: This is somewhat overkill, we really only need it + // for types that are put into interfaces. + reflectdata.MarkTypeUsedInInterface(t, lsym) } subst := typecheck.Tsubster{ Tparams: info.tparams, @@ -1577,6 +1580,7 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) infoPrint(" - %v\n", ts) s := reflectdata.TypeLinksym(ts) off = objw.SymPtr(lsym, off, s, 0) + reflectdata.MarkTypeUsedInInterface(ts, lsym) } // Emit an entry for each subdictionary (after substituting targs) for _, n := range info.subDictCalls { From 4a97fe8c2298ae879904d3cf304ca29500abf169 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 20 Jul 2021 14:52:19 -0700 Subject: [PATCH 751/940] [dev.typeparams] cmd/compile: avoid adding incorrectly instantiated types to the dictionary FUNCINST nodes aren't instantiated correctly. Skip those types when adding to the set of types considered for the dictionary. Those types include those which are uninstantiated(have tparams), and those with type parameters that aren't a parameter of the containing function (they are the type parameter of the function being called). Allow func types to be put in the dictionary. Change-Id: I26bab85d3eebc2f54d02b4bba5e31407faf7c5b2 Reviewed-on: https://go-review.googlesource.com/c/go/+/336129 Reviewed-by: Dan Scales Trust: Dan Scales Trust: Keith Randall --- src/cmd/compile/internal/noder/stencil.go | 63 +++++++++++++++++++++-- 1 file changed, 58 insertions(+), 5 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 9e0f1982622..460d926a0d6 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -1836,11 +1836,7 @@ func addType(info *gfInfo, n ir.Node, t *types.Type) { if t.IsTypeParam() && t.Underlying() == t { return } - if t.Kind() == types.TFUNC && n != nil && - (n.Op() != ir.ONAME || n.Name().Class == ir.PFUNC) { - // For now, only record function types that are associate with a - // local/global variable (a name which is not a named global - // function). + if !parameterizedBy(t, info.tparams) { return } if t.Kind() == types.TSTRUCT && t.IsFuncArgStruct() { @@ -1855,3 +1851,60 @@ func addType(info *gfInfo, n ir.Node, t *types.Type) { } info.derivedTypes = append(info.derivedTypes, t) } + +// parameterizedBy returns true if t is parameterized by (at most) params. +func parameterizedBy(t *types.Type, params []*types.Type) bool { + return parameterizedBy1(t, params, map[*types.Type]bool{}) +} +func parameterizedBy1(t *types.Type, params []*types.Type, visited map[*types.Type]bool) bool { + if visited[t] { + return true + } + visited[t] = true + switch t.Kind() { + case types.TTYPEPARAM: + for _, p := range params { + if p == t { + return true + } + } + return false + + case types.TARRAY, types.TPTR, types.TSLICE, types.TCHAN: + return parameterizedBy1(t.Elem(), params, visited) + + case types.TMAP: + return parameterizedBy1(t.Key(), params, visited) && parameterizedBy1(t.Elem(), params, visited) + + case types.TFUNC: + if t.NumTParams() > 0 { + return false + } + return parameterizedBy1(t.Recvs(), params, visited) && parameterizedBy1(t.Params(), params, visited) && parameterizedBy1(t.Results(), params, visited) + + case types.TSTRUCT: + for _, f := range t.Fields().Slice() { + if !parameterizedBy1(f.Type, params, visited) { + return false + } + } + return true + + case types.TINTER: + for _, f := range t.Methods().Slice() { + if !parameterizedBy1(f.Type, params, visited) { + return false + } + } + return true + + case types.TINT, types.TINT8, types.TINT16, types.TINT32, types.TINT64, + types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, + types.TUINTPTR, types.TBOOL, types.TSTRING, types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128: + return true + + default: + base.Fatalf("bad type kind %+v", t) + return true + } +} From e6a2cf233f736e6852b64b53d66dbda21c2e062d Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 20 Jul 2021 15:02:01 -0700 Subject: [PATCH 752/940] [dev.typeparams] cmd/compile: get runtime stuff working Remaining stuff from Dan's CL 335412 to get tests passing. - Removed PTRLIT case in node() that was added with the gcshape change. I don't think it is needed anymore. - Modified (*itab).init() to add an irrelevant pointer (the itab itself) for the '==' entry of interfaces with 'comparable'. That entry is not used, so we just want to avoid the error that the given type doesn't actually have an '==' method. Change-Id: I9b2d4c8342c0b2048d76e003d95023f4ccd559f5 Reviewed-on: https://go-review.googlesource.com/c/go/+/336149 Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Dan Scales Trust: Dan Scales Trust: Keith Randall --- src/cmd/compile/internal/noder/stencil.go | 5 ----- src/runtime/iface.go | 10 ++++++++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 460d926a0d6..cff36dd3bf2 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -1394,11 +1394,6 @@ func (subst *subster) node(n ir.Node) ir.Node { // TODO: need to modify m.X? I don't think any downstream passes use it. m.SetType(subst.unshapifyTyp(m.Type())) - case ir.OPTRLIT: - m := m.(*ir.AddrExpr) - // Walk uses the type of the argument of ptrlit. Also could be a shape type? - m.X.SetType(subst.unshapifyTyp(m.X.Type())) - case ir.OMETHEXPR: se := m.(*ir.SelectorExpr) se.X = ir.TypeNodeAt(se.X.Pos(), subst.unshapifyTyp(se.X.Type())) diff --git a/src/runtime/iface.go b/src/runtime/iface.go index 79a49c0dffb..71bd2d2f072 100644 --- a/src/runtime/iface.go +++ b/src/runtime/iface.go @@ -214,6 +214,16 @@ imethods: if ipkg == "" { ipkg = inter.pkgpath.name() } + if iname == "==" { + // Don't need '==' method right now (from comparable), + // just fill in with a random pointer for now. + if k == 0 { + fun0 = unsafe.Pointer(m) + } else { + methods[k] = unsafe.Pointer(m) + } + continue imethods + } for ; j < nt; j++ { t := &xmhdr[j] tname := typ.nameOff(t.name) From f19e49e7b185472b8ff919285e740cc198596497 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Tue, 20 Jul 2021 09:37:35 -0700 Subject: [PATCH 753/940] [dev.typeparams] cmd/compile: added a builtins.go test, fixed one bug The builtins.go test is derived from cmd/compile/internal/types2/testdata/check/builtins.go2, after removing the error cases. Added a few extra tests for len/cap/append. Fixed one bug, which is that DELETE operations can't be transformed if their argument is a typeparam. Also, the tranform of LEN/CAP calls does not need to be delayed. Removed out-date references to the old typechecker in the comments. Change-Id: If7a21506a7ff63ff7c8e87ccd614ef4ff3a0d3c8 Reviewed-on: https://go-review.googlesource.com/c/go/+/336010 Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall Trust: Dan Scales --- src/cmd/compile/internal/noder/helpers.go | 23 ++--- src/cmd/compile/internal/noder/stencil.go | 2 +- test/typeparam/builtins.go | 114 ++++++++++++++++++++++ 3 files changed, 124 insertions(+), 15 deletions(-) create mode 100644 test/typeparam/builtins.go diff --git a/src/cmd/compile/internal/noder/helpers.go b/src/cmd/compile/internal/noder/helpers.go index b0fb913ee84..7da5aa3102e 100644 --- a/src/cmd/compile/internal/noder/helpers.go +++ b/src/cmd/compile/internal/noder/helpers.go @@ -126,22 +126,17 @@ func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool) } if fun, ok := fun.(*ir.Name); ok && fun.BuiltinOp != 0 { - // For Builtin ops, we currently stay with using the old - // typechecker to transform the call to a more specific expression - // and possibly use more specific ops. However, for a bunch of the - // ops, we delay doing the old typechecker if any of the args have - // type params, for a variety of reasons: + // For most Builtin ops, we delay doing transformBuiltin if any of the + // args have type params, for a variety of reasons: // - // OMAKE: hard to choose specific ops OMAKESLICE, etc. until arg type is known - // OREAL/OIMAG: can't determine type float32/float64 until arg type know - // OLEN/OCAP: old typechecker will complain if arg is not obviously a slice/array. - // OAPPEND: old typechecker will complain if arg is not obviously slice, etc. - // - // We will eventually break out the transforming functionality - // needed for builtin's, and call it here or during stenciling, as - // appropriate. + // OMAKE: transformMake can't choose specific ops OMAKESLICE, etc. + // until arg type is known + // OREAL/OIMAG: transformRealImag can't determine type float32/float64 + // until arg type known + // OAPPEND: transformAppend requires that the arg is a slice + // ODELETE: transformDelete requires that the arg is a map switch fun.BuiltinOp { - case ir.OMAKE, ir.OREAL, ir.OIMAG, ir.OLEN, ir.OCAP, ir.OAPPEND: + case ir.OMAKE, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.ODELETE: hasTParam := false for _, arg := range args { if arg.Type().HasTParam() { diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index cff36dd3bf2..d1527c5d5c7 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -1270,7 +1270,7 @@ func (subst *subster) node(n ir.Node) ir.Node { name := call.X.Name() if name.BuiltinOp != ir.OXXX { switch name.BuiltinOp { - case ir.OMAKE, ir.OREAL, ir.OIMAG, ir.OLEN, ir.OCAP, ir.OAPPEND: + case ir.OMAKE, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.ODELETE: // Transform these builtins now that we // know the type of the args. m = transformBuiltin(call) diff --git a/test/typeparam/builtins.go b/test/typeparam/builtins.go new file mode 100644 index 00000000000..3fe6f79391f --- /dev/null +++ b/test/typeparam/builtins.go @@ -0,0 +1,114 @@ +// compile -G=3 + +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file tests built-in calls on generic types. + +// derived and expanded from cmd/compile/internal/types2/testdata/check/builtins.go2 + +package builtins + +// close + +type C0 interface{ int } +type C1 interface{ chan int } +type C2 interface{ chan int | <-chan int } +type C3 interface{ chan int | chan float32 } +type C4 interface{ chan int | chan<- int } +type C5[T any] interface{ ~chan T | chan<- T } + +func _[T C1](ch T) { + close(ch) +} + +func _[T C3](ch T) { + close(ch) +} + +func _[T C4](ch T) { + close(ch) +} + +func _[T C5[X], X any](ch T) { + close(ch) +} + +// delete + +type M0 interface{ int } +type M1 interface{ map[string]int } +type M2 interface { map[string]int | map[string]float64 } +type M3 interface{ map[string]int | map[rune]int } +type M4[K comparable, V any] interface{ map[K]V | map[rune]V } + +func _[T M1](m T) { + delete(m, "foo") +} + +func _[T M2](m T) { + delete(m, "foo") +} + +func _[T M4[rune, V], V any](m T) { + delete(m, 'k') +} + +// make + +type Bmc interface { + ~map[rune]string | ~chan int +} + +type Bms interface { + ~map[string]int | ~[]int +} + +type Bcs interface { + ~chan bool | ~[]float64 +} + +type Bss interface { + ~[]int | ~[]string +} + +func _[T Bmc]() { + _ = make(T) + _ = make(T, 10) +} + +func _[T Bms]() { + _ = make(T, 10) +} + +func _[T Bcs]() { + _ = make(T, 10) +} + +func _[T Bss]() { + _ = make(T, 10) + _ = make(T, 10, 20) +} + +// len/cap + +type Slice[T any] interface { + type []T +} + +func _[T any, S Slice[T]]() { + x := make(S, 5, 10) + _ = len(x) + _ = cap(x) +} + +// append + +func _[T any, S Slice[T]]() { + x := make(S, 5) + y := make(S, 2) + var z T + _ = append(x, y...) + _ = append(x, z) +} From dcc8350ad304714824cc8e5b8a00105dabb61c54 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Sun, 18 Jul 2021 22:10:13 -0700 Subject: [PATCH 754/940] [dev.typeparams] cmd/compile: handle ++/-- in noder2 for operands with generic type types2 will have already proved the expression's type is compatible, so just assign the one const to have the same type as the operand. Fixes #47258. Change-Id: If0844e6bf6d0a5e6b11453b87df71353863ccc5d Reviewed-on: https://go-review.googlesource.com/c/go/+/336009 Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall Trust: Dan Scales --- src/cmd/compile/internal/noder/helpers.go | 12 ++++++++- test/typeparam/issue47258.go | 32 +++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 test/typeparam/issue47258.go diff --git a/src/cmd/compile/internal/noder/helpers.go b/src/cmd/compile/internal/noder/helpers.go index 7da5aa3102e..15b32779080 100644 --- a/src/cmd/compile/internal/noder/helpers.go +++ b/src/cmd/compile/internal/noder/helpers.go @@ -337,5 +337,15 @@ var one = constant.MakeInt64(1) func IncDec(pos src.XPos, op ir.Op, x ir.Node) *ir.AssignOpStmt { assert(x.Type() != nil) - return ir.NewAssignOpStmt(pos, op, x, typecheck.DefaultLit(ir.NewBasicLit(pos, one), x.Type())) + bl := ir.NewBasicLit(pos, one) + if x.Type().HasTParam() { + // If the operand is generic, then types2 will have proved it must be + // a type that fits with increment/decrement, so just set the type of + // "one" to n.Type(). This works even for types that are eventually + // float or complex. + typed(x.Type(), bl) + } else { + bl = typecheck.DefaultLit(bl, x.Type()) + } + return ir.NewAssignOpStmt(pos, op, x, bl) } diff --git a/test/typeparam/issue47258.go b/test/typeparam/issue47258.go new file mode 100644 index 00000000000..76629f74240 --- /dev/null +++ b/test/typeparam/issue47258.go @@ -0,0 +1,32 @@ +// run -gcflags=-G=3 + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" +) + +type Numeric interface { + int32|int64|float64|complex64 +} + +//go:noline +func inc[T Numeric](x T) T { + x++ + return x +} +func main() { + if got, want := inc(int32(5)), int32(6); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + if got, want := inc(float64(5)), float64(6.0); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + if got, want := inc(complex64(5)), complex64(6.0); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } +} From 4e6836e82c981af7c041474f139b3de03906c3b0 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Tue, 20 Jul 2021 19:18:15 -0700 Subject: [PATCH 755/940] [dev.typeparams] Fix the types of the OFUNCINST nodes in noder2 types2 doesn't actually give us the type of an instantiated function/method after the type args have been applied. So, do a substitution at the point that we create the OFUNCINST nodes. We also needed to add in translation of the typeparams of a function signature in the type substituter. If the type params of the function become all concrete after the substitution, then we just drop them, since the whole signature must now be concrete. Change-Id: I6116d2aa248be6924ec9e6d8516678db45aa65c4 Reviewed-on: https://go-review.googlesource.com/c/go/+/336370 Run-TryBot: Dan Scales TryBot-Result: Go Bot Trust: Dan Scales Reviewed-by: Keith Randall --- src/cmd/compile/internal/noder/expr.go | 44 +++++++++++++++++++--- src/cmd/compile/internal/typecheck/subr.go | 16 +++++++- 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go index 66ce1bfe4c8..131ee89cbb9 100644 --- a/src/cmd/compile/internal/noder/expr.go +++ b/src/cmd/compile/internal/noder/expr.go @@ -80,7 +80,7 @@ func (g *irgen) expr(expr syntax.Expr) ir.Node { if n.Typecheck() != 1 && n.Typecheck() != 3 { base.FatalfAt(g.pos(expr), "missed typecheck: %+v", n) } - if !g.match(n.Type(), typ, tv.HasOk()) { + if n.Op() != ir.OFUNCINST && !g.match(n.Type(), typ, tv.HasOk()) { base.FatalfAt(g.pos(expr), "expected %L to have type %v", n, typ) } return n @@ -128,11 +128,14 @@ func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node { // includes the additional inferred type args fun.(*ir.InstExpr).Targs = targs } else { - // Create a function instantiation here, given - // there are only inferred type args (e.g. - // min(5,6), where min is a generic function) + // Create a function instantiation here, given there + // are only inferred type args (e.g. min(5,6), where + // min is a generic function). Substitute the type + // args for the type params in the uninstantiated function's + // type. inst := ir.NewInstExpr(pos, ir.OFUNCINST, fun, targs) - typed(fun.Type(), inst) + newt := g.substType(fun.Type(), fun.Type().TParams(), targs) + typed(newt, inst) fun = inst } @@ -169,7 +172,14 @@ func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node { panic("Incorrect argument for generic func instantiation") } n := ir.NewInstExpr(pos, ir.OFUNCINST, x, targs) - typed(g.typ(typ), n) + newt := g.typ(typ) + // Substitute the type args for the type params in the uninstantiated + // function's type. If there aren't enough type args, then the rest + // will be inferred at the call node, so don't try the substitution yet. + if x.Type().TParams().NumFields() == len(targs) { + newt = g.substType(g.typ(typ), x.Type().TParams(), targs) + } + typed(newt, n) return n case *syntax.SelectorExpr: @@ -201,6 +211,28 @@ func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node { } } +// substType does a normal type substition, but tparams is in the form of a field +// list, and targs is in terms of a slice of type nodes. substType records any newly +// instantiated types into g.instTypeList. +func (g *irgen) substType(typ *types.Type, tparams *types.Type, targs []ir.Node) *types.Type { + fields := tparams.FieldSlice() + tparams1 := make([]*types.Type, len(fields)) + for i, f := range fields { + tparams1[i] = f.Type + } + targs1 := make([]*types.Type, len(targs)) + for i, n := range targs { + targs1[i] = n.Type() + } + ts := typecheck.Tsubster{ + Tparams: tparams1, + Targs: targs1, + } + newt := ts.Typ(typ) + g.instTypeList = append(g.instTypeList, ts.InstTypeList...) + return newt +} + // selectorExpr resolves the choice of ODOT, ODOTPTR, OMETHVALUE (eventually // ODOTMETH & ODOTINTER), and OMETHEXPR and deals with embedded fields here rather // than in typecheck.go. diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index c6ffa175f1f..53221bc1cdf 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -1130,7 +1130,10 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type { newrecvs := ts.tstruct(t.Recvs(), false) newparams := ts.tstruct(t.Params(), false) newresults := ts.tstruct(t.Results(), false) - if newrecvs != t.Recvs() || newparams != t.Params() || newresults != t.Results() || targsChanged { + // Translate the tparams of a signature. + newtparams := ts.tstruct(t.TParams(), false) + if newrecvs != t.Recvs() || newparams != t.Params() || + newresults != t.Results() || newtparams != t.TParams() || targsChanged { // If any types have changed, then the all the fields of // of recv, params, and results must be copied, because they have // offset fields that are dependent, and so must have an @@ -1148,7 +1151,16 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type { if newresults == t.Results() { newresults = ts.tstruct(t.Results(), true) } - newt = types.NewSignature(t.Pkg(), newrecv, t.TParams().FieldSlice(), newparams.FieldSlice(), newresults.FieldSlice()) + var tparamfields []*types.Field + if newtparams.HasTParam() { + tparamfields = newtparams.FieldSlice() + } else { + // Completely remove the tparams from the resulting + // signature, if the tparams are now concrete types. + tparamfields = nil + } + newt = types.NewSignature(t.Pkg(), newrecv, tparamfields, + newparams.FieldSlice(), newresults.FieldSlice()) } case types.TINTER: From ee20dff27debb738ca3a89a7a30113771c1c078f Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Sun, 18 Jul 2021 11:09:12 -0700 Subject: [PATCH 756/940] [dev.typeparams] Get dictionaryCapture.go working. METHVALUE in a generic function (that is not called) was not causing buildClosure() to be called and therefore not using dictionaries. Also, had to add an extra check to make sure that if we have a FUNCINST node above a METHVALUE, we only call buildClosure once. Change-Id: I49756152fc343e5ac1c449e697960fc2a0f482ae Reviewed-on: https://go-review.googlesource.com/c/go/+/336429 Reviewed-by: Keith Randall Trust: Dan Scales Run-TryBot: Dan Scales TryBot-Result: Go Bot --- src/cmd/compile/internal/noder/stencil.go | 26 ++++++++++++++++++----- test/run.go | 7 +++--- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index d1527c5d5c7..71edc82deab 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -92,8 +92,8 @@ func (g *irgen) stencil() { // generic F, not immediately called closureRequired = true } - if n.Op() == ir.OMETHEXPR && len(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) > 0 && !types.IsInterfaceMethod(n.(*ir.SelectorExpr).Selection.Type) { - // T.M, T a type which is generic, not immediately + if (n.Op() == ir.OMETHEXPR || n.Op() == ir.OMETHVALUE) && len(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) > 0 && !types.IsInterfaceMethod(n.(*ir.SelectorExpr).Selection.Type) { + // T.M or x.M, where T or x is generic, but not immediately // called. Not necessary if the method selected is // actually for an embedded interface field. closureRequired = true @@ -180,18 +180,31 @@ func (g *irgen) stencil() { // in the infrequent case of an OFUNCINST without a corresponding // call. if closureRequired { + modified = true var edit func(ir.Node) ir.Node var outer *ir.Func if f, ok := decl.(*ir.Func); ok { outer = f } edit = func(x ir.Node) ir.Node { + if x.Op() == ir.OFUNCINST { + child := x.(*ir.InstExpr).X + if child.Op() == ir.OMETHEXPR || child.Op() == ir.OMETHVALUE { + // Call EditChildren on child (x.X), + // not x, so that we don't do + // buildClosure() on the + // METHEXPR/METHVALUE nodes as well. + ir.EditChildren(child, edit) + return g.buildClosure(outer, x) + } + } ir.EditChildren(x, edit) switch { case x.Op() == ir.OFUNCINST: return g.buildClosure(outer, x) - case x.Op() == ir.OMETHEXPR && len(deref(x.(*ir.SelectorExpr).X.Type()).RParams()) > 0 && - !types.IsInterfaceMethod(x.(*ir.SelectorExpr).Selection.Type): // TODO: test for ptr-to-method case + case (x.Op() == ir.OMETHEXPR || x.Op() == ir.OMETHVALUE) && + len(deref(x.(*ir.SelectorExpr).X.Type()).RParams()) > 0 && + !types.IsInterfaceMethod(x.(*ir.SelectorExpr).Selection.Type): return g.buildClosure(outer, x) } return x @@ -264,13 +277,16 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { fmt.Printf("%s in %v for generic method value %v\n", dictkind, outer, inst.X) } } - } else { // ir.OMETHEXPR + } else { // ir.OMETHEXPR or ir.METHVALUE // Method expression T.M where T is a generic type. se := x.(*ir.SelectorExpr) targs := deref(se.X.Type()).RParams() if len(targs) == 0 { panic("bad") } + if x.Op() == ir.OMETHVALUE { + rcvrValue = se.X + } // se.X.Type() is the top-level type of the method expression. To // correctly handle method expressions involving embedded fields, diff --git a/test/run.go b/test/run.go index 6e0c12d46b3..55c508dd423 100644 --- a/test/run.go +++ b/test/run.go @@ -2174,10 +2174,9 @@ var g3Failures = setOf( "typeparam/mdempsky/4.go", // -G=3 can't export functions with labeled breaks in loops - "typeparam/cons.go", // causes an unreachable method - "typeparam/dictionaryCapture.go", // segv, dictionary access failure? - "typeparam/issue44688.go", // interface conversion fails due to missing method - "typeparam/mdempsky/14.go", // interface comparison failure + "typeparam/cons.go", // causes an unreachable method + "typeparam/issue44688.go", // interface conversion fails due to missing method + "typeparam/mdempsky/14.go", // interface comparison failure ) var unifiedFailures = setOf( From 8e9109e95a8c4be92ba018a1353104706acf8466 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Mon, 19 Jul 2021 12:41:30 -0700 Subject: [PATCH 757/940] [dev.typeparams] Fix problem with 14.go Removed a case in transformCall() where we were setting a type on n, which isn't needed, since noder2 already set the type of n. More importantly, we are losing information, since the type of the results may be a shape type, but the actual type of call is the known type from types2, which may be a concrete type (in this case Zero[MyInt]). That concrete type will then be used correctly if the concrete result is converted to an interface. If we are inlining the call to Zero[MyInt], we need to add an implicit CONVNOP operation, since we are going to use the result variable directly, which has a shape type. So, add an implicit CONVNOP to remember that the known type is the concrete type. Also cleaned up 14.go a bit, so it is more understandable. Renamed type T to AnyInt, since T is used elsewhere as a type parameter. Reformatted Zero function and added a comment. Change-Id: Id917a2e054e0bbae9bd302232853fa8741d49b64 Reviewed-on: https://go-review.googlesource.com/c/go/+/336430 Trust: Dan Scales Reviewed-by: Keith Randall --- src/cmd/compile/internal/ir/expr.go | 8 ++++++++ src/cmd/compile/internal/noder/transform.go | 2 -- test/run.go | 5 ++--- test/typeparam/mdempsky/14.go | 11 +++++++---- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/cmd/compile/internal/ir/expr.go b/src/cmd/compile/internal/ir/expr.go index 9c800dcd1a7..09d6d87f060 100644 --- a/src/cmd/compile/internal/ir/expr.go +++ b/src/cmd/compile/internal/ir/expr.go @@ -349,6 +349,14 @@ func (n *InlinedCallExpr) SingleResult() Node { if have := len(n.ReturnVars); have != 1 { base.FatalfAt(n.Pos(), "inlined call has %v results, expected 1", have) } + if !n.Type().HasShape() && n.ReturnVars[0].Type().HasShape() { + // If the type of the call is not a shape, but the type of the return value + // is a shape, we need to do an implicit conversion, so the real type + // of n is maintained. + r := NewConvExpr(n.Pos(), OCONVNOP, n.Type(), n.ReturnVars[0]) + r.SetTypecheck(1) + return r + } return n.ReturnVars[0] } diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go index efbc8f68cee..86bdb91395c 100644 --- a/src/cmd/compile/internal/noder/transform.go +++ b/src/cmd/compile/internal/noder/transform.go @@ -161,8 +161,6 @@ func transformCall(n *ir.CallExpr) { typecheck.FixMethodCall(n) } if t.NumResults() == 1 { - n.SetType(l.Type().Results().Field(0).Type) - if n.Op() == ir.OCALLFUNC && n.X.Op() == ir.ONAME { if sym := n.X.(*ir.Name).Sym(); types.IsRuntimePkg(sym.Pkg) && sym.Name == "getg" { // Emit code for runtime.getg() directly instead of calling function. diff --git a/test/run.go b/test/run.go index 55c508dd423..1e01d160674 100644 --- a/test/run.go +++ b/test/run.go @@ -2174,9 +2174,8 @@ var g3Failures = setOf( "typeparam/mdempsky/4.go", // -G=3 can't export functions with labeled breaks in loops - "typeparam/cons.go", // causes an unreachable method - "typeparam/issue44688.go", // interface conversion fails due to missing method - "typeparam/mdempsky/14.go", // interface comparison failure + "typeparam/cons.go", // causes an unreachable method + "typeparam/issue44688.go", // interface conversion fails due to missing method ) var unifiedFailures = setOf( diff --git a/test/typeparam/mdempsky/14.go b/test/typeparam/mdempsky/14.go index 61f9436910c..ba685bc35c8 100644 --- a/test/typeparam/mdempsky/14.go +++ b/test/typeparam/mdempsky/14.go @@ -6,11 +6,14 @@ package main -func Zero[T any]() (_ T) { return } +// Zero returns the zero value of T +func Zero[T any]() (_ T) { + return +} -type T[X any] int +type AnyInt[X any] int -func (T[X]) M() { +func (AnyInt[X]) M() { var have interface{} = Zero[X]() var want interface{} = Zero[MyInt]() @@ -22,7 +25,7 @@ func (T[X]) M() { type I interface{ M() } type MyInt int -type U = T[MyInt] +type U = AnyInt[MyInt] var x = U(0) var i I = x From 61f69d2559a1177c23dea06343a4784514e8dd85 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Mon, 19 Jul 2021 13:11:50 -0400 Subject: [PATCH 758/940] [dev.typeparams] go/types: merge instance and Named to eliminate sanitization Storing temporary syntactic information using an *instance type forces us to be careful not to leak references to *instance in the checker output. This is complex and error prone, as types are written in many places during type checking. Instead, temporarily pin the necessary syntactic information directly to the Named type during the type checking pass. This allows us to avoid having to sanitize references. This includes a couple of small, unrelated changes that were made in the process of debugging: - eliminate the expandf indirection: it is no longer necessary - include type parameters when printing objects For #46151 Change-Id: I767e35b289f2fea512a168997af0f861cd242175 Reviewed-on: https://go-review.googlesource.com/c/go/+/335929 Trust: Robert Findley Trust: Robert Griesemer Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/check.go | 4 - src/go/types/decl.go | 8 +- src/go/types/infer.go | 3 - src/go/types/instance.go | 53 +++---- src/go/types/instantiate.go | 67 ++++---- src/go/types/named.go | 28 ++-- src/go/types/object.go | 3 + src/go/types/predicates.go | 6 +- src/go/types/sanitize.go | 206 ------------------------- src/go/types/sizeof_test.go | 1 - src/go/types/subst.go | 15 +- src/go/types/testdata/check/issues.go2 | 4 +- src/go/types/typeparam.go | 3 +- src/go/types/typestring.go | 7 - src/go/types/typexpr.go | 2 +- 15 files changed, 96 insertions(+), 314 deletions(-) delete mode 100644 src/go/types/sanitize.go diff --git a/src/go/types/check.go b/src/go/types/check.go index 4398475501c..b2d076dc680 100644 --- a/src/go/types/check.go +++ b/src/go/types/check.go @@ -273,10 +273,6 @@ func (check *Checker) checkFiles(files []*ast.File) (err error) { check.recordUntyped() - if check.Info != nil { - sanitizeInfo(check.Info) - } - check.pkg.complete = true // no longer needed - release memory diff --git a/src/go/types/decl.go b/src/go/types/decl.go index e38124f077a..1195104b59d 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -317,6 +317,7 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo { } case *Named: + t.complete() // don't touch the type if it is from a different package or the Universe scope // (doing so would lead to a race condition - was issue #35049) if t.obj.pkg != check.pkg { @@ -349,9 +350,6 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo { panic("internal error: cycle start not found") } return t.info - - case *instance: - return check.validType(t.expand(), path) } return valid @@ -607,6 +605,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) { // determine underlying type of named named.fromRHS = check.definedType(tdecl.Type, named) + assert(named.fromRHS != nil) // The underlying type of named may be itself a named type that is // incomplete: @@ -685,7 +684,8 @@ func (check *Checker) boundType(e ast.Expr) Type { bound := check.typ(e) check.later(func() { - if _, ok := under(bound).(*Interface); !ok && bound != Typ[Invalid] { + u := under(bound) + if _, ok := u.(*Interface); !ok && u != Typ[Invalid] { check.errorf(e, _Todo, "%s is not an interface", bound) } }) diff --git a/src/go/types/infer.go b/src/go/types/infer.go index 9faf7b75203..774d2fd158f 100644 --- a/src/go/types/infer.go +++ b/src/go/types/infer.go @@ -337,9 +337,6 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { // t must be one of w.tparams return t.index < len(w.tparams) && w.tparams[t.index].typ == t - case *instance: - return w.isParameterizedList(t.targs) - default: unreachable() } diff --git a/src/go/types/instance.go b/src/go/types/instance.go index 25f1442881d..205cb470464 100644 --- a/src/go/types/instance.go +++ b/src/go/types/instance.go @@ -4,56 +4,39 @@ package types +// TODO(rfindley): move this code to named.go. + import "go/token" -// An instance represents an instantiated generic type syntactically -// (without expanding the instantiation). Type instances appear only -// during type-checking and are replaced by their fully instantiated -// (expanded) types before the end of type-checking. +// instance holds a Checker along with syntactic information +// information, for use in lazy instantiation. type instance struct { - check *Checker // for lazy instantiation + check *Checker pos token.Pos // position of type instantiation; for error reporting only - base *Named // parameterized type to be instantiated - targs []Type // type arguments posList []token.Pos // position of each targ; for error reporting only verify bool // if set, constraint satisfaction is verified - value Type // base[targs...] after instantiation or Typ[Invalid]; nil if not yet set } -// expand returns the instantiated (= expanded) type of t. -// The result is either an instantiated *Named type, or -// Typ[Invalid] if there was an error. -func (t *instance) expand() Type { - v := t.value - if v == nil { - v = t.check.Instantiate(t.pos, t.base, t.targs, t.posList, t.verify) - if v == nil { - v = Typ[Invalid] - } - t.value = v +// complete ensures that the underlying type of n is instantiated. +// The underlying type will be Typ[Invalid] if there was an error. +// TODO(rfindley): expand would be a better name for this method, but conflicts +// with the existing concept of lazy expansion. Need to reconcile this. +func (n *Named) complete() { + if n.instance != nil && len(n.targs) > 0 && n.underlying == nil { + check := n.instance.check + inst := check.instantiate(n.instance.pos, n.orig.underlying, n.tparams, n.targs, n.instance.posList, n.instance.verify) + n.underlying = inst + n.fromRHS = inst + n.methods = n.orig.methods } - // After instantiation we must have an invalid or a *Named type. - if debug && v != Typ[Invalid] { - _ = v.(*Named) - } - return v } // expand expands a type instance into its instantiated // type and leaves all other types alone. expand does // not recurse. func expand(typ Type) Type { - if t, _ := typ.(*instance); t != nil { - return t.expand() + if t, _ := typ.(*Named); t != nil { + t.complete() } return typ } - -// expandf is set to expand. -// Call expandf when calling expand causes compile-time cycle error. -var expandf func(Type) Type - -func init() { expandf = expand } - -func (t *instance) Underlying() Type { return t } -func (t *instance) String() string { return TypeString(t, nil) } diff --git a/src/go/types/instantiate.go b/src/go/types/instantiate.go index 99ffb9e6048..270652149f6 100644 --- a/src/go/types/instantiate.go +++ b/src/go/types/instantiate.go @@ -25,29 +25,6 @@ import ( // Any methods attached to a *Named are simply copied; they are not // instantiated. func (check *Checker) Instantiate(pos token.Pos, typ Type, targs []Type, posList []token.Pos, verify bool) (res Type) { - if verify && check == nil { - panic("cannot have nil receiver if verify is set") - } - - if check != nil && trace { - check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs)) - check.indent++ - defer func() { - check.indent-- - var under Type - if res != nil { - // Calling under() here may lead to endless instantiations. - // Test case: type T[P any] T[P] - // TODO(gri) investigate if that's a bug or to be expected. - under = res.Underlying() - } - check.trace(pos, "=> %s (under = %s)", res, under) - }() - } - - assert(len(posList) <= len(targs)) - - // TODO(gri) What is better here: work with TypeParams, or work with TypeNames? var tparams []*TypeName switch t := typ.(type) { case *Named: @@ -77,6 +54,10 @@ func (check *Checker) Instantiate(pos token.Pos, typ Type, targs []Type, posList panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) } + return check.instantiate(pos, typ, tparams, targs, posList, verify) +} + +func (check *Checker) instantiate(pos token.Pos, typ Type, tparams []*TypeName, targs []Type, posList []token.Pos, verify bool) (res Type) { // the number of supplied types must match the number of type parameters if len(targs) != len(tparams) { // TODO(gri) provide better error message @@ -86,6 +67,29 @@ func (check *Checker) Instantiate(pos token.Pos, typ Type, targs []Type, posList } panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, len(targs), len(tparams))) } + if verify && check == nil { + panic("cannot have nil receiver if verify is set") + } + + if check != nil && trace { + check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs)) + check.indent++ + defer func() { + check.indent-- + var under Type + if res != nil { + // Calling under() here may lead to endless instantiations. + // Test case: type T[P any] T[P] + // TODO(gri) investigate if that's a bug or to be expected. + under = res.Underlying() + } + check.trace(pos, "=> %s (under = %s)", res, under) + }() + } + + assert(len(posList) <= len(targs)) + + // TODO(gri) What is better here: work with TypeParams, or work with TypeNames? if len(tparams) == 0 { return typ // nothing to do (minor optimization) @@ -120,15 +124,26 @@ func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type, pos if base == nil { panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) } + h := instantiatedHash(base, targs) + if check != nil { + if named := check.typMap[h]; named != nil { + return named + } + } - return &instance{ + tname := NewTypeName(pos, base.obj.pkg, base.obj.name, nil) + named := check.newNamed(tname, base, nil, base.tparams, base.methods) // methods are instantiated lazily + named.targs = targs + named.instance = &instance{ check: check, pos: pos, - base: base, - targs: targs, posList: posList, verify: verify, } + if check != nil { + check.typMap[h] = named + } + return named } // satisfies reports whether the type argument targ satisfies the constraint of type parameter diff --git a/src/go/types/named.go b/src/go/types/named.go index 4511f395e08..a500f5663ba 100644 --- a/src/go/types/named.go +++ b/src/go/types/named.go @@ -10,7 +10,7 @@ import "sync" // A Named represents a named (defined) type. type Named struct { - check *Checker // for Named.under implementation; nilled once under has been called + instance *instance // syntactic information for lazy instantiation info typeInfo // for cycle detection obj *TypeName // corresponding declared object orig *Named // original, uninstantiated type @@ -65,7 +65,13 @@ func (t *Named) expand() *Named { // newNamed is like NewNamed but with a *Checker receiver and additional orig argument. func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams []*TypeName, methods []*Func) *Named { - typ := &Named{check: check, obj: obj, orig: orig, fromRHS: underlying, underlying: underlying, tparams: tparams, methods: methods} + var inst *instance + if check != nil { + inst = &instance{ + check: check, + } + } + typ := &Named{instance: inst, obj: obj, orig: orig, fromRHS: underlying, underlying: underlying, tparams: tparams, methods: methods} if typ.orig == nil { typ.orig = typ } @@ -83,10 +89,10 @@ func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tpar if check != nil { check.later(func() { switch typ.under().(type) { - case *Named, *instance: + case *Named: panic("internal error: unexpanded underlying type") } - typ.check = nil + typ.instance = nil }) } return typ @@ -153,6 +159,8 @@ func (t *Named) String() string { return TypeString(t, nil) } // is detected, the result is Typ[Invalid]. If a cycle is detected and // n0.check != nil, the cycle is reported. func (n0 *Named) under() Type { + n0.complete() + u := n0.Underlying() if u == Typ[Invalid] { @@ -168,17 +176,17 @@ func (n0 *Named) under() Type { default: // common case return u - case *Named, *instance: + case *Named: // handled below } - if n0.check == nil { + if n0.instance == nil || n0.instance.check == nil { panic("internal error: Named.check == nil but type is incomplete") } // Invariant: after this point n0 as well as any named types in its // underlying chain should be set up when this function exits. - check := n0.check + check := n0.instance.check // If we can't expand u at this point, it is invalid. n := asNamed(u) @@ -199,12 +207,8 @@ func (n0 *Named) under() Type { var n1 *Named switch u1 := u.(type) { case *Named: + u1.complete() n1 = u1 - case *instance: - n1, _ = u1.expand().(*Named) - if n1 == nil { - u = Typ[Invalid] - } } if n1 == nil { break // end of chain diff --git a/src/go/types/object.go b/src/go/types/object.go index 7913008814c..4ea2837ea7c 100644 --- a/src/go/types/object.go +++ b/src/go/types/object.go @@ -429,6 +429,9 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) { if _, ok := typ.(*Basic); ok { return } + if named, _ := typ.(*Named); named != nil && len(named.tparams) > 0 { + writeTParamList(buf, named.tparams, qf, nil) + } if tname.IsAlias() { buf.WriteString(" =") } else { diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index ea2bed720a1..ce350f4470d 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -10,7 +10,7 @@ package types // isNamed may be called with types that are not fully set up. func isNamed(typ Type) bool { switch typ.(type) { - case *Basic, *Named, *TypeParam, *instance: + case *Basic, *Named, *TypeParam: return true } return false @@ -159,8 +159,8 @@ func (p *ifacePair) identical(q *ifacePair) bool { // For changes to this code the corresponding changes should be made to unifier.nify. func identical(x, y Type, cmpTags bool, p *ifacePair) bool { // types must be expanded for comparison - x = expandf(x) - y = expandf(y) + x = expand(x) + y = expand(y) if x == y { return true diff --git a/src/go/types/sanitize.go b/src/go/types/sanitize.go deleted file mode 100644 index 62b91ef8c32..00000000000 --- a/src/go/types/sanitize.go +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright 2020 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 types - -// sanitizeInfo walks the types contained in info to ensure that all instances -// are expanded. -// -// This includes some objects that may be shared across concurrent -// type-checking passes (such as those in the universe scope), so we are -// careful here not to write types that are already sanitized. This avoids a -// data race as any shared types should already be sanitized. -func sanitizeInfo(info *Info) { - var s sanitizer = make(map[Type]Type) - - // Note: Some map entries are not references. - // If modified, they must be assigned back. - - for e, tv := range info.Types { - if typ := s.typ(tv.Type); typ != tv.Type { - tv.Type = typ - info.Types[e] = tv - } - } - - inferred := info.Inferred - for e, inf := range inferred { - changed := false - for i, targ := range inf.TArgs { - if typ := s.typ(targ); typ != targ { - inf.TArgs[i] = typ - changed = true - } - } - if typ := s.typ(inf.Sig); typ != inf.Sig { - inf.Sig = typ.(*Signature) - changed = true - } - if changed { - inferred[e] = inf - } - } - - for _, obj := range info.Defs { - if obj != nil { - if typ := s.typ(obj.Type()); typ != obj.Type() { - obj.setType(typ) - } - } - } - - for _, obj := range info.Uses { - if obj != nil { - if typ := s.typ(obj.Type()); typ != obj.Type() { - obj.setType(typ) - } - } - } - - // TODO(gri) sanitize as needed - // - info.Implicits - // - info.Selections - // - info.Scopes - // - info.InitOrder -} - -type sanitizer map[Type]Type - -func (s sanitizer) typ(typ Type) Type { - if typ == nil { - return nil - } - - if t, found := s[typ]; found { - return t - } - s[typ] = typ - - switch t := typ.(type) { - case *Basic, *top: - // nothing to do - - case *Array: - if elem := s.typ(t.elem); elem != t.elem { - t.elem = elem - } - - case *Slice: - if elem := s.typ(t.elem); elem != t.elem { - t.elem = elem - } - - case *Struct: - s.varList(t.fields) - - case *Pointer: - if base := s.typ(t.base); base != t.base { - t.base = base - } - - case *Tuple: - s.tuple(t) - - case *Signature: - s.var_(t.recv) - s.tuple(t.params) - s.tuple(t.results) - - case *Union: - s.typeList(t.types) - - case *Interface: - s.funcList(t.methods) - s.typeList(t.embeddeds) - // TODO(gri) do we need to sanitize type sets? - tset := t.typeSet() - s.funcList(tset.methods) - if types := s.typ(tset.types); types != tset.types { - tset.types = types - } - - case *Map: - if key := s.typ(t.key); key != t.key { - t.key = key - } - if elem := s.typ(t.elem); elem != t.elem { - t.elem = elem - } - - case *Chan: - if elem := s.typ(t.elem); elem != t.elem { - t.elem = elem - } - - case *Named: - if debug && t.check != nil { - panic("internal error: Named.check != nil") - } - t.expand() - if orig := s.typ(t.fromRHS); orig != t.fromRHS { - t.fromRHS = orig - } - if under := s.typ(t.underlying); under != t.underlying { - t.underlying = under - } - s.typeList(t.targs) - s.funcList(t.methods) - - case *TypeParam: - if bound := s.typ(t.bound); bound != t.bound { - t.bound = bound - } - - case *instance: - typ = t.expand() - s[t] = typ - - default: - panic("unimplemented") - } - - return typ -} - -func (s sanitizer) var_(v *Var) { - if v != nil { - if typ := s.typ(v.typ); typ != v.typ { - v.typ = typ - } - } -} - -func (s sanitizer) varList(list []*Var) { - for _, v := range list { - s.var_(v) - } -} - -func (s sanitizer) tuple(t *Tuple) { - if t != nil { - s.varList(t.vars) - } -} - -func (s sanitizer) func_(f *Func) { - if f != nil { - if typ := s.typ(f.typ); typ != f.typ { - f.typ = typ - } - } -} - -func (s sanitizer) funcList(list []*Func) { - for _, f := range list { - s.func_(f) - } -} - -func (s sanitizer) typeList(list []Type) { - for i, t := range list { - if typ := s.typ(t); typ != t { - list[i] = typ - } - } -} diff --git a/src/go/types/sizeof_test.go b/src/go/types/sizeof_test.go index 8c18de8675d..fc548f7c589 100644 --- a/src/go/types/sizeof_test.go +++ b/src/go/types/sizeof_test.go @@ -32,7 +32,6 @@ func TestSizeof(t *testing.T) { {Chan{}, 12, 24}, {Named{}, 84, 160}, {TypeParam{}, 28, 48}, - {instance{}, 48, 96}, {top{}, 0, 0}, // Objects diff --git a/src/go/types/subst.go b/src/go/types/subst.go index ec85a6bfc49..42be508cd91 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -29,12 +29,7 @@ func makeSubstMap(tpars []*TypeName, targs []Type) *substMap { assert(len(tpars) == len(targs)) proj := make(map[*TypeParam]Type, len(tpars)) for i, tpar := range tpars { - // We must expand type arguments otherwise *instance - // types end up as components in composite types. - // TODO(gri) explain why this causes problems, if it does - targ := expand(targs[i]) // possibly nil - targs[i] = targ - proj[tpar.typ.(*TypeParam)] = targ + proj[tpar.typ.(*TypeParam)] = targs[i] } return &substMap{targs, proj} } @@ -86,6 +81,7 @@ func (check *Checker) subst(pos token.Pos, typ Type, smap *substMap) Type { // for recursive types (example: type T[P any] *T[P]). subst.typMap = make(map[string]*Named) } + return subst.typ(typ) } @@ -248,10 +244,13 @@ func (subst *subster) typ(typ Type) Type { named := subst.check.newNamed(tname, t, t.Underlying(), t.TParams(), t.methods) // method signatures are updated lazily named.targs = newTargs subst.typMap[h] = named + t.complete() // must happen after typMap update to avoid infinite recursion // do the substitution dump(">>> subst %s with %s (new: %s)", t.underlying, subst.smap, newTargs) named.underlying = subst.typOrNil(t.Underlying()) + dump(">>> underlying: %v", named.underlying) + assert(named.underlying != nil) named.fromRHS = named.underlying // for cycle detection (Checker.validType) return named @@ -259,10 +258,6 @@ func (subst *subster) typ(typ Type) Type { case *TypeParam: return subst.smap.lookup(t) - case *instance: - // TODO(gri) can we avoid the expansion here and just substitute the type parameters? - return subst.typ(t.expand()) - default: panic("unimplemented") } diff --git a/src/go/types/testdata/check/issues.go2 b/src/go/types/testdata/check/issues.go2 index c57f0023034..ce0d6082163 100644 --- a/src/go/types/testdata/check/issues.go2 +++ b/src/go/types/testdata/check/issues.go2 @@ -81,8 +81,10 @@ func (u T2[U]) Add1() U { return u.s + 1 } +// TODO(rfindley): we should probably report an error here as well, not +// just when the type is first instantiated. func NewT2[U any]() T2[U /* ERROR U has no type constraints */ ] { - return T2[U /* ERROR U has no type constraints */ ]{} + return T2[U]{} } func _() { diff --git a/src/go/types/typeparam.go b/src/go/types/typeparam.go index e42c24f8cbe..bb5b28cdf87 100644 --- a/src/go/types/typeparam.go +++ b/src/go/types/typeparam.go @@ -24,7 +24,8 @@ type TypeParam struct { id uint64 // unique id, for debugging only obj *TypeName // corresponding type name index int // type parameter index in source order, starting at 0 - bound Type // *Named or *Interface; underlying type is always *Interface + // TODO(rfindley): this could also be Typ[Invalid]. Verify that this is handled correctly. + bound Type // *Named or *Interface; underlying type is always *Interface } // NewTypeParam returns a new TypeParam. bound can be nil (and set later). diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go index cba678588a9..ef3808230ad 100644 --- a/src/go/types/typestring.go +++ b/src/go/types/typestring.go @@ -295,13 +295,6 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { } buf.WriteString(s + subscript(t.id)) - case *instance: - buf.WriteByte(instanceMarker) // indicate "non-evaluated" syntactic instance - writeTypeName(buf, t.base.obj, qf) - buf.WriteByte('[') - writeTypeList(buf, t.targs, qf, visited) - buf.WriteByte(']') - case *top: buf.WriteString("⊤") diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index f2c4762a6b3..a812ba6519a 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -436,7 +436,7 @@ func (check *Checker) instantiatedType(x ast.Expr, targsx []ast.Expr, def *Named // make sure we check instantiation works at least once // and that the resulting type is valid check.later(func() { - t := typ.(*instance).expand() + t := expand(typ) check.validType(t, nil) }) From b7149b781fda907078b9312d301ea384e91482ef Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Tue, 20 Jul 2021 13:07:50 -0400 Subject: [PATCH 759/940] [dev.typeparams] go/types: trigger verification while resolving instance The refactoring of CL 335929 to merge the instance and Named types resulted in type instances only being evaluated once. As a side effect, we only verified constraints once per unique instantiation expression. This can be confusing if type instantations are occurring far apart in the code. Resolve this by lifting up the verification logic into Instantiate and InstantiateLazy. Change-Id: Icd5a482d097d983073955c62931441edfd92f5c2 Reviewed-on: https://go-review.googlesource.com/c/go/+/335978 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/instance.go | 2 +- src/go/types/instantiate.go | 52 +++++++++++++++----------- src/go/types/testdata/check/issues.go2 | 4 +- 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/src/go/types/instance.go b/src/go/types/instance.go index 205cb470464..9d31b42690a 100644 --- a/src/go/types/instance.go +++ b/src/go/types/instance.go @@ -24,7 +24,7 @@ type instance struct { func (n *Named) complete() { if n.instance != nil && len(n.targs) > 0 && n.underlying == nil { check := n.instance.check - inst := check.instantiate(n.instance.pos, n.orig.underlying, n.tparams, n.targs, n.instance.posList, n.instance.verify) + inst := check.instantiate(n.instance.pos, n.orig.underlying, n.tparams, n.targs, n.instance.posList) n.underlying = inst n.fromRHS = inst n.methods = n.orig.methods diff --git a/src/go/types/instantiate.go b/src/go/types/instantiate.go index 270652149f6..14bbf2b12b1 100644 --- a/src/go/types/instantiate.go +++ b/src/go/types/instantiate.go @@ -54,10 +54,14 @@ func (check *Checker) Instantiate(pos token.Pos, typ Type, targs []Type, posList panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) } - return check.instantiate(pos, typ, tparams, targs, posList, verify) + inst := check.instantiate(pos, typ, tparams, targs, posList) + if verify && len(tparams) == len(targs) { + check.verify(pos, tparams, targs, posList) + } + return inst } -func (check *Checker) instantiate(pos token.Pos, typ Type, tparams []*TypeName, targs []Type, posList []token.Pos, verify bool) (res Type) { +func (check *Checker) instantiate(pos token.Pos, typ Type, tparams []*TypeName, targs []Type, posList []token.Pos) (res Type) { // the number of supplied types must match the number of type parameters if len(targs) != len(tparams) { // TODO(gri) provide better error message @@ -67,9 +71,6 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, tparams []*TypeName, } panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, len(targs), len(tparams))) } - if verify && check == nil { - panic("cannot have nil receiver if verify is set") - } if check != nil && trace { check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs)) @@ -97,22 +98,6 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, tparams []*TypeName, smap := makeSubstMap(tparams, targs) - // check bounds - if verify { - for i, tname := range tparams { - // best position for error reporting - pos := pos - if i < len(posList) { - pos = posList[i] - } - - // stop checking bounds after the first failure - if !check.satisfies(pos, targs[i], tname.typ.(*TypeParam), smap) { - break - } - } - } - return check.subst(pos, typ, smap) } @@ -124,6 +109,11 @@ func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type, pos if base == nil { panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) } + if verify && len(base.tparams) == len(targs) { + check.later(func() { + check.verify(pos, base.tparams, targs, posList) + }) + } h := instantiatedHash(base, targs) if check != nil { if named := check.typMap[h]; named != nil { @@ -146,6 +136,26 @@ func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type, pos return named } +func (check *Checker) verify(pos token.Pos, tparams []*TypeName, targs []Type, posList []token.Pos) { + if check == nil { + panic("cannot have nil Checker if verifying constraints") + } + + smap := makeSubstMap(tparams, targs) + for i, tname := range tparams { + // best position for error reporting + pos := pos + if i < len(posList) { + pos = posList[i] + } + + // stop checking bounds after the first failure + if !check.satisfies(pos, targs[i], tname.typ.(*TypeParam), smap) { + break + } + } +} + // satisfies reports whether the type argument targ satisfies the constraint of type parameter // parameter tpar (after any of its type parameters have been substituted through smap). // A suitable error is reported if the result is false. diff --git a/src/go/types/testdata/check/issues.go2 b/src/go/types/testdata/check/issues.go2 index ce0d6082163..c57f0023034 100644 --- a/src/go/types/testdata/check/issues.go2 +++ b/src/go/types/testdata/check/issues.go2 @@ -81,10 +81,8 @@ func (u T2[U]) Add1() U { return u.s + 1 } -// TODO(rfindley): we should probably report an error here as well, not -// just when the type is first instantiated. func NewT2[U any]() T2[U /* ERROR U has no type constraints */ ] { - return T2[U]{} + return T2[U /* ERROR U has no type constraints */ ]{} } func _() { From fdb45acd1f062884c77ea6961fb638e004af1b8e Mon Sep 17 00:00:00 2001 From: David Chase Date: Wed, 21 Jul 2021 18:38:05 -0400 Subject: [PATCH 760/940] runtime: move mem profile sampling into m-acquired section It was not safe to do mcache profiling updates outside the critical section, but we got lucky because the runtime was not preemptible. Adding chunked memory clearing (CL 270943) created preemption opportunities, which led to corruption of runtime data structures. Fixes #47304. Fixes #47302. Change-Id: I461615470d62328a83ccbac537fbdc6dcde81c85 Reviewed-on: https://go-review.googlesource.com/c/go/+/336449 Trust: David Chase Run-TryBot: David Chase TryBot-Result: Go Bot Reviewed-by: Austin Clements Reviewed-by: Keith Randall --- src/runtime/malloc.go | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 2759bbdaf90..cc22b0f2765 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -1135,13 +1135,21 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { msanmalloc(x, size) } + if rate := MemProfileRate; rate > 0 { + // Note cache c only valid while m acquired; see #47302 + if rate != 1 && size < c.nextSample { + c.nextSample -= size + } else { + profilealloc(mp, x, size) + } + } mp.mallocing = 0 releasem(mp) // Pointerfree data can be zeroed late in a context where preemption can occur. // x will keep the memory alive. if !isZeroed && needzero { - memclrNoHeapPointersChunked(size, x) + memclrNoHeapPointersChunked(size, x) // This is a possible preemption point: see #47302 } if debug.malloc { @@ -1155,16 +1163,6 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { } } - if rate := MemProfileRate; rate > 0 { - if rate != 1 && size < c.nextSample { - c.nextSample -= size - } else { - mp := acquirem() - profilealloc(mp, x, size) - releasem(mp) - } - } - if assistG != nil { // Account for internal fragmentation in the assist // debt now that we know it. From 311baf65f49f4b15396f7e88c05bc97d47f2e4ed Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 2 Jul 2021 15:42:20 -0700 Subject: [PATCH 761/940] [dev.typeparams] test: cleanup 'go env' and -goexperiment This CL makes two related changes: 1. It uses 'go env -json' to query the environment configuration, rather than attempting to manually reconstruct the values that cmd/go is going to use. 2. It changes the -goexperiment flag to *extend* any ambient GOEXPERIMENT configuration. Notably, this means that '-goexperiment fieldtrack' now tests fieldtracking in conjunction with any other experiments (e.g., unified IR). Tests that want to test an exact GOEXPERIMENT config should use '-goexperiment none,foo' instead. Change-Id: I96a97198209e540e934fe7035110c3ae3a8f0e6a Reviewed-on: https://go-review.googlesource.com/c/go/+/332610 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- test/run.go | 66 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/test/run.go b/test/run.go index 1e01d160674..23eebcee2e8 100644 --- a/test/run.go +++ b/test/run.go @@ -9,6 +9,7 @@ package main import ( "bytes" + "encoding/json" "errors" "flag" "fmt" @@ -49,17 +50,36 @@ var ( shards = flag.Int("shards", 0, "number of shards. If 0, all tests are run. This is used by the continuous build.") ) -var unifiedEnabled, defaultGLevels = func() (bool, string) { - // TODO(mdempsky): Change this to just "go env GOEXPERIMENT" after - // CL 328751 is merged back to dev.typeparams. In the mean time, we - // infer whether the "unified" experiment is default enabled by - // inspecting the output from `go tool compile -V`. - output := runOutput(goTool(), "tool", "compile", "-V") +type envVars struct { + GOOS string + GOARCH string + GOEXPERIMENT string + CGO_ENABLED string +} +var env = func() (res envVars) { + cmd := exec.Command("go", "env", "-json") + stdout, err := cmd.StdoutPipe() + if err != nil { + log.Fatal("StdoutPipe:", err) + } + if err := cmd.Start(); err != nil { + log.Fatal("Start:", err) + } + if err := json.NewDecoder(stdout).Decode(&res); err != nil { + log.Fatal("Decode:", err) + } + if err := cmd.Wait(); err != nil { + log.Fatal("Wait:", err) + } + return +}() + +var unifiedEnabled, defaultGLevels = func() (bool, string) { // TODO(mdempsky): This will give false negatives if the unified // experiment is enabled by default, but presumably at that point we // won't need to disable tests for it anymore anyway. - enabled := strings.Contains(output, "unified") + enabled := strings.Contains(","+env.GOEXPERIMENT+",", ",unified,") // Normal test runs should test with both -G=0 and -G=3 for types2 // coverage. But the unified experiment always uses types2, so @@ -81,8 +101,9 @@ func defaultAllCodeGen() bool { } var ( - goos, goarch string - cgoEnabled bool + goos = env.GOOS + goarch = env.GOARCH + cgoEnabled, _ = strconv.ParseBool(env.CGO_ENABLED) // dirs are the directories to look for *.go files in. // TODO(bradfitz): just use all directories? @@ -116,12 +137,6 @@ func main() { glevels = append(glevels, glevel) } - goos = getenv("GOOS", runtime.GOOS) - goarch = getenv("GOARCH", runtime.GOARCH) - - cgoEnv := runOutput(goTool(), "env", "CGO_ENABLED") - cgoEnabled, _ = strconv.ParseBool(strings.TrimSpace(cgoEnv)) - findExecCmd() // Disable parallelism if printing or if using a simulator. @@ -214,17 +229,6 @@ func main() { } } -// runOutput runs the specified command and returns its output as a -// string. If the command fails, runOutput logs the error and exits. -func runOutput(name string, args ...string) string { - cmd := exec.Command(name, args...) - output, err := cmd.Output() - if err != nil { - log.Fatalf("running %v: %v", cmd, err) - } - return string(output) -} - // goTool reports the path of the go tool to use to run the tests. // If possible, use the same Go used to run run.go, otherwise // fallback to the go version found in the PATH. @@ -672,6 +676,8 @@ func (t *test) run() { return } + goexp := env.GOEXPERIMENT + // collect flags for len(args) > 0 && strings.HasPrefix(args[0], "-") { switch args[0] { @@ -698,7 +704,11 @@ func (t *test) run() { } case "-goexperiment": // set GOEXPERIMENT environment args = args[1:] - runenv = append(runenv, "GOEXPERIMENT="+args[0]) + if goexp != "" { + goexp += "," + } + goexp += args[0] + runenv = append(runenv, "GOEXPERIMENT="+goexp) default: flags = append(flags, args[0]) @@ -1258,7 +1268,7 @@ func (t *test) run() { runInDir = "" var out []byte var err error - if len(flags)+len(args) == 0 && t.goGcflagsIsEmpty() && !*linkshared && goarch == runtime.GOARCH && goos == runtime.GOOS { + if len(flags)+len(args) == 0 && t.goGcflagsIsEmpty() && !*linkshared && goarch == runtime.GOARCH && goos == runtime.GOOS && goexp == env.GOEXPERIMENT { // If we're not using special go command flags, // skip all the go command machinery. // This avoids any time the go command would From 6f57139c7a6bc776f1335aca13d276d36343cf7c Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Wed, 21 Jul 2021 10:21:23 -0400 Subject: [PATCH 762/940] [dev.typeparams] go/types: set type parameter indices when they are bound It is invalid to use a type parameter for more than one type, so we can avoid passing the type parameter index to NewTypeParam and just set it when type parameters are bound to a type via SetTParams or during type checking. In order to enforce the correctness of this change, introduce a TypeParams type to represent a list of type parameters that have been associated with a type. For now, expose this new type as the API for type parameters, but this is of course not necessarily a final API. Allowing *TypeParams to be nil also decreases the size of Named and Signature, which is good as most instances of these types will not be parameterized. Change-Id: Ia1e39ba51edb05bb535eb5f41c34e9dd02d39c38 Reviewed-on: https://go-review.googlesource.com/c/go/+/336249 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/api_test.go | 2 +- src/go/types/assignments.go | 2 +- src/go/types/builtins.go | 3 ++- src/go/types/call.go | 20 +++++++-------- src/go/types/decl.go | 8 +++--- src/go/types/index.go | 2 +- src/go/types/instance.go | 2 +- src/go/types/instantiate.go | 10 ++++---- src/go/types/lookup.go | 18 ++++++------- src/go/types/named.go | 16 ++++++------ src/go/types/object.go | 4 +-- src/go/types/predicates.go | 2 +- src/go/types/signature.go | 25 +++++++++++-------- src/go/types/sizeof_test.go | 4 +-- src/go/types/subst.go | 4 +-- src/go/types/typeparam.go | 50 ++++++++++++++++++++++++++++++++++--- src/go/types/typestring.go | 4 +-- 17 files changed, 111 insertions(+), 65 deletions(-) diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go index 444cb440872..b2d532c4c8b 100644 --- a/src/go/types/api_test.go +++ b/src/go/types/api_test.go @@ -1828,7 +1828,7 @@ func TestInstantiate(t *testing.T) { // type T should have one type parameter T := pkg.Scope().Lookup("T").Type().(*Named) - if n := len(T.TParams()); n != 1 { + if n := T.TParams().Len(); n != 1 { t.Fatalf("expected 1 type parameter; found %d", n) } diff --git a/src/go/types/assignments.go b/src/go/types/assignments.go index 18eae621840..595f426e109 100644 --- a/src/go/types/assignments.go +++ b/src/go/types/assignments.go @@ -71,7 +71,7 @@ func (check *Checker) assignment(x *operand, T Type, context string) { } // A generic (non-instantiated) function value cannot be assigned to a variable. - if sig := asSignature(x.typ); sig != nil && len(sig.tparams) > 0 { + if sig := asSignature(x.typ); sig != nil && sig.TParams().Len() > 0 { check.errorf(x, _Todo, "cannot use generic function %s without instantiation in %s", x, context) } diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index 2edf9011654..b6fb36b185a 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -806,7 +806,8 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { // type param is placed in the current package so export/import // works as expected. tpar := NewTypeName(token.NoPos, check.pkg, "", nil) - ptyp := check.NewTypeParam(tpar, tp.index, &emptyInterface) // assigns type to tpar as a side-effect + ptyp := check.NewTypeParam(tpar, &emptyInterface) // assigns type to tpar as a side-effect + ptyp.index = tp.index tsum := newUnion(rtypes, tildes) ptyp.bound = &Interface{complete: true, tset: &TypeSet{types: tsum}} diff --git a/src/go/types/call.go b/src/go/types/call.go index 9453b53c3a2..96d0429af95 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -27,7 +27,7 @@ func (check *Checker) funcInst(x *operand, ix *typeparams.IndexExpr) { // check number of type arguments (got) vs number of type parameters (want) sig := x.typ.(*Signature) - got, want := len(targs), len(sig.tparams) + got, want := len(targs), sig.TParams().Len() if got > want { check.errorf(ix.Indices[got-1], _Todo, "got %d type arguments but want %d", got, want) x.mode = invalid @@ -39,7 +39,7 @@ func (check *Checker) funcInst(x *operand, ix *typeparams.IndexExpr) { inferred := false if got < want { - targs = check.infer(ix.Orig, sig.tparams, targs, nil, nil, true) + targs = check.infer(ix.Orig, sig.TParams().list(), targs, nil, nil, true) if targs == nil { // error was already reported x.mode = invalid @@ -160,7 +160,7 @@ func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind { assert(len(targs) == len(ix.Indices)) // check number of type arguments (got) vs number of type parameters (want) - got, want := len(targs), len(sig.tparams) + got, want := len(targs), sig.TParams().Len() if got > want { check.errorf(ix.Indices[want], _Todo, "got %d type arguments but want %d", got, want) check.use(call.Args...) @@ -194,7 +194,7 @@ func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind { // if type inference failed, a parametrized result must be invalidated // (operands cannot have a parametrized type) - if x.mode == value && len(sig.tparams) > 0 && isParameterized(sig.tparams, x.typ) { + if x.mode == value && sig.TParams().Len() > 0 && isParameterized(sig.TParams().list(), x.typ) { x.mode = invalid } @@ -324,10 +324,10 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, targs []Type } // infer type arguments and instantiate signature if necessary - if len(sig.tparams) > 0 { + if sig.TParams().Len() > 0 { // TODO(gri) provide position information for targs so we can feed // it to the instantiate call for better error reporting - targs := check.infer(call, sig.tparams, targs, sigParams, args, true) + targs := check.infer(call, sig.TParams().list(), targs, sigParams, args, true) if targs == nil { return // error already reported } @@ -341,7 +341,7 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, targs []Type // need to compute it from the adjusted list; otherwise we can // simply use the result signature's parameter list. if adjusted { - sigParams = check.subst(call.Pos(), sigParams, makeSubstMap(sig.tparams, targs)).(*Tuple) + sigParams = check.subst(call.Pos(), sigParams, makeSubstMap(sig.TParams().list(), targs)).(*Tuple) } else { sigParams = rsig.params } @@ -517,7 +517,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) { // the signature accordingly. // TODO(gri) factor this code out sig := m.typ.(*Signature) - if len(sig.rparams) > 0 { + if sig.RParams().Len() > 0 { // For inference to work, we must use the receiver type // matching the receiver in the actual method declaration. // If the method is embedded, the matching receiver is the @@ -545,7 +545,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) { // the receiver type arguments here, the receiver must be be otherwise invalid // and an error has been reported elsewhere. arg := operand{mode: variable, expr: x.expr, typ: recv} - targs := check.infer(m, sig.rparams, nil, NewTuple(sig.recv), []*operand{&arg}, false /* no error reporting */) + targs := check.infer(m, sig.RParams().list(), nil, NewTuple(sig.recv), []*operand{&arg}, false /* no error reporting */) if targs == nil { // We may reach here if there were other errors (see issue #40056). goto Error @@ -554,7 +554,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) { // (If we modify m, some tests will fail; possibly because the m is in use.) // TODO(gri) investigate and provide a correct explanation here copy := *m - copy.typ = check.subst(e.Pos(), m.typ, makeSubstMap(sig.rparams, targs)) + copy.typ = check.subst(e.Pos(), m.typ, makeSubstMap(sig.RParams().list(), targs)) obj = © } // TODO(gri) we also need to do substitution for parameterized interface methods diff --git a/src/go/types/decl.go b/src/go/types/decl.go index 1195104b59d..be7753d9d18 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -625,13 +625,13 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) { named.underlying = under(named) // If the RHS is a type parameter, it must be from this type declaration. - if tpar, _ := named.underlying.(*TypeParam); tpar != nil && tparamIndex(named.tparams, tpar) < 0 { + if tpar, _ := named.underlying.(*TypeParam); tpar != nil && tparamIndex(named.tparams.list(), tpar) < 0 { check.errorf(tdecl.Type, _Todo, "cannot use function type parameter %s as RHS in type declaration", tpar) named.underlying = Typ[Invalid] } } -func (check *Checker) collectTypeParams(list *ast.FieldList) []*TypeName { +func (check *Checker) collectTypeParams(list *ast.FieldList) *TypeParams { var tparams []*TypeName // Declare type parameters up-front, with empty interface as type bound. // The scope of type parameters starts at the beginning of the type parameter @@ -655,13 +655,13 @@ func (check *Checker) collectTypeParams(list *ast.FieldList) []*TypeName { index += len(f.Names) } - return tparams + return bindTParams(tparams) } func (check *Checker) declareTypeParams(tparams []*TypeName, names []*ast.Ident) []*TypeName { for _, name := range names { tpar := NewTypeName(name.Pos(), check.pkg, name.Name, nil) - check.NewTypeParam(tpar, len(tparams), &emptyInterface) // assigns type to tpar as a side-effect + check.NewTypeParam(tpar, &emptyInterface) // assigns type to tpar as a side-effect check.declare(check.scope, name, tpar, check.scope.pos) // TODO(gri) check scope position tparams = append(tparams, tpar) } diff --git a/src/go/types/index.go b/src/go/types/index.go index b2a5a2e9488..a49bc5519cf 100644 --- a/src/go/types/index.go +++ b/src/go/types/index.go @@ -33,7 +33,7 @@ func (check *Checker) indexExpr(x *operand, e *typeparams.IndexExpr) (isFuncInst return false case value: - if sig := asSignature(x.typ); sig != nil && len(sig.tparams) > 0 { + if sig := asSignature(x.typ); sig != nil && sig.TParams().Len() > 0 { // function instantiation return true } diff --git a/src/go/types/instance.go b/src/go/types/instance.go index 9d31b42690a..7e158ea3521 100644 --- a/src/go/types/instance.go +++ b/src/go/types/instance.go @@ -24,7 +24,7 @@ type instance struct { func (n *Named) complete() { if n.instance != nil && len(n.targs) > 0 && n.underlying == nil { check := n.instance.check - inst := check.instantiate(n.instance.pos, n.orig.underlying, n.tparams, n.targs, n.instance.posList) + inst := check.instantiate(n.instance.pos, n.orig.underlying, n.TParams().list(), n.targs, n.instance.posList) n.underlying = inst n.fromRHS = inst n.methods = n.orig.methods diff --git a/src/go/types/instantiate.go b/src/go/types/instantiate.go index 14bbf2b12b1..7e2f3173c3f 100644 --- a/src/go/types/instantiate.go +++ b/src/go/types/instantiate.go @@ -28,9 +28,9 @@ func (check *Checker) Instantiate(pos token.Pos, typ Type, targs []Type, posList var tparams []*TypeName switch t := typ.(type) { case *Named: - tparams = t.TParams() + tparams = t.TParams().list() case *Signature: - tparams = t.tparams + tparams = t.TParams().list() defer func() { // If we had an unexpected failure somewhere don't panic below when // asserting res.(*Signature). Check for *Signature in case Typ[Invalid] @@ -109,9 +109,9 @@ func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type, pos if base == nil { panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) } - if verify && len(base.tparams) == len(targs) { + if verify && base.TParams().Len() == len(targs) { check.later(func() { - check.verify(pos, base.tparams, targs, posList) + check.verify(pos, base.tparams.list(), targs, posList) }) } h := instantiatedHash(base, targs) @@ -122,7 +122,7 @@ func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type, pos } tname := NewTypeName(pos, base.obj.pkg, base.obj.name, nil) - named := check.newNamed(tname, base, nil, base.tparams, base.methods) // methods are instantiated lazily + named := check.newNamed(tname, base, nil, base.TParams(), base.methods) // methods are instantiated lazily named.targs = targs named.instance = &instance{ check: check, diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go index 304ae6e3c90..8b1d70a9784 100644 --- a/src/go/types/lookup.go +++ b/src/go/types/lookup.go @@ -317,10 +317,10 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // both methods must have the same number of type parameters ftyp := f.typ.(*Signature) mtyp := m.typ.(*Signature) - if len(ftyp.tparams) != len(mtyp.tparams) { + if ftyp.TParams().Len() != mtyp.TParams().Len() { return m, f } - if len(ftyp.tparams) > 0 { + if ftyp.TParams().Len() > 0 { panic("internal error: method with type parameters") } @@ -330,7 +330,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // TODO(gri) is this always correct? what about type bounds? // (Alternative is to rename/subst type parameters and compare.) u := newUnifier(true) - u.x.init(ftyp.tparams) + u.x.init(ftyp.TParams().list()) if !u.unify(ftyp, mtyp) { return m, f } @@ -373,10 +373,10 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // both methods must have the same number of type parameters ftyp := f.typ.(*Signature) mtyp := m.typ.(*Signature) - if len(ftyp.tparams) != len(mtyp.tparams) { + if ftyp.TParams().Len() != mtyp.TParams().Len() { return m, f } - if len(ftyp.tparams) > 0 { + if ftyp.TParams().Len() > 0 { panic("internal error: method with type parameters") } @@ -387,17 +387,17 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // In order to compare the signatures, substitute the receiver // type parameters of ftyp with V's instantiation type arguments. // This lazily instantiates the signature of method f. - if Vn != nil && len(Vn.TParams()) > 0 { + if Vn != nil && Vn.TParams().Len() > 0 { // Be careful: The number of type arguments may not match // the number of receiver parameters. If so, an error was // reported earlier but the length discrepancy is still // here. Exit early in this case to prevent an assertion // failure in makeSubstMap. // TODO(gri) Can we avoid this check by fixing the lengths? - if len(ftyp.rparams) != len(Vn.targs) { + if len(ftyp.RParams().list()) != len(Vn.targs) { return } - ftyp = check.subst(token.NoPos, ftyp, makeSubstMap(ftyp.rparams, Vn.targs)).(*Signature) + ftyp = check.subst(token.NoPos, ftyp, makeSubstMap(ftyp.RParams().list(), Vn.targs)).(*Signature) } // If the methods have type parameters we don't care whether they @@ -406,7 +406,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // TODO(gri) is this always correct? what about type bounds? // (Alternative is to rename/subst type parameters and compare.) u := newUnifier(true) - u.x.init(ftyp.rparams) + u.x.init(ftyp.RParams().list()) if !u.unify(ftyp, mtyp) { return m, f } diff --git a/src/go/types/named.go b/src/go/types/named.go index a500f5663ba..03af3fbc5aa 100644 --- a/src/go/types/named.go +++ b/src/go/types/named.go @@ -16,7 +16,7 @@ type Named struct { orig *Named // original, uninstantiated type fromRHS Type // type (on RHS of declaration) this *Named type is derived of (for cycle reporting) underlying Type // possibly a *Named during setup; never a *Named once set up completely - tparams []*TypeName // type parameters, or nil + tparams *TypeParams // type parameters, or nil targs []Type // type arguments (after instantiation), or nil methods []*Func // methods declared for this type (not the method set of this type); signatures are type-checked lazily @@ -56,7 +56,7 @@ func (t *Named) expand() *Named { panic("invalid underlying type") } - t.tparams = tparams + t.tparams = bindTParams(tparams) t.underlying = underlying t.methods = methods }) @@ -64,7 +64,7 @@ func (t *Named) expand() *Named { } // newNamed is like NewNamed but with a *Checker receiver and additional orig argument. -func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams []*TypeName, methods []*Func) *Named { +func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams *TypeParams, methods []*Func) *Named { var inst *instance if check != nil { inst = &instance{ @@ -108,14 +108,14 @@ func (t *Named) _Orig() *Named { return t.orig } // TODO(gri) Come up with a better representation and API to distinguish // between parameterized instantiated and non-instantiated types. -// _TParams returns the type parameters of the named type t, or nil. +// TParams returns the type parameters of the named type t, or nil. // The result is non-nil for an (originally) parameterized type even if it is instantiated. -func (t *Named) TParams() []*TypeName { return t.expand().tparams } +func (t *Named) TParams() *TypeParams { return t.expand().tparams } -// _SetTParams sets the type parameters of the named type t. -func (t *Named) SetTParams(tparams []*TypeName) { t.expand().tparams = tparams } +// SetTParams sets the type parameters of the named type t. +func (t *Named) SetTParams(tparams []*TypeName) { t.expand().tparams = bindTParams(tparams) } -// _TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated. +// TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated. func (t *Named) TArgs() []Type { return t.targs } // SetTArgs sets the type arguments of the named type t. diff --git a/src/go/types/object.go b/src/go/types/object.go index 4ea2837ea7c..7266623fbe9 100644 --- a/src/go/types/object.go +++ b/src/go/types/object.go @@ -429,8 +429,8 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) { if _, ok := typ.(*Basic); ok { return } - if named, _ := typ.(*Named); named != nil && len(named.tparams) > 0 { - writeTParamList(buf, named.tparams, qf, nil) + if named, _ := typ.(*Named); named != nil && named.TParams().Len() > 0 { + writeTParamList(buf, named.TParams().list(), qf, nil) } if tname.IsAlias() { buf.WriteString(" =") diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index ce350f4470d..181e2fcfc54 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -242,7 +242,7 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { // parameter names. if y, ok := y.(*Signature); ok { return x.variadic == y.variadic && - identicalTParams(x.tparams, y.tparams, cmpTags, p) && + identicalTParams(x.TParams().list(), y.TParams().list(), cmpTags, p) && identical(x.params, y.params, cmpTags, p) && identical(x.results, y.results, cmpTags, p) } diff --git a/src/go/types/signature.go b/src/go/types/signature.go index da01ec801a5..5a69bb17b57 100644 --- a/src/go/types/signature.go +++ b/src/go/types/signature.go @@ -21,8 +21,8 @@ type Signature struct { // and store it in the Func Object) because when type-checking a function // literal we call the general type checker which returns a general Type. // We then unpack the *Signature and use the scope for the literal body. - rparams []*TypeName // receiver type parameters from left to right, or nil - tparams []*TypeName // type parameters from left to right, or nil + rparams *TypeParams // receiver type parameters from left to right, or nil + tparams *TypeParams // type parameters from left to right, or nil scope *Scope // function scope, present for package-local signatures recv *Var // nil if not a method params *Tuple // (incoming) parameters from left to right; or nil @@ -56,13 +56,16 @@ func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature { func (s *Signature) Recv() *Var { return s.recv } // TParams returns the type parameters of signature s, or nil. -func (s *Signature) TParams() []*TypeName { return s.tparams } +func (s *Signature) TParams() *TypeParams { return s.tparams } // SetTParams sets the type parameters of signature s. -func (s *Signature) SetTParams(tparams []*TypeName) { s.tparams = tparams } +func (s *Signature) SetTParams(tparams []*TypeName) { s.tparams = bindTParams(tparams) } + +// RParams returns the receiver type parameters of signature s, or nil. +func (s *Signature) RParams() *TypeParams { return s.rparams } // SetRParams sets the receiver type params of signature s. -func (s *Signature) SetRParams(rparams []*TypeName) { s.rparams = rparams } +func (s *Signature) SetRParams(rparams []*TypeName) { s.rparams = bindTParams(rparams) } // Params returns the parameters of signature s, or nil. func (s *Signature) Params() *Tuple { return s.params } @@ -115,7 +118,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast // blank identifiers were found => use rewritten receiver type recvTyp = isubst(recvPar.List[0].Type, smap) } - sig.rparams = check.declareTypeParams(nil, rparams) + sig.rparams = bindTParams(check.declareTypeParams(nil, rparams)) // determine receiver type to get its type parameters // and the respective type parameter bounds var recvTParams []*TypeName @@ -125,19 +128,19 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast // again when we type-check the signature. // TODO(gri) maybe the receiver should be marked as invalid instead? if recv := asNamed(check.genericType(rname, false)); recv != nil { - recvTParams = recv.TParams() + recvTParams = recv.TParams().list() } } // provide type parameter bounds // - only do this if we have the right number (otherwise an error is reported elsewhere) - if len(sig.rparams) == len(recvTParams) { + if sig.RParams().Len() == len(recvTParams) { // We have a list of *TypeNames but we need a list of Types. - list := make([]Type, len(sig.rparams)) - for i, t := range sig.rparams { + list := make([]Type, sig.RParams().Len()) + for i, t := range sig.RParams().list() { list[i] = t.typ } smap := makeSubstMap(recvTParams, list) - for i, tname := range sig.rparams { + for i, tname := range sig.RParams().list() { bound := recvTParams[i].typ.(*TypeParam).bound // bound is (possibly) parameterized in the context of the // receiver type declaration. Substitute parameters for the diff --git a/src/go/types/sizeof_test.go b/src/go/types/sizeof_test.go index fc548f7c589..29e298103bf 100644 --- a/src/go/types/sizeof_test.go +++ b/src/go/types/sizeof_test.go @@ -25,12 +25,12 @@ func TestSizeof(t *testing.T) { {Struct{}, 24, 48}, {Pointer{}, 8, 16}, {Tuple{}, 12, 24}, - {Signature{}, 44, 88}, + {Signature{}, 28, 56}, {Union{}, 24, 48}, {Interface{}, 40, 80}, {Map{}, 16, 32}, {Chan{}, 12, 24}, - {Named{}, 84, 160}, + {Named{}, 76, 144}, {TypeParam{}, 28, 48}, {top{}, 0, 0}, diff --git a/src/go/types/subst.go b/src/go/types/subst.go index 42be508cd91..197d79b6a8d 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -203,7 +203,7 @@ func (subst *subster) typ(typ Type) Type { if len(t.targs) > 0 { // already instantiated dump(">>> %s already instantiated", t) - assert(len(t.targs) == len(t.TParams())) + assert(len(t.targs) == t.TParams().Len()) // For each (existing) type argument targ, determine if it needs // to be substituted; i.e., if it is or contains a type parameter // that has a type argument for it. @@ -213,7 +213,7 @@ func (subst *subster) typ(typ Type) Type { if newTarg != targ { dump(">>> substituted %d targ %s => %s", i, targ, newTarg) if newTargs == nil { - newTargs = make([]Type, len(t.TParams())) + newTargs = make([]Type, t.TParams().Len()) copy(newTargs, t.targs) } newTargs[i] = newTarg diff --git a/src/go/types/typeparam.go b/src/go/types/typeparam.go index bb5b28cdf87..8c18b52a9a9 100644 --- a/src/go/types/typeparam.go +++ b/src/go/types/typeparam.go @@ -28,15 +28,19 @@ type TypeParam struct { bound Type // *Named or *Interface; underlying type is always *Interface } -// NewTypeParam returns a new TypeParam. bound can be nil (and set later). -func (check *Checker) NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam { +// NewTypeParam returns a new TypeParam. Type parameters may be set on a Named +// or Signature type by calling SetTParams. Setting a type parameter on more +// than one type will result in a panic. +// +// The bound argument can be nil, and set later via SetBound. +func (check *Checker) NewTypeParam(obj *TypeName, bound Type) *TypeParam { // Always increment lastID, even if it is not used. id := nextID() if check != nil { check.nextID++ id = check.nextID } - typ := &TypeParam{check: check, id: id, obj: obj, index: index, bound: bound} + typ := &TypeParam{check: check, id: id, obj: obj, index: -1, bound: bound} if obj.typ == nil { obj.typ = typ } @@ -56,6 +60,8 @@ func (t *TypeParam) _SetId(id uint64) { t.id = id } +// TODO(rfindley): document the Bound and SetBound methods. + func (t *TypeParam) Bound() *Interface { // we may not have an interface (error reported elsewhere) iface, _ := under(t.bound).(*Interface) @@ -72,7 +78,7 @@ func (t *TypeParam) Bound() *Interface { return iface } -func (t *TypeParam) _SetBound(bound Type) { +func (t *TypeParam) SetBound(bound Type) { if bound == nil { panic("internal error: bound must not be nil") } @@ -82,6 +88,42 @@ func (t *TypeParam) _SetBound(bound Type) { func (t *TypeParam) Underlying() Type { return t } func (t *TypeParam) String() string { return TypeString(t, nil) } +// TypeParams holds a list of type parameters bound to a type. +type TypeParams struct{ tparams []*TypeName } + +// Len returns the number of type parameters in the list. +// It is safe to call on a nil receiver. +func (tps *TypeParams) Len() int { + return len(tps.list()) +} + +// At returns the i'th type parameter in the list. +// It is safe to call on a nil receiver. +func (tps *TypeParams) At(i int) *TypeName { + return tps.list()[i] +} + +func (tps *TypeParams) list() []*TypeName { + if tps == nil { + return nil + } + return tps.tparams +} + +func bindTParams(list []*TypeName) *TypeParams { + if len(list) == 0 { + return nil + } + for i, tp := range list { + typ := tp.Type().(*TypeParam) + if typ.index >= 0 { + panic("internal error: type parameter bound more than once") + } + typ.index = i + } + return &TypeParams{tparams: list} +} + // ---------------------------------------------------------------------------- // Implementation diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go index ef3808230ad..18c436e3efb 100644 --- a/src/go/types/typestring.go +++ b/src/go/types/typestring.go @@ -278,7 +278,7 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { buf.WriteByte(']') } else if t.TParams() != nil { // parameterized type - writeTParamList(buf, t.TParams(), qf, visited) + writeTParamList(buf, t.TParams().list(), qf, visited) } case *TypeParam: @@ -425,7 +425,7 @@ func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) { func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) { if sig.tparams != nil { - writeTParamList(buf, sig.tparams, qf, visited) + writeTParamList(buf, sig.TParams().list(), qf, visited) } writeTuple(buf, sig.params, sig.variadic, qf, visited) From 5ba06495c1ab2c0e7f6e25260d1f92b5008c380e Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Wed, 21 Jul 2021 11:26:00 -0400 Subject: [PATCH 763/940] [dev.typeparams] go/types: use the TParams API consistently Even internally to the type checker, we should use the TParams and RParams methods instead of accessing fields directly, as TParams may be lazily expanded, and in the future we may want to pack receiver and function type parameters into a single field on Signature. We should also not differentiate a nil *TParamList from an empty *TParamList. Change-Id: I85c616e6c708a89b6a5eb1e69fe0b014276eda90 Reviewed-on: https://go-review.googlesource.com/c/go/+/336251 Trust: Robert Findley Run-TryBot: Robert Findley Reviewed-by: Robert Griesemer --- src/go/types/call.go | 4 ++-- src/go/types/decl.go | 2 +- src/go/types/subst.go | 2 +- src/go/types/typestring.go | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/go/types/call.go b/src/go/types/call.go index 96d0429af95..16b8e4eb7c4 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -61,7 +61,7 @@ func (check *Checker) funcInst(x *operand, ix *typeparams.IndexExpr) { // instantiate function signature res := check.Instantiate(x.Pos(), sig, targs, poslist, true).(*Signature) - assert(res.tparams == nil) // signature is not generic anymore + assert(res.TParams().Len() == 0) // signature is not generic anymore if inferred { check.recordInferred(ix.Orig, targs, res) } @@ -334,7 +334,7 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, targs []Type // compute result signature rsig = check.Instantiate(call.Pos(), sig, targs, nil, true).(*Signature) - assert(rsig.tparams == nil) // signature is not generic anymore + assert(rsig.TParams().Len() == 0) // signature is not generic anymore check.recordInferred(call, targs, rsig) // Optimization: Only if the parameter list was adjusted do we diff --git a/src/go/types/decl.go b/src/go/types/decl.go index be7753d9d18..ad88c302820 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -625,7 +625,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) { named.underlying = under(named) // If the RHS is a type parameter, it must be from this type declaration. - if tpar, _ := named.underlying.(*TypeParam); tpar != nil && tparamIndex(named.tparams.list(), tpar) < 0 { + if tpar, _ := named.underlying.(*TypeParam); tpar != nil && tparamIndex(named.TParams().list(), tpar) < 0 { check.errorf(tdecl.Type, _Todo, "cannot use function type parameter %s as RHS in type declaration", tpar) named.underlying = Typ[Invalid] } diff --git a/src/go/types/subst.go b/src/go/types/subst.go index 197d79b6a8d..60fc7ae8192 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -193,7 +193,7 @@ func (subst *subster) typ(typ Type) Type { } } - if t.TParams() == nil { + if t.TParams().Len() == 0 { dump(">>> %s is not parameterized", t) return t // type is not parameterized } diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go index 18c436e3efb..6a9e7f2ac89 100644 --- a/src/go/types/typestring.go +++ b/src/go/types/typestring.go @@ -276,7 +276,7 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { buf.WriteByte('[') writeTypeList(buf, t.targs, qf, visited) buf.WriteByte(']') - } else if t.TParams() != nil { + } else if t.TParams().Len() != 0 { // parameterized type writeTParamList(buf, t.TParams().list(), qf, visited) } @@ -424,7 +424,7 @@ func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) { } func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) { - if sig.tparams != nil { + if sig.TParams().Len() != 0 { writeTParamList(buf, sig.TParams().list(), qf, visited) } From fca3e5c4452e8dac6c7ae028dcccc323e1d57ed5 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Thu, 22 Jul 2021 23:54:19 +0700 Subject: [PATCH 764/940] [dev.typeparams] cmd/compile: fix missing condition in usemethod CL 330670 simplified usemethod, but dropped the previous condition to ensure the function have 1 or 2 result. This CL restore that condition, and also add a test for it. Change-Id: I434e3736785b43ceea0b386d8d9d01ad78a4ccd2 Reviewed-on: https://go-review.googlesource.com/c/go/+/336609 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/walk/expr.go | 9 ++++++++- test/reflectmethod8.go | 26 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 test/reflectmethod8.go diff --git a/src/cmd/compile/internal/walk/expr.go b/src/cmd/compile/internal/walk/expr.go index 19fb1885264..eed6ef86c23 100644 --- a/src/cmd/compile/internal/walk/expr.go +++ b/src/cmd/compile/internal/walk/expr.go @@ -957,7 +957,14 @@ func usemethod(n *ir.CallExpr) { if t.NumParams() != 1 || t.Params().Field(0).Type.Kind() != pKind { return } - if t.NumResults() == 2 && t.Results().Field(1).Type.Kind() != types.TBOOL { + switch t.NumResults() { + case 1: + // ok + case 2: + if t.Results().Field(1).Type.Kind() != types.TBOOL { + return + } + default: return } diff --git a/test/reflectmethod8.go b/test/reflectmethod8.go new file mode 100644 index 00000000000..482163bae6f --- /dev/null +++ b/test/reflectmethod8.go @@ -0,0 +1,26 @@ +// compile + +// Copyright 2021 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. + +// Make sure that the compiler can analyze non-reflect +// Type.{Method,MethodByName} calls. + +package p + +type I interface { + MethodByName(string) + Method(int) +} + +type M struct{} + +func (M) MethodByName(string) {} +func (M) Method(int) {} + +func f() { + var m M + I.MethodByName(m, "") + I.Method(m, 42) +} From 80127a7dfe6951fb16d2b67dbe9badb5952e3a2f Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Sun, 18 Jul 2021 15:51:31 -0700 Subject: [PATCH 765/940] [dev.typeparams] cmd/compile/internal/types2: adjust unsafe.Alignof/Offsetof/Sizeof Changed the implementation such that the result is a variable rather than a constant if the argument type (or the struct in case of unsafe.Offsetof) has a size that depends on type parameters. Minor unrelated adjustments. For #40301. Change-Id: I1e988f1479b95648ad95a455c764ead829d75749 Reviewed-on: https://go-review.googlesource.com/c/go/+/335413 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/builtins.go | 73 ++++++++---- .../compile/internal/types2/builtins_test.go | 13 ++- src/cmd/compile/internal/types2/infer.go | 4 +- src/cmd/compile/internal/types2/sizes.go | 10 +- .../types2/testdata/check/builtins.go2 | 107 ++++++++++++++++++ .../types2/testdata/fixedbugs/issue40301.go2 | 4 +- 6 files changed, 182 insertions(+), 29 deletions(-) diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index 14be24e2514..2af2679d5ed 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -624,19 +624,22 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( case _Alignof: // unsafe.Alignof(x T) uintptr - if asTypeParam(x.typ) != nil { - check.errorf(call, invalidOp+"unsafe.Alignof undefined for %s", x) - return - } check.assignment(x, nil, "argument to unsafe.Alignof") if x.mode == invalid { return } - x.mode = constant_ - x.val = constant.MakeInt64(check.conf.alignof(x.typ)) + if hasVarSize(x.typ) { + x.mode = value + if check.Types != nil { + check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], x.typ)) + } + } else { + x.mode = constant_ + x.val = constant.MakeInt64(check.conf.alignof(x.typ)) + // result is constant - no need to record signature + } x.typ = Typ[Uintptr] - // result is constant - no need to record signature case _Offsetof: // unsafe.Offsetof(x T) uintptr, where x must be a selector @@ -674,30 +677,43 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( return } - // TODO(gri) Should we pass x.typ instead of base (and indirect report if derefStructPtr indirected)? + // TODO(gri) Should we pass x.typ instead of base (and have indirect report if derefStructPtr indirected)? check.recordSelection(selx, FieldVal, base, obj, index, false) - offs := check.conf.offsetof(base, index) - x.mode = constant_ - x.val = constant.MakeInt64(offs) + // The field offset is considered a variable even if the field is declared before + // the part of the struct which is variable-sized. This makes both the rules + // simpler and also permits (or at least doesn't prevent) a compiler from re- + // arranging struct fields if it wanted to. + if hasVarSize(base) { + x.mode = value + if check.Types != nil { + check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], obj.Type())) + } + } else { + x.mode = constant_ + x.val = constant.MakeInt64(check.conf.offsetof(base, index)) + // result is constant - no need to record signature + } x.typ = Typ[Uintptr] - // result is constant - no need to record signature case _Sizeof: // unsafe.Sizeof(x T) uintptr - if asTypeParam(x.typ) != nil { - check.errorf(call, invalidOp+"unsafe.Sizeof undefined for %s", x) - return - } check.assignment(x, nil, "argument to unsafe.Sizeof") if x.mode == invalid { return } - x.mode = constant_ - x.val = constant.MakeInt64(check.conf.sizeof(x.typ)) + if hasVarSize(x.typ) { + x.mode = value + if check.Types != nil { + check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], x.typ)) + } + } else { + x.mode = constant_ + x.val = constant.MakeInt64(check.conf.sizeof(x.typ)) + // result is constant - no need to record signature + } x.typ = Typ[Uintptr] - // result is constant - no need to record signature case _Slice: // unsafe.Slice(ptr *T, len IntegerType) []T @@ -769,6 +785,25 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( return true } +// hasVarSize reports if the size of type t is variable due to type parameters. +func hasVarSize(t Type) bool { + switch t := under(t).(type) { + case *Array: + return hasVarSize(t.elem) + case *Struct: + for _, f := range t.fields { + if hasVarSize(f.typ) { + return true + } + } + case *TypeParam: + return true + case *Named, *Union, *instance, *top: + unreachable() + } + return false +} + // applyTypeFunc applies f to x. If x is a type parameter, // the result is a type parameter constrained by an new // interface bound. The type bounds for that interface diff --git a/src/cmd/compile/internal/types2/builtins_test.go b/src/cmd/compile/internal/types2/builtins_test.go index 82c786b86ea..52dbba1cb98 100644 --- a/src/cmd/compile/internal/types2/builtins_test.go +++ b/src/cmd/compile/internal/types2/builtins_test.go @@ -7,6 +7,7 @@ package types2_test import ( "cmd/compile/internal/syntax" "fmt" + "strings" "testing" . "cmd/compile/internal/types2" @@ -111,12 +112,15 @@ var builtinCalls = []struct { {"Alignof", `_ = unsafe.Alignof(0)`, `invalid type`}, // constant {"Alignof", `var x struct{}; _ = unsafe.Alignof(x)`, `invalid type`}, // constant + {"Alignof", `var x P; _ = unsafe.Alignof(x)`, `func(p.P₁) uintptr`}, {"Offsetof", `var x struct{f bool}; _ = unsafe.Offsetof(x.f)`, `invalid type`}, // constant {"Offsetof", `var x struct{_ int; f bool}; _ = unsafe.Offsetof((&x).f)`, `invalid type`}, // constant + {"Offsetof", `var x struct{_ int; f P}; _ = unsafe.Offsetof((&x).f)`, `func(p.P₁) uintptr`}, {"Sizeof", `_ = unsafe.Sizeof(0)`, `invalid type`}, // constant {"Sizeof", `var x struct{}; _ = unsafe.Sizeof(x)`, `invalid type`}, // constant + {"Sizeof", `var x P; _ = unsafe.Sizeof(x)`, `func(p.P₁) uintptr`}, {"Slice", `var p *int; _ = unsafe.Slice(p, 1)`, `func(*int, int) []int`}, {"Slice", `var p *byte; var n uintptr; _ = unsafe.Slice(p, n)`, `func(*byte, uintptr) []byte`}, @@ -149,9 +153,14 @@ func TestBuiltinSignatures(t *testing.T) { } } +func parseGenericSrc(path, src string) (*syntax.File, error) { + errh := func(error) {} // dummy error handler so that parsing continues in presence of errors + return syntax.Parse(syntax.NewFileBase(path), strings.NewReader(src), errh, nil, syntax.AllowGenerics) +} + func testBuiltinSignature(t *testing.T, name, src0, want string) { - src := fmt.Sprintf(`package p; import "unsafe"; type _ unsafe.Pointer /* use unsafe */; func _() { %s }`, src0) - f, err := parseSrc("", src) + src := fmt.Sprintf(`package p; import "unsafe"; type _ unsafe.Pointer /* use unsafe */; func _[P any]() { %s }`, src0) + f, err := parseGenericSrc("", src) if err != nil { t.Errorf("%s: %s", src0, err) return diff --git a/src/cmd/compile/internal/types2/infer.go b/src/cmd/compile/internal/types2/infer.go index e5d94e44d97..b44ff7377a4 100644 --- a/src/cmd/compile/internal/types2/infer.go +++ b/src/cmd/compile/internal/types2/infer.go @@ -401,8 +401,8 @@ func (check *Checker) inferB(tparams []*TypeName, targs []Type, report bool) (ty // u.x.types() now contains the incoming type arguments plus any additional type // arguments for which there were structural constraints. The newly inferred non- - // nil entries may still contain references to other type parameters. For instance, - // for [A any, B interface{type []C}, C interface{type *A}], if A == int + // nil entries may still contain references to other type parameters. + // For instance, for [A any, B interface{ []C }, C interface{ *A }], if A == int // was given, unification produced the type list [int, []C, *A]. We eliminate the // remaining type parameters by substituting the type parameters in this type list // until nothing changes anymore. diff --git a/src/cmd/compile/internal/types2/sizes.go b/src/cmd/compile/internal/types2/sizes.go index cb789598e57..6a3d19d8eaf 100644 --- a/src/cmd/compile/internal/types2/sizes.go +++ b/src/cmd/compile/internal/types2/sizes.go @@ -48,7 +48,7 @@ type StdSizes struct { func (s *StdSizes) Alignof(T Type) int64 { // For arrays and structs, alignment is defined in terms // of alignment of the elements and fields, respectively. - switch t := optype(T).(type) { + switch t := under(T).(type) { case *Array: // spec: "For a variable x of array type: unsafe.Alignof(x) // is the same as unsafe.Alignof(x[0]), but at least 1." @@ -73,6 +73,8 @@ func (s *StdSizes) Alignof(T Type) int64 { if t.Info()&IsString != 0 { return s.WordSize } + case *TypeParam, *Union: + unreachable() } a := s.Sizeof(T) // may be 0 // spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1." @@ -118,7 +120,7 @@ var basicSizes = [...]byte{ } func (s *StdSizes) Sizeof(T Type) int64 { - switch t := optype(T).(type) { + switch t := under(T).(type) { case *Basic: assert(isTyped(T)) k := t.kind @@ -148,10 +150,10 @@ func (s *StdSizes) Sizeof(T Type) int64 { } offsets := s.Offsetsof(t.fields) return offsets[n-1] + s.Sizeof(t.fields[n-1].typ) - case *Union: - panic("Sizeof unimplemented for union") case *Interface: return s.WordSize * 2 + case *TypeParam, *Union: + unreachable() } return s.WordSize // catch-all } diff --git a/src/cmd/compile/internal/types2/testdata/check/builtins.go2 b/src/cmd/compile/internal/types2/testdata/check/builtins.go2 index 8fe6d7b332e..3881090603e 100644 --- a/src/cmd/compile/internal/types2/testdata/check/builtins.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/builtins.go2 @@ -6,6 +6,8 @@ package builtins +import "unsafe" + // close type C0 interface{ int } @@ -127,3 +129,108 @@ func _[T Bss]() { _ = make(T, 10) _ = make(T, 10, 20) } + +// unsafe.Alignof + +func _[T comparable]() { + var ( + b int64 + a [10]T + s struct{ f T } + p *T + l []T + f func(T) + i interface{ m() T } + c chan T + m map[T]T + t T + ) + + const bb = unsafe.Alignof(b) + assert(bb == 8) + const _ = unsafe /* ERROR not constant */ .Alignof(a) + const _ = unsafe /* ERROR not constant */ .Alignof(s) + const pp = unsafe.Alignof(p) + assert(pp == 8) + const ll = unsafe.Alignof(l) + assert(ll == 8) + const ff = unsafe.Alignof(f) + assert(ff == 8) + const ii = unsafe.Alignof(i) + assert(ii == 8) + const cc = unsafe.Alignof(c) + assert(cc == 8) + const mm = unsafe.Alignof(m) + assert(mm == 8) + const _ = unsafe /* ERROR not constant */ .Alignof(t) +} + +// unsafe.Offsetof + +func _[T comparable]() { + var ( + b struct{ _, f int64 } + a struct{ _, f [10]T } + s struct{ _, f struct{ f T } } + p struct{ _, f *T } + l struct{ _, f []T } + f struct{ _, f func(T) } + i struct{ _, f interface{ m() T } } + c struct{ _, f chan T } + m struct{ _, f map[T]T } + t struct{ _, f T } + ) + + const bb = unsafe.Offsetof(b.f) + assert(bb == 8) + const _ = unsafe /* ERROR not constant */ .Alignof(a) + const _ = unsafe /* ERROR not constant */ .Alignof(s) + const pp = unsafe.Offsetof(p.f) + assert(pp == 8) + const ll = unsafe.Offsetof(l.f) + assert(ll == 24) + const ff = unsafe.Offsetof(f.f) + assert(ff == 8) + const ii = unsafe.Offsetof(i.f) + assert(ii == 16) + const cc = unsafe.Offsetof(c.f) + assert(cc == 8) + const mm = unsafe.Offsetof(m.f) + assert(mm == 8) + const _ = unsafe /* ERROR not constant */ .Alignof(t) +} + +// unsafe.Sizeof + +func _[T comparable]() { + var ( + b int64 + a [10]T + s struct{ f T } + p *T + l []T + f func(T) + i interface{ m() T } + c chan T + m map[T]T + t T + ) + + const bb = unsafe.Sizeof(b) + assert(bb == 8) + const _ = unsafe /* ERROR not constant */ .Alignof(a) + const _ = unsafe /* ERROR not constant */ .Alignof(s) + const pp = unsafe.Sizeof(p) + assert(pp == 8) + const ll = unsafe.Sizeof(l) + assert(ll == 24) + const ff = unsafe.Sizeof(f) + assert(ff == 8) + const ii = unsafe.Sizeof(i) + assert(ii == 16) + const cc = unsafe.Sizeof(c) + assert(cc == 8) + const mm = unsafe.Sizeof(m) + assert(mm == 8) + const _ = unsafe /* ERROR not constant */ .Alignof(t) +} diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40301.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40301.go2 index 5d97855f8a1..c78f9a1fa04 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40301.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40301.go2 @@ -7,6 +7,6 @@ package p import "unsafe" func _[T any](x T) { - _ = unsafe /* ERROR undefined */ .Alignof(x) - _ = unsafe /* ERROR undefined */ .Sizeof(x) + _ = unsafe.Alignof(x) + _ = unsafe.Sizeof(x) } From 73162a54c2885d32d40067d2e4fbe26bbe5c7d65 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Fri, 23 Jul 2021 00:24:50 +0700 Subject: [PATCH 766/940] [dev.typeparams] cmd/compile: remove outdate TODO in escape analysis We now understand the root cause of #47227, it will be fixed in #47317. Change-Id: Ifcd44f887a0bd3195818df33e409bd3e818e0b27 Reviewed-on: https://go-review.googlesource.com/c/go/+/336610 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le Reviewed-by: Matthew Dempsky TryBot-Result: Go Bot --- src/cmd/compile/internal/escape/call.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/cmd/compile/internal/escape/call.go b/src/cmd/compile/internal/escape/call.go index 65c76d6870b..9e5abed5914 100644 --- a/src/cmd/compile/internal/escape/call.go +++ b/src/cmd/compile/internal/escape/call.go @@ -320,8 +320,6 @@ func (e *escape) rewriteArgument(argp *ir.Node, init *ir.Nodes, call ir.Node, fn return case ir.ONAME: if arg.(*ir.Name).Class == ir.PFUNC { - // TODO(cuonglm): figure it why this is necessary, we should not depend on this to make - // ABI analyze works correctly (see #47227 and discussion in CL 334882). return } } From 5cb84f0604797df436d8fde548d4f797b3a6c245 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Wed, 21 Jul 2021 19:17:20 -0700 Subject: [PATCH 767/940] [dev.typeparams] cmd/compile: make sure types added to the dictionary are instantiated correctly Make sure the instantiating types are the type parameters of the containing function (or types derived from those). The one exception is the argument of a OFUNCINST, whose type parameters are those of the declaration site of the function or method being instantiated. We skip those types. Change-Id: I4b3ff22eb8a81a76476930cf8ed2a7dd6489d8b8 Reviewed-on: https://go-review.googlesource.com/c/go/+/336352 Trust: Keith Randall Trust: Dan Scales Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/noder/stencil.go | 31 ++++++++++++++++++----- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 71edc82deab..59f11bbe237 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -22,6 +22,9 @@ import ( "strconv" ) +// Enable extra consistency checks. +const doubleCheck = true + func assert(p bool) { base.Assert(p) } @@ -1820,7 +1823,6 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo { ir.Visit(n1, visitFunc) } } - addType(&info, n, n.Type()) } @@ -1847,9 +1849,17 @@ func addType(info *gfInfo, n ir.Node, t *types.Type) { if t.IsTypeParam() && t.Underlying() == t { return } - if !parameterizedBy(t, info.tparams) { + if t.Kind() == types.TFUNC && n != nil && + (t.Recv() != nil || + n.Op() == ir.ONAME && n.Name().Class == ir.PFUNC) { + // Don't use the type of a named generic function or method, + // since that is parameterized by other typeparams. + // (They all come from arguments of a FUNCINST node.) return } + if doubleCheck && !parameterizedBy(t, info.tparams) { + base.Fatalf("adding type with invalid parameters %+v", t) + } if t.Kind() == types.TSTRUCT && t.IsFuncArgStruct() { // Multiple return values are not a relevant new type (?). return @@ -1872,13 +1882,25 @@ func parameterizedBy1(t *types.Type, params []*types.Type, visited map[*types.Ty return true } visited[t] = true + + if t.Sym() != nil && len(t.RParams()) > 0 { + // This defined type is instantiated. Check the instantiating types. + for _, r := range t.RParams() { + if !parameterizedBy1(r, params, visited) { + return false + } + } + return true + } switch t.Kind() { case types.TTYPEPARAM: + // Check if t is one of the allowed parameters in scope. for _, p := range params { if p == t { return true } } + // Couldn't find t in the list of allowed parameters. return false case types.TARRAY, types.TPTR, types.TSLICE, types.TCHAN: @@ -1888,10 +1910,7 @@ func parameterizedBy1(t *types.Type, params []*types.Type, visited map[*types.Ty return parameterizedBy1(t.Key(), params, visited) && parameterizedBy1(t.Elem(), params, visited) case types.TFUNC: - if t.NumTParams() > 0 { - return false - } - return parameterizedBy1(t.Recvs(), params, visited) && parameterizedBy1(t.Params(), params, visited) && parameterizedBy1(t.Results(), params, visited) + return parameterizedBy1(t.TParams(), params, visited) && parameterizedBy1(t.Recvs(), params, visited) && parameterizedBy1(t.Params(), params, visited) && parameterizedBy1(t.Results(), params, visited) case types.TSTRUCT: for _, f := range t.Fields().Slice() { From 798ec73519a7226d6d436e42498a54aed23b8468 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 21 Jul 2021 19:57:56 -0700 Subject: [PATCH 768/940] runtime: don't clear timerModifiedEarliest if adjustTimers is 0 This avoids a race when a new timerModifiedEarlier timer is created by a different goroutine. Fixes #47329 Change-Id: I6f6c87b4a9b5491b201c725c10bc98e23e0ed9d1 Reviewed-on: https://go-review.googlesource.com/c/go/+/336432 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/runtime/runtime2.go | 2 +- src/runtime/time.go | 5 ----- src/time/sleep_test.go | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index 2a66826f34b..8a15787382c 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -681,7 +681,7 @@ type p struct { // timerModifiedEarlier status. Because the timer may have been // modified again, there need not be any timer with this value. // This is updated using atomic functions. - // This is 0 if the value is unknown. + // This is 0 if there are no timerModifiedEarlier timers. timerModifiedEarliest uint64 // Per-P GC state diff --git a/src/runtime/time.go b/src/runtime/time.go index dee6a674e4c..7b84d2af571 100644 --- a/src/runtime/time.go +++ b/src/runtime/time.go @@ -668,11 +668,6 @@ func adjusttimers(pp *p, now int64) { if verifyTimers { verifyTimerHeap(pp) } - // There are no timers to adjust, so it is safe to clear - // timerModifiedEarliest. Do so in case it is stale. - // Everything will work if we don't do this, - // but clearing here may save future calls to adjusttimers. - atomic.Store64(&pp.timerModifiedEarliest, 0) return } diff --git a/src/time/sleep_test.go b/src/time/sleep_test.go index 6ee0631a855..e0172bf5e0b 100644 --- a/src/time/sleep_test.go +++ b/src/time/sleep_test.go @@ -527,6 +527,40 @@ func TestZeroTimer(t *testing.T) { } } +// Test that rapidly moving a timer earlier doesn't cause it to get dropped. +// Issue 47329. +func TestTimerModifiedEarlier(t *testing.T) { + past := Until(Unix(0, 0)) + count := 1000 + fail := 0 + for i := 0; i < count; i++ { + timer := NewTimer(Hour) + for j := 0; j < 10; j++ { + if !timer.Stop() { + <-timer.C + } + timer.Reset(past) + } + + deadline := NewTimer(10 * Second) + defer deadline.Stop() + now := Now() + select { + case <-timer.C: + if since := Since(now); since > 8*Second { + t.Errorf("timer took too long (%v)", since) + fail++ + } + case <-deadline.C: + t.Error("deadline expired") + } + } + + if fail > 0 { + t.Errorf("%d failures", fail) + } +} + // Benchmark timer latency when the thread that creates the timer is busy with // other work and the timers must be serviced by other threads. // https://golang.org/issue/38860 From d8ceb133cac65b47c3f5bb292fbb28690c8b89a5 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 21 Jul 2021 11:43:57 -0700 Subject: [PATCH 769/940] [dev.typeparams] runtime: mark TestGcSys as flaky I don't know what this test is doing, but it very frequently flakes for me while testing mundane compiler CLs. According to the issue log, it's been flaky for ~3 years. Updates #37331. Change-Id: I81c43ad646ee12d4c6561290a54e4bf637695bc6 Reviewed-on: https://go-review.googlesource.com/c/go/+/336349 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/runtime/gc_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/runtime/gc_test.go b/src/runtime/gc_test.go index 5e7c6c574fe..0ec53315348 100644 --- a/src/runtime/gc_test.go +++ b/src/runtime/gc_test.go @@ -21,6 +21,7 @@ import ( ) func TestGcSys(t *testing.T) { + t.Skip("skipping known-flaky test; golang.org/issue/37331") if os.Getenv("GOGC") == "off" { t.Skip("skipping test; GOGC=off in environment") } From 052da5717e02659da49707873b3868fe36f2aaf0 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 22 Jul 2021 12:42:09 -0400 Subject: [PATCH 770/940] cmd/compile: do not change field offset in ABI analysis Currently, the ABI analysis assigns parameter/result offsets to the fields of function *Type. In some cases, we may have an ABI0 function reference and an ABIInternal reference share the same function *Type. For example, for an ABI0 function F, "f := F" will make f and (ABI0) F having the same *Type. But f, as a func value, should use ABIInternal. Analyses on F and f will collide and cause ICE. Also, changing field offsets in ABI analysis has to be done very carefully to avoid data races. It has been causing trickiness/difficulty. This CL removes the change of field offsets in ABI analysis altogether. The analysis result is stored in ABIParamAssignment, which is the only way to access parameter/result stack offset now. Fixes #47317. Fixes #47227. Change-Id: I23a3e081a6cf327ac66855da222daaa636ed1ead Reviewed-on: https://go-review.googlesource.com/c/go/+/336629 Trust: Cherry Mui Reviewed-by: Cuong Manh Le Reviewed-by: Than McIntosh --- src/cmd/compile/internal/abi/abiutils.go | 21 +++------------------ src/cmd/compile/internal/ssagen/ssa.go | 11 +++++++---- test/fixedbugs/issue47317.dir/a.s | 6 ++++++ test/fixedbugs/issue47317.dir/x.go | 17 +++++++++++++++++ test/fixedbugs/issue47317.go | 7 +++++++ 5 files changed, 40 insertions(+), 22 deletions(-) create mode 100644 test/fixedbugs/issue47317.dir/a.s create mode 100644 test/fixedbugs/issue47317.dir/x.go create mode 100644 test/fixedbugs/issue47317.go diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go index b8ea1955d13..d657ddc867b 100644 --- a/src/cmd/compile/internal/abi/abiutils.go +++ b/src/cmd/compile/internal/abi/abiutils.go @@ -446,35 +446,20 @@ func (config *ABIConfig) ABIAnalyze(t *types.Type, setNname bool) *ABIParamResul return result } -// parameterUpdateMu protects the Offset field of function/method parameters (a subset of structure Fields) -var parameterUpdateMu sync.Mutex - -// FieldOffsetOf returns a concurrency-safe version of f.Offset -func FieldOffsetOf(f *types.Field) int64 { - parameterUpdateMu.Lock() - defer parameterUpdateMu.Unlock() - return f.Offset -} - func (config *ABIConfig) updateOffset(result *ABIParamResultInfo, f *types.Field, a ABIParamAssignment, isReturn, setNname bool) { // Everything except return values in registers has either a frame home (if not in a register) or a frame spill location. if !isReturn || len(a.Registers) == 0 { // The type frame offset DOES NOT show effects of minimum frame size. // Getting this wrong breaks stackmaps, see liveness/plive.go:WriteFuncMap and typebits/typebits.go:Set - parameterUpdateMu.Lock() - defer parameterUpdateMu.Unlock() off := a.FrameOffset(result) fOffset := f.Offset if fOffset == types.BOGUS_FUNARG_OFFSET { - // Set the Offset the first time. After that, we may recompute it, but it should never change. - f.Offset = off - if f.Nname != nil { - // always set it in this case. + if setNname && f.Nname != nil { f.Nname.(*ir.Name).SetFrameOffset(off) f.Nname.(*ir.Name).SetIsOutputParamInRegisters(false) } - } else if fOffset != off { - base.Fatalf("offset for %s at %s changed from %d to %d", f.Sym.Name, base.FmtPos(f.Pos), fOffset, off) + } else { + base.Fatalf("field offset for %s at %s has been set to %d", f.Sym.Name, base.FmtPos(f.Pos), fOffset) } } else { if setNname && f.Nname != nil { diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index a5cb0857b31..dfa76006de7 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -1296,7 +1296,7 @@ func (s *state) instrumentFields(t *types.Type, addr *ssa.Value, kind instrument if f.Sym.IsBlank() { continue } - offptr := s.newValue1I(ssa.OpOffPtr, types.NewPtr(f.Type), abi.FieldOffsetOf(f), addr) + offptr := s.newValue1I(ssa.OpOffPtr, types.NewPtr(f.Type), f.Offset, addr) s.instrumentFields(f.Type, offptr, kind) } } @@ -5053,19 +5053,23 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val ft := fn.Type() off := t.FieldOff(12) // TODO register args: be sure this isn't a hardcoded param stack offset. args := n.Args + i0 := 0 // Set receiver (for interface calls). Always a pointer. if rcvr != nil { p := s.newValue1I(ssa.OpOffPtr, ft.Recv().Type.PtrTo(), off, addr) s.store(types.Types[types.TUINTPTR], p, rcvr) + i0 = 1 } // Set receiver (for method calls). if n.Op() == ir.OCALLMETH { base.Fatalf("OCALLMETH missed by walkCall") } // Set other args. - for _, f := range ft.Params().Fields().Slice() { - s.storeArgWithBase(args[0], f.Type, addr, off+abi.FieldOffsetOf(f)) + // This code is only used when RegabiDefer is not enabled, and arguments are always + // passed on stack. + for i, f := range ft.Params().Fields().Slice() { + s.storeArgWithBase(args[0], f.Type, addr, off+params.InParam(i+i0).FrameOffset(params)) args = args[1:] } @@ -5078,7 +5082,6 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val if stksize < int64(types.PtrSize) { // We need room for both the call to deferprocStack and the call to // the deferred function. - // TODO(register args) Revisit this if/when we pass args in registers. stksize = int64(types.PtrSize) } call.AuxInt = stksize diff --git a/test/fixedbugs/issue47317.dir/a.s b/test/fixedbugs/issue47317.dir/a.s new file mode 100644 index 00000000000..b969ddb972c --- /dev/null +++ b/test/fixedbugs/issue47317.dir/a.s @@ -0,0 +1,6 @@ +// Copyright 2021 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. + +TEXT ·G(SB),4,$0 + RET diff --git a/test/fixedbugs/issue47317.dir/x.go b/test/fixedbugs/issue47317.dir/x.go new file mode 100644 index 00000000000..83b5542144d --- /dev/null +++ b/test/fixedbugs/issue47317.dir/x.go @@ -0,0 +1,17 @@ +// Copyright 2021 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. + +// Issue 47317: ICE when calling ABI0 function via func value. + +package main + +func main() { F() } + +func F() interface{} { + g := G + g(1) + return G +} + +func G(x int) [2]int diff --git a/test/fixedbugs/issue47317.go b/test/fixedbugs/issue47317.go new file mode 100644 index 00000000000..3548e90d020 --- /dev/null +++ b/test/fixedbugs/issue47317.go @@ -0,0 +1,7 @@ +// builddir + +// Copyright 2021 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 ignored From 4cdc65d32a3f0378cc508e8eb395063b83683fd4 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 22 Jul 2021 15:30:01 -0700 Subject: [PATCH 771/940] [dev.typeparams] cmd/compile/internal/types: format union types Previously it was just printing . Now it prints things like int32|~int64. Change-Id: I960b011ce8ed360020a49ae7809d85d1d1fdbfb2 Reviewed-on: https://go-review.googlesource.com/c/go/+/336692 Trust: Keith Randall Trust: Dan Scales Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/types/fmt.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/cmd/compile/internal/types/fmt.go b/src/cmd/compile/internal/types/fmt.go index a52dd060a01..0824f6d0936 100644 --- a/src/cmd/compile/internal/types/fmt.go +++ b/src/cmd/compile/internal/types/fmt.go @@ -590,6 +590,18 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type b.WriteString(fmt.Sprintf("%p", t)) } + case TUNION: + for i := 0; i < t.NumTerms(); i++ { + if i > 0 { + b.WriteString("|") + } + elem, tilde := t.Term(i) + if tilde { + b.WriteString("~") + } + tconv2(b, elem, 0, mode, visited) + } + case Txxx: b.WriteString("Txxx") From 0914646ab91a3157666d845d74d8d9a4a2831e1e Mon Sep 17 00:00:00 2001 From: Alberto Donizetti Date: Fri, 23 Jul 2021 18:45:41 +0200 Subject: [PATCH 772/940] doc/1.17: fix two dead rfc links Updates #44513 Change-Id: Ia0c6b48bde2719f3a99cb216b6166d82159198d1 Reviewed-on: https://go-review.googlesource.com/c/go/+/336930 Trust: Alberto Donizetti Reviewed-by: Ian Lance Taylor --- doc/go1.17.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 7739d1c62e0..48811e6b679 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -886,8 +886,8 @@ func Foo() bool {

The new method IP.IsPrivate reports whether an address is - a private IPv4 address according to RFC 1918 - or a local IPv6 address according RFC 4193. + a private IPv4 address according to RFC 1918 + or a local IPv6 address according RFC 4193.

From 12866bd8ea13e43bc5995f58cdeb67ffd64a1c8c Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Wed, 21 Jul 2021 16:23:17 -0700 Subject: [PATCH 773/940] [dev.typeparams] Add CONVIFACE nodes in noder2, where possible Changes to add CONVIFACE nodes where possible in noder2, even when the args are typeparams. The transformation to insert a CONVIFACE node can usually happen when there an obvious assignment/conversion to an interface type from a non-interface type. So, we now do this tranformation for: - direct conversions to an interface type - function arguments that are implicitly converted to an interface based on the parameter types. - EQ/NE comparison of an interface and a non-interface With this change, we can remove some special case checks for CONVIFACE nodes after transformation in node(), and instead just have the one check in the CONVIFACE check. Change-Id: I7cf2ef920aebf9e5553210aeaf19f344e128ca62 Reviewed-on: https://go-review.googlesource.com/c/go/+/336992 Trust: Dan Scales Reviewed-by: Keith Randall --- src/cmd/compile/internal/noder/helpers.go | 40 +++++++++++++------- src/cmd/compile/internal/noder/stencil.go | 41 +-------------------- src/cmd/compile/internal/noder/transform.go | 21 ++++++----- 3 files changed, 41 insertions(+), 61 deletions(-) diff --git a/src/cmd/compile/internal/noder/helpers.go b/src/cmd/compile/internal/noder/helpers.go index 15b32779080..2b00a9d7a63 100644 --- a/src/cmd/compile/internal/noder/helpers.go +++ b/src/cmd/compile/internal/noder/helpers.go @@ -116,9 +116,12 @@ func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool) if fun.Op() == ir.OTYPE { // Actually a type conversion, not a function call. - if fun.Type().HasTParam() || args[0].Type().HasTParam() { - // For type params, don't typecheck until we actually know - // the type. + if !fun.Type().IsInterface() && + (fun.Type().HasTParam() || args[0].Type().HasTParam()) { + // For type params, we can transform if fun.Type() is known + // to be an interface (in which case a CONVIFACE node will be + // inserted). Otherwise, don't typecheck until we actually + // know the type. return typed(typ, n) } typed(typ, n) @@ -169,11 +172,15 @@ func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool) } if fun.Type().HasTParam() { - // If the fun arg is or has a type param, don't do any extra - // transformations, since we may not have needed properties yet - // (e.g. number of return values, etc). The type param is probably - // described by a structural constraint that requires it to be a - // certain function type, etc., but we don't want to analyze that. + // If the fun arg is or has a type param, we can't do all the + // transformations, since we may not have needed properties yet. + // (e.g. number of return values, etc). However, if we do have the + // function type (even though it is parameterized), then can add in + // any needed CONVIFACE nodes. We can't do anything if fun is a type + // param (which is probably described by a structural constraint) + if fun.Type().Kind() == types.TFUNC { + typecheckaste(ir.OCALL, fun, n.IsDDD, fun.Type().Params(), n.Args, true) + } return typed(typ, n) } @@ -203,11 +210,18 @@ func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool) func Compare(pos src.XPos, typ *types.Type, op ir.Op, x, y ir.Node) ir.Node { n := ir.NewBinaryExpr(pos, op, x, y) if x.Type().HasTParam() || y.Type().HasTParam() { - // Delay transformCompare() if either arg has a type param, since - // it needs to know the exact types to decide on any needed conversions. - n.SetType(typ) - n.SetTypecheck(3) - return n + xIsInt := x.Type().IsInterface() + yIsInt := y.Type().IsInterface() + if !(xIsInt && !yIsInt || !xIsInt && yIsInt) { + // If either arg is a type param, then we can still do the + // transformCompare() if we know that one arg is an interface + // and the other is not. Otherwise, we delay + // transformCompare(), since it needs to know the exact types + // to decide on any needed conversions. + n.SetType(typ) + n.SetTypecheck(3) + return n + } } typed(typ, n) transformCompare(n) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 59f11bbe237..a8f9cf3b3e8 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -1251,21 +1251,13 @@ func (subst *subster) node(n ir.Node) ir.Node { case ir.OCALL: call := m.(*ir.CallExpr) - convcheck := false switch call.X.Op() { case ir.OTYPE: // Transform the conversion, now that we know the // type argument. m = transformConvCall(call) - if m.Op() == ir.OCONVIFACE { - // Note: srcType uses x.Args[0], not m.X or call.Args[0], because - // we need the type before the type parameter -> type argument substitution. - srcType := x.(*ir.CallExpr).Args[0].Type() - if ix := subst.findDictType(srcType); ix >= 0 { - c := m.(*ir.ConvExpr) - m = subst.convertUsingDictionary(c.Pos(), c.X, c.Type(), srcType, ix) - } - } + // CONVIFACE transformation was already done in node2 + assert(m.Op() != ir.OCONVIFACE) case ir.OMETHVALUE, ir.OMETHEXPR: // Redo the transformation of OXDOT, now that we @@ -1275,7 +1267,6 @@ func (subst *subster) node(n ir.Node) ir.Node { transformDot(call.X.(*ir.SelectorExpr), true) call.X.SetType(subst.unshapifyTyp(call.X.Type())) transformCall(call) - convcheck = true case ir.ODOT, ir.ODOTPTR: // An OXDOT for a generic receiver was resolved to @@ -1283,7 +1274,6 @@ func (subst *subster) node(n ir.Node) ir.Node { // value. Transform the call to that function, now // that the OXDOT was resolved. transformCall(call) - convcheck = true case ir.ONAME: name := call.X.Name() @@ -1308,12 +1298,10 @@ func (subst *subster) node(n ir.Node) ir.Node { // type parameter (implied to be a function via a // structural constraint) which is now resolved. transformCall(call) - convcheck = true } case ir.OCLOSURE: transformCall(call) - convcheck = true case ir.OFUNCINST: // A call with an OFUNCINST will get transformed @@ -1323,16 +1311,6 @@ func (subst *subster) node(n ir.Node) ir.Node { default: base.FatalfAt(call.Pos(), fmt.Sprintf("Unexpected op with CALL during stenciling: %v", call.X.Op())) } - if convcheck { - for i, arg := range x.(*ir.CallExpr).Args { - if arg.Type().HasTParam() && arg.Op() != ir.OCONVIFACE && - call.Args[i].Op() == ir.OCONVIFACE { - ix := subst.findDictType(arg.Type()) - assert(ix >= 0) - call.Args[i] = subst.convertUsingDictionary(arg.Pos(), call.Args[i].(*ir.ConvExpr).X, call.Args[i].Type(), arg.Type(), ix) - } - } - } case ir.OCLOSURE: // We're going to create a new closure from scratch, so clear m @@ -1391,21 +1369,6 @@ func (subst *subster) node(n ir.Node) ir.Node { if ix := subst.findDictType(t); ix >= 0 { m = subst.convertUsingDictionary(x.Pos(), m.(*ir.ConvExpr).X, m.Type(), t, ix) } - case ir.OEQ, ir.ONE: - // Equality between a non-interface and an interface requires the non-interface - // to be promoted to an interface. - x := x.(*ir.BinaryExpr) - m := m.(*ir.BinaryExpr) - if i := x.Y.Type(); i.IsInterface() { - if ix := subst.findDictType(x.X.Type()); ix >= 0 { - m.X = subst.convertUsingDictionary(m.X.Pos(), m.X, i, x.X.Type(), ix) - } - } - if i := x.X.Type(); i.IsInterface() { - if ix := subst.findDictType(x.Y.Type()); ix >= 0 { - m.Y = subst.convertUsingDictionary(m.Y.Pos(), m.Y, i, x.X.Type(), ix) - } - } case ir.ONEW: // New needs to pass a concrete type to the runtime. diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go index 86bdb91395c..f89ae132379 100644 --- a/src/cmd/compile/internal/noder/transform.go +++ b/src/cmd/compile/internal/noder/transform.go @@ -156,7 +156,7 @@ func transformCall(n *ir.CallExpr) { n.SetOp(ir.OCALLFUNC) } - typecheckaste(ir.OCALL, n.X, n.IsDDD, t.Params(), n.Args) + typecheckaste(ir.OCALL, n.X, n.IsDDD, t.Params(), n.Args, false) if l.Op() == ir.ODOTMETH && len(deref(n.X.Type().Recv().Type).RParams()) == 0 { typecheck.FixMethodCall(n) } @@ -194,7 +194,7 @@ func transformCompare(n *ir.BinaryExpr) { aop, _ := typecheck.Assignop(lt, rt) if aop != ir.OXXX { types.CalcSize(lt) - if rt.IsInterface() == lt.IsInterface() || lt.Width >= 1<<16 { + if lt.HasTParam() || rt.IsInterface() == lt.IsInterface() || lt.Width >= 1<<16 { l = ir.NewConvExpr(base.Pos, aop, rt, l) l.SetTypecheck(1) } @@ -207,7 +207,7 @@ func transformCompare(n *ir.BinaryExpr) { aop, _ := typecheck.Assignop(rt, lt) if aop != ir.OXXX { types.CalcSize(rt) - if rt.IsInterface() == lt.IsInterface() || rt.Width >= 1<<16 { + if rt.HasTParam() || rt.IsInterface() == lt.IsInterface() || rt.Width >= 1<<16 { r = ir.NewConvExpr(base.Pos, aop, lt, r) r.SetTypecheck(1) } @@ -468,8 +468,11 @@ func assignconvfn(n ir.Node, t *types.Type) ir.Node { return r } -// Corresponds to typecheck.typecheckaste. -func typecheckaste(op ir.Op, call ir.Node, isddd bool, tstruct *types.Type, nl ir.Nodes) { +// Corresponds to typecheck.typecheckaste, but we add an extra flag convifaceOnly +// only. If convifaceOnly is true, we only do interface conversion. We use this to do +// early insertion of CONVIFACE nodes during noder2, when the function or args may +// have typeparams. +func typecheckaste(op ir.Op, call ir.Node, isddd bool, tstruct *types.Type, nl ir.Nodes, convifaceOnly bool) { var t *types.Type var i int @@ -488,7 +491,7 @@ func typecheckaste(op ir.Op, call ir.Node, isddd bool, tstruct *types.Type, nl i if isddd { n = nl[i] ir.SetPos(n) - if n.Type() != nil { + if n.Type() != nil && (!convifaceOnly || t.IsInterface()) { nl[i] = assignconvfn(n, t) } return @@ -498,7 +501,7 @@ func typecheckaste(op ir.Op, call ir.Node, isddd bool, tstruct *types.Type, nl i for ; i < len(nl); i++ { n = nl[i] ir.SetPos(n) - if n.Type() != nil { + if n.Type() != nil && (!convifaceOnly || t.IsInterface()) { nl[i] = assignconvfn(n, t.Elem()) } } @@ -507,7 +510,7 @@ func typecheckaste(op ir.Op, call ir.Node, isddd bool, tstruct *types.Type, nl i n = nl[i] ir.SetPos(n) - if n.Type() != nil { + if n.Type() != nil && (!convifaceOnly || t.IsInterface()) { nl[i] = assignconvfn(n, t) } i++ @@ -529,7 +532,7 @@ func transformReturn(rs *ir.ReturnStmt) { return } - typecheckaste(ir.ORETURN, nil, false, ir.CurFunc.Type().Results(), nl) + typecheckaste(ir.ORETURN, nil, false, ir.CurFunc.Type().Results(), nl, false) } // transformSelect transforms a select node, creating an assignment list as needed From 02c01725002a73739cefbc9fcf2575469be6da13 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Mon, 12 Jul 2021 19:34:15 -0700 Subject: [PATCH 774/940] [dev.typeparams] cmd/compile: add dictionary entries for itab conversion This fix the case where a type param or derived type is converted to a non-empty interface. Previously, we were converting to an empty interface and then using DOTTYPE to convert to the correct non-empty interface. In that case, we can get the needed itab directly from the dictionary. This is needed for correctness from shapes, if the destination interface is parameterized, else we will incorrectly convert to the shape version of the interface. Creating/writing an itab can involve generating wrappers for a bunch of methods, which may use dictionaries. So, all the dictionaries/instantiations are being generated on the fly and have recursive relationships, it is simplest to finish creating/writing the itabs at the end of the stenciling phase. So, we create a list of the dictionaries which need to be completed by writing out their itab entries. The existing tests ordered.go, ifaceconv.go, and issue44688.go make use of this optimization. Got itab conversions for bound calls working, except for 13.go. Also, want to get rid of the concretify, but I think we need more info on the Bound from types2. Change-Id: If552958a7b8a435500d6cc42c401572c367b30d1 Reviewed-on: https://go-review.googlesource.com/c/go/+/336993 Trust: Dan Scales Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/noder/irgen.go | 19 ++- src/cmd/compile/internal/noder/stencil.go | 127 +++++++++++++----- .../compile/internal/reflectdata/reflect.go | 18 +++ test/run.go | 3 +- 4 files changed, 134 insertions(+), 33 deletions(-) diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go index 880073a89ec..6a8763c9088 100644 --- a/src/cmd/compile/internal/noder/irgen.go +++ b/src/cmd/compile/internal/noder/irgen.go @@ -104,6 +104,9 @@ type gfInfo struct { // method and function calls (OCALL), function values (OFUNCINST), method // values/expressions (OXDOT). subDictCalls []ir.Node + // Nodes in generic functions that are a conversion from a typeparam/derived + // type to a specific interface. + itabConvs []ir.Node } // instInfo is information gathered on an gcshape (or fully concrete) @@ -115,8 +118,9 @@ type instInfo struct { gf *ir.Name // The associated generic function gfInfo *gfInfo - startSubDict int // Start of dict entries for subdictionaries - dictLen int // Total number of entries in dictionary + startSubDict int // Start of dict entries for subdictionaries + startItabConv int // Start of dict entries for itab conversions + dictLen int // Total number of entries in dictionary // Map from nodes in instantiated fun (OCALL, OCALLMETHOD, OFUNCINST, and // OMETHEXPR) to the associated dictionary entry for a sub-dictionary @@ -146,6 +150,17 @@ type irgen struct { // its instantiated function, associated generic function/method, and the // mapping from IR nodes to dictionary entries. instInfoMap map[*types.Sym]*instInfo + + // dictionary syms which we need to finish, by writing out any itabconv + // entries. + dictSymsToFinalize []*delayInfo +} + +type delayInfo struct { + gf *ir.Name + targs []*types.Type + sym *types.Sym + off int } func (g *irgen) generate(noders []*noder) { diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index a8f9cf3b3e8..461083d1710 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -225,6 +225,7 @@ func (g *irgen) stencil() { g.instantiateMethods() } + g.finalizeSyms() } // buildClosure makes a closure to implement x, a OFUNCINST or OMETHEXPR @@ -823,11 +824,12 @@ func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth // to the list of decls. gfInfo := g.getGfInfo(nameNode) info = &instInfo{ - gf: nameNode, - gfInfo: gfInfo, - startSubDict: len(targs) + len(gfInfo.derivedTypes), - dictLen: len(targs) + len(gfInfo.derivedTypes) + len(gfInfo.subDictCalls), - dictEntryMap: make(map[ir.Node]int), + gf: nameNode, + gfInfo: gfInfo, + startSubDict: len(targs) + len(gfInfo.derivedTypes), + startItabConv: len(targs) + len(gfInfo.derivedTypes) + len(gfInfo.subDictCalls), + dictLen: len(targs) + len(gfInfo.derivedTypes) + len(gfInfo.subDictCalls) + len(gfInfo.itabConvs), + dictEntryMap: make(map[ir.Node]int), } // genericSubst fills in info.dictParam and info.dictEntryMap. st := g.genericSubst(sym, nameNode, shapes, targs, isMeth, info) @@ -1235,12 +1237,9 @@ func (subst *subster) node(n ir.Node) ir.Node { // Implement x.M as a conversion-to-bound-interface // 1) convert x to the bound interface // 2) call M on that interface - dst := subst.concretify.Typ(subst.shape2param[src].Bound()) - // Mark that we use the methods of this concrete type. - // Otherwise the linker deadcode-eliminates them :( - ix := subst.findDictType(subst.shape2param[src]) - assert(ix >= 0) - mse.X = subst.convertUsingDictionary(m.Pos(), mse.X, dst, subst.shape2param[src], ix) + gsrc := x.(*ir.SelectorExpr).X.Type() + dst := subst.concretify.Typ(gsrc.Bound()) + mse.X = subst.convertUsingDictionary(m.Pos(), mse.X, x, dst, gsrc) } } transformDot(mse, false) @@ -1365,9 +1364,8 @@ func (subst *subster) node(n ir.Node) ir.Node { x := x.(*ir.ConvExpr) // Note: x's argument is still typed as a type parameter. // m's argument now has an instantiated type. - t := x.X.Type() - if ix := subst.findDictType(t); ix >= 0 { - m = subst.convertUsingDictionary(x.Pos(), m.(*ir.ConvExpr).X, m.Type(), t, ix) + if x.X.Type().HasTParam() { + m = subst.convertUsingDictionary(m.Pos(), m.(*ir.ConvExpr).X, x, m.Type(), x.X.Type()) } case ir.ONEW: @@ -1411,14 +1409,35 @@ func (subst *subster) findDictType(t *types.Type) int { return -1 } -// convertUsingDictionary converts value v from instantiated type src (which is index -// 'ix' in the instantiation's dictionary) to an interface type dst. -func (subst *subster) convertUsingDictionary(pos src.XPos, v ir.Node, dst, src *types.Type, ix int) ir.Node { - if !dst.IsInterface() { - base.Fatalf("can only convert type parameters to interfaces %+v -> %+v", src, dst) +// convertUsingDictionary converts value v from instantiated type src to an interface +// type dst, by returning a new set of nodes that make use of a dictionary entry. src +// is the generic (not shape) type, and gn is the original generic node of the +// CONVIFACE node or XDOT node (for a bound method call) that is causing the +// conversion. +func (subst *subster) convertUsingDictionary(pos src.XPos, v ir.Node, gn ir.Node, dst, src *types.Type) ir.Node { + assert(src.HasTParam()) + assert(dst.IsInterface()) + + var rt ir.Node + if !dst.IsEmptyInterface() { + // We should have an itab entry in the dictionary. Using this itab + // will be more efficient than converting to an empty interface first + // and then type asserting to dst. + ix := -1 + for i, ic := range subst.info.gfInfo.itabConvs { + if ic == gn { + ix = subst.info.startItabConv + i + break + } + } + assert(ix >= 0) + rt = getDictionaryEntry(pos, subst.info.dictParam, ix, subst.info.dictLen) + } else { + ix := subst.findDictType(src) + assert(ix >= 0) + // Load the actual runtime._type of the type parameter from the dictionary. + rt = subst.getDictionaryType(pos, ix) } - // Load the actual runtime._type of the type parameter from the dictionary. - rt := subst.getDictionaryType(pos, ix) // Convert value to an interface type, so the data field is what we want. if !v.Type().IsInterface() { @@ -1432,12 +1451,6 @@ func (subst *subster) convertUsingDictionary(pos src.XPos, v ir.Node, dst, src * data := ir.NewUnaryExpr(pos, ir.OIDATA, v) typed(types.Types[types.TUNSAFEPTR], data) var i ir.Node = ir.NewBinaryExpr(pos, ir.OEFACE, rt, data) - if !dst.IsEmptyInterface() { - // We just built an empty interface{}. Type it as such, - // then assert it to the required non-empty interface. - typed(types.NewInterface(types.LocalPkg, nil), i) - i = ir.NewTypeAssertExpr(pos, i, nil) - } typed(dst, i) // TODO: we're throwing away the type word of the original version // of m here (it would be OITAB(m)), which probably took some @@ -1650,14 +1663,58 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) infoPrint(" - Subdict %v\n", sym.Name) } } - objw.Global(lsym, int32(off), obj.DUPOK|obj.RODATA) - infoPrint("=== Done dictionary\n") - // Add any new, fully instantiated types seen during the substitution to g.instTypeList. + delay := &delayInfo{ + gf: gf, + targs: targs, + sym: sym, + off: off, + } + g.dictSymsToFinalize = append(g.dictSymsToFinalize, delay) g.instTypeList = append(g.instTypeList, subst.InstTypeList...) } return sym } + +// finalizeSyms finishes up all dictionaries on g.dictSymsToFinalize, by writing out +// any needed LSyms for itabs. The itab lsyms create wrappers which need various +// dictionaries and method instantiations to be complete, so, to avoid recursive +// dependencies, we finalize the itab lsyms only after all dictionaries syms and +// instantiations have been created. +func (g *irgen) finalizeSyms() { + for _, d := range g.dictSymsToFinalize { + lsym := d.sym.Linksym() + info := g.getGfInfo(d.gf) + + subst := typecheck.Tsubster{ + Tparams: info.tparams, + Targs: d.targs, + } + + // Emit an entry for each itab + for _, n := range info.itabConvs { + var srctype, dsttype *types.Type + if n.Op() == ir.OXDOT { + se := n.(*ir.SelectorExpr) + srctype = subst.Typ(se.X.Type()) + dsttype = subst.Typ(se.X.Type().Bound()) + } else { + assert(n.Op() == ir.OCONVIFACE) + srctype = subst.Typ(n.(*ir.ConvExpr).X.Type()) + dsttype = subst.Typ(n.Type()) + } + itabLsym := reflectdata.ITabLsym(srctype, dsttype) + d.off = objw.SymPtr(lsym, d.off, itabLsym, 0) + } + + objw.Global(lsym, int32(d.off), obj.DUPOK|obj.RODATA) + infoPrint("=== Finalized dictionary %s\n", d.sym.Name) + + g.instTypeList = append(g.instTypeList, subst.InstTypeList...) + } + g.dictSymsToFinalize = nil +} + func (g *irgen) getDictionaryValue(gf *ir.Name, targs []*types.Type, isMeth bool) ir.Node { sym := g.getDictionarySym(gf, targs, isMeth) @@ -1778,6 +1835,16 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo { infoPrint(" Optional subdictionary at generic bound call: %v\n", n) info.subDictCalls = append(info.subDictCalls, n) } + if n.Op() == ir.OCONVIFACE && n.Type().IsInterface() && + !n.Type().IsEmptyInterface() && + n.(*ir.ConvExpr).X.Type().HasTParam() { + infoPrint(" Itab for interface conv: %v\n", n) + info.itabConvs = append(info.itabConvs, n) + } + if n.Op() == ir.OXDOT && n.(*ir.SelectorExpr).X.Type().IsTypeParam() { + infoPrint(" Itab for interface conv: %v\n", n) + info.itabConvs = append(info.itabConvs, n) + } if n.Op() == ir.OCLOSURE { // Visit the closure body and add all relevant entries to the // dictionary of the outer function (closure will just use diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index 2236c7f1cff..1391102d0f0 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -833,6 +833,18 @@ func TypePtr(t *types.Type) *ir.AddrExpr { return typecheck.Expr(typecheck.NodAddr(n)).(*ir.AddrExpr) } +// ITabLsym returns the LSym representing the itab for concreate type typ +// implementing interface iface. +func ITabLsym(typ, iface *types.Type) *obj.LSym { + s, existed := ir.Pkgs.Itab.LookupOK(typ.LinkString() + "," + iface.LinkString()) + lsym := s.Linksym() + + if !existed { + writeITab(lsym, typ, iface) + } + return lsym +} + // ITabAddr returns an expression representing a pointer to the itab // for concrete type typ implementing interface iface. func ITabAddr(typ, iface *types.Type) *ir.AddrExpr { @@ -1288,6 +1300,12 @@ func writeITab(lsym *obj.LSym, typ, iface *types.Type) { break } } + if sigs[0].Sym.Name == "==" { + sigs = sigs[1:] + if len(sigs) == 0 { + break + } + } } if len(sigs) != 0 { base.Fatalf("incomplete itab") diff --git a/test/run.go b/test/run.go index 23eebcee2e8..5624654fec9 100644 --- a/test/run.go +++ b/test/run.go @@ -2182,7 +2182,8 @@ var g3Failures = setOf( "typeparam/nested.go", // -G=3 doesn't support function-local types with generics - "typeparam/mdempsky/4.go", // -G=3 can't export functions with labeled breaks in loops + "typeparam/mdempsky/4.go", // -G=3 can't export functions with labeled breaks in loops + "typeparam/mdempsky/13.go", // problem with interface as as a type arg. "typeparam/cons.go", // causes an unreachable method "typeparam/issue44688.go", // interface conversion fails due to missing method From e6d956e1c521b948257dd20056436d133df176f6 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Fri, 23 Jul 2021 14:38:04 -0700 Subject: [PATCH 775/940] [dev.typeparams] cmd/compile: add CONVIFACE nodes for return values during noder2 Even if we can otherwise transform a return statement because of type params, add CONVIFACE nodes where appropriate. Change-Id: Ia2216d5f6805926075ba6802a4385eee1d63e37e Reviewed-on: https://go-review.googlesource.com/c/go/+/337049 Trust: Dan Scales Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/noder/stmt.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/cmd/compile/internal/noder/stmt.go b/src/cmd/compile/internal/noder/stmt.go index b7085c4776e..5af4a2da9c6 100644 --- a/src/cmd/compile/internal/noder/stmt.go +++ b/src/cmd/compile/internal/noder/stmt.go @@ -128,6 +128,11 @@ func (g *irgen) stmt(stmt syntax.Stmt) ir.Node { if e.Type().HasTParam() { // Delay transforming the return statement if any of the // return values have a type param. + if !ir.HasNamedResults(ir.CurFunc) { + // But add CONVIFACE nodes where needed if + // any of the return values have interface type. + typecheckaste(ir.ORETURN, nil, false, ir.CurFunc.Type().Results(), n.Results, true) + } n.SetTypecheck(3) return n } From 6992dcdad9b94a2b33b957474ef0eb210d563a40 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Fri, 23 Jul 2021 15:23:57 -0700 Subject: [PATCH 776/940] [dev.typeparams] cmd/compile: fix some issues with cons.go Add a test to make sure there's no invalid OCONVIFACEs when stenciling is done. Use concrete types for the type of DOTTYPE and DOTTYPE2. MarkTypeUsedInInterface - should we allow types with shape types underneath? I think the itab CL will help with this (at least, for a remaining cons.go issue). Change-Id: I2c96d74e8daaca26cadc84ea94abb9a27c0bb240 Reviewed-on: https://go-review.googlesource.com/c/go/+/337069 Trust: Keith Randall Trust: Dan Scales Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/noder/stencil.go | 24 ++++++++++++++++++- .../compile/internal/reflectdata/reflect.go | 6 +++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 461083d1710..85538f590dc 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -994,6 +994,26 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, shapes, targs g.instTypeList = append(g.instTypeList, subst.unshapify.InstTypeList...) g.instTypeList = append(g.instTypeList, subst.concretify.InstTypeList...) + if doubleCheck { + okConvs := map[ir.Node]bool{} + ir.Visit(newf, func(n ir.Node) { + if n.Op() == ir.OIDATA { + // IDATA(OCONVIFACE(x)) is ok, as we don't use the type of x. + // TODO: use some other op besides OCONVIFACE. ONEW might work + // (with appropriate direct vs. indirect interface cases). + okConvs[n.(*ir.UnaryExpr).X] = true + } + if n.Op() == ir.OCONVIFACE && !okConvs[n] { + c := n.(*ir.ConvExpr) + if c.X.Type().HasShape() { + ir.Dump("BAD FUNCTION", newf) + ir.Dump("BAD CONVERSION", c) + base.Fatalf("converting shape type to interface") + } + } + }) + } + return newf } @@ -1367,6 +1387,8 @@ func (subst *subster) node(n ir.Node) ir.Node { if x.X.Type().HasTParam() { m = subst.convertUsingDictionary(m.Pos(), m.(*ir.ConvExpr).X, x, m.Type(), x.X.Type()) } + case ir.ODOTTYPE, ir.ODOTTYPE2: + m.SetType(subst.unshapifyTyp(m.Type())) case ir.ONEW: // New needs to pass a concrete type to the runtime. @@ -1535,7 +1557,7 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) // Enforce that only concrete types can make it to here. for _, t := range targs { - if t.IsShape() { + if t.HasShape() { panic(fmt.Sprintf("shape %+v in dictionary for %s", t, gf.Sym().Name)) } } diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index 1391102d0f0..875d53b3cca 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -1982,6 +1982,12 @@ var ZeroSize int64 // MarkTypeUsedInInterface marks that type t is converted to an interface. // This information is used in the linker in dead method elimination. func MarkTypeUsedInInterface(t *types.Type, from *obj.LSym) { + if t.HasShape() { + // TODO: shape types shouldn't be put in interfaces, so we shouldn't ever get here. + // We don't from ../noder/stencil.go, but we do from ../walk/walk.go when we let + // shape types become the types of interfaces. + //base.Fatalf("shape types have no methods %+v", t) + } tsym := TypeLinksym(t) // Emit a marker relocation. The linker will know the type is converted // to an interface if "from" is reachable. From 9f928f9318efb9e6a9d45e7ed959afaaee4b7315 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 23 Jul 2021 10:00:10 -0400 Subject: [PATCH 777/940] [dev.typeparams] go/types, types2: set tset when constructing interfaces in the universe As of CL 334894, type sets are lazily evaluated on interfaces. For the universe interfaces error and comparable, this can lead to data races when type checking concurrently. Fix this by computing their type set when they are defined. Tested using the repro from #47345. I considered checking this in as a test, but it probably wouldn't add much value going forward. Fixes #47345 Change-Id: I014a511b8e3c092c86201a8bfc7f5f494f8f20e8 Reviewed-on: https://go-review.googlesource.com/c/go/+/336910 Trust: Robert Findley Run-TryBot: Robert Findley Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types2/universe.go | 8 ++++++-- src/go/types/universe.go | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/cmd/compile/internal/types2/universe.go b/src/cmd/compile/internal/types2/universe.go index e2dd0df69e8..0f711a6b684 100644 --- a/src/cmd/compile/internal/types2/universe.go +++ b/src/cmd/compile/internal/types2/universe.go @@ -88,7 +88,9 @@ func defPredeclaredTypes() { res := NewVar(nopos, nil, "", Typ[String]) sig := NewSignature(nil, nil, NewTuple(res), false) err := NewFunc(nopos, nil, "Error", sig) - typ := NewNamed(obj, NewInterfaceType([]*Func{err}, nil), nil) + ityp := NewInterfaceType([]*Func{err}, nil) + computeTypeSet(nil, nopos, ityp) // prevent races due to lazy computation of tset + typ := NewNamed(obj, ityp, nil) sig.recv = NewVar(nopos, nil, "", typ) def(obj) } @@ -99,7 +101,9 @@ func defPredeclaredTypes() { obj.setColor(black) sig := NewSignature(nil, nil, nil, false) eql := NewFunc(nopos, nil, "==", sig) - typ := NewNamed(obj, NewInterfaceType([]*Func{eql}, nil), nil) + ityp := NewInterfaceType([]*Func{eql}, nil) + computeTypeSet(nil, nopos, ityp) // prevent races due to lazy computation of tset + typ := NewNamed(obj, ityp, nil) sig.recv = NewVar(nopos, nil, "", typ) def(obj) } diff --git a/src/go/types/universe.go b/src/go/types/universe.go index 59952bc6427..489587f3938 100644 --- a/src/go/types/universe.go +++ b/src/go/types/universe.go @@ -89,7 +89,9 @@ func defPredeclaredTypes() { res := NewVar(token.NoPos, nil, "", Typ[String]) sig := NewSignature(nil, nil, NewTuple(res), false) err := NewFunc(token.NoPos, nil, "Error", sig) - typ := NewNamed(obj, NewInterfaceType([]*Func{err}, nil), nil) + ityp := NewInterfaceType([]*Func{err}, nil) + computeTypeSet(nil, token.NoPos, ityp) // prevent races due to lazy computation of tset + typ := NewNamed(obj, ityp, nil) sig.recv = NewVar(token.NoPos, nil, "", typ) def(obj) } @@ -100,7 +102,9 @@ func defPredeclaredTypes() { obj.setColor(black) sig := NewSignature(nil, nil, nil, false) eql := NewFunc(token.NoPos, nil, "==", sig) - typ := NewNamed(obj, NewInterfaceType([]*Func{eql}, nil), nil) + ityp := NewInterfaceType([]*Func{eql}, nil) + computeTypeSet(nil, token.NoPos, ityp) // prevent races due to lazy computation of tset + typ := NewNamed(obj, ityp, nil) sig.recv = NewVar(token.NoPos, nil, "", typ) def(obj) } From 77e0bf294cc431d5608c183d56b6aadbb95b09b0 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Fri, 23 Jul 2021 18:10:58 -0700 Subject: [PATCH 778/940] [dev.typeparams] cmd/compile: introduce OCONVIDATA op This operation computes just the data field needed to put its argument into an interface. Used by generics because we produce the type field of an interface using dictionaries (instead of statically). With this operation defined, we can now assert that shape types are never marked as used in interfaces (the only previous use was IDATA(CONVIFACE(t))). Change-Id: Idb1eb5f3b238285cb99413d382599c0621b7681a Reviewed-on: https://go-review.googlesource.com/c/go/+/337109 Trust: Keith Randall Trust: Dan Scales Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/escape/expr.go | 2 +- src/cmd/compile/internal/ir/expr.go | 2 +- src/cmd/compile/internal/ir/fmt.go | 4 +- src/cmd/compile/internal/ir/node.go | 1 + src/cmd/compile/internal/ir/op_string.go | 233 +++++++++--------- src/cmd/compile/internal/noder/stencil.go | 22 +- .../compile/internal/reflectdata/reflect.go | 6 +- src/cmd/compile/internal/typecheck/iexport.go | 2 +- src/cmd/compile/internal/typecheck/iimport.go | 2 +- src/cmd/compile/internal/walk/assign.go | 1 + src/cmd/compile/internal/walk/convert.go | 14 +- src/cmd/compile/internal/walk/expr.go | 7 + src/cmd/compile/internal/walk/order.go | 10 +- 13 files changed, 161 insertions(+), 145 deletions(-) diff --git a/src/cmd/compile/internal/escape/expr.go b/src/cmd/compile/internal/escape/expr.go index 60b44fe0aa6..b7423e114ad 100644 --- a/src/cmd/compile/internal/escape/expr.go +++ b/src/cmd/compile/internal/escape/expr.go @@ -109,7 +109,7 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) { } else { e.expr(k, n.X) } - case ir.OCONVIFACE: + case ir.OCONVIFACE, ir.OCONVIDATA: n := n.(*ir.ConvExpr) if !n.X.Type().IsInterface() && !types.IsDirectIface(n.X.Type()) { k = e.spill(k, n) diff --git a/src/cmd/compile/internal/ir/expr.go b/src/cmd/compile/internal/ir/expr.go index 09d6d87f060..86323e6b8f8 100644 --- a/src/cmd/compile/internal/ir/expr.go +++ b/src/cmd/compile/internal/ir/expr.go @@ -270,7 +270,7 @@ func (n *ConvExpr) SetOp(op Op) { switch op { default: panic(n.no("SetOp " + op.String())) - case OCONV, OCONVIFACE, OCONVNOP, OBYTES2STR, OBYTES2STRTMP, ORUNES2STR, OSTR2BYTES, OSTR2BYTESTMP, OSTR2RUNES, ORUNESTR, OSLICE2ARRPTR: + case OCONV, OCONVIFACE, OCONVIDATA, OCONVNOP, OBYTES2STR, OBYTES2STRTMP, ORUNES2STR, OSTR2BYTES, OSTR2BYTESTMP, OSTR2RUNES, ORUNESTR, OSLICE2ARRPTR: n.op = op } } diff --git a/src/cmd/compile/internal/ir/fmt.go b/src/cmd/compile/internal/ir/fmt.go index e8dd9df69d0..3c5a928590f 100644 --- a/src/cmd/compile/internal/ir/fmt.go +++ b/src/cmd/compile/internal/ir/fmt.go @@ -185,6 +185,7 @@ var OpPrec = []int{ OCLOSE: 8, OCOMPLIT: 8, OCONVIFACE: 8, + OCONVIDATA: 8, OCONVNOP: 8, OCONV: 8, OCOPY: 8, @@ -546,7 +547,7 @@ func exprFmt(n Node, s fmt.State, prec int) { n = nn.X continue } - case OCONV, OCONVNOP, OCONVIFACE: + case OCONV, OCONVNOP, OCONVIFACE, OCONVIDATA: nn := nn.(*ConvExpr) if nn.Implicit() { n = nn.X @@ -813,6 +814,7 @@ func exprFmt(n Node, s fmt.State, prec int) { case OCONV, OCONVIFACE, + OCONVIDATA, OCONVNOP, OBYTES2STR, ORUNES2STR, diff --git a/src/cmd/compile/internal/ir/node.go b/src/cmd/compile/internal/ir/node.go index f6eae58b040..0fbc867c1d9 100644 --- a/src/cmd/compile/internal/ir/node.go +++ b/src/cmd/compile/internal/ir/node.go @@ -170,6 +170,7 @@ const ( OPTRLIT // &X (X is composite literal) OCONV // Type(X) (type conversion) OCONVIFACE // Type(X) (type conversion, to interface) + OCONVIDATA // Builds a data word to store X in an interface. Equivalent to IDATA(CONVIFACE(X)). Is an ir.ConvExpr. OCONVNOP // Type(X) (type conversion, no effect) OCOPY // copy(X, Y) ODCL // var X (declares X of type X.Type) diff --git a/src/cmd/compile/internal/ir/op_string.go b/src/cmd/compile/internal/ir/op_string.go index 05a37a60b1d..0235d5eab39 100644 --- a/src/cmd/compile/internal/ir/op_string.go +++ b/src/cmd/compile/internal/ir/op_string.go @@ -52,125 +52,126 @@ func _() { _ = x[OPTRLIT-41] _ = x[OCONV-42] _ = x[OCONVIFACE-43] - _ = x[OCONVNOP-44] - _ = x[OCOPY-45] - _ = x[ODCL-46] - _ = x[ODCLFUNC-47] - _ = x[ODCLCONST-48] - _ = x[ODCLTYPE-49] - _ = x[ODELETE-50] - _ = x[ODOT-51] - _ = x[ODOTPTR-52] - _ = x[ODOTMETH-53] - _ = x[ODOTINTER-54] - _ = x[OXDOT-55] - _ = x[ODOTTYPE-56] - _ = x[ODOTTYPE2-57] - _ = x[OEQ-58] - _ = x[ONE-59] - _ = x[OLT-60] - _ = x[OLE-61] - _ = x[OGE-62] - _ = x[OGT-63] - _ = x[ODEREF-64] - _ = x[OINDEX-65] - _ = x[OINDEXMAP-66] - _ = x[OKEY-67] - _ = x[OSTRUCTKEY-68] - _ = x[OLEN-69] - _ = x[OMAKE-70] - _ = x[OMAKECHAN-71] - _ = x[OMAKEMAP-72] - _ = x[OMAKESLICE-73] - _ = x[OMAKESLICECOPY-74] - _ = x[OMUL-75] - _ = x[ODIV-76] - _ = x[OMOD-77] - _ = x[OLSH-78] - _ = x[ORSH-79] - _ = x[OAND-80] - _ = x[OANDNOT-81] - _ = x[ONEW-82] - _ = x[ONOT-83] - _ = x[OBITNOT-84] - _ = x[OPLUS-85] - _ = x[ONEG-86] - _ = x[OOROR-87] - _ = x[OPANIC-88] - _ = x[OPRINT-89] - _ = x[OPRINTN-90] - _ = x[OPAREN-91] - _ = x[OSEND-92] - _ = x[OSLICE-93] - _ = x[OSLICEARR-94] - _ = x[OSLICESTR-95] - _ = x[OSLICE3-96] - _ = x[OSLICE3ARR-97] - _ = x[OSLICEHEADER-98] - _ = x[ORECOVER-99] - _ = x[ORECOVERFP-100] - _ = x[ORECV-101] - _ = x[ORUNESTR-102] - _ = x[OSELRECV2-103] - _ = x[OIOTA-104] - _ = x[OREAL-105] - _ = x[OIMAG-106] - _ = x[OCOMPLEX-107] - _ = x[OALIGNOF-108] - _ = x[OOFFSETOF-109] - _ = x[OSIZEOF-110] - _ = x[OUNSAFEADD-111] - _ = x[OUNSAFESLICE-112] - _ = x[OMETHEXPR-113] - _ = x[OMETHVALUE-114] - _ = x[OBLOCK-115] - _ = x[OBREAK-116] - _ = x[OCASE-117] - _ = x[OCONTINUE-118] - _ = x[ODEFER-119] - _ = x[OFALL-120] - _ = x[OFOR-121] - _ = x[OFORUNTIL-122] - _ = x[OGOTO-123] - _ = x[OIF-124] - _ = x[OLABEL-125] - _ = x[OGO-126] - _ = x[ORANGE-127] - _ = x[ORETURN-128] - _ = x[OSELECT-129] - _ = x[OSWITCH-130] - _ = x[OTYPESW-131] - _ = x[OFUNCINST-132] - _ = x[OTCHAN-133] - _ = x[OTMAP-134] - _ = x[OTSTRUCT-135] - _ = x[OTINTER-136] - _ = x[OTFUNC-137] - _ = x[OTARRAY-138] - _ = x[OTSLICE-139] - _ = x[OINLCALL-140] - _ = x[OEFACE-141] - _ = x[OITAB-142] - _ = x[OIDATA-143] - _ = x[OSPTR-144] - _ = x[OCFUNC-145] - _ = x[OCHECKNIL-146] - _ = x[OVARDEF-147] - _ = x[OVARKILL-148] - _ = x[OVARLIVE-149] - _ = x[ORESULT-150] - _ = x[OINLMARK-151] - _ = x[OLINKSYMOFFSET-152] - _ = x[OTAILCALL-153] - _ = x[OGETG-154] - _ = x[OGETCALLERPC-155] - _ = x[OGETCALLERSP-156] - _ = x[OEND-157] + _ = x[OCONVIDATA-44] + _ = x[OCONVNOP-45] + _ = x[OCOPY-46] + _ = x[ODCL-47] + _ = x[ODCLFUNC-48] + _ = x[ODCLCONST-49] + _ = x[ODCLTYPE-50] + _ = x[ODELETE-51] + _ = x[ODOT-52] + _ = x[ODOTPTR-53] + _ = x[ODOTMETH-54] + _ = x[ODOTINTER-55] + _ = x[OXDOT-56] + _ = x[ODOTTYPE-57] + _ = x[ODOTTYPE2-58] + _ = x[OEQ-59] + _ = x[ONE-60] + _ = x[OLT-61] + _ = x[OLE-62] + _ = x[OGE-63] + _ = x[OGT-64] + _ = x[ODEREF-65] + _ = x[OINDEX-66] + _ = x[OINDEXMAP-67] + _ = x[OKEY-68] + _ = x[OSTRUCTKEY-69] + _ = x[OLEN-70] + _ = x[OMAKE-71] + _ = x[OMAKECHAN-72] + _ = x[OMAKEMAP-73] + _ = x[OMAKESLICE-74] + _ = x[OMAKESLICECOPY-75] + _ = x[OMUL-76] + _ = x[ODIV-77] + _ = x[OMOD-78] + _ = x[OLSH-79] + _ = x[ORSH-80] + _ = x[OAND-81] + _ = x[OANDNOT-82] + _ = x[ONEW-83] + _ = x[ONOT-84] + _ = x[OBITNOT-85] + _ = x[OPLUS-86] + _ = x[ONEG-87] + _ = x[OOROR-88] + _ = x[OPANIC-89] + _ = x[OPRINT-90] + _ = x[OPRINTN-91] + _ = x[OPAREN-92] + _ = x[OSEND-93] + _ = x[OSLICE-94] + _ = x[OSLICEARR-95] + _ = x[OSLICESTR-96] + _ = x[OSLICE3-97] + _ = x[OSLICE3ARR-98] + _ = x[OSLICEHEADER-99] + _ = x[ORECOVER-100] + _ = x[ORECOVERFP-101] + _ = x[ORECV-102] + _ = x[ORUNESTR-103] + _ = x[OSELRECV2-104] + _ = x[OIOTA-105] + _ = x[OREAL-106] + _ = x[OIMAG-107] + _ = x[OCOMPLEX-108] + _ = x[OALIGNOF-109] + _ = x[OOFFSETOF-110] + _ = x[OSIZEOF-111] + _ = x[OUNSAFEADD-112] + _ = x[OUNSAFESLICE-113] + _ = x[OMETHEXPR-114] + _ = x[OMETHVALUE-115] + _ = x[OBLOCK-116] + _ = x[OBREAK-117] + _ = x[OCASE-118] + _ = x[OCONTINUE-119] + _ = x[ODEFER-120] + _ = x[OFALL-121] + _ = x[OFOR-122] + _ = x[OFORUNTIL-123] + _ = x[OGOTO-124] + _ = x[OIF-125] + _ = x[OLABEL-126] + _ = x[OGO-127] + _ = x[ORANGE-128] + _ = x[ORETURN-129] + _ = x[OSELECT-130] + _ = x[OSWITCH-131] + _ = x[OTYPESW-132] + _ = x[OFUNCINST-133] + _ = x[OTCHAN-134] + _ = x[OTMAP-135] + _ = x[OTSTRUCT-136] + _ = x[OTINTER-137] + _ = x[OTFUNC-138] + _ = x[OTARRAY-139] + _ = x[OTSLICE-140] + _ = x[OINLCALL-141] + _ = x[OEFACE-142] + _ = x[OITAB-143] + _ = x[OIDATA-144] + _ = x[OSPTR-145] + _ = x[OCFUNC-146] + _ = x[OCHECKNIL-147] + _ = x[OVARDEF-148] + _ = x[OVARKILL-149] + _ = x[OVARLIVE-150] + _ = x[ORESULT-151] + _ = x[OINLMARK-152] + _ = x[OLINKSYMOFFSET-153] + _ = x[OTAILCALL-154] + _ = x[OGETG-155] + _ = x[OGETCALLERPC-156] + _ = x[OGETCALLERSP-157] + _ = x[OEND-158] } -const _Op_name = "XXXNAMENONAMETYPEPACKLITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFUNSAFEADDUNSAFESLICEMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWFUNCINSTTCHANTMAPTSTRUCTTINTERTFUNCTARRAYTSLICEINLCALLEFACEITABIDATASPTRCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKLINKSYMOFFSETTAILCALLGETGGETCALLERPCGETCALLERSPEND" +const _Op_name = "XXXNAMENONAMETYPEPACKLITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVIDATACONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFUNSAFEADDUNSAFESLICEMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWFUNCINSTTCHANTMAPTSTRUCTTINTERTFUNCTARRAYTSLICEINLCALLEFACEITABIDATASPTRCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKLINKSYMOFFSETTAILCALLGETGGETCALLERPCGETCALLERSPEND" -var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 37, 39, 42, 48, 52, 58, 64, 73, 85, 94, 103, 115, 124, 136, 138, 141, 151, 158, 165, 172, 176, 180, 188, 196, 205, 208, 213, 220, 227, 233, 242, 250, 258, 264, 268, 277, 284, 288, 291, 298, 306, 313, 319, 322, 328, 335, 343, 347, 354, 362, 364, 366, 368, 370, 372, 374, 379, 384, 392, 395, 404, 407, 411, 419, 426, 435, 448, 451, 454, 457, 460, 463, 466, 472, 475, 478, 484, 488, 491, 495, 500, 505, 511, 516, 520, 525, 533, 541, 547, 556, 567, 574, 583, 587, 594, 602, 606, 610, 614, 621, 628, 636, 642, 651, 662, 670, 679, 684, 689, 693, 701, 706, 710, 713, 721, 725, 727, 732, 734, 739, 745, 751, 757, 763, 771, 776, 780, 787, 793, 798, 804, 810, 817, 822, 826, 831, 835, 840, 848, 854, 861, 868, 874, 881, 894, 902, 906, 917, 928, 931} +var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 37, 39, 42, 48, 52, 58, 64, 73, 85, 94, 103, 115, 124, 136, 138, 141, 151, 158, 165, 172, 176, 180, 188, 196, 205, 208, 213, 220, 227, 233, 242, 250, 258, 264, 268, 277, 286, 293, 297, 300, 307, 315, 322, 328, 331, 337, 344, 352, 356, 363, 371, 373, 375, 377, 379, 381, 383, 388, 393, 401, 404, 413, 416, 420, 428, 435, 444, 457, 460, 463, 466, 469, 472, 475, 481, 484, 487, 493, 497, 500, 504, 509, 514, 520, 525, 529, 534, 542, 550, 556, 565, 576, 583, 592, 596, 603, 611, 615, 619, 623, 630, 637, 645, 651, 660, 671, 679, 688, 693, 698, 702, 710, 715, 719, 722, 730, 734, 736, 741, 743, 748, 754, 760, 766, 772, 780, 785, 789, 796, 802, 807, 813, 819, 826, 831, 835, 840, 844, 849, 857, 863, 870, 877, 883, 890, 903, 911, 915, 926, 937, 940} func (i Op) String() string { if i >= Op(len(_Op_index)-1) { diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 85538f590dc..e308dd7a05b 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -1461,24 +1461,18 @@ func (subst *subster) convertUsingDictionary(pos src.XPos, v ir.Node, gn ir.Node rt = subst.getDictionaryType(pos, ix) } - // Convert value to an interface type, so the data field is what we want. - if !v.Type().IsInterface() { - v = ir.NewConvExpr(v.Pos(), ir.OCONVIFACE, nil, v) - typed(types.NewInterface(types.LocalPkg, nil), v) + // Figure out what the data field of the interface will be. + var data ir.Node + if v.Type().IsInterface() { + data = ir.NewUnaryExpr(pos, ir.OIDATA, v) + } else { + data = ir.NewConvExpr(pos, ir.OCONVIDATA, nil, v) } - - // At this point, v is an interface type with a data word we want. - // But the type word represents a gcshape type, which we don't want. - // Replace with the instantiated type loaded from the dictionary. - data := ir.NewUnaryExpr(pos, ir.OIDATA, v) typed(types.Types[types.TUNSAFEPTR], data) + + // Build an interface from the type and data parts. var i ir.Node = ir.NewBinaryExpr(pos, ir.OEFACE, rt, data) typed(dst, i) - // TODO: we're throwing away the type word of the original version - // of m here (it would be OITAB(m)), which probably took some - // work to generate. Can we avoid generating it at all? - // (The linker will throw them away if not needed, so it would just - // save toolchain work, not binary size.) return i } diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index 875d53b3cca..7eba5fb41e4 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -1983,10 +1983,8 @@ var ZeroSize int64 // This information is used in the linker in dead method elimination. func MarkTypeUsedInInterface(t *types.Type, from *obj.LSym) { if t.HasShape() { - // TODO: shape types shouldn't be put in interfaces, so we shouldn't ever get here. - // We don't from ../noder/stencil.go, but we do from ../walk/walk.go when we let - // shape types become the types of interfaces. - //base.Fatalf("shape types have no methods %+v", t) + // Shape types shouldn't be put in interfaces, so we shouldn't ever get here. + base.Fatalf("shape types have no methods %+v", t) } tsym := TypeLinksym(t) // Emit a marker relocation. The linker will know the type is converted diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index b054c73ad80..25a0bfbb3a4 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -1873,7 +1873,7 @@ func (w *exportWriter) expr(n ir.Node) { w.op(ir.OEND) } - case ir.OCONV, ir.OCONVIFACE, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR, ir.OSLICE2ARRPTR: + case ir.OCONV, ir.OCONVIFACE, ir.OCONVIDATA, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR, ir.OSLICE2ARRPTR: n := n.(*ir.ConvExpr) if go117ExportTypes { w.op(n.Op()) diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 9bef07b6365..b389c7fcb07 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -1446,7 +1446,7 @@ func (r *importReader) node() ir.Node { } return n - case ir.OCONV, ir.OCONVIFACE, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR, ir.OSLICE2ARRPTR: + case ir.OCONV, ir.OCONVIFACE, ir.OCONVIDATA, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR, ir.OSLICE2ARRPTR: if !go117ExportTypes && op != ir.OCONV { // unreachable - mapped to OCONV case by exporter goto error diff --git a/src/cmd/compile/internal/walk/assign.go b/src/cmd/compile/internal/walk/assign.go index 6d697a53ae3..d4c1aafdc12 100644 --- a/src/cmd/compile/internal/walk/assign.go +++ b/src/cmd/compile/internal/walk/assign.go @@ -429,6 +429,7 @@ func readsMemory(n ir.Node) bool { ir.OBITNOT, ir.OCONV, ir.OCONVIFACE, + ir.OCONVIDATA, ir.OCONVNOP, ir.ODIV, ir.ODOT, diff --git a/src/cmd/compile/internal/walk/convert.go b/src/cmd/compile/internal/walk/convert.go index e659ee59f14..d15575f643c 100644 --- a/src/cmd/compile/internal/walk/convert.go +++ b/src/cmd/compile/internal/walk/convert.go @@ -39,14 +39,22 @@ func walkConv(n *ir.ConvExpr, init *ir.Nodes) ir.Node { return typecheck.Conv(mkcall(fn, types.Types[result], init, typecheck.Conv(n.X, types.Types[param])), n.Type()) } -// walkConvInterface walks an OCONVIFACE node. +// walkConvInterface walks an OCONVIFACE or OCONVIDATA node. func walkConvInterface(n *ir.ConvExpr, init *ir.Nodes) ir.Node { + n.X = walkExpr(n.X, init) fromType := n.X.Type() toType := n.Type() - - if !fromType.IsInterface() && !ir.IsBlank(ir.CurFunc.Nname) { // skip unnamed functions (func _()) + if n.Op() == ir.OCONVIDATA { + // Just convert to empty interface, to make it easy. + // The caller throws away the type word. + toType = types.NewInterface(types.LocalPkg, nil) + // Note: don't pass fromType to MarkTypeUsedInInterface because it is likely + // a shape type. The appropriate call to MarkTypeUsedInInterface will come + // when building the dictionary (from which the matching type word will come). + } else if !fromType.IsInterface() && !ir.IsBlank(ir.CurFunc.Nname) { + // skip unnamed functions (func _()) reflectdata.MarkTypeUsedInInterface(fromType, ir.CurFunc.LSym) } diff --git a/src/cmd/compile/internal/walk/expr.go b/src/cmd/compile/internal/walk/expr.go index eed6ef86c23..f0d37198d37 100644 --- a/src/cmd/compile/internal/walk/expr.go +++ b/src/cmd/compile/internal/walk/expr.go @@ -206,6 +206,13 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node { n := n.(*ir.ConvExpr) return walkConvInterface(n, init) + case ir.OCONVIDATA: + n := n.(*ir.ConvExpr) + r := ir.NewUnaryExpr(n.Pos(), ir.OIDATA, walkConvInterface(n, init)) + r.SetType(types.Types[types.TUNSAFEPTR]) + r.SetTypecheck(1) + return r + case ir.OCONV, ir.OCONVNOP: n := n.(*ir.ConvExpr) return walkConv(n, init) diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go index cd2bbcb73ba..fe6ae3fda00 100644 --- a/src/cmd/compile/internal/walk/order.go +++ b/src/cmd/compile/internal/walk/order.go @@ -1156,16 +1156,20 @@ func (o *orderState) expr1(n, lhs ir.Node) ir.Node { // concrete type (not interface) argument might need an addressable // temporary to pass to the runtime conversion routine. - case ir.OCONVIFACE: + case ir.OCONVIFACE, ir.OCONVIDATA: n := n.(*ir.ConvExpr) n.X = o.expr(n.X, nil) if n.X.Type().IsInterface() { return n } - if _, _, needsaddr := convFuncName(n.X.Type(), n.Type()); needsaddr || isStaticCompositeLiteral(n.X) { + to := n.Type() + if n.Op() == ir.OCONVIDATA { + to = types.NewInterface(types.LocalPkg, nil) + } + if _, _, needsaddr := convFuncName(n.X.Type(), to); needsaddr || isStaticCompositeLiteral(n.X) { // Need a temp if we need to pass the address to the conversion function. // We also process static composite literal node here, making a named static global - // whose address we can put directly in an interface (see OCONVIFACE case in walk). + // whose address we can put directly in an interface (see OCONVIFACE/OCONVIDATA case in walk). n.X = o.addrTemp(n.X) } return n From 3dc0a0a2c5a7d8959a43265d4f73d7e2e509de5e Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Fri, 23 Jul 2021 17:19:51 -0700 Subject: [PATCH 779/940] [dev.typeparams] cmd/compile: get rid of concretify use for bounds. We just need to substitute from the typeparams to the shapes for the dst type of the bound. Removed concretify substituter, not used anymore. Also removed shape2params, not needed anymore. However, since the dst type is now not concrete, this gives more cases where the linker can't find a method. I realized that we need to call MarkUsedIfaceMethod to mark a method as used on a particular interface, else a type's method can be still deadcoded even though MarkTypeUsedInInterface has been called on the concrete type. I added a new version MarkUsedIfaceMethodIndex to fit my use case. Change-Id: Id67b72b350889dd3688b42739c337d5d79a0d1a2 Reviewed-on: https://go-review.googlesource.com/c/go/+/337230 Trust: Dan Scales Reviewed-by: Keith Randall --- src/cmd/compile/internal/noder/stencil.go | 36 +++++++++---------- .../compile/internal/reflectdata/reflect.go | 12 ++++++- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index e308dd7a05b..f1de1152c55 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -855,13 +855,9 @@ type subster struct { ts typecheck.Tsubster info *instInfo // Place to put extra info in the instantiation - // Which type parameter the shape type came from. - shape2param map[*types.Type]*types.Type - // unshapeify maps from shape types to the concrete types they represent. // TODO: remove when we no longer need it. - unshapify typecheck.Tsubster - concretify typecheck.Tsubster + unshapify typecheck.Tsubster // TODO: some sort of map from to index in the // dictionary where a *runtime.itab for the corresponding Date: Sun, 18 Jul 2021 11:10:41 -0700 Subject: [PATCH 780/940] [dev.typeparams] transformDot() should set Selection and tc flag for added ODOTs Fixes -G=3 issue with issue44688.go. Change-Id: Ie98c0cbd48683dedd115332043f14c8f3160f46c Reviewed-on: https://go-review.googlesource.com/c/go/+/337029 Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall Trust: Dan Scales --- src/cmd/compile/internal/noder/transform.go | 18 ++++++++++++++++++ test/run.go | 3 +-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go index f89ae132379..2fe55a6852f 100644 --- a/src/cmd/compile/internal/noder/transform.go +++ b/src/cmd/compile/internal/noder/transform.go @@ -591,6 +591,24 @@ func transformDot(n *ir.SelectorExpr, isCall bool) ir.Node { if n.Op() == ir.OXDOT { n = typecheck.AddImplicitDots(n) n.SetOp(ir.ODOT) + + // Set the Selection field and typecheck flag for any new ODOT nodes + // added by AddImplicitDots(), and also transform to ODOTPTR if + // needed. Equivalent to 'n.X = typecheck(n.X, ctxExpr|ctxType)' in + // tcDot. + for n1 := n; n1.X.Op() == ir.ODOT; { + n1 = n1.X.(*ir.SelectorExpr) + if !n1.Implicit() { + break + } + t1 := n1.X.Type() + if t1.IsPtr() && !t1.Elem().IsInterface() { + t1 = t1.Elem() + n1.SetOp(ir.ODOTPTR) + } + typecheck.Lookdot(n1, t1, 0) + n1.SetTypecheck(1) + } } t := n.X.Type() diff --git a/test/run.go b/test/run.go index 5624654fec9..1e7fab4359d 100644 --- a/test/run.go +++ b/test/run.go @@ -2185,8 +2185,7 @@ var g3Failures = setOf( "typeparam/mdempsky/4.go", // -G=3 can't export functions with labeled breaks in loops "typeparam/mdempsky/13.go", // problem with interface as as a type arg. - "typeparam/cons.go", // causes an unreachable method - "typeparam/issue44688.go", // interface conversion fails due to missing method + "typeparam/cons.go", // causes an unreachable method ) var unifiedFailures = setOf( From b27c7e30dc5d222766057e62c16cb765b636d244 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Sat, 24 Jul 2021 14:11:27 -0700 Subject: [PATCH 781/940] [dev.typeparams] cmd/compile: fix HasShape, add dottype test HasShape needs a TINTER case. Add a test for x.(T) in various situations. Needs the fix above. Also remove ONEW unshapify case. It is ok for ONEW to have a shape type, as it will just be passed to mallocgc, or possibly used as a stack object type, both of which are ok. Change-Id: Ibddf8f5c8c254d32cb5ebcaca7dc94b4c00ab893 Reviewed-on: https://go-review.googlesource.com/c/go/+/337231 Trust: Keith Randall Trust: Dan Scales Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/noder/stencil.go | 6 -- src/cmd/compile/internal/types/type.go | 8 ++- test/typeparam/dottype.go | 81 +++++++++++++++++++++++ test/typeparam/dottype.out | 8 +++ 4 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 test/typeparam/dottype.go create mode 100644 test/typeparam/dottype.out diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index f1de1152c55..575b879762f 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -1376,12 +1376,6 @@ func (subst *subster) node(n ir.Node) ir.Node { case ir.ODOTTYPE, ir.ODOTTYPE2: m.SetType(subst.unshapifyTyp(m.Type())) - case ir.ONEW: - // New needs to pass a concrete type to the runtime. - // Or maybe it doesn't? We could use a shape type. - // TODO: need to modify m.X? I don't think any downstream passes use it. - m.SetType(subst.unshapifyTyp(m.Type())) - case ir.OMETHEXPR: se := m.(*ir.SelectorExpr) se.X = ir.TypeNodeAt(se.X.Pos(), subst.unshapifyTyp(se.X.Type())) diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index e6ae0e7bc1a..58ac4db95a2 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -2189,7 +2189,13 @@ func (t *Type) HasShape1(visited map[*Type]bool) bool { } } } - // TODO: TINTER - check methods? + case TINTER: + for _, f := range t.Methods().Slice() { + if f.Type.HasShape1(visited) { + return true + } + } + return false } return false } diff --git a/test/typeparam/dottype.go b/test/typeparam/dottype.go new file mode 100644 index 00000000000..0131f642028 --- /dev/null +++ b/test/typeparam/dottype.go @@ -0,0 +1,81 @@ +// run -gcflags=-G=3 + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func f[T any](x interface{}) T { + return x.(T) +} +func f2[T any](x interface{}) (T, bool) { + t, ok := x.(T) + return t, ok +} + +type I interface { + foo() +} + +type myint int + +func (myint) foo() { +} + +type myfloat float64 + +func (myfloat) foo() { +} + +func g[T I](x I) T { + return x.(T) +} +func g2[T I](x I) (T, bool) { + t, ok := x.(T) + return t, ok +} + +func h[T any](x interface{}) struct{a, b T} { + return x.(struct{a, b T}) +} + +func k[T any](x interface{}) interface { bar() T } { + return x.(interface{bar() T }) +} + +type mybar int +func (x mybar) bar() int { + return int(x) +} + + +func main() { + var i interface{} = int(3) + var j I = myint(3) + var x interface{} = float64(3) + var y I = myfloat(3) + + println(f[int](i)) + shouldpanic(func() { f[int](x) }) + println(f2[int](i)) + println(f2[int](x)) + + println(g[myint](j)) + shouldpanic(func() { g[myint](y) }) + println(g2[myint](j)) + println(g2[myint](y)) + + println(h[int](struct{a, b int}{3, 5}).a) + + println(k[int](mybar(3)).bar()) +} +func shouldpanic(x func()) { + defer func() { + e := recover() + if e == nil { + panic("didn't panic") + } + }() + x() +} diff --git a/test/typeparam/dottype.out b/test/typeparam/dottype.out new file mode 100644 index 00000000000..058c923a5ce --- /dev/null +++ b/test/typeparam/dottype.out @@ -0,0 +1,8 @@ +3 +3 true +0 false +3 +3 true +0 false +3 +3 From 849b7911293c3cb11d76ff2778ed560100f987d1 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sat, 24 Jul 2021 16:53:02 -0700 Subject: [PATCH 782/940] spec: use consistent capitalization for rune literal hex constants Fixes #47368 Change-Id: I2f65c0008658532123f04d08e99e5d083f33461a Reviewed-on: https://go-review.googlesource.com/c/go/+/337234 Trust: Ian Lance Taylor Trust: Robert Griesemer Reviewed-by: Emmanuel Odeke Reviewed-by: Robert Griesemer --- doc/go_spec.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index df256f0f0ee..cc7ed6a5618 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -490,8 +490,8 @@ After a backslash, certain single-character escapes represent special values: \n U+000A line feed or newline \r U+000D carriage return \t U+0009 horizontal tab -\v U+000b vertical tab -\\ U+005c backslash +\v U+000B vertical tab +\\ U+005C backslash \' U+0027 single quote (valid escape only within rune literals) \" U+0022 double quote (valid escape only within string literals) From 1868f8296eb15d11c45c2c7c1d373b211f745d84 Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Sun, 25 Jul 2021 21:04:33 -0400 Subject: [PATCH 783/940] crypto/x509: update iOS bundled roots to version 55188.120.1.0.1 Updates #38843. Change-Id: I6e003ed03cd13d8ecf86ce05ab0e11c47e271c0b Reviewed-on: https://go-review.googlesource.com/c/go/+/337329 Trust: Dmitri Shuralyov Run-TryBot: Dmitri Shuralyov TryBot-Result: Go Bot Reviewed-by: Filippo Valsorda --- src/crypto/x509/root.go | 2 +- src/crypto/x509/root_ios.go | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/crypto/x509/root.go b/src/crypto/x509/root.go index cc53f7aefca..eef9c047b2e 100644 --- a/src/crypto/x509/root.go +++ b/src/crypto/x509/root.go @@ -8,7 +8,7 @@ package x509 // argument to the latest security_certificates version from // https://opensource.apple.com/source/security_certificates/ // and run "go generate". See https://golang.org/issue/38843. -//go:generate go run root_ios_gen.go -version 55188.40.9 +//go:generate go run root_ios_gen.go -version 55188.120.1.0.1 import "sync" diff --git a/src/crypto/x509/root_ios.go b/src/crypto/x509/root_ios.go index 50432f3d2c5..9bc62f8abb6 100644 --- a/src/crypto/x509/root_ios.go +++ b/src/crypto/x509/root_ios.go @@ -1,4 +1,4 @@ -// Code generated by root_ios_gen.go -version 55188.40.9; DO NOT EDIT. +// Code generated by root_ios_gen.go -version 55188.120.1.0.1; DO NOT EDIT. // Update the version in root.go and regenerate with "go generate". //go:build ios && !x509omitbundledroots @@ -2223,6 +2223,41 @@ uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs ewv4n4Q= -----END CERTIFICATE----- +# "GlobalSign" +# 2C AB EA FE 37 D0 6C A2 2A BA 73 91 C0 03 3D 25 +# 98 29 52 C4 53 64 73 49 76 3A 3A B5 AD 6C CF 69 +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg +MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh +bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx +MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET +MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI +xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k +ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD +aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw +LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw +1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX +k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2 +SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h +bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n +WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY +rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce +MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu +bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN +nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt +Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61 +55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj +vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf +cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz +oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp +nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs +pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v +JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R +8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4 +5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= +-----END CERTIFICATE----- # "GlobalSign Root CA" # EB D4 10 40 E4 BB 3E C7 42 C9 E3 81 D3 1E F2 A4 # 1A 48 B6 68 5C 96 E7 CE F3 C1 DF 6C D4 33 1C 99 From ecaa6816bfdbcef2ad749958a11a321de5c2ebd8 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Sat, 24 Jul 2021 18:34:16 +0700 Subject: [PATCH 784/940] doc: clarify non-nil zero length slice to array pointer conversion There is an example for nil slice already, so adding example for non-nil zero length slice, too, clarifying to the reader that the result is also non-nil and different from nil slice case. Updates #395 Change-Id: I019db1b1a1c0c621161ecaaacab5a4d888764b1a Reviewed-on: https://go-review.googlesource.com/c/go/+/336890 Trust: Cuong Manh Le Trust: Robert Griesemer Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- doc/go_spec.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index cc7ed6a5618..0e14a1f3b63 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -4335,6 +4335,9 @@ s4 := (*[4]byte)(s) // panics: len([4]byte) > len(s) var t []string t0 := (*[0]string)(t) // t0 == nil t1 := (*[1]string)(t) // panics: len([1]string) > len(t) + +u := make([]byte, 0) +u0 = (*[0]byte)(u) // u0 != nil

Constant expressions

From bfcb7c4c8adadd6191c3fdacf2b59136b0da5c1c Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 2 Jul 2021 16:59:01 -0700 Subject: [PATCH 785/940] [dev.typeparams] cmd/compile: fix unified IR support for //go:nointerface This CL changes fixedbugs/issue30862.go into a "runindir" test so that it can use '-goexperiment fieldtrack' and test that //go:nointerface works with cmd/compile. In particular, this revealed that -G=3 and unified IR did not handle it correctly. This CL also fixes unified IR's support for //go:nointerface and adds a test that checks that //go:nointerface, promoted methods, and generics all interact as expected. Updates #47045. Change-Id: Ib8acff8ae18bf124520d00c98e8915699cba2abd Reviewed-on: https://go-review.googlesource.com/c/go/+/332611 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Trust: Matthew Dempsky Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/noder/reader.go | 5 +- test/fixedbugs/issue30862.dir/{ => a}/a.go | 0 test/fixedbugs/issue30862.dir/{ => b}/b.go | 2 +- test/fixedbugs/issue30862.dir/main.go | 2 +- test/fixedbugs/issue30862.go | 4 +- test/run.go | 6 +- test/typeparam/mdempsky/15.go | 69 ++++++++++++++++++++++ 7 files changed, 78 insertions(+), 10 deletions(-) rename test/fixedbugs/issue30862.dir/{ => a}/a.go (100%) rename test/fixedbugs/issue30862.dir/{ => b}/b.go (95%) create mode 100644 test/typeparam/mdempsky/15.go diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 44d1c4f28be..516bf8f1f74 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -750,13 +750,12 @@ func (r *reader) method() *types.Field { name.Func = ir.NewFunc(r.pos()) name.Func.Nname = name - // TODO(mdempsky): Make sure we're handling //go:nointerface - // correctly. I don't think this is exercised within the Go repo. - r.ext.funcExt(name) meth := types.NewField(name.Func.Pos(), sym, typ) meth.Nname = name + meth.SetNointerface(name.Func.Pragma&ir.Nointerface != 0) + return meth } diff --git a/test/fixedbugs/issue30862.dir/a.go b/test/fixedbugs/issue30862.dir/a/a.go similarity index 100% rename from test/fixedbugs/issue30862.dir/a.go rename to test/fixedbugs/issue30862.dir/a/a.go diff --git a/test/fixedbugs/issue30862.dir/b.go b/test/fixedbugs/issue30862.dir/b/b.go similarity index 95% rename from test/fixedbugs/issue30862.dir/b.go rename to test/fixedbugs/issue30862.dir/b/b.go index 3e501bb8dcb..230221d5036 100644 --- a/test/fixedbugs/issue30862.dir/b.go +++ b/test/fixedbugs/issue30862.dir/b/b.go @@ -4,7 +4,7 @@ package b -import "./a" +import "issue30862.dir/a" type EmbedImported struct { a.NoitfStruct diff --git a/test/fixedbugs/issue30862.dir/main.go b/test/fixedbugs/issue30862.dir/main.go index 80db0e13a84..1489c5a3425 100644 --- a/test/fixedbugs/issue30862.dir/main.go +++ b/test/fixedbugs/issue30862.dir/main.go @@ -8,7 +8,7 @@ import ( "fmt" "os" - "./b" + "issue30862.dir/b" ) // Test case for issue 30862. diff --git a/test/fixedbugs/issue30862.go b/test/fixedbugs/issue30862.go index ba122cc3c8b..acac71e2cca 100644 --- a/test/fixedbugs/issue30862.go +++ b/test/fixedbugs/issue30862.go @@ -1,4 +1,4 @@ -// rundir +// runindir -goexperiment fieldtrack // Copyright 2019 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -9,6 +9,4 @@ // is set when building it, whereas gccgo has field tracking // enabled by default (hence the build tag below). -// +build gccgo - package ignored diff --git a/test/run.go b/test/run.go index 1e7fab4359d..2e72d55b761 100644 --- a/test/run.go +++ b/test/run.go @@ -2180,12 +2180,14 @@ var types2Failures32Bit = setOf( var g3Failures = setOf( "writebarrier.go", // correct diagnostics, but different lines (probably irgen's fault) + "fixedbugs/issue30862.go", // -G=3 doesn't handle //go:nointerface + + "typeparam/cons.go", // causes an unreachable method "typeparam/nested.go", // -G=3 doesn't support function-local types with generics "typeparam/mdempsky/4.go", // -G=3 can't export functions with labeled breaks in loops "typeparam/mdempsky/13.go", // problem with interface as as a type arg. - - "typeparam/cons.go", // causes an unreachable method + "typeparam/mdempsky/15.go", // ICE in (*irgen).buildClosure ) var unifiedFailures = setOf( diff --git a/test/typeparam/mdempsky/15.go b/test/typeparam/mdempsky/15.go new file mode 100644 index 00000000000..4899fc75eec --- /dev/null +++ b/test/typeparam/mdempsky/15.go @@ -0,0 +1,69 @@ +// run -goexperiment fieldtrack -gcflags=-G=3 + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test that generics, promoted methods, and //go:nointerface +// interoperate as expected. + +package main + +import ( + "reflect" +) + +func TypeString[T any]() string { + return reflect.TypeOf(new(T)).Elem().String() +} + +func Test[T, Bad, Good any]() { + switch interface{}(new(T)).(type) { + case Bad: + println("FAIL:", TypeString[T](), "matched", TypeString[Bad]()) + case Good: + // ok + default: + println("FAIL:", TypeString[T](), "did not match", TypeString[Good]()) + } +} + +func TestE[T any]() { Test[T, interface{ EBad() }, interface{ EGood() }]() } +func TestX[T any]() { Test[T, interface{ XBad() }, interface{ XGood() }]() } + +type E struct{} + +//go:nointerface +func (E) EBad() {} +func (E) EGood() {} + +type X[T any] struct{ E } + +//go:nointerface +func (X[T]) XBad() {} +func (X[T]) XGood() {} + +type W struct{ X[int] } + +func main() { + _ = E.EGood + _ = E.EBad + + TestE[E]() + + _ = X[int].EGood + _ = X[int].EBad + _ = X[int].XGood + _ = X[int].XBad + + TestE[X[int]]() + TestX[X[int]]() + + _ = W.EGood + _ = W.EBad + _ = W.XGood + _ = W.XBad + + TestE[W]() + TestX[W]() +} From b93f646125882fc59a6dd5a9c83813dce674bc6b Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 21 Jul 2021 16:36:49 -0700 Subject: [PATCH 786/940] [dev.typeparams] cmd/compile/internal/types2: fix a bug in package qualification logic This is a partial port of https://golang.org/cl/330629, containing only the actual bug fix and adjustements to another test file. The respective test case has not been ported yet as it requires some bigger adjustments. For #46905 Change-Id: Ibd20658b8a31855da20cf56e24bcce9560656ca0 Reviewed-on: https://go-review.googlesource.com/c/go/+/336350 Trust: Robert Griesemer Run-TryBot: Robert Griesemer Reviewed-by: Robert Findley TryBot-Result: Go Bot --- src/cmd/compile/internal/types2/errors.go | 2 +- src/cmd/compile/internal/types2/testdata/check/issues.src | 4 ++-- test/run.go | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/cmd/compile/internal/types2/errors.go b/src/cmd/compile/internal/types2/errors.go index af4ecb2300a..8c5e185f6cb 100644 --- a/src/cmd/compile/internal/types2/errors.go +++ b/src/cmd/compile/internal/types2/errors.go @@ -111,7 +111,7 @@ func (check *Checker) qualifier(pkg *Package) string { if check.pkgPathMap == nil { check.pkgPathMap = make(map[string]map[string]bool) check.seenPkgMap = make(map[*Package]bool) - check.markImports(pkg) + check.markImports(check.pkg) } // If the same package name was used by multiple packages, display the full path. if len(check.pkgPathMap[pkg.name]) > 1 { diff --git a/src/cmd/compile/internal/types2/testdata/check/issues.src b/src/cmd/compile/internal/types2/testdata/check/issues.src index 60d23b3c3bc..7219a560b1c 100644 --- a/src/cmd/compile/internal/types2/testdata/check/issues.src +++ b/src/cmd/compile/internal/types2/testdata/check/issues.src @@ -332,7 +332,7 @@ func issue28281g() (... /* ERROR can only use ... with final parameter in list * func issue26234a(f *syn.File) { // The error message below should refer to the actual package name (syntax) // not the local package name (syn). - f.foo /* ERROR f.foo undefined \(type \*syntax.File has no field or method foo\) */ + f.foo /* ERROR f\.foo undefined \(type \*syntax\.File has no field or method foo\) */ } type T struct { @@ -361,7 +361,7 @@ func issue35895() { // Because both t1 and t2 have the same global package name (template), // qualify packages with full path name in this case. - var _ t1.Template = t2 /* ERROR cannot use .* \(value of type "html/template".Template\) as "text/template".Template */ .Template{} + var _ t1.Template = t2 /* ERROR cannot use .* \(value of type .html/template.\.Template\) as .text/template.\.Template */ .Template{} } func issue42989(s uint) { diff --git a/test/run.go b/test/run.go index 2e72d55b761..edf26a5d82d 100644 --- a/test/run.go +++ b/test/run.go @@ -2140,7 +2140,6 @@ var types2Failures = setOf( "fixedbugs/issue11610.go", // types2 not run after syntax errors "fixedbugs/issue11614.go", // types2 reports an extra error "fixedbugs/issue14520.go", // missing import path error by types2 - "fixedbugs/issue16133.go", // types2 doesn't use package path for qualified identifiers when package name is ambiguous "fixedbugs/issue16428.go", // types2 reports two instead of one error "fixedbugs/issue17038.go", // types2 doesn't report a follow-on error (pref: types2) "fixedbugs/issue17645.go", // multiple errors on same line From 9e3274bb3d8170efba1c0b42fa09334f1d3f6677 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 21 Jul 2021 16:45:00 -0700 Subject: [PATCH 787/940] [dev.typeparams] cmd/compile/internal/types2: import regexp/syntax instead of cmd/compile/internal/syntax This is a straight port of https://golang.org/cl/330431. For #43232 Change-Id: I5954bdff22a524eaa08754947da9b428b27f7d95 Reviewed-on: https://go-review.googlesource.com/c/go/+/336351 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/testdata/check/issues.src | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cmd/compile/internal/types2/testdata/check/issues.src b/src/cmd/compile/internal/types2/testdata/check/issues.src index 7219a560b1c..692ed37ef4b 100644 --- a/src/cmd/compile/internal/types2/testdata/check/issues.src +++ b/src/cmd/compile/internal/types2/testdata/check/issues.src @@ -6,7 +6,7 @@ package go1_17 // don't permit non-interface elements in interfaces import ( "fmt" - syn "cmd/compile/internal/syntax" + syn "regexp/syntax" t1 "text/template" t2 "html/template" ) @@ -329,10 +329,10 @@ func (... /* ERROR can only use ... with final parameter in list */ TT) f() func issue28281g() (... /* ERROR can only use ... with final parameter in list */ TT) // Issue #26234: Make various field/method lookup errors easier to read by matching cmd/compile's output -func issue26234a(f *syn.File) { +func issue26234a(f *syn.Prog) { // The error message below should refer to the actual package name (syntax) // not the local package name (syn). - f.foo /* ERROR f\.foo undefined \(type \*syntax\.File has no field or method foo\) */ + f.foo /* ERROR f\.foo undefined \(type \*syntax\.Prog has no field or method foo\) */ } type T struct { @@ -357,7 +357,7 @@ func issue35895() { var _ T = 0 // ERROR cannot use 0 \(untyped int constant\) as T // There is only one package with name syntax imported, only use the (global) package name in error messages. - var _ *syn.File = 0 // ERROR cannot use 0 \(untyped int constant\) as \*syntax.File + var _ *syn.Prog = 0 // ERROR cannot use 0 \(untyped int constant\) as \*syntax.Prog // Because both t1 and t2 have the same global package name (template), // qualify packages with full path name in this case. From d6753fd491c101e71f5e86d87b44d396828e2deb Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 23 Jul 2021 10:26:07 -0700 Subject: [PATCH 788/940] [dev.typeparams] cmd/compile/internal/types2: implement TypeParam.Constraint Change-Id: I95a96f9dbd199cee3a4be8f42cd64e7f44ba5e5b Reviewed-on: https://go-review.googlesource.com/c/go/+/336989 Trust: Robert Griesemer Run-TryBot: Robert Griesemer Reviewed-by: Robert Findley TryBot-Result: Go Bot --- src/cmd/compile/internal/types2/typeparam.go | 32 ++++++++++++-------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/cmd/compile/internal/types2/typeparam.go b/src/cmd/compile/internal/types2/typeparam.go index b73b4edf79f..0aca227c0a7 100644 --- a/src/cmd/compile/internal/types2/typeparam.go +++ b/src/cmd/compile/internal/types2/typeparam.go @@ -53,20 +53,28 @@ func (t *TypeParam) SetId(id uint64) { t.id = id } +// Constraint returns the type constraint specified for t. +func (t *TypeParam) Constraint() Type { + // compute the type set if possible (we may not have an interface) + if iface, _ := under(t.bound).(*Interface); iface != nil { + // use the type bound position if we have one + pos := nopos + if n, _ := t.bound.(*Named); n != nil { + pos = n.obj.pos + } + computeTypeSet(t.check, pos, iface) + } + return t.bound +} + +// Bound returns the underlying type of the type parameter's +// constraint. +// Deprecated for external use. Use Constraint instead. func (t *TypeParam) Bound() *Interface { - // we may not have an interface (error reported elsewhere) - iface, _ := under(t.bound).(*Interface) - if iface == nil { - return &emptyInterface + if iface, _ := under(t.Constraint()).(*Interface); iface != nil { + return iface } - // use the type bound position if we have one - pos := nopos - if n, _ := t.bound.(*Named); n != nil { - pos = n.obj.pos - } - // TODO(gri) switch this to an unexported method on Checker. - computeTypeSet(t.check, pos, iface) - return iface + return &emptyInterface } func (t *TypeParam) SetBound(bound Type) { From 37d2219960340614f4d7e67c2e620013594e131a Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 26 Jul 2021 12:13:45 -0700 Subject: [PATCH 789/940] [dev.typeparams] cmd/compile/internal/types2: embedded type cannot be a (pointer to) a type parameter Change-Id: I5eb03ae349925f0799dd866e207221429bc9fb3c Reviewed-on: https://go-review.googlesource.com/c/go/+/337353 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/struct.go | 4 +++- .../internal/types2/testdata/check/typeparams.go2 | 4 ++-- .../internal/types2/testdata/fixedbugs/issue39938.go2 | 4 ++-- test/typeparam/interfacearg.go | 10 +++++----- test/typeparam/lockable.go | 10 +++++----- 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/cmd/compile/internal/types2/struct.go b/src/cmd/compile/internal/types2/struct.go index f1d82fb50c0..f0c27c01504 100644 --- a/src/cmd/compile/internal/types2/struct.go +++ b/src/cmd/compile/internal/types2/struct.go @@ -135,7 +135,7 @@ func (check *Checker) structType(styp *Struct, e *syntax.StructType) { embeddedPos := pos check.later(func() { t, isPtr := deref(embeddedTyp) - switch t := optype(t).(type) { + switch t := under(t).(type) { case *Basic: if t == Typ[Invalid] { // error was reported before @@ -147,6 +147,8 @@ func (check *Checker) structType(styp *Struct, e *syntax.StructType) { } case *Pointer: check.error(embeddedPos, "embedded field type cannot be a pointer") + case *TypeParam: + check.error(embeddedPos, "embedded field type cannot be a (pointer to a) type parameter") case *Interface: if isPtr { check.error(embeddedPos, "embedded field type cannot be a pointer to an interface") diff --git a/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 b/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 index 2755a539e52..54efd1485b1 100644 --- a/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 @@ -79,11 +79,11 @@ var _ *int = new[int]() func _[T any](map[T /* ERROR invalid map key type T \(missing comparable constraint\) */]int) // w/o constraint we don't know if T is comparable -func f1[T1 any](struct{T1}) int +func f1[T1 any](struct{T1 /* ERROR cannot be a .* type parameter */ }) int var _ = f1[int](struct{T1}{}) type T1 = int -func f2[t1 any](struct{t1; x float32}) int +func f2[t1 any](struct{t1 /* ERROR cannot be a .* type parameter */ ; x float32}) int var _ = f2[t1](struct{t1; x float32}{}) type t1 = int diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39938.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39938.go2 index 76e7e369ca1..0da6e103fd1 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39938.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39938.go2 @@ -8,8 +8,8 @@ package p type E0[P any] P type E1[P any] *P -type E2[P any] struct{ P } -type E3[P any] struct{ *P } +type E2[P any] struct{ _ P } +type E3[P any] struct{ _ *P } type T0 /* ERROR illegal cycle */ struct { _ E0[T0] diff --git a/test/typeparam/interfacearg.go b/test/typeparam/interfacearg.go index e2d85e3647b..1d194993187 100644 --- a/test/typeparam/interfacearg.go +++ b/test/typeparam/interfacearg.go @@ -9,14 +9,14 @@ package main type I interface{} type _S[T any] struct { - *T + x *T } // F is a non-generic function, but has a type _S[I] which is instantiated from a // generic type. Test that _S[I] is successfully exported. func F() { v := _S[I]{} - if v.T != nil { + if v.x != nil { panic(v) } } @@ -33,9 +33,9 @@ func _F1[T interface{ M() }](t T) { } func F2() { - _F1(&S1{}) - _F1(S2{}) - _F1(&S2{}) + _F1(&S1{}) + _F1(S2{}) + _F1(&S2{}) } func main() { diff --git a/test/typeparam/lockable.go b/test/typeparam/lockable.go index 3a03652cd8a..9372c76b4db 100644 --- a/test/typeparam/lockable.go +++ b/test/typeparam/lockable.go @@ -11,7 +11,7 @@ import "sync" // A Lockable is a value that may be safely simultaneously accessed // from multiple goroutines via the Get and Set methods. type Lockable[T any] struct { - T + x T mu sync.Mutex } @@ -19,18 +19,18 @@ type Lockable[T any] struct { func (l *Lockable[T]) get() T { l.mu.Lock() defer l.mu.Unlock() - return l.T + return l.x } // set sets the value in a Lockable. func (l *Lockable[T]) set(v T) { l.mu.Lock() defer l.mu.Unlock() - l.T = v + l.x = v } func main() { - sl := Lockable[string]{T: "a"} + sl := Lockable[string]{x: "a"} if got := sl.get(); got != "a" { panic(got) } @@ -39,7 +39,7 @@ func main() { panic(got) } - il := Lockable[int]{T: 1} + il := Lockable[int]{x: 1} if got := il.get(); got != 1 { panic(got) } From 9c81fd53b3ae52e286d3020ee8b381328b6b9bd2 Mon Sep 17 00:00:00 2001 From: 180909 <734461790@qq.com> Date: Sun, 25 Jul 2021 11:21:14 +0000 Subject: [PATCH 790/940] cmd/vet: add missing copyright header Change-Id: I78942dde77547f91daebe763328f52b4c476ddaf GitHub-Last-Rev: 423f1683fc7db8c1764383cf0a61c54ee21c06f2 GitHub-Pull-Request: golang/go#47334 Reviewed-on: https://go-review.googlesource.com/c/go/+/336434 Reviewed-by: Ian Lance Taylor Trust: Than McIntosh --- src/cmd/vet/main.go | 4 ++++ src/cmd/vet/testdata/copylock/copylock.go | 4 ++++ src/cmd/vet/testdata/httpresponse/httpresponse.go | 4 ++++ src/cmd/vet/testdata/testingpkg/tests.go | 4 ++++ src/cmd/vet/testdata/testingpkg/tests_test.go | 4 ++++ 5 files changed, 20 insertions(+) diff --git a/src/cmd/vet/main.go b/src/cmd/vet/main.go index a33bba24666..7da8606eceb 100644 --- a/src/cmd/vet/main.go +++ b/src/cmd/vet/main.go @@ -1,3 +1,7 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package main import ( diff --git a/src/cmd/vet/testdata/copylock/copylock.go b/src/cmd/vet/testdata/copylock/copylock.go index 8079cf3248b..7cfafe64086 100644 --- a/src/cmd/vet/testdata/copylock/copylock.go +++ b/src/cmd/vet/testdata/copylock/copylock.go @@ -1,3 +1,7 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package copylock import "sync" diff --git a/src/cmd/vet/testdata/httpresponse/httpresponse.go b/src/cmd/vet/testdata/httpresponse/httpresponse.go index 6141f6e06dc..98e394a2715 100644 --- a/src/cmd/vet/testdata/httpresponse/httpresponse.go +++ b/src/cmd/vet/testdata/httpresponse/httpresponse.go @@ -1,3 +1,7 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package httpresponse import ( diff --git a/src/cmd/vet/testdata/testingpkg/tests.go b/src/cmd/vet/testdata/testingpkg/tests.go index 69d29d3c6c6..8f4674d33c0 100644 --- a/src/cmd/vet/testdata/testingpkg/tests.go +++ b/src/cmd/vet/testdata/testingpkg/tests.go @@ -1 +1,5 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package testdata diff --git a/src/cmd/vet/testdata/testingpkg/tests_test.go b/src/cmd/vet/testdata/testingpkg/tests_test.go index 09bb98d980e..815dcc8a95f 100644 --- a/src/cmd/vet/testdata/testingpkg/tests_test.go +++ b/src/cmd/vet/testdata/testingpkg/tests_test.go @@ -1,3 +1,7 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package testdata func Example_BadSuffix() {} // ERROR "Example_BadSuffix has malformed example suffix: BadSuffix" From bfbb288574841f2db2499a580d7bf985a5df4556 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 25 Jul 2021 16:26:13 -0700 Subject: [PATCH 791/940] runtime: remove adjustTimers counter In CL 336432 we changed adjusttimers so that it no longer cleared timerModifiedEarliest if there were no timersModifiedEarlier timers. This caused some Google internal tests to time out, presumably due to the increased contention on timersLock. We can avoid that by simply not skipping the loop in adjusttimers, which lets us safely clear timerModifiedEarliest. And if we don't skip the loop, then there isn't much reason to keep the count of timerModifiedEarlier timers at all. So remove it. The effect will be that for programs that create some timerModifiedEarlier timers and then remove them all, the program will do an occasional additional loop over all the timers. And, programs that have some timerModifiedEarlier timers will always loop over all the timers, without the quicker exit when they have all been seen. But the loops should not occur all that often, due to timerModifiedEarliest. For #47329 Change-Id: I7b244c1244d97b169a3c7fbc8f8a8b115731ddee Reviewed-on: https://go-review.googlesource.com/c/go/+/337309 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Michael Pratt --- src/runtime/proc.go | 1 - src/runtime/runtime2.go | 6 ----- src/runtime/time.go | 55 +++++++---------------------------------- 3 files changed, 9 insertions(+), 53 deletions(-) diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 4c92588a66e..7bc2a925907 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -4919,7 +4919,6 @@ func (pp *p) destroy() { moveTimers(plocal, pp.timers) pp.timers = nil pp.numTimers = 0 - pp.adjustTimers = 0 pp.deletedTimers = 0 atomic.Store64(&pp.timer0When, 0) unlock(&pp.timersLock) diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index 8a15787382c..5051ec4d3e9 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -727,12 +727,6 @@ type p struct { // Modified using atomic instructions. numTimers uint32 - // Number of timerModifiedEarlier timers on P's heap. - // This should only be modified while holding timersLock, - // or while the timer status is in a transient state - // such as timerModifying. - adjustTimers uint32 - // Number of timerDeleted timers in P's heap. // Modified using atomic instructions. deletedTimers uint32 diff --git a/src/runtime/time.go b/src/runtime/time.go index 7b84d2af571..666b2423164 100644 --- a/src/runtime/time.go +++ b/src/runtime/time.go @@ -333,7 +333,6 @@ func deltimer(t *timer) bool { // Must fetch t.pp before setting status // to timerDeleted. tpp := t.pp.ptr() - atomic.Xadd(&tpp.adjustTimers, -1) if !atomic.Cas(&t.status, timerModifying, timerDeleted) { badTimer() } @@ -510,20 +509,9 @@ loop: tpp := t.pp.ptr() - // Update the adjustTimers field. Subtract one if we - // are removing a timerModifiedEarlier, add one if we - // are adding a timerModifiedEarlier. - adjust := int32(0) - if status == timerModifiedEarlier { - adjust-- - } if newStatus == timerModifiedEarlier { - adjust++ updateTimerModifiedEarliest(tpp, when) } - if adjust != 0 { - atomic.Xadd(&tpp.adjustTimers, adjust) - } // Set the new status of the timer. if !atomic.Cas(&t.status, timerModifying, newStatus) { @@ -591,9 +579,6 @@ func cleantimers(pp *p) { // Move t to the right position. dodeltimer0(pp) doaddtimer(pp, t) - if s == timerModifiedEarlier { - atomic.Xadd(&pp.adjustTimers, -1) - } if !atomic.Cas(&t.status, timerMoving, timerWaiting) { badTimer() } @@ -664,32 +649,23 @@ func moveTimers(pp *p, timers []*timer) { // it also moves timers that have been modified to run later, // and removes deleted timers. The caller must have locked the timers for pp. func adjusttimers(pp *p, now int64) { - if atomic.Load(&pp.adjustTimers) == 0 { + // If we haven't yet reached the time of the first timerModifiedEarlier + // timer, don't do anything. This speeds up programs that adjust + // a lot of timers back and forth if the timers rarely expire. + // We'll postpone looking through all the adjusted timers until + // one would actually expire. + first := atomic.Load64(&pp.timerModifiedEarliest) + if first == 0 || int64(first) > now { if verifyTimers { verifyTimerHeap(pp) } return } - // If we haven't yet reached the time of the first timerModifiedEarlier - // timer, don't do anything. This speeds up programs that adjust - // a lot of timers back and forth if the timers rarely expire. - // We'll postpone looking through all the adjusted timers until - // one would actually expire. - if first := atomic.Load64(&pp.timerModifiedEarliest); first != 0 { - if int64(first) > now { - if verifyTimers { - verifyTimerHeap(pp) - } - return - } - - // We are going to clear all timerModifiedEarlier timers. - atomic.Store64(&pp.timerModifiedEarliest, 0) - } + // We are going to clear all timerModifiedEarlier timers. + atomic.Store64(&pp.timerModifiedEarliest, 0) var moved []*timer -loop: for i := 0; i < len(pp.timers); i++ { t := pp.timers[i] if t.pp.ptr() != pp { @@ -716,11 +692,6 @@ loop: // loop to skip some other timer. dodeltimer(pp, i) moved = append(moved, t) - if s == timerModifiedEarlier { - if n := atomic.Xadd(&pp.adjustTimers, -1); int32(n) <= 0 { - break loop - } - } // Look at this heap position again. i-- } @@ -819,9 +790,6 @@ func runtimer(pp *p, now int64) int64 { t.when = t.nextwhen dodeltimer0(pp) doaddtimer(pp, t) - if s == timerModifiedEarlier { - atomic.Xadd(&pp.adjustTimers, -1) - } if !atomic.Cas(&t.status, timerMoving, timerWaiting) { badTimer() } @@ -916,7 +884,6 @@ func clearDeletedTimers(pp *p) { atomic.Store64(&pp.timerModifiedEarliest, 0) cdel := int32(0) - cearlier := int32(0) to := 0 changedHeap := false timers := pp.timers @@ -941,9 +908,6 @@ nextTimer: if !atomic.Cas(&t.status, timerMoving, timerWaiting) { badTimer() } - if s == timerModifiedEarlier { - cearlier++ - } continue nextTimer } case timerDeleted: @@ -980,7 +944,6 @@ nextTimer: atomic.Xadd(&pp.deletedTimers, -cdel) atomic.Xadd(&pp.numTimers, -cdel) - atomic.Xadd(&pp.adjustTimers, -cearlier) timers = timers[:to] pp.timers = timers From 840e583ff340d22a6263a348922283e6d5cd2e31 Mon Sep 17 00:00:00 2001 From: Koichi Shiraishi Date: Sun, 25 Jul 2021 03:00:04 +0900 Subject: [PATCH 792/940] runtime: correct variable name in comment Change-Id: Ic35ec2ed320c3c266afbeec8bdea1dedac4725e4 Reviewed-on: https://go-review.googlesource.com/c/go/+/336892 Reviewed-by: Ian Lance Taylor Trust: Austin Clements --- src/runtime/race.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/race.go b/src/runtime/race.go index cc8c5db1bd2..ce6b5b54681 100644 --- a/src/runtime/race.go +++ b/src/runtime/race.go @@ -343,7 +343,7 @@ func racereadrangepc1(addr, size, pc uintptr) func racewriterangepc1(addr, size, pc uintptr) func racecallbackthunk(uintptr) -// racecall allows calling an arbitrary function f from C race runtime +// racecall allows calling an arbitrary function fn from C race runtime // with up to 4 uintptr arguments. func racecall(fn *byte, arg0, arg1, arg2, arg3 uintptr) From 33ff1559702388c57c45f9e6cd032f06e8c3c163 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Mon, 26 Jul 2021 16:33:44 -0400 Subject: [PATCH 793/940] go/types: preserve untyped constants on the RHS of a shift expression CL 291316 fixed go/types to verify that untyped shift counts are representable by uint, but as a side effect also converted their types to uint. Rearrange the logic to keep the check for representability, but not actually convert untyped integer constants. Untyped non-integer constants are still converted, to preserve the behavior of 1.16. This behavior for non-integer types is a bug, filed as #47410. Updates #47410 Fixes #47243 Change-Id: I5eab4aab35b97f932fccdee2d4a18623ee2ccad5 Reviewed-on: https://go-review.googlesource.com/c/go/+/337529 Trust: Robert Findley Trust: Robert Griesemer Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/api_test.go | 12 ++++++++++++ src/go/types/check_test.go | 7 +++++++ src/go/types/expr.go | 34 +++++++++++++++++++++++++--------- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go index f37b91d5a4e..f964c656f93 100644 --- a/src/go/types/api_test.go +++ b/src/go/types/api_test.go @@ -322,6 +322,18 @@ func TestTypesInfo(t *testing.T) { `[][]struct{}`, }, + // issue 47243 + {`package issue47243_a; var x int32; var _ = x << 3`, `3`, `untyped int`}, + {`package issue47243_b; var x int32; var _ = x << 3.`, `3.`, `uint`}, // issue 47410: should be untyped float + {`package issue47243_c; var x int32; var _ = 1 << x`, `1 << x`, `int`}, + {`package issue47243_d; var x int32; var _ = 1 << x`, `1`, `int`}, + {`package issue47243_e; var x int32; var _ = 1 << 2`, `1`, `untyped int`}, + {`package issue47243_f; var x int32; var _ = 1 << 2`, `2`, `untyped int`}, + {`package issue47243_g; var x int32; var _ = int(1) << 2`, `2`, `untyped int`}, + {`package issue47243_h; var x int32; var _ = 1 << (2 << x)`, `1`, `int`}, + {`package issue47243_i; var x int32; var _ = 1 << (2 << x)`, `(2 << x)`, `untyped int`}, + {`package issue47243_j; var x int32; var _ = 1 << (2 << x)`, `2`, `untyped int`}, + // tests for broken code that doesn't parse or type-check {broken + `x0; func _() { var x struct {f string}; x.f := 0 }`, `x.f`, `string`}, {broken + `x1; func _() { var z string; type x struct {f string}; y := &x{q: z}}`, `z`, `string`}, diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go index c85a8e46fbb..f83abf11ce2 100644 --- a/src/go/types/check_test.go +++ b/src/go/types/check_test.go @@ -344,6 +344,13 @@ func TestIssue46453(t *testing.T) { checkFiles(t, nil, "", []string{"issue46453.go"}, [][]byte{[]byte(src)}, false, nil) } +func TestIssue47243_TypedRHS(t *testing.T) { + // The RHS of the shift expression below overflows uint on 32bit platforms, + // but this is OK as it is explicitly typed. + const src = "package issue47243\n\nvar a uint64; var _ = a << uint64(4294967296)" // uint64(1<<32) + checkFiles(t, &StdSizes{4, 4}, "", []string{"p.go"}, [][]byte{[]byte(src)}, false, nil) +} + func TestCheck(t *testing.T) { DefPredeclaredTestFuncs(); testDir(t, "check") } func TestExamples(t *testing.T) { testDir(t, "examples") } func TestFixedbugs(t *testing.T) { testDir(t, "fixedbugs") } diff --git a/src/go/types/expr.go b/src/go/types/expr.go index 5c65fad4479..58962e777bc 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -778,32 +778,48 @@ func (check *Checker) shift(x, y *operand, e ast.Expr, op token.Token) { // spec: "The right operand in a shift expression must have integer type // or be an untyped constant representable by a value of type uint." - // Provide a good error message for negative shift counts. + // Check that constants are representable by uint, but do not convert them + // (see also issue #47243). if y.mode == constant_ { + // Provide a good error message for negative shift counts. yval := constant.ToInt(y.val) // consider -1, 1.0, but not -1.1 if yval.Kind() == constant.Int && constant.Sign(yval) < 0 { check.invalidOp(y, _InvalidShiftCount, "negative shift count %s", y) x.mode = invalid return } + + if isUntyped(y.typ) { + // Caution: Check for representability here, rather than in the switch + // below, because isInteger includes untyped integers (was bug #43697). + check.representable(y, Typ[Uint]) + if y.mode == invalid { + x.mode = invalid + return + } + } } - // Caution: Check for isUntyped first because isInteger includes untyped - // integers (was bug #43697). - if isUntyped(y.typ) { + // Check that RHS is otherwise at least of integer type. + switch { + case isInteger(y.typ): + if !isUnsigned(y.typ) && !check.allowVersion(check.pkg, 1, 13) { + check.invalidOp(y, _InvalidShiftCount, "signed shift count %s requires go1.13 or later", y) + x.mode = invalid + return + } + case isUntyped(y.typ): + // This is incorrect, but preserves pre-existing behavior. + // See also bug #47410. check.convertUntyped(y, Typ[Uint]) if y.mode == invalid { x.mode = invalid return } - } else if !isInteger(y.typ) { + default: check.invalidOp(y, _InvalidShiftCount, "shift count %s must be integer", y) x.mode = invalid return - } else if !isUnsigned(y.typ) && !check.allowVersion(check.pkg, 1, 13) { - check.invalidOp(y, _InvalidShiftCount, "signed shift count %s requires go1.13 or later", y) - x.mode = invalid - return } if x.mode == constant_ { From 7ba8e796c91eaf4befcacc4d24127ae54475d6a5 Mon Sep 17 00:00:00 2001 From: Changkun Ou Date: Mon, 26 Jul 2021 15:04:48 +0200 Subject: [PATCH 794/940] testing: clarify T.Name returns a distinct name of the running test According to the discussion, it is clear that T.Name returns a distinct name among all tests. However, there is no specification of how sub-tests with the same specified test name are constructed. This change only clarifies the uniqueness and the components of the name without suggesting any explicit format of the returned name. Fixes #46488 Change-Id: I6cebd419b69fb08d8646cb744a129548452042ef Reviewed-on: https://go-review.googlesource.com/c/go/+/337392 Reviewed-by: Ian Lance Taylor Reviewed-by: Emmanuel Odeke Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot --- src/testing/testing.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/testing/testing.go b/src/testing/testing.go index 681f99ef934..a19238d31e2 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -680,7 +680,11 @@ type T struct { func (c *common) private() {} -// Name returns the name of the running test or benchmark. +// Name returns the name of the running (sub-) test or benchmark. +// +// The name will include the name of the test along with the names of +// any nested sub-tests. If two sibling sub-tests have the same name, +// Name will append a suffix to guarantee the returned name is unique. func (c *common) Name() string { return c.name } From cb14e673ec62f09f1216c3d40b03a460785a931e Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Mon, 26 Jul 2021 10:54:57 -0400 Subject: [PATCH 795/940] [dev.typeparams] runtime: don't keep stack uintptr across potential stack move Currently, deferproc stores the caller SP as a uintptr in a local variable across a call to newdefer, but newdefer could grow the stack and invalidate this saved SP, causing deferproc to store a stale SP in the defer record. This would lead to us later failing to match that defer to its calling frame, and we wouldn't run the defer at the right time (or possibly at all). It turns out this isn't crashing horribly right now only because the compiler happens to only materialize the result of getcallersp when this variable is used, *after* the call to newdefer. But this is clearly on thin ice, so this CL moves the getcallersp() to the place where we actually need the result. Change-Id: Iae8ab226e03e4482f16acfb965885f0bd83a13b0 Reviewed-on: https://go-review.googlesource.com/c/go/+/337649 Trust: Austin Clements Run-TryBot: Austin Clements TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/runtime/panic.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/runtime/panic.go b/src/runtime/panic.go index abf76537b05..85d39b92508 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -234,9 +234,6 @@ func deferproc(fn *funcval) { // TODO: Make deferproc just take a func(). throw("defer on system stack") } - sp := getcallersp() - callerpc := getcallerpc() - d := newdefer() if d._panic != nil { throw("deferproc: d.panic != nil after newdefer") @@ -244,8 +241,11 @@ func deferproc(fn *funcval) { // TODO: Make deferproc just take a func(). d.link = gp._defer gp._defer = d d.fn = fn - d.pc = callerpc - d.sp = sp + d.pc = getcallerpc() + // We must not be preempted between calling getcallersp and + // storing it to d.sp because getcallersp's result is a + // uintptr stack pointer. + d.sp = getcallersp() // deferproc returns 0 normally. // a deferred func that stops a panic From 5d8f90f90405e9faa9c5425627024d2cfa67faa3 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 26 Jul 2021 19:37:10 -0700 Subject: [PATCH 796/940] [dev.typeparams] cmd/compile: don't need to unshapify append calls append is fine using shape types. Change-Id: Iae829b9b5929d4dc7aa74bed57da13d4f6d746be Reviewed-on: https://go-review.googlesource.com/c/go/+/337669 Trust: Keith Randall Trust: Dan Scales Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/noder/stencil.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 575b879762f..e482281a3c1 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -1291,13 +1291,6 @@ func (subst *subster) node(n ir.Node) ir.Node { default: base.FatalfAt(call.Pos(), "Unexpected builtin op") } - switch m.Op() { - case ir.OAPPEND: - // Append needs to pass a concrete type to the runtime. - // TODO: there's no way to record a dictionary-loaded type for walk to use here - m.SetType(subst.unshapifyTyp(m.Type())) - } - } else { // This is the case of a function value that was a // type parameter (implied to be a function via a From c8cf0f74e4a8f078ab5570e76c37621a0daf0309 Mon Sep 17 00:00:00 2001 From: 180909 <734461790@qq.com> Date: Tue, 27 Jul 2021 09:49:55 +0000 Subject: [PATCH 797/940] cmd/go: add missing flag in UsageLine Change-Id: I31689dc8de1f6b95bb35578b20533c63903f7258 GitHub-Last-Rev: 5bfee0535ded703f84d45390d5a87295b6e5fe5a GitHub-Pull-Request: golang/go#47418 Reviewed-on: https://go-review.googlesource.com/c/go/+/337691 Run-TryBot: Jay Conrod TryBot-Result: Go Bot Reviewed-by: Jay Conrod Trust: Jay Conrod Trust: Russ Cox --- src/cmd/go/alldocs.go | 4 ++-- src/cmd/go/internal/modcmd/edit.go | 2 +- src/cmd/go/internal/modcmd/init.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index 954caae9fb1..7f88d3216cf 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -1078,7 +1078,7 @@ // // Usage: // -// go mod edit [editing flags] [go.mod] +// go mod edit [editing flags] [-fmt|-print|-json] [go.mod] // // Edit provides a command-line interface for editing go.mod, // for use primarily by tools or scripts. It reads only go.mod; @@ -1204,7 +1204,7 @@ // // Usage: // -// go mod init [module] +// go mod init [module-path] // // Init initializes and writes a new go.mod file in the current directory, in // effect creating a new module rooted at the current directory. The go.mod file diff --git a/src/cmd/go/internal/modcmd/edit.go b/src/cmd/go/internal/modcmd/edit.go index e856e7c6304..bb3d5210926 100644 --- a/src/cmd/go/internal/modcmd/edit.go +++ b/src/cmd/go/internal/modcmd/edit.go @@ -25,7 +25,7 @@ import ( ) var cmdEdit = &base.Command{ - UsageLine: "go mod edit [editing flags] [go.mod]", + UsageLine: "go mod edit [editing flags] [-fmt|-print|-json] [go.mod]", Short: "edit go.mod from tools or scripts", Long: ` Edit provides a command-line interface for editing go.mod, diff --git a/src/cmd/go/internal/modcmd/init.go b/src/cmd/go/internal/modcmd/init.go index 73cc282d814..958c3066ac1 100644 --- a/src/cmd/go/internal/modcmd/init.go +++ b/src/cmd/go/internal/modcmd/init.go @@ -13,7 +13,7 @@ import ( ) var cmdInit = &base.Command{ - UsageLine: "go mod init [module]", + UsageLine: "go mod init [module-path]", Short: "initialize new module in current directory", Long: ` Init initializes and writes a new go.mod file in the current directory, in From c751e2e6ba30fc319c93b9cfe207dc7d1b48c3fb Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 26 Jul 2021 14:50:57 -0700 Subject: [PATCH 798/940] [dev.typeparams] cmd/compile/internal/types2: use comparable bit rather than ==() method This removes the special "==" methods from comparable interfaces in favor of a "comparable" flag in TypeSets indicating that the interface is or embeds comparable. Fixes various related implementation inaccuracies. While at it, fix setup of the predeclared error and comparable interface types by associating their respective type name objects with them. For #47411. Change-Id: I409f880c8c8f2fe345621401267e4aaabd17124d Reviewed-on: https://go-review.googlesource.com/c/go/+/337354 Trust: Robert Griesemer Reviewed-by: Robert Findley --- .../compile/internal/types2/instantiate.go | 16 ++++++++--- src/cmd/compile/internal/types2/interface.go | 2 +- src/cmd/compile/internal/types2/lookup.go | 10 +------ src/cmd/compile/internal/types2/predicates.go | 17 +----------- .../compile/internal/types2/sizeof_test.go | 2 +- .../internal/types2/testdata/check/issues.go2 | 6 ++--- .../types2/testdata/fixedbugs/issue47411.go2 | 26 ++++++++++++++++++ src/cmd/compile/internal/types2/typeset.go | 27 +++++++++++++++---- src/cmd/compile/internal/types2/universe.go | 12 +++------ 9 files changed, 71 insertions(+), 47 deletions(-) create mode 100644 src/cmd/compile/internal/types2/testdata/fixedbugs/issue47411.go2 diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go index cc96375027f..db398c65632 100644 --- a/src/cmd/compile/internal/types2/instantiate.go +++ b/src/cmd/compile/internal/types2/instantiate.go @@ -146,6 +146,17 @@ func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap // the parameterized type. iface = check.subst(pos, iface, smap).(*Interface) + // if iface is comparable, targ must be comparable + // TODO(gri) the error messages needs to be better, here + if iface.IsComparable() && !Comparable(targ) { + if tpar := asTypeParam(targ); tpar != nil && tpar.Bound().typeSet().IsTop() { + check.softErrorf(pos, "%s has no constraints", targ) + return false + } + check.softErrorf(pos, "%s does not satisfy comparable", targ) + return false + } + // targ must implement iface (methods) // - check only if we have methods if iface.NumMethods() > 0 { @@ -161,10 +172,7 @@ func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap // (print warning for now) // Old warning: // check.softErrorf(pos, "%s does not satisfy %s (warning: name not updated) = %s (missing method %s)", targ, tpar.bound, iface, m) - if m.name == "==" { - // We don't want to report "missing method ==". - check.softErrorf(pos, "%s does not satisfy comparable", targ) - } else if wrong != nil { + if wrong != nil { // TODO(gri) This can still report uninstantiated types which makes the error message // more difficult to read then necessary. check.softErrorf(pos, diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go index c344f8ed019..cf8ec1a5e23 100644 --- a/src/cmd/compile/internal/types2/interface.go +++ b/src/cmd/compile/internal/types2/interface.go @@ -107,7 +107,7 @@ func (t *Interface) Method(i int) *Func { return t.typeSet().Method(i) } // Empty reports whether t is the empty interface. func (t *Interface) Empty() bool { return t.typeSet().IsTop() } -// IsComparable reports whether interface t is or embeds the predeclared interface "comparable". +// IsComparable reports whether each type in interface t's type set is comparable. func (t *Interface) IsComparable() bool { return t.typeSet().IsComparable() } // IsConstraint reports whether interface t is not just a method set. diff --git a/src/cmd/compile/internal/types2/lookup.go b/src/cmd/compile/internal/types2/lookup.go index 91be14bde3e..ecf6926c0ab 100644 --- a/src/cmd/compile/internal/types2/lookup.go +++ b/src/cmd/compile/internal/types2/lookup.go @@ -308,11 +308,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, for _, m := range T.typeSet().methods { _, f := ityp.typeSet().LookupMethod(m.pkg, m.name) - if f == nil { - // if m is the magic method == we're ok (interfaces are comparable) - if m.name == "==" || !static { - continue - } + if f == nil && static { return m, f } @@ -360,10 +356,6 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // we must have a method (not a field of matching function type) f, _ := obj.(*Func) if f == nil { - // if m is the magic method == and V is comparable, we're ok - if m.name == "==" && Comparable(V) { - continue - } return m, nil } diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go index e862c0fca8a..f2215b36cb2 100644 --- a/src/cmd/compile/internal/types2/predicates.go +++ b/src/cmd/compile/internal/types2/predicates.go @@ -96,19 +96,6 @@ func comparable(T Type, seen map[Type]bool) bool { } seen[T] = true - // If T is a type parameter not constrained by any type - // (i.e., it's operational type is the top type), - // T is comparable if it has the == method. Otherwise, - // the operational type "wins". For instance - // - // interface{ comparable; type []byte } - // - // is not comparable because []byte is not comparable. - // TODO(gri) this code is not 100% correct (see comment for TypeSet.IsComparable) - if t := asTypeParam(T); t != nil && optype(t) == theTop { - return t.Bound().IsComparable() - } - switch t := under(T).(type) { case *Basic: // assume invalid types to be comparable @@ -126,9 +113,7 @@ func comparable(T Type, seen map[Type]bool) bool { case *Array: return comparable(t.elem, seen) case *TypeParam: - return t.underIs(func(t Type) bool { - return comparable(t, seen) - }) + return t.Bound().IsComparable() } return false } diff --git a/src/cmd/compile/internal/types2/sizeof_test.go b/src/cmd/compile/internal/types2/sizeof_test.go index f7f191f6292..22ef3696836 100644 --- a/src/cmd/compile/internal/types2/sizeof_test.go +++ b/src/cmd/compile/internal/types2/sizeof_test.go @@ -49,7 +49,7 @@ func TestSizeof(t *testing.T) { // Misc {Scope{}, 60, 104}, {Package{}, 40, 80}, - {TypeSet{}, 20, 40}, + {TypeSet{}, 24, 48}, } for _, test := range tests { diff --git a/src/cmd/compile/internal/types2/testdata/check/issues.go2 b/src/cmd/compile/internal/types2/testdata/check/issues.go2 index 32c4320d271..1ede383ebe5 100644 --- a/src/cmd/compile/internal/types2/testdata/check/issues.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/issues.go2 @@ -58,7 +58,7 @@ func _() { type T1[P interface{~uint}] struct{} func _[P any]() { - _ = T1[P /* ERROR P has no type constraints */ ]{} + _ = T1[P /* ERROR P has no constraints */ ]{} } // This is the original (simplified) program causing the same issue. @@ -74,8 +74,8 @@ func (u T2[U]) Add1() U { return u.s + 1 } -func NewT2[U any]() T2[U /* ERROR U has no type constraints */ ] { - return T2[U /* ERROR U has no type constraints */ ]{} +func NewT2[U any]() T2[U /* ERROR U has no constraints */ ] { + return T2[U /* ERROR U has no constraints */ ]{} } func _() { diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47411.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47411.go2 new file mode 100644 index 00000000000..72968f9d43f --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47411.go2 @@ -0,0 +1,26 @@ +// Copyright 2021 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 + +func f[_ comparable]() +func g[_ interface{interface{comparable; ~int|~string}}]() + +func _[P comparable, + Q interface{ comparable; ~int|~string }, + R any, // not comparable + S interface{ comparable; ~func() }, // not comparable +]() { + _ = f[int] + _ = f[P] + _ = f[Q] + _ = f[func( /* ERROR does not satisfy comparable */ )] + _ = f[R /* ERROR R has no constraints */ ] + + _ = g[int] + _ = g[P /* ERROR P has no type constraints */ ] + _ = g[Q] + _ = g[func( /* ERROR does not satisfy comparable */ )] + _ = g[R /* ERROR R has no constraints */ ] +} diff --git a/src/cmd/compile/internal/types2/typeset.go b/src/cmd/compile/internal/types2/typeset.go index 8e6af8e65ce..cc28625070a 100644 --- a/src/cmd/compile/internal/types2/typeset.go +++ b/src/cmd/compile/internal/types2/typeset.go @@ -16,22 +16,30 @@ import ( // A TypeSet represents the type set of an interface. type TypeSet struct { + comparable bool // if set, the interface is or embeds comparable // TODO(gri) consider using a set for the methods for faster lookup methods []*Func // all methods of the interface; sorted by unique ID types Type // typically a *Union; nil means no type restrictions } // IsTop reports whether type set s is the top type set (corresponding to the empty interface). -func (s *TypeSet) IsTop() bool { return len(s.methods) == 0 && s.types == nil } +func (s *TypeSet) IsTop() bool { return !s.comparable && len(s.methods) == 0 && s.types == nil } // IsMethodSet reports whether the type set s is described by a single set of methods. -func (s *TypeSet) IsMethodSet() bool { return s.types == nil && !s.IsComparable() } +func (s *TypeSet) IsMethodSet() bool { return !s.comparable && s.types == nil } // IsComparable reports whether each type in the set is comparable. -// TODO(gri) this is not correct - there may be s.types values containing non-comparable types func (s *TypeSet) IsComparable() bool { - _, m := s.LookupMethod(nil, "==") - return m != nil + if s.types == nil { + return s.comparable + } + tcomparable := s.underIs(func(u Type) bool { + return Comparable(u) + }) + if !s.comparable { + return tcomparable + } + return s.comparable && tcomparable } // NumMethods returns the number of methods available. @@ -54,6 +62,12 @@ func (s *TypeSet) String() string { var buf bytes.Buffer buf.WriteByte('{') + if s.comparable { + buf.WriteString(" comparable") + if len(s.methods) > 0 || s.types != nil { + buf.WriteByte(';') + } + } for i, m := range s.methods { if i > 0 { buf.WriteByte(';') @@ -205,6 +219,9 @@ func computeTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet { switch t := under(typ).(type) { case *Interface: tset := computeTypeSet(check, pos, t) + if tset.comparable { + ityp.tset.comparable = true + } for _, m := range tset.methods { addMethod(pos, m, false) // use embedding position pos rather than m.pos } diff --git a/src/cmd/compile/internal/types2/universe.go b/src/cmd/compile/internal/types2/universe.go index 0f711a6b684..a3dd4bd0d66 100644 --- a/src/cmd/compile/internal/types2/universe.go +++ b/src/cmd/compile/internal/types2/universe.go @@ -88,23 +88,19 @@ func defPredeclaredTypes() { res := NewVar(nopos, nil, "", Typ[String]) sig := NewSignature(nil, nil, NewTuple(res), false) err := NewFunc(nopos, nil, "Error", sig) - ityp := NewInterfaceType([]*Func{err}, nil) + ityp := &Interface{obj, []*Func{err}, nil, nil, true, nil} computeTypeSet(nil, nopos, ityp) // prevent races due to lazy computation of tset typ := NewNamed(obj, ityp, nil) sig.recv = NewVar(nopos, nil, "", typ) def(obj) } - // type comparable interface{ ==() } + // type comparable interface{ /* type set marked comparable */ } { obj := NewTypeName(nopos, nil, "comparable", nil) obj.setColor(black) - sig := NewSignature(nil, nil, nil, false) - eql := NewFunc(nopos, nil, "==", sig) - ityp := NewInterfaceType([]*Func{eql}, nil) - computeTypeSet(nil, nopos, ityp) // prevent races due to lazy computation of tset - typ := NewNamed(obj, ityp, nil) - sig.recv = NewVar(nopos, nil, "", typ) + ityp := &Interface{obj, nil, nil, nil, true, &TypeSet{true, nil, nil}} + NewNamed(obj, ityp, nil) def(obj) } } From 7cd10c1149e51a9d2f0868babaf66b8091b9c0b9 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Tue, 27 Jul 2021 10:22:35 -0700 Subject: [PATCH 799/940] cmd/go: use .mod instead of .zip to determine if version has go.mod file When checking for updates, the go command checks whether the highest compatible version has a go.mod file in order to determine whether +incompatible versions may be considered "latest". Previously, to perform this check, the go command would download the content of the module (the .zip file) to see whether a go.mod file was present at the root. This is slower than necessary, and it caused 'go list -m -u' to try to save the sum for the .zip file in go.sum in some cases. With this change, the go command only downloads the .mod file and checks whether it appears to be a fake file generated for a version that didn't have a go.mod file. This is faster and requires less verification. Fake files only have a "module" directive. It's possible to commit a file that passes this test, but it would be difficult to do accidentally: Go 1.12 and later at least add a "go" directive. A false positive here would cause version queries to have slightly different results but would not affect builds. Fixes #47377 Change-Id: Ie5ffd0b45e39bd0921328a60af99a9f6e5ab6346 Reviewed-on: https://go-review.googlesource.com/c/go/+/337850 Trust: Jay Conrod Run-TryBot: Jay Conrod TryBot-Result: Go Bot Reviewed-by: Michael Matloob --- src/cmd/go/internal/modfetch/coderepo.go | 23 ++--- src/cmd/go/internal/modload/modfile.go | 83 ++++++++++--------- src/cmd/go/internal/modload/query.go | 30 +++++-- .../script/mod_update_sum_readonly.txt | 34 ++++++++ 4 files changed, 114 insertions(+), 56 deletions(-) create mode 100644 src/cmd/go/testdata/script/mod_update_sum_readonly.txt diff --git a/src/cmd/go/internal/modfetch/coderepo.go b/src/cmd/go/internal/modfetch/coderepo.go index f817a045834..dfef9f73c27 100644 --- a/src/cmd/go/internal/modfetch/coderepo.go +++ b/src/cmd/go/internal/modfetch/coderepo.go @@ -864,22 +864,25 @@ func (r *codeRepo) GoMod(version string) (data []byte, err error) { data, err = r.code.ReadFile(rev, path.Join(dir, "go.mod"), codehost.MaxGoMod) if err != nil { if os.IsNotExist(err) { - return r.legacyGoMod(rev, dir), nil + return LegacyGoMod(r.modPath), nil } return nil, err } return data, nil } -func (r *codeRepo) legacyGoMod(rev, dir string) []byte { - // We used to try to build a go.mod reflecting pre-existing - // package management metadata files, but the conversion - // was inherently imperfect (because those files don't have - // exactly the same semantics as go.mod) and, when done - // for dependencies in the middle of a build, impossible to - // correct. So we stopped. - // Return a fake go.mod that simply declares the module path. - return []byte(fmt.Sprintf("module %s\n", modfile.AutoQuote(r.modPath))) +// LegacyGoMod generates a fake go.mod file for a module that doesn't have one. +// The go.mod file contains a module directive and nothing else: no go version, +// no requirements. +// +// We used to try to build a go.mod reflecting pre-existing +// package management metadata files, but the conversion +// was inherently imperfect (because those files don't have +// exactly the same semantics as go.mod) and, when done +// for dependencies in the middle of a build, impossible to +// correct. So we stopped. +func LegacyGoMod(modPath string) []byte { + return []byte(fmt.Sprintf("module %s\n", modfile.AutoQuote(modPath))) } func (r *codeRepo) modPrefix(rev string) string { diff --git a/src/cmd/go/internal/modload/modfile.go b/src/cmd/go/internal/modload/modfile.go index d280945ea63..6145e8b2f03 100644 --- a/src/cmd/go/internal/modload/modfile.go +++ b/src/cmd/go/internal/modload/modfile.go @@ -595,47 +595,14 @@ func rawGoModSummary(m module.Version) (*modFileSummary, error) { } c := rawGoModSummaryCache.Do(m, func() interface{} { summary := new(modFileSummary) - var f *modfile.File - if m.Version == "" { - // m is a replacement module with only a file path. - dir := m.Path - if !filepath.IsAbs(dir) { - dir = filepath.Join(ModRoot(), dir) - } - gomod := filepath.Join(dir, "go.mod") - var data []byte - var err error - if gomodActual, ok := fsys.OverlayPath(gomod); ok { - // Don't lock go.mod if it's part of the overlay. - // On Plan 9, locking requires chmod, and we don't want to modify any file - // in the overlay. See #44700. - data, err = os.ReadFile(gomodActual) - } else { - data, err = lockedfile.Read(gomodActual) - } - if err != nil { - return cached{nil, module.VersionError(m, fmt.Errorf("reading %s: %v", base.ShortPath(gomod), err))} - } - f, err = modfile.ParseLax(gomod, data, nil) - if err != nil { - return cached{nil, module.VersionError(m, fmt.Errorf("parsing %s: %v", base.ShortPath(gomod), err))} - } - } else { - if !semver.IsValid(m.Version) { - // Disallow the broader queries supported by fetch.Lookup. - base.Fatalf("go: internal error: %s@%s: unexpected invalid semantic version", m.Path, m.Version) - } - - data, err := modfetch.GoMod(m.Path, m.Version) - if err != nil { - return cached{nil, err} - } - f, err = modfile.ParseLax("go.mod", data, nil) - if err != nil { - return cached{nil, module.VersionError(m, fmt.Errorf("parsing go.mod: %v", err))} - } + name, data, err := rawGoModData(m) + if err != nil { + return cached{nil, err} + } + f, err := modfile.ParseLax(name, data, nil) + if err != nil { + return cached{nil, module.VersionError(m, fmt.Errorf("parsing %s: %v", base.ShortPath(name), err))} } - if f.Module != nil { summary.module = f.Module.Mod summary.deprecated = f.Module.Deprecated @@ -671,6 +638,42 @@ func rawGoModSummary(m module.Version) (*modFileSummary, error) { var rawGoModSummaryCache par.Cache // module.Version → rawGoModSummary result +// rawGoModData returns the content of the go.mod file for module m, ignoring +// all replacements that may apply to m. +// +// rawGoModData cannot be used on the Target module. +// +// Unlike rawGoModSummary, rawGoModData does not cache its results in memory. +// Use rawGoModSummary instead unless you specifically need these bytes. +func rawGoModData(m module.Version) (name string, data []byte, err error) { + if m.Version == "" { + // m is a replacement module with only a file path. + dir := m.Path + if !filepath.IsAbs(dir) { + dir = filepath.Join(ModRoot(), dir) + } + gomod := filepath.Join(dir, "go.mod") + if gomodActual, ok := fsys.OverlayPath(gomod); ok { + // Don't lock go.mod if it's part of the overlay. + // On Plan 9, locking requires chmod, and we don't want to modify any file + // in the overlay. See #44700. + data, err = os.ReadFile(gomodActual) + } else { + data, err = lockedfile.Read(gomodActual) + } + if err != nil { + return gomod, nil, module.VersionError(m, fmt.Errorf("reading %s: %v", base.ShortPath(gomod), err)) + } + } else { + if !semver.IsValid(m.Version) { + // Disallow the broader queries supported by fetch.Lookup. + base.Fatalf("go: internal error: %s@%s: unexpected invalid semantic version", m.Path, m.Version) + } + data, err = modfetch.GoMod(m.Path, m.Version) + } + return "go.mod", data, err +} + // queryLatestVersionIgnoringRetractions looks up the latest version of the // module with the given path without considering retracted or excluded // versions. diff --git a/src/cmd/go/internal/modload/query.go b/src/cmd/go/internal/modload/query.go index dda9004a9f4..e737ca90fcd 100644 --- a/src/cmd/go/internal/modload/query.go +++ b/src/cmd/go/internal/modload/query.go @@ -5,13 +5,13 @@ package modload import ( + "bytes" "context" "errors" "fmt" "io/fs" "os" pathpkg "path" - "path/filepath" "sort" "strings" "sync" @@ -931,14 +931,32 @@ func moduleHasRootPackage(ctx context.Context, m module.Version) (bool, error) { return ok, err } -func versionHasGoMod(ctx context.Context, m module.Version) (bool, error) { - needSum := false - root, _, err := fetch(ctx, m, needSum) +// versionHasGoMod returns whether a version has a go.mod file. +// +// versionHasGoMod fetches the go.mod file (possibly a fake) and true if it +// contains anything other than a module directive with the same path. When a +// module does not have a real go.mod file, the go command acts as if it had one +// that only contained a module directive. Normal go.mod files created after +// 1.12 at least have a go directive. +// +// This function is a heuristic, since it's possible to commit a file that would +// pass this test. However, we only need a heurstic for determining whether +// +incompatible versions may be "latest", which is what this function is used +// for. +// +// This heuristic is useful for two reasons: first, when using a proxy, +// this lets us fetch from the .mod endpoint which is much faster than the .zip +// endpoint. The .mod file is used anyway, even if the .zip file contains a +// go.mod with different content. Second, if we don't fetch the .zip, then +// we don't need to verify it in go.sum. This makes 'go list -m -u' faster +// and simpler. +func versionHasGoMod(_ context.Context, m module.Version) (bool, error) { + _, data, err := rawGoModData(m) if err != nil { return false, err } - fi, err := os.Stat(filepath.Join(root, "go.mod")) - return err == nil && !fi.IsDir(), nil + isFake := bytes.Equal(data, modfetch.LegacyGoMod(m.Path)) + return !isFake, nil } // A versionRepo is a subset of modfetch.Repo that can report information about diff --git a/src/cmd/go/testdata/script/mod_update_sum_readonly.txt b/src/cmd/go/testdata/script/mod_update_sum_readonly.txt new file mode 100644 index 00000000000..41f12e4084d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_update_sum_readonly.txt @@ -0,0 +1,34 @@ +# When finding the latest version of a module, we should not download version +# contents. Previously, we downloaded .zip files to determine whether a real +# .mod file was present in order to decide whether +incompatible versions +# could be "latest". +# +# Verifies #47377. + +# rsc.io/breaker has two versions, neither of which has a .mod file. +go list -m -versions rsc.io/breaker +stdout '^rsc.io/breaker v1.0.0 v2.0.0\+incompatible$' +go mod download rsc.io/breaker@v1.0.0 +! grep '^go' $GOPATH/pkg/mod/cache/download/rsc.io/breaker/@v/v1.0.0.mod +go mod download rsc.io/breaker@v2.0.0+incompatible +! grep '^go' $GOPATH/pkg/mod/cache/download/rsc.io/breaker/@v/v2.0.0+incompatible.mod + +# Delete downloaded .zip files. +go clean -modcache + +# Check for updates. +go list -m -u rsc.io/breaker +stdout '^rsc.io/breaker v1.0.0 \[v2.0.0\+incompatible\]$' + +# We should not have downloaded zips. +! exists $GOPATH/pkg/mod/cache/download/rsc.io/breaker/@v/v1.0.0.zip +! exists $GOPATH/pkg/mod/cache/download/rsc.io/breaker/@v/v2.0.0+incompatible.zip + +-- go.mod -- +module m + +go 1.16 + +require rsc.io/breaker v1.0.0 +-- go.sum -- +rsc.io/breaker v1.0.0/go.mod h1:s5yxDXvD88U1/ESC23I2FK3Lkv4YIKaB1ij/Hbm805g= From e00a6ec084605b773cdb87971de5b5536c0cc13e Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Sun, 25 Jul 2021 18:27:15 -0700 Subject: [PATCH 800/940] [dev.typeparams] cmd/compile: mark methods of instantiated interface types as used Fix the cons.go missing method error. Mark all the methods of instantiated interface types as used. We could try to record all the exact methods used for generic interface types, but for now, just mark all the methods as used so that their methods are not dead-code eliminated. Change-Id: I35685eda82476244371379b97691a1b8506ef0f7 Reviewed-on: https://go-review.googlesource.com/c/go/+/337349 Trust: Dan Scales Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/noder/stencil.go | 25 +++++++++++++++++------ test/run.go | 1 - 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index e482281a3c1..02a380e63f9 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -1515,6 +1515,23 @@ func deref(t *types.Type) *types.Type { return t } +// markTypeUsed marks type t as used in order to help avoid dead-code elimination of +// needed methods. +func markTypeUsed(t *types.Type, lsym *obj.LSym) { + if t.IsInterface() { + // Mark all the methods of the interface as used. + // TODO: we should really only mark the interface methods + // that are actually called in the application. + for i, _ := range t.AllMethods().Slice() { + reflectdata.MarkUsedIfaceMethodIndex(lsym, t, i) + } + } else { + // TODO: This is somewhat overkill, we really only need it + // for types that are put into interfaces. + reflectdata.MarkTypeUsedInInterface(t, lsym) + } +} + // getDictionarySym returns the dictionary for the named generic function gf, which // is instantiated with the type arguments targs. func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) *types.Sym { @@ -1543,11 +1560,7 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) infoPrint(" * %v\n", t) s := reflectdata.TypeLinksym(t) off = objw.SymPtr(lsym, off, s, 0) - // Ensure that methods on t don't get deadcode eliminated - // by the linker. - // TODO: This is somewhat overkill, we really only need it - // for types that are put into interfaces. - reflectdata.MarkTypeUsedInInterface(t, lsym) + markTypeUsed(t, lsym) } subst := typecheck.Tsubster{ Tparams: info.tparams, @@ -1559,7 +1572,7 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) infoPrint(" - %v\n", ts) s := reflectdata.TypeLinksym(ts) off = objw.SymPtr(lsym, off, s, 0) - reflectdata.MarkTypeUsedInInterface(ts, lsym) + markTypeUsed(ts, lsym) } // Emit an entry for each subdictionary (after substituting targs) for _, n := range info.subDictCalls { diff --git a/test/run.go b/test/run.go index edf26a5d82d..4971043ab64 100644 --- a/test/run.go +++ b/test/run.go @@ -2181,7 +2181,6 @@ var g3Failures = setOf( "fixedbugs/issue30862.go", // -G=3 doesn't handle //go:nointerface - "typeparam/cons.go", // causes an unreachable method "typeparam/nested.go", // -G=3 doesn't support function-local types with generics "typeparam/mdempsky/4.go", // -G=3 can't export functions with labeled breaks in loops From b39e0f461c099abf98f5a8c81d58d32d9a765a03 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 27 Jul 2021 18:30:38 -0700 Subject: [PATCH 801/940] runtime: don't crash on nil pointers in checkptrAlignment Ironically, checkptrAlignment had a latent case of bad pointer arithmetic: if ptr is nil, then `add(ptr, size-1)` might produce an illegal pointer value. The fix is to simply check for nil at the top of checkptrAlignment, and short-circuit if so. This CL also adds a more explicit bounds check in checkptrStraddles, rather than relying on `add(ptr, size-1)` to wrap around. I don't think this is necessary today, but it seems prudent to be careful. Fixes #47430. Change-Id: I5c50b2f7f41415dbebbd803e1b8e7766ca95e1fd Reviewed-on: https://go-review.googlesource.com/c/go/+/338029 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/runtime/checkptr.go | 11 +++++-- src/runtime/checkptr_test.go | 1 + src/runtime/testdata/testprog/checkptr.go | 36 ++++++++++++++++++++++- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/runtime/checkptr.go b/src/runtime/checkptr.go index d42950844b5..2d4afd5cf68 100644 --- a/src/runtime/checkptr.go +++ b/src/runtime/checkptr.go @@ -7,6 +7,11 @@ package runtime import "unsafe" func checkptrAlignment(p unsafe.Pointer, elem *_type, n uintptr) { + // nil pointer is always suitably aligned (#47430). + if p == nil { + return + } + // Check that (*[n]elem)(p) is appropriately aligned. // Note that we allow unaligned pointers if the types they point to contain // no pointers themselves. See issue 37298. @@ -29,10 +34,12 @@ func checkptrStraddles(ptr unsafe.Pointer, size uintptr) bool { return false } - end := add(ptr, size-1) - if uintptr(end) < uintptr(ptr) { + // Check that add(ptr, size-1) won't overflow. This avoids the risk + // of producing an illegal pointer value (assuming ptr is legal). + if uintptr(ptr) >= -(size - 1) { return true } + end := add(ptr, size-1) // TODO(mdempsky): Detect when [ptr, end] contains Go allocations, // but neither ptr nor end point into one themselves. diff --git a/src/runtime/checkptr_test.go b/src/runtime/checkptr_test.go index 2a5c364e97b..d5dd101adbe 100644 --- a/src/runtime/checkptr_test.go +++ b/src/runtime/checkptr_test.go @@ -26,6 +26,7 @@ func TestCheckPtr(t *testing.T) { }{ {"CheckPtrAlignmentPtr", "fatal error: checkptr: misaligned pointer conversion\n"}, {"CheckPtrAlignmentNoPtr", ""}, + {"CheckPtrAlignmentNilPtr", ""}, {"CheckPtrArithmetic", "fatal error: checkptr: pointer arithmetic result points to invalid allocation\n"}, {"CheckPtrArithmetic2", "fatal error: checkptr: pointer arithmetic result points to invalid allocation\n"}, {"CheckPtrSize", "fatal error: checkptr: converted pointer straddles multiple allocations\n"}, diff --git a/src/runtime/testdata/testprog/checkptr.go b/src/runtime/testdata/testprog/checkptr.go index f76b64ad96f..9c5561396e5 100644 --- a/src/runtime/testdata/testprog/checkptr.go +++ b/src/runtime/testdata/testprog/checkptr.go @@ -4,11 +4,16 @@ package main -import "unsafe" +import ( + "runtime" + "time" + "unsafe" +) func init() { register("CheckPtrAlignmentNoPtr", CheckPtrAlignmentNoPtr) register("CheckPtrAlignmentPtr", CheckPtrAlignmentPtr) + register("CheckPtrAlignmentNilPtr", CheckPtrAlignmentNilPtr) register("CheckPtrArithmetic", CheckPtrArithmetic) register("CheckPtrArithmetic2", CheckPtrArithmetic2) register("CheckPtrSize", CheckPtrSize) @@ -29,6 +34,35 @@ func CheckPtrAlignmentPtr() { sink2 = (**int64)(unsafe.Pointer(uintptr(p) + 1)) } +// CheckPtrAlignmentNilPtr tests that checkptrAlignment doesn't crash +// on nil pointers (#47430). +func CheckPtrAlignmentNilPtr() { + var do func(int) + do = func(n int) { + // Inflate the stack so runtime.shrinkstack gets called during GC + if n > 0 { + do(n - 1) + } + + var p unsafe.Pointer + _ = (*int)(p) + } + + go func() { + for { + runtime.GC() + } + }() + + go func() { + for i := 0; ; i++ { + do(i % 1024) + } + }() + + time.Sleep(time.Second) +} + func CheckPtrArithmetic() { var x int i := uintptr(unsafe.Pointer(&x)) From 473e493d18c277d69e40a4930af045d474ff2be4 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Wed, 21 Jul 2021 12:12:22 -0400 Subject: [PATCH 802/940] [dev.typeparams] cmd/compile/internal/types2: merge instance and Named to eliminate sanitization This is a port of CL 335929 to types2. It differs significantly from that CL to handle lazy loading, which wasn't tested in go/types. Additionally, the *Checker field was moved out of instance and back onto Named. This way we can tell whether a Named type is uninstantiated simply by checking whether Named.instance is non-nil, which simplified the code considerably. Fixes #46151 Change-Id: I617263bcfaa768ac5442213cecad8d567c2749fc Reviewed-on: https://go-review.googlesource.com/c/go/+/336252 Trust: Robert Findley Trust: Robert Griesemer Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types2/builtins.go | 2 +- src/cmd/compile/internal/types2/check.go | 5 - src/cmd/compile/internal/types2/decl.go | 12 +- src/cmd/compile/internal/types2/infer.go | 3 - src/cmd/compile/internal/types2/instance.go | 62 ++---- .../compile/internal/types2/instantiate.go | 72 +++--- src/cmd/compile/internal/types2/lookup.go | 2 +- src/cmd/compile/internal/types2/named.go | 45 ++-- src/cmd/compile/internal/types2/object.go | 3 + src/cmd/compile/internal/types2/predicates.go | 8 +- src/cmd/compile/internal/types2/sanitize.go | 205 ------------------ .../compile/internal/types2/sizeof_test.go | 3 +- src/cmd/compile/internal/types2/subst.go | 15 +- .../internal/types2/testdata/check/issues.go2 | 4 +- src/cmd/compile/internal/types2/typeparam.go | 3 +- src/cmd/compile/internal/types2/typestring.go | 10 +- src/cmd/compile/internal/types2/typexpr.go | 2 +- 17 files changed, 127 insertions(+), 329 deletions(-) delete mode 100644 src/cmd/compile/internal/types2/sanitize.go diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index 2af2679d5ed..b9fcf3c898b 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -798,7 +798,7 @@ func hasVarSize(t Type) bool { } case *TypeParam: return true - case *Named, *Union, *instance, *top: + case *Named, *Union, *top: unreachable() } return false diff --git a/src/cmd/compile/internal/types2/check.go b/src/cmd/compile/internal/types2/check.go index 071afef0587..6bc965c4978 100644 --- a/src/cmd/compile/internal/types2/check.go +++ b/src/cmd/compile/internal/types2/check.go @@ -282,11 +282,6 @@ func (check *Checker) checkFiles(files []*syntax.File) (err error) { print("== recordUntyped ==") check.recordUntyped() - if check.Info != nil { - print("== sanitizeInfo ==") - sanitizeInfo(check.Info) - } - check.pkg.complete = true // no longer needed - release memory diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go index 4f656e374af..6ca8f75e9a9 100644 --- a/src/cmd/compile/internal/types2/decl.go +++ b/src/cmd/compile/internal/types2/decl.go @@ -317,6 +317,8 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo { } case *Named: + t.expand() + // don't touch the type if it is from a different package or the Universe scope // (doing so would lead to a race condition - was issue #35049) if t.obj.pkg != check.pkg { @@ -349,9 +351,6 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo { panic("internal error: cycle start not found") } return t.info - - case *instance: - return check.validType(t.expand(), path) } return valid @@ -557,7 +556,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named // determine underlying type of named named.fromRHS = check.definedType(tdecl.Type, named) - + assert(named.fromRHS != nil) // The underlying type of named may be itself a named type that is // incomplete: // @@ -624,7 +623,8 @@ func (check *Checker) boundType(e syntax.Expr) Type { bound := check.typ(e) check.later(func() { - if _, ok := under(bound).(*Interface); !ok && bound != Typ[Invalid] { + u := under(bound) + if _, ok := u.(*Interface); !ok && u != Typ[Invalid] { check.errorf(e, "%s is not an interface", bound) } }) @@ -692,7 +692,7 @@ func (check *Checker) collectMethods(obj *TypeName) { } if base != nil { - base.expand() // TODO(mdempsky): Probably unnecessary. + base.load() // TODO(mdempsky): Probably unnecessary. base.methods = append(base.methods, m) } } diff --git a/src/cmd/compile/internal/types2/infer.go b/src/cmd/compile/internal/types2/infer.go index b44ff7377a4..6e7a2177094 100644 --- a/src/cmd/compile/internal/types2/infer.go +++ b/src/cmd/compile/internal/types2/infer.go @@ -342,9 +342,6 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { // t must be one of w.tparams return t.index < len(w.tparams) && w.tparams[t.index].typ == t - case *instance: - return w.isParameterizedList(t.targs) - default: unreachable() } diff --git a/src/cmd/compile/internal/types2/instance.go b/src/cmd/compile/internal/types2/instance.go index 798d58811f5..df0fc17ba7a 100644 --- a/src/cmd/compile/internal/types2/instance.go +++ b/src/cmd/compile/internal/types2/instance.go @@ -4,56 +4,40 @@ package types2 +// TODO(rfindley): move this code to named.go. + import "cmd/compile/internal/syntax" -// An instance represents an instantiated generic type syntactically -// (without expanding the instantiation). Type instances appear only -// during type-checking and are replaced by their fully instantiated -// (expanded) types before the end of type-checking. +// instance holds position information for use in lazy instantiation. +// +// TODO(rfindley): come up with a better name for this type, now that its usage +// has changed. type instance struct { - check *Checker // for lazy instantiation pos syntax.Pos // position of type instantiation; for error reporting only - base *Named // parameterized type to be instantiated - targs []Type // type arguments posList []syntax.Pos // position of each targ; for error reporting only - verify bool // if set, constraint satisfaction is verified - value Type // base[targs...] after instantiation or Typ[Invalid]; nil if not yet set + verify bool // if set, check constraint satisfaction upon instantiation } -// expand returns the instantiated (= expanded) type of t. -// The result is either an instantiated *Named type, or -// Typ[Invalid] if there was an error. -func (t *instance) expand() Type { - v := t.value - if v == nil { - v = t.check.Instantiate(t.pos, t.base, t.targs, t.posList, t.verify) - if v == nil { - v = Typ[Invalid] - } - t.value = v +// expand ensures that the underlying type of n is instantiated. +// The underlying type will be Typ[Invalid] if there was an error. +func (n *Named) expand() { + if n.instance != nil { + // n must be loaded before instantiation, in order to have accurate + // tparams. This is done implicitly by the call to n.TParams, but making it + // explicit is harmless: load is idempotent. + n.load() + inst := n.check.instantiate(n.instance.pos, n.orig.underlying, n.TParams(), n.targs, n.instance.posList, n.instance.verify) + n.underlying = inst + n.fromRHS = inst + n.instance = nil } - // After instantiation we must have an invalid or a *Named type. - if debug && v != Typ[Invalid] { - _ = v.(*Named) - } - return v } -// expand expands a type instance into its instantiated -// type and leaves all other types alone. expand does -// not recurse. +// expand expands uninstantiated named types and leaves all other types alone. +// expand does not recurse. func expand(typ Type) Type { - if t, _ := typ.(*instance); t != nil { - return t.expand() + if t, _ := typ.(*Named); t != nil { + t.expand() } return typ } - -// expandf is set to expand. -// Call expandf when calling expand causes compile-time cycle error. -var expandf func(Type) Type - -func init() { expandf = expand } - -func (t *instance) Underlying() Type { return t } -func (t *instance) String() string { return TypeString(t, nil) } diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go index db398c65632..1294b08490d 100644 --- a/src/cmd/compile/internal/types2/instantiate.go +++ b/src/cmd/compile/internal/types2/instantiate.go @@ -25,28 +25,6 @@ import ( // Any methods attached to a *Named are simply copied; they are not // instantiated. func (check *Checker) Instantiate(pos syntax.Pos, typ Type, targs []Type, posList []syntax.Pos, verify bool) (res Type) { - if verify && check == nil { - panic("cannot have nil receiver if verify is set") - } - - if check != nil && check.conf.Trace { - check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs)) - check.indent++ - defer func() { - check.indent-- - var under Type - if res != nil { - // Calling under() here may lead to endless instantiations. - // Test case: type T[P any] T[P] - // TODO(gri) investigate if that's a bug or to be expected. - under = res.Underlying() - } - check.trace(pos, "=> %s (under = %s)", res, under) - }() - } - - assert(len(posList) <= len(targs)) - // TODO(gri) What is better here: work with TypeParams, or work with TypeNames? var tparams []*TypeName switch t := typ.(type) { @@ -76,7 +54,10 @@ func (check *Checker) Instantiate(pos syntax.Pos, typ Type, targs []Type, posLis // only types and functions can be generic panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) } + return check.instantiate(pos, typ, tparams, targs, posList, verify) +} +func (check *Checker) instantiate(pos syntax.Pos, typ Type, tparams []*TypeName, targs []Type, posList []syntax.Pos, verify bool) (res Type) { // the number of supplied types must match the number of type parameters if len(targs) != len(tparams) { // TODO(gri) provide better error message @@ -86,6 +67,27 @@ func (check *Checker) Instantiate(pos syntax.Pos, typ Type, targs []Type, posLis } panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, len(targs), len(tparams))) } + if verify && check == nil { + panic("cannot have nil receiver if verify is set") + } + + if check != nil && check.conf.Trace { + check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs)) + check.indent++ + defer func() { + check.indent-- + var under Type + if res != nil { + // Calling under() here may lead to endless instantiations. + // Test case: type T[P any] T[P] + // TODO(gri) investigate if that's a bug or to be expected. + under = res.Underlying() + } + check.trace(pos, "=> %s (under = %s)", res, under) + }() + } + + assert(len(posList) <= len(targs)) if len(tparams) == 0 { return typ // nothing to do (minor optimization) @@ -115,19 +117,35 @@ func (check *Checker) Instantiate(pos syntax.Pos, typ Type, targs []Type, posLis // instantiating the type until needed. typ must be a *Named // type. func (check *Checker) InstantiateLazy(pos syntax.Pos, typ Type, targs []Type, posList []syntax.Pos, verify bool) Type { - base := asNamed(typ) + // Don't use asNamed here: we don't want to expand the base during lazy + // instantiation. + base := typ.(*Named) + if base == nil { panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) } + h := instantiatedHash(base, targs) + if check != nil { + // typ may already have been instantiated with identical type arguments. In + // that case, re-use the existing instance. + if named := check.typMap[h]; named != nil { + return named + } + } - return &instance{ - check: check, + tname := NewTypeName(pos, base.obj.pkg, base.obj.name, nil) + named := check.newNamed(tname, base, nil, nil, nil) // methods and tparams are set when named is loaded. + named.targs = targs + named.instance = &instance{ pos: pos, - base: base, - targs: targs, posList: posList, verify: verify, } + + if check != nil { + check.typMap[h] = named + } + return named } // satisfies reports whether the type argument targ satisfies the constraint of type parameter diff --git a/src/cmd/compile/internal/types2/lookup.go b/src/cmd/compile/internal/types2/lookup.go index ecf6926c0ab..9e9d6dfb29b 100644 --- a/src/cmd/compile/internal/types2/lookup.go +++ b/src/cmd/compile/internal/types2/lookup.go @@ -119,7 +119,7 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o seen[named] = true // look for a matching attached method - named.expand() + named.load() if i, m := lookupMethod(named.methods, pkg, name); m != nil { // potential match // caution: method may not have a proper signature yet diff --git a/src/cmd/compile/internal/types2/named.go b/src/cmd/compile/internal/types2/named.go index da098b58b7a..a88aeb00779 100644 --- a/src/cmd/compile/internal/types2/named.go +++ b/src/cmd/compile/internal/types2/named.go @@ -10,12 +10,13 @@ import "sync" // A Named represents a named (defined) type. type Named struct { - check *Checker // for Named.under implementation; nilled once under has been called + check *Checker info typeInfo // for cycle detection obj *TypeName // corresponding declared object orig *Named // original, uninstantiated type fromRHS Type // type (on RHS of declaration) this *Named type is derived from (for cycle reporting) underlying Type // possibly a *Named during setup; never a *Named once set up completely + instance *instance // position information for lazy instantiation, or nil tparams []*TypeName // type parameters, or nil targs []Type // type arguments (after instantiation), or nil methods []*Func // methods declared for this type (not the method set of this type); signatures are type-checked lazily @@ -34,7 +35,19 @@ func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named { return (*Checker)(nil).newNamed(obj, nil, underlying, nil, methods) } -func (t *Named) expand() *Named { +func (t *Named) load() *Named { + // If t is an instantiated type, it derives its methods and tparams from its + // base type. Since we expect type parameters and methods to be set after a + // call to load, we must load the base and copy here. + // + // underlying is set when t is expanded. + // + // By convention, a type instance is loaded iff its tparams are set. + if len(t.targs) > 0 && t.tparams == nil { + t.orig.load() + t.tparams = t.orig.tparams + t.methods = t.orig.methods + } if t.resolve == nil { return t } @@ -83,7 +96,7 @@ func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tpar if check != nil { check.later(func() { switch typ.under().(type) { - case *Named, *instance: + case *Named: panic("internal error: unexpanded underlying type") } typ.check = nil @@ -104,10 +117,12 @@ func (t *Named) Orig() *Named { return t.orig } // TParams returns the type parameters of the named type t, or nil. // The result is non-nil for an (originally) parameterized type even if it is instantiated. -func (t *Named) TParams() []*TypeName { return t.expand().tparams } +func (t *Named) TParams() []*TypeName { + return t.load().tparams +} // SetTParams sets the type parameters of the named type t. -func (t *Named) SetTParams(tparams []*TypeName) { t.expand().tparams = tparams } +func (t *Named) SetTParams(tparams []*TypeName) { t.load().tparams = tparams } // TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated. func (t *Named) TArgs() []Type { return t.targs } @@ -116,10 +131,10 @@ func (t *Named) TArgs() []Type { return t.targs } func (t *Named) SetTArgs(args []Type) { t.targs = args } // NumMethods returns the number of explicit methods whose receiver is named type t. -func (t *Named) NumMethods() int { return len(t.expand().methods) } +func (t *Named) NumMethods() int { return len(t.load().methods) } // Method returns the i'th method of named type t for 0 <= i < t.NumMethods(). -func (t *Named) Method(i int) *Func { return t.expand().methods[i] } +func (t *Named) Method(i int) *Func { return t.load().methods[i] } // SetUnderlying sets the underlying type and marks t as complete. func (t *Named) SetUnderlying(underlying Type) { @@ -129,18 +144,18 @@ func (t *Named) SetUnderlying(underlying Type) { if _, ok := underlying.(*Named); ok { panic("types2.Named.SetUnderlying: underlying type must not be *Named") } - t.expand().underlying = underlying + t.load().underlying = underlying } // AddMethod adds method m unless it is already in the method list. func (t *Named) AddMethod(m *Func) { - t.expand() + t.load() if i, _ := lookupMethod(t.methods, m.pkg, m.name); i < 0 { t.methods = append(t.methods, m) } } -func (t *Named) Underlying() Type { return t.expand().underlying } +func (t *Named) Underlying() Type { return t.load().underlying } func (t *Named) String() string { return TypeString(t, nil) } // ---------------------------------------------------------------------------- @@ -153,6 +168,8 @@ func (t *Named) String() string { return TypeString(t, nil) } // is detected, the result is Typ[Invalid]. If a cycle is detected and // n0.check != nil, the cycle is reported. func (n0 *Named) under() Type { + n0.expand() + u := n0.Underlying() if u == Typ[Invalid] { @@ -168,7 +185,7 @@ func (n0 *Named) under() Type { default: // common case return u - case *Named, *instance: + case *Named: // handled below } @@ -199,12 +216,8 @@ func (n0 *Named) under() Type { var n1 *Named switch u1 := u.(type) { case *Named: + u1.expand() n1 = u1 - case *instance: - n1, _ = u1.expand().(*Named) - if n1 == nil { - u = Typ[Invalid] - } } if n1 == nil { break // end of chain diff --git a/src/cmd/compile/internal/types2/object.go b/src/cmd/compile/internal/types2/object.go index 82297ff17f1..48fd1e44de1 100644 --- a/src/cmd/compile/internal/types2/object.go +++ b/src/cmd/compile/internal/types2/object.go @@ -475,6 +475,9 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) { if _, ok := typ.(*Basic); ok { return } + if named, _ := typ.(*Named); named != nil && len(named.tparams) > 0 { + writeTParamList(buf, named.tparams, qf, nil) + } if tname.IsAlias() { buf.WriteString(" =") } else { diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go index f2215b36cb2..e448ade9e57 100644 --- a/src/cmd/compile/internal/types2/predicates.go +++ b/src/cmd/compile/internal/types2/predicates.go @@ -10,7 +10,7 @@ package types2 // isNamed may be called with types that are not fully set up. func isNamed(typ Type) bool { switch typ.(type) { - case *Basic, *Named, *TypeParam, *instance: + case *Basic, *Named, *TypeParam: return true } return false @@ -21,7 +21,7 @@ func isNamed(typ Type) bool { func isGeneric(typ Type) bool { // A parameterized type is only instantiated if it doesn't have an instantiation already. named, _ := typ.(*Named) - return named != nil && named.obj != nil && named.TParams() != nil && named.targs == nil + return named != nil && named.obj != nil && named.targs == nil && named.TParams() != nil } func is(typ Type, what BasicInfo) bool { @@ -144,8 +144,8 @@ func (p *ifacePair) identical(q *ifacePair) bool { // For changes to this code the corresponding changes should be made to unifier.nify. func identical(x, y Type, cmpTags bool, p *ifacePair) bool { // types must be expanded for comparison - x = expandf(x) - y = expandf(y) + x = expand(x) + y = expand(y) if x == y { return true diff --git a/src/cmd/compile/internal/types2/sanitize.go b/src/cmd/compile/internal/types2/sanitize.go deleted file mode 100644 index 3d2323a0a29..00000000000 --- a/src/cmd/compile/internal/types2/sanitize.go +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright 2020 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 types2 - -// sanitizeInfo walks the types contained in info to ensure that all instances -// are expanded. -// -// This includes some objects that may be shared across concurrent -// type-checking passes (such as those in the universe scope), so we are -// careful here not to write types that are already sanitized. This avoids a -// data race as any shared types should already be sanitized. -func sanitizeInfo(info *Info) { - var s sanitizer = make(map[Type]Type) - - // Note: Some map entries are not references. - // If modified, they must be assigned back. - - for e, tv := range info.Types { - if typ := s.typ(tv.Type); typ != tv.Type { - tv.Type = typ - info.Types[e] = tv - } - } - - for e, inf := range info.Inferred { - changed := false - for i, targ := range inf.TArgs { - if typ := s.typ(targ); typ != targ { - inf.TArgs[i] = typ - changed = true - } - } - if typ := s.typ(inf.Sig); typ != inf.Sig { - inf.Sig = typ.(*Signature) - changed = true - } - if changed { - info.Inferred[e] = inf - } - } - - for _, obj := range info.Defs { - if obj != nil { - if typ := s.typ(obj.Type()); typ != obj.Type() { - obj.setType(typ) - } - } - } - - for _, obj := range info.Uses { - if obj != nil { - if typ := s.typ(obj.Type()); typ != obj.Type() { - obj.setType(typ) - } - } - } - - // TODO(gri) sanitize as needed - // - info.Implicits - // - info.Selections - // - info.Scopes - // - info.InitOrder -} - -type sanitizer map[Type]Type - -func (s sanitizer) typ(typ Type) Type { - if typ == nil { - return nil - } - - if t, found := s[typ]; found { - return t - } - s[typ] = typ - - switch t := typ.(type) { - case *Basic, *top: - // nothing to do - - case *Array: - if elem := s.typ(t.elem); elem != t.elem { - t.elem = elem - } - - case *Slice: - if elem := s.typ(t.elem); elem != t.elem { - t.elem = elem - } - - case *Struct: - s.varList(t.fields) - - case *Pointer: - if base := s.typ(t.base); base != t.base { - t.base = base - } - - case *Tuple: - s.tuple(t) - - case *Signature: - s.var_(t.recv) - s.tuple(t.params) - s.tuple(t.results) - - case *Union: - s.typeList(t.types) - - case *Interface: - s.funcList(t.methods) - s.typeList(t.embeddeds) - // TODO(gri) do we need to sanitize type sets? - tset := t.typeSet() - s.funcList(tset.methods) - if types := s.typ(tset.types); types != tset.types { - tset.types = types - } - - case *Map: - if key := s.typ(t.key); key != t.key { - t.key = key - } - if elem := s.typ(t.elem); elem != t.elem { - t.elem = elem - } - - case *Chan: - if elem := s.typ(t.elem); elem != t.elem { - t.elem = elem - } - - case *Named: - if debug && t.check != nil { - panic("internal error: Named.check != nil") - } - t.expand() - if orig := s.typ(t.fromRHS); orig != t.fromRHS { - t.fromRHS = orig - } - if under := s.typ(t.underlying); under != t.underlying { - t.underlying = under - } - s.typeList(t.targs) - s.funcList(t.methods) - - case *TypeParam: - if bound := s.typ(t.bound); bound != t.bound { - t.bound = bound - } - - case *instance: - typ = t.expand() - s[t] = typ - - default: - unimplemented() - } - - return typ -} - -func (s sanitizer) var_(v *Var) { - if v != nil { - if typ := s.typ(v.typ); typ != v.typ { - v.typ = typ - } - } -} - -func (s sanitizer) varList(list []*Var) { - for _, v := range list { - s.var_(v) - } -} - -func (s sanitizer) tuple(t *Tuple) { - if t != nil { - s.varList(t.vars) - } -} - -func (s sanitizer) func_(f *Func) { - if f != nil { - if typ := s.typ(f.typ); typ != f.typ { - f.typ = typ - } - } -} - -func (s sanitizer) funcList(list []*Func) { - for _, f := range list { - s.func_(f) - } -} - -func (s sanitizer) typeList(list []Type) { - for i, t := range list { - if typ := s.typ(t); typ != t { - list[i] = typ - } - } -} diff --git a/src/cmd/compile/internal/types2/sizeof_test.go b/src/cmd/compile/internal/types2/sizeof_test.go index 22ef3696836..a62b7cb3e25 100644 --- a/src/cmd/compile/internal/types2/sizeof_test.go +++ b/src/cmd/compile/internal/types2/sizeof_test.go @@ -31,9 +31,8 @@ func TestSizeof(t *testing.T) { {Interface{}, 40, 80}, {Map{}, 16, 32}, {Chan{}, 12, 24}, - {Named{}, 84, 160}, + {Named{}, 88, 168}, {TypeParam{}, 28, 48}, - {instance{}, 56, 104}, {top{}, 0, 0}, // Objects diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index 63b234a60e2..87e3e3018ed 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -26,12 +26,7 @@ func makeSubstMap(tpars []*TypeName, targs []Type) *substMap { assert(len(tpars) == len(targs)) proj := make(map[*TypeParam]Type, len(tpars)) for i, tpar := range tpars { - // We must expand type arguments otherwise *instance - // types end up as components in composite types. - // TODO(gri) explain why this causes problems, if it does - targ := expand(targs[i]) // possibly nil - targs[i] = targ - proj[tpar.typ.(*TypeParam)] = targ + proj[tpar.typ.(*TypeParam)] = targs[i] } return &substMap{targs, proj} } @@ -83,6 +78,7 @@ func (check *Checker) subst(pos syntax.Pos, typ Type, smap *substMap) Type { // for recursive types (example: type T[P any] *T[P]). subst.typMap = make(map[string]*Named) } + return subst.typ(typ) } @@ -241,10 +237,13 @@ func (subst *subster) typ(typ Type) Type { named := subst.check.newNamed(tname, t, t.Underlying(), t.TParams(), t.methods) // method signatures are updated lazily named.targs = new_targs subst.typMap[h] = named + t.expand() // must happen after typMap update to avoid infinite recursion // do the substitution dump(">>> subst %s with %s (new: %s)", t.underlying, subst.smap, new_targs) named.underlying = subst.typOrNil(t.Underlying()) + dump(">>> underlying: %v", named.underlying) + assert(named.underlying != nil) named.fromRHS = named.underlying // for cycle detection (Checker.validType) return named @@ -252,10 +251,6 @@ func (subst *subster) typ(typ Type) Type { case *TypeParam: return subst.smap.lookup(t) - case *instance: - // TODO(gri) can we avoid the expansion here and just substitute the type parameters? - return subst.typ(t.expand()) - default: unimplemented() } diff --git a/src/cmd/compile/internal/types2/testdata/check/issues.go2 b/src/cmd/compile/internal/types2/testdata/check/issues.go2 index 1ede383ebe5..e29357de0b8 100644 --- a/src/cmd/compile/internal/types2/testdata/check/issues.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/issues.go2 @@ -74,8 +74,10 @@ func (u T2[U]) Add1() U { return u.s + 1 } +// TODO(rfindley): we should probably report an error here as well, not +// just when the type is first instantiated. func NewT2[U any]() T2[U /* ERROR U has no constraints */ ] { - return T2[U /* ERROR U has no constraints */ ]{} + return T2[U]{} } func _() { diff --git a/src/cmd/compile/internal/types2/typeparam.go b/src/cmd/compile/internal/types2/typeparam.go index 0aca227c0a7..b66256cf00d 100644 --- a/src/cmd/compile/internal/types2/typeparam.go +++ b/src/cmd/compile/internal/types2/typeparam.go @@ -21,7 +21,8 @@ type TypeParam struct { id uint64 // unique id, for debugging only obj *TypeName // corresponding type name index int // type parameter index in source order, starting at 0 - bound Type // *Named or *Interface; underlying type is always *Interface + // TODO(rfindley): this could also be Typ[Invalid]. Verify that this is handled correctly. + bound Type // *Named or *Interface; underlying type is always *Interface } // Obj returns the type name for the type parameter t. diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go index 44099133a03..74d2f1dc519 100644 --- a/src/cmd/compile/internal/types2/typestring.go +++ b/src/cmd/compile/internal/types2/typestring.go @@ -269,6 +269,9 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { } case *Named: + if t.instance != nil { + buf.WriteByte(instanceMarker) + } writeTypeName(buf, t.obj, qf) if t.targs != nil { // instantiated type @@ -294,13 +297,6 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { } buf.WriteString(s + subscript(t.id)) - case *instance: - buf.WriteByte(instanceMarker) // indicate "non-evaluated" syntactic instance - writeTypeName(buf, t.base.obj, qf) - buf.WriteByte('[') - writeTypeList(buf, t.targs, qf, visited) - buf.WriteByte(']') - case *top: buf.WriteString("⊤") diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index 83cefa19bae..c55d5c093ab 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -446,7 +446,7 @@ func (check *Checker) instantiatedType(x syntax.Expr, targsx []syntax.Expr, def // make sure we check instantiation works at least once // and that the resulting type is valid check.later(func() { - t := typ.(*instance).expand() + t := expand(typ) check.validType(t, nil) }) From 9eee0ed4391942c73157c868a9ddcfdef48982f9 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Wed, 28 Jul 2021 11:52:14 -0700 Subject: [PATCH 803/940] cmd/go: fix go.mod file name printed in error messages for replacements This fixes a logic error introduced in CL 337850. Fixes #47444 Change-Id: I6a49c8fc71fdde4ecb7f2e3329ad1f2cd286b7eb Reviewed-on: https://go-review.googlesource.com/c/go/+/338189 Run-TryBot: Jay Conrod TryBot-Result: Go Bot Reviewed-by: Michael Matloob Trust: Jay Conrod --- src/cmd/go/internal/modload/modfile.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/cmd/go/internal/modload/modfile.go b/src/cmd/go/internal/modload/modfile.go index 6145e8b2f03..03e02e73b63 100644 --- a/src/cmd/go/internal/modload/modfile.go +++ b/src/cmd/go/internal/modload/modfile.go @@ -652,8 +652,8 @@ func rawGoModData(m module.Version) (name string, data []byte, err error) { if !filepath.IsAbs(dir) { dir = filepath.Join(ModRoot(), dir) } - gomod := filepath.Join(dir, "go.mod") - if gomodActual, ok := fsys.OverlayPath(gomod); ok { + name = filepath.Join(dir, "go.mod") + if gomodActual, ok := fsys.OverlayPath(name); ok { // Don't lock go.mod if it's part of the overlay. // On Plan 9, locking requires chmod, and we don't want to modify any file // in the overlay. See #44700. @@ -662,16 +662,17 @@ func rawGoModData(m module.Version) (name string, data []byte, err error) { data, err = lockedfile.Read(gomodActual) } if err != nil { - return gomod, nil, module.VersionError(m, fmt.Errorf("reading %s: %v", base.ShortPath(gomod), err)) + return "", nil, module.VersionError(m, fmt.Errorf("reading %s: %v", base.ShortPath(name), err)) } } else { if !semver.IsValid(m.Version) { // Disallow the broader queries supported by fetch.Lookup. base.Fatalf("go: internal error: %s@%s: unexpected invalid semantic version", m.Path, m.Version) } + name = "go.mod" data, err = modfetch.GoMod(m.Path, m.Version) } - return "go.mod", data, err + return name, data, err } // queryLatestVersionIgnoringRetractions looks up the latest version of the From 53557530093938e19c21f6b02a482939ac6e634b Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 28 Jul 2021 13:39:30 -0700 Subject: [PATCH 804/940] [dev.typeparams] test/typeparam: gofmt -w We don't usually reformat the test directory, but all of the files in test/typeparam are syntactically valid. I suspect the misformattings here are because developers aren't re-installing gofmt with -tags=typeparams, not intentionally exercising non-standard formatting. Change-Id: I3767d480434c19225568f3c7d656dc8589197183 Reviewed-on: https://go-review.googlesource.com/c/go/+/338093 Trust: Matthew Dempsky Trust: Robert Griesemer Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- test/typeparam/absdiff.go | 6 +- test/typeparam/absdiffimp.dir/a.go | 2 +- test/typeparam/aliasimp.dir/a.go | 2 +- test/typeparam/aliasimp.dir/main.go | 2 +- test/typeparam/boundmethod.go | 44 +++++----- test/typeparam/builtins.go | 4 +- test/typeparam/chans.go | 2 +- test/typeparam/chansimp.dir/a.go | 2 +- test/typeparam/combine.go | 28 +++---- test/typeparam/cons.go | 4 +- test/typeparam/dictionaryCapture-noinline.go | 26 +++--- test/typeparam/dictionaryCapture.go | 31 ++++--- test/typeparam/dottype.go | 12 +-- test/typeparam/double.go | 10 +-- test/typeparam/equal.go | 20 ++--- test/typeparam/fact.go | 4 +- test/typeparam/factimp.dir/a.go | 4 +- test/typeparam/graph.go | 1 - test/typeparam/ifaceconv.go | 6 +- test/typeparam/index.go | 1 - test/typeparam/interfacearg.go | 2 + test/typeparam/issue39755.go | 4 +- test/typeparam/issue44688.go | 2 +- test/typeparam/issue45817.go | 3 +- test/typeparam/issue46472.go | 2 +- test/typeparam/issue47258.go | 2 +- test/typeparam/list.go | 26 +++--- test/typeparam/list2.go | 4 +- test/typeparam/listimp.dir/a.go | 50 ++++++------ test/typeparam/listimp.dir/main.go | 72 ++++++++-------- test/typeparam/listimp2.dir/a.go | 2 +- test/typeparam/listimp2.dir/main.go | 1 - test/typeparam/lockable.go | 2 +- test/typeparam/mapimp.dir/a.go | 10 +-- test/typeparam/mincheck.dir/a.go | 10 +-- test/typeparam/minimp.dir/a.go | 10 +-- test/typeparam/mutualimp.dir/a.go | 3 +- test/typeparam/ordered.go | 14 ++-- test/typeparam/orderedmap.go | 10 +-- test/typeparam/orderedmapsimp.dir/a.go | 10 +-- test/typeparam/orderedmapsimp.dir/main.go | 2 +- test/typeparam/pair.go | 5 +- test/typeparam/pairimp.dir/a.go | 4 +- test/typeparam/pairimp.dir/main.go | 27 +++--- test/typeparam/sets.go | 2 +- test/typeparam/settable.go | 1 - test/typeparam/sliceimp.dir/a.go | 26 +++--- test/typeparam/sliceimp.dir/main.go | 60 +++++++------- test/typeparam/slices.go | 86 ++++++++++---------- test/typeparam/smallest.go | 8 +- test/typeparam/smoketest.go | 4 +- test/typeparam/stringable.go | 4 +- test/typeparam/struct.go | 6 +- test/typeparam/subdict.go | 3 +- test/typeparam/sum.go | 4 +- test/typeparam/tparam1.go | 16 ++-- test/typeparam/typelist.go | 30 ++++--- test/typeparam/valimp.dir/a.go | 10 +-- test/typeparam/valimp.dir/main.go | 73 ++++++++--------- 59 files changed, 413 insertions(+), 408 deletions(-) diff --git a/test/typeparam/absdiff.go b/test/typeparam/absdiff.go index e76a998b4d3..cad6e84c4e4 100644 --- a/test/typeparam/absdiff.go +++ b/test/typeparam/absdiff.go @@ -61,7 +61,7 @@ type complexAbs[T Complex] T func (a complexAbs[T]) Abs() complexAbs[T] { r := float64(real(a)) i := float64(imag(a)) - d := math.Sqrt(r * r + i * i) + d := math.Sqrt(r*r + i*i) return complexAbs[T](complex(d, 0)) } @@ -88,10 +88,10 @@ func main() { panic(fmt.Sprintf("got = %v, want = %v", got, want)) } - if got, want := complexAbsDifference(5.0 + 2.0i, 2.0 - 2.0i), 5+0i; got != want { + if got, want := complexAbsDifference(5.0+2.0i, 2.0-2.0i), 5+0i; got != want { panic(fmt.Sprintf("got = %v, want = %v", got, want)) } - if got, want := complexAbsDifference(2.0 - 2.0i, 5.0 + 2.0i), 5+0i; got != want { + if got, want := complexAbsDifference(2.0-2.0i, 5.0+2.0i), 5+0i; got != want { panic(fmt.Sprintf("got = %v, want = %v", got, want)) } } diff --git a/test/typeparam/absdiffimp.dir/a.go b/test/typeparam/absdiffimp.dir/a.go index df81dcf5387..7b5bfbe2ace 100644 --- a/test/typeparam/absdiffimp.dir/a.go +++ b/test/typeparam/absdiffimp.dir/a.go @@ -58,7 +58,7 @@ type complexAbs[T Complex] T func (a complexAbs[T]) Abs() complexAbs[T] { r := float64(real(a)) i := float64(imag(a)) - d := math.Sqrt(r * r + i * i) + d := math.Sqrt(r*r + i*i) return complexAbs[T](complex(d, 0)) } diff --git a/test/typeparam/aliasimp.dir/a.go b/test/typeparam/aliasimp.dir/a.go index 3fac4aac987..c64e87c10fa 100644 --- a/test/typeparam/aliasimp.dir/a.go +++ b/test/typeparam/aliasimp.dir/a.go @@ -5,5 +5,5 @@ package a type Rimp[T any] struct { - F T + F T } diff --git a/test/typeparam/aliasimp.dir/main.go b/test/typeparam/aliasimp.dir/main.go index 6638fa94545..221a6c758dc 100644 --- a/test/typeparam/aliasimp.dir/main.go +++ b/test/typeparam/aliasimp.dir/main.go @@ -7,7 +7,7 @@ package main import "a" type R[T any] struct { - F T + F T } type S = R diff --git a/test/typeparam/boundmethod.go b/test/typeparam/boundmethod.go index c150f9d85ae..3deabbcdcef 100644 --- a/test/typeparam/boundmethod.go +++ b/test/typeparam/boundmethod.go @@ -11,50 +11,50 @@ package main import ( - "fmt" - "reflect" - "strconv" + "fmt" + "reflect" + "strconv" ) type myint int //go:noinline func (m myint) String() string { - return strconv.Itoa(int(m)) + return strconv.Itoa(int(m)) } type Stringer interface { - String() string + String() string } func stringify[T Stringer](s []T) (ret []string) { - for _, v := range s { - ret = append(ret, v.String()) - } - return ret + for _, v := range s { + ret = append(ret, v.String()) + } + return ret } type StringInt[T any] T //go:noinline func (m StringInt[T]) String() string { - return "aa" + return "aa" } func main() { - x := []myint{myint(1), myint(2), myint(3)} + x := []myint{myint(1), myint(2), myint(3)} - got := stringify(x) - want := []string{"1", "2", "3"} - if !reflect.DeepEqual(got, want) { - panic(fmt.Sprintf("got %s, want %s", got, want)) - } + got := stringify(x) + want := []string{"1", "2", "3"} + if !reflect.DeepEqual(got, want) { + panic(fmt.Sprintf("got %s, want %s", got, want)) + } - x2 := []StringInt[myint]{StringInt[myint](1), StringInt[myint](2), StringInt[myint](3)} + x2 := []StringInt[myint]{StringInt[myint](1), StringInt[myint](2), StringInt[myint](3)} - got2 := stringify(x2) - want2 := []string{"aa", "aa", "aa"} - if !reflect.DeepEqual(got2, want2) { - panic(fmt.Sprintf("got %s, want %s", got2, want2)) - } + got2 := stringify(x2) + want2 := []string{"aa", "aa", "aa"} + if !reflect.DeepEqual(got2, want2) { + panic(fmt.Sprintf("got %s, want %s", got2, want2)) + } } diff --git a/test/typeparam/builtins.go b/test/typeparam/builtins.go index 3fe6f79391f..819588b07d0 100644 --- a/test/typeparam/builtins.go +++ b/test/typeparam/builtins.go @@ -39,7 +39,9 @@ func _[T C5[X], X any](ch T) { type M0 interface{ int } type M1 interface{ map[string]int } -type M2 interface { map[string]int | map[string]float64 } +type M2 interface { + map[string]int | map[string]float64 +} type M3 interface{ map[string]int | map[rune]int } type M4[K comparable, V any] interface{ map[K]V | map[rune]V } diff --git a/test/typeparam/chans.go b/test/typeparam/chans.go index 2fcd4af75e5..c30c21c37bf 100644 --- a/test/typeparam/chans.go +++ b/test/typeparam/chans.go @@ -183,7 +183,7 @@ func _Ranger[Elem any]() (*_Sender[Elem], *_Receiver[Elem]) { values: c, done: d, } - r := &_Receiver[Elem] { + r := &_Receiver[Elem]{ values: c, done: d, } diff --git a/test/typeparam/chansimp.dir/a.go b/test/typeparam/chansimp.dir/a.go index a3f73b21996..73219927041 100644 --- a/test/typeparam/chansimp.dir/a.go +++ b/test/typeparam/chansimp.dir/a.go @@ -176,7 +176,7 @@ func Ranger[Elem any]() (*Sender[Elem], *Receiver[Elem]) { values: c, done: d, } - r := &Receiver[Elem] { + r := &Receiver[Elem]{ values: c, done: d, } diff --git a/test/typeparam/combine.go b/test/typeparam/combine.go index 0e120cf2427..5dfdb784425 100644 --- a/test/typeparam/combine.go +++ b/test/typeparam/combine.go @@ -13,18 +13,18 @@ import ( type Gen[A any] func() (A, bool) func Combine[T1, T2, T any](g1 Gen[T1], g2 Gen[T2], join func(T1, T2) T) Gen[T] { - return func() (T, bool) { - var t T - t1, ok := g1() - if !ok { - return t, false - } - t2, ok := g2() - if !ok { - return t, false - } - return join(t1, t2), true - } + return func() (T, bool) { + var t T + t1, ok := g1() + if !ok { + return t, false + } + t2, ok := g2() + if !ok { + return t, false + } + return join(t1, t2), true + } } type Pair[A, B any] struct { @@ -37,7 +37,7 @@ func _NewPair[A, B any](a A, b B) Pair[A, B] { } func Combine2[A, B any](ga Gen[A], gb Gen[B]) Gen[Pair[A, B]] { - return Combine(ga, gb, _NewPair[A, B]) + return Combine(ga, gb, _NewPair[A, B]) } func main() { @@ -60,6 +60,6 @@ func main() { } gc4 := Combine2(g1, g3) if got, ok := gc4(); !ok || got.A != 3 || got.B != "y" { - panic (fmt.Sprintf("got %v, %v, wanted {3, y}, true", got, ok)) + panic(fmt.Sprintf("got %v, %v, wanted {3, y}, true", got, ok)) } } diff --git a/test/typeparam/cons.go b/test/typeparam/cons.go index f20514fb66e..4750392a955 100644 --- a/test/typeparam/cons.go +++ b/test/typeparam/cons.go @@ -51,7 +51,7 @@ type List[a any] interface { Match(casenil Function[Nil[a], any], casecons Function[Cons[a], any]) any } -type Nil[a any] struct{ +type Nil[a any] struct { } func (xs Nil[a]) Match(casenil Function[Nil[a], any], casecons Function[Cons[a], any]) any { @@ -67,7 +67,7 @@ func (xs Cons[a]) Match(casenil Function[Nil[a], any], casecons Function[Cons[a] return casecons.Apply(xs) } -type mapNil[a, b any] struct{ +type mapNil[a, b any] struct { } func (m mapNil[a, b]) Apply(_ Nil[a]) any { diff --git a/test/typeparam/dictionaryCapture-noinline.go b/test/typeparam/dictionaryCapture-noinline.go index 4b46d5f57f3..ad5bfa008e9 100644 --- a/test/typeparam/dictionaryCapture-noinline.go +++ b/test/typeparam/dictionaryCapture-noinline.go @@ -44,7 +44,7 @@ func is7(x int) { } func is77(x, y int) { if x != 7 || y != 7 { - println(x,y) + println(x, y) panic("assertion failed") } } @@ -63,7 +63,7 @@ func (x s[T]) g2() (T, T) { } func methodExpressions() { - x := s[int]{a:7} + x := s[int]{a: 7} f0 := s[int].g0 f0(x) f1 := s[int].g1 @@ -73,7 +73,7 @@ func methodExpressions() { } func methodValues() { - x := s[int]{a:7} + x := s[int]{a: 7} f0 := x.g0 f0() f1 := x.g1 @@ -82,20 +82,20 @@ func methodValues() { is77(f2()) } -var x interface{ +var x interface { g0() - g1()int - g2()(int,int) -} = s[int]{a:7} -var y interface{} = s[int]{a:7} + g1() int + g2() (int, int) +} = s[int]{a: 7} +var y interface{} = s[int]{a: 7} func interfaceMethods() { x.g0() is7(x.g1()) is77(x.g2()) - y.(interface{g0()}).g0() - is7(y.(interface{g1()int}).g1()) - is77(y.(interface{g2()(int,int)}).g2()) + y.(interface{ g0() }).g0() + is7(y.(interface{ g1() int }).g1()) + is77(y.(interface{ g2() (int, int) }).g2()) } // Also check for instantiations outside functions. @@ -107,7 +107,7 @@ var hh0 = s[int].g0 var hh1 = s[int].g1 var hh2 = s[int].g2 -var xtop = s[int]{a:7} +var xtop = s[int]{a: 7} var ii0 = x.g0 var ii1 = x.g1 var ii2 = x.g2 @@ -116,7 +116,7 @@ func globals() { gg0(7) is7(gg1(7)) is77(gg2(7)) - x := s[int]{a:7} + x := s[int]{a: 7} hh0(x) is7(hh1(x)) is77(hh2(x)) diff --git a/test/typeparam/dictionaryCapture.go b/test/typeparam/dictionaryCapture.go index 26af7a09b0b..7c7948145a8 100644 --- a/test/typeparam/dictionaryCapture.go +++ b/test/typeparam/dictionaryCapture.go @@ -51,7 +51,7 @@ func is7(x int) { } func is77(x, y int) { if x != 7 || y != 7 { - println(x,y) + println(x, y) panic("assertion failed") } } @@ -70,7 +70,7 @@ func (x s[T]) g2() (T, T) { } func methodExpressions() { - x := s[int]{a:7} + x := s[int]{a: 7} f0 := s[int].g0 f0(x) f0p := (*s[int]).g0 @@ -106,7 +106,7 @@ func genMethodExpressions[T comparable](want T) { } func methodValues() { - x := s[int]{a:7} + x := s[int]{a: 7} f0 := x.g0 f0() f1 := x.g1 @@ -129,20 +129,20 @@ func genMethodValues[T comparable](want T) { } } -var x interface{ +var x interface { g0() - g1()int - g2()(int,int) -} = s[int]{a:7} -var y interface{} = s[int]{a:7} + g1() int + g2() (int, int) +} = s[int]{a: 7} +var y interface{} = s[int]{a: 7} func interfaceMethods() { x.g0() is7(x.g1()) is77(x.g2()) - y.(interface{g0()}).g0() - is7(y.(interface{g1()int}).g1()) - is77(y.(interface{g2()(int,int)}).g2()) + y.(interface{ g0() }).g0() + is7(y.(interface{ g1() int }).g1()) + is77(y.(interface{ g2() (int, int) }).g2()) } // Also check for instantiations outside functions. @@ -154,7 +154,7 @@ var hh0 = s[int].g0 var hh1 = s[int].g1 var hh2 = s[int].g2 -var xtop = s[int]{a:7} +var xtop = s[int]{a: 7} var ii0 = x.g0 var ii1 = x.g1 var ii2 = x.g2 @@ -163,7 +163,7 @@ func globals() { gg0(7) is7(gg1(7)) is77(gg2(7)) - x := s[int]{a:7} + x := s[int]{a: 7} hh0(x) is7(hh1(x)) is77(hh2(x)) @@ -172,7 +172,6 @@ func globals() { is77(ii2()) } - func recursive() { if got, want := recur1[int](5), 110; got != want { panic(fmt.Sprintf("recur1[int](5) = %d, want = %d", got, want)) @@ -187,14 +186,14 @@ func recur1[T Integer](n T) T { if n == 0 || n == 1 { return T(1) } else { - return n * recur2(n - 1) + return n * recur2(n-1) } } func recur2[T Integer](n T) T { list := make([]T, n) for i, _ := range list { - list[i] = T(i+1) + list[i] = T(i + 1) } var sum T for _, elt := range list { diff --git a/test/typeparam/dottype.go b/test/typeparam/dottype.go index 0131f642028..89a9b021119 100644 --- a/test/typeparam/dottype.go +++ b/test/typeparam/dottype.go @@ -36,20 +36,20 @@ func g2[T I](x I) (T, bool) { return t, ok } -func h[T any](x interface{}) struct{a, b T} { - return x.(struct{a, b T}) +func h[T any](x interface{}) struct{ a, b T } { + return x.(struct{ a, b T }) } -func k[T any](x interface{}) interface { bar() T } { - return x.(interface{bar() T }) +func k[T any](x interface{}) interface{ bar() T } { + return x.(interface{ bar() T }) } type mybar int + func (x mybar) bar() int { return int(x) } - func main() { var i interface{} = int(3) var j I = myint(3) @@ -66,7 +66,7 @@ func main() { println(g2[myint](j)) println(g2[myint](y)) - println(h[int](struct{a, b int}{3, 5}).a) + println(h[int](struct{ a, b int }{3, 5}).a) println(k[int](mybar(3)).bar()) } diff --git a/test/typeparam/double.go b/test/typeparam/double.go index 66526138145..6ddb6b2d08b 100644 --- a/test/typeparam/double.go +++ b/test/typeparam/double.go @@ -44,29 +44,29 @@ func main() { want := MySlice{2, 4, 6} got := _DoubleElems[MySlice, int](arg) if !reflect.DeepEqual(got, want) { - panic(fmt.Sprintf("got %s, want %s", got, want)) + panic(fmt.Sprintf("got %s, want %s", got, want)) } // constraint type inference got = _DoubleElems[MySlice](arg) if !reflect.DeepEqual(got, want) { - panic(fmt.Sprintf("got %s, want %s", got, want)) + panic(fmt.Sprintf("got %s, want %s", got, want)) } got = _DoubleElems(arg) if !reflect.DeepEqual(got, want) { - panic(fmt.Sprintf("got %s, want %s", got, want)) + panic(fmt.Sprintf("got %s, want %s", got, want)) } farg := MyFloatSlice{1.2, 2.0, 3.5} fwant := MyFloatSlice{2.4, 4.0, 7.0} fgot := _DoubleElems(farg) if !reflect.DeepEqual(fgot, fwant) { - panic(fmt.Sprintf("got %s, want %s", fgot, fwant)) + panic(fmt.Sprintf("got %s, want %s", fgot, fwant)) } fgot = _DoubleElems2(farg) if !reflect.DeepEqual(fgot, fwant) { - panic(fmt.Sprintf("got %s, want %s", fgot, fwant)) + panic(fmt.Sprintf("got %s, want %s", fgot, fwant)) } } diff --git a/test/typeparam/equal.go b/test/typeparam/equal.go index 6776b19d125..a1d3e8ae023 100644 --- a/test/typeparam/equal.go +++ b/test/typeparam/equal.go @@ -40,7 +40,7 @@ func (x myint) foo() { func k[T comparable](t T, i interface{}) bool { // Compare derived type value to interface. - return struct{a, b T}{t, t} == i + return struct{ a, b T }{t, t} == i } func main() { @@ -51,21 +51,19 @@ func main() { assert(h(myint(3), myint(3))) assert(!h(myint(3), myint(5))) - type S struct { a, b float64 } + type S struct{ a, b float64 } - assert(f(S{3,5}, S{3,5})) - assert(!f(S{3,5}, S{4,6})) - assert(g(S{3,5}, S{3,5})) - assert(!g(S{3,5}, S{4,6})) + assert(f(S{3, 5}, S{3, 5})) + assert(!f(S{3, 5}, S{4, 6})) + assert(g(S{3, 5}, S{3, 5})) + assert(!g(S{3, 5}, S{4, 6})) - assert(k(3, struct{a, b int}{3, 3})) - assert(!k(3, struct{a, b int}{3, 4})) + assert(k(3, struct{ a, b int }{3, 3})) + assert(!k(3, struct{ a, b int }{3, 4})) } -func assert(b bool) { +func assert(b bool) { if !b { panic("assertion failed") } } - - diff --git a/test/typeparam/fact.go b/test/typeparam/fact.go index baa7fbc68e5..e19cfe69565 100644 --- a/test/typeparam/fact.go +++ b/test/typeparam/fact.go @@ -8,11 +8,11 @@ package main import "fmt" -func fact[T interface { ~int | ~int64 | ~float64 }](n T) T { +func fact[T interface{ ~int | ~int64 | ~float64 }](n T) T { if n == 1 { return 1 } - return n * fact(n - 1) + return n * fact(n-1) } func main() { diff --git a/test/typeparam/factimp.dir/a.go b/test/typeparam/factimp.dir/a.go index cb1ff2615b0..0bd73a88e7d 100644 --- a/test/typeparam/factimp.dir/a.go +++ b/test/typeparam/factimp.dir/a.go @@ -4,9 +4,9 @@ package a -func Fact[T interface { int | int64 | float64 }](n T) T { +func Fact[T interface{ int | int64 | float64 }](n T) T { if n == 1 { return 1 } - return n * Fact(n - 1) + return n * Fact(n-1) } diff --git a/test/typeparam/graph.go b/test/typeparam/graph.go index f2a2630ad09..cecf349a9ad 100644 --- a/test/typeparam/graph.go +++ b/test/typeparam/graph.go @@ -225,7 +225,6 @@ func TestShortestPath() { } } - func main() { TestShortestPath() } diff --git a/test/typeparam/ifaceconv.go b/test/typeparam/ifaceconv.go index f4023366b9e..ee3a9e0dc3a 100644 --- a/test/typeparam/ifaceconv.go +++ b/test/typeparam/ifaceconv.go @@ -37,11 +37,11 @@ type C interface { type myInt int func (x myInt) foo() int { - return int(x+1) + return int(x + 1) } -func h[T C](x T) interface{foo() int} { - var i interface{foo()int} = x +func h[T C](x T) interface{ foo() int } { + var i interface{ foo() int } = x return i } func i[T C](x T) C { diff --git a/test/typeparam/index.go b/test/typeparam/index.go index 80824efac37..906f76d325c 100644 --- a/test/typeparam/index.go +++ b/test/typeparam/index.go @@ -79,4 +79,3 @@ func main() { panic(fmt.Sprintf("got %d, want %d", got, want)) } } - diff --git a/test/typeparam/interfacearg.go b/test/typeparam/interfacearg.go index 1d194993187..28ea3e3afbb 100644 --- a/test/typeparam/interfacearg.go +++ b/test/typeparam/interfacearg.go @@ -23,9 +23,11 @@ func F() { // Testing the various combinations of method expressions. type S1 struct{} + func (*S1) M() {} type S2 struct{} + func (S2) M() {} func _F1[T interface{ M() }](t T) { diff --git a/test/typeparam/issue39755.go b/test/typeparam/issue39755.go index 13a575d16fb..c4b6902eead 100644 --- a/test/typeparam/issue39755.go +++ b/test/typeparam/issue39755.go @@ -8,14 +8,14 @@ package p -func _[T interface{~map[string]int}](x T) { +func _[T interface{ ~map[string]int }](x T) { _ = x == nil } // simplified test case from issue type PathParamsConstraint interface { - ~map[string]string | ~[]struct{key, value string} + ~map[string]string | ~[]struct{ key, value string } } type PathParams[T PathParamsConstraint] struct { diff --git a/test/typeparam/issue44688.go b/test/typeparam/issue44688.go index de1140b67cf..5ebce72628f 100644 --- a/test/typeparam/issue44688.go +++ b/test/typeparam/issue44688.go @@ -8,7 +8,7 @@ package main -type A1[T any] struct{ +type A1[T any] struct { val T } diff --git a/test/typeparam/issue45817.go b/test/typeparam/issue45817.go index 744698f40be..1efee3b0af2 100644 --- a/test/typeparam/issue45817.go +++ b/test/typeparam/issue45817.go @@ -13,11 +13,12 @@ import ( type s[T any] struct { a T } + func (x s[T]) f() T { return x.a } func main() { - x := s[int]{a:7} + x := s[int]{a: 7} f := x.f if got, want := f(), 7; got != want { panic(fmt.Sprintf("got %d, want %d", got, want)) diff --git a/test/typeparam/issue46472.go b/test/typeparam/issue46472.go index bab48e7d2f5..cd4d923ef55 100644 --- a/test/typeparam/issue46472.go +++ b/test/typeparam/issue46472.go @@ -10,7 +10,7 @@ func foo[T any](d T) { switch v := interface{}(d).(type) { case string: if v != "x" { - panic("unexpected v: "+v) + panic("unexpected v: " + v) } } diff --git a/test/typeparam/issue47258.go b/test/typeparam/issue47258.go index 76629f74240..717329471e1 100644 --- a/test/typeparam/issue47258.go +++ b/test/typeparam/issue47258.go @@ -11,7 +11,7 @@ import ( ) type Numeric interface { - int32|int64|float64|complex64 + int32 | int64 | float64 | complex64 } //go:noline diff --git a/test/typeparam/list.go b/test/typeparam/list.go index c63c9bff79f..adfe72f1de1 100644 --- a/test/typeparam/list.go +++ b/test/typeparam/list.go @@ -11,10 +11,10 @@ import ( ) type Ordered interface { - ~int | ~int8 | ~int16 | ~int32 | ~int64 | - ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | - ~float32 | ~float64 | - ~string + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string } // _List is a linked list of ordered values of type T. @@ -34,9 +34,9 @@ func (l *_List[T]) Largest() T { } type OrderedNum interface { - ~int | ~int8 | ~int16 | ~int32 | ~int64 | - ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | - ~float32 | ~float64 + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 } // _ListNum is a linked _List of ordered numeric values of type T. @@ -64,40 +64,40 @@ func main() { i2 := &_List[int]{i3, 3} i1 := &_List[int]{i2, 2} if got, want := i1.Largest(), 3; got != want { - panic(fmt.Sprintf("got %d, want %d", got, want)) + panic(fmt.Sprintf("got %d, want %d", got, want)) } b3 := &_List[byte]{nil, byte(1)} b2 := &_List[byte]{b3, byte(3)} b1 := &_List[byte]{b2, byte(2)} if got, want := b1.Largest(), byte(3); got != want { - panic(fmt.Sprintf("got %d, want %d", got, want)) + panic(fmt.Sprintf("got %d, want %d", got, want)) } f3 := &_List[float64]{nil, 13.5} f2 := &_List[float64]{f3, 1.2} f1 := &_List[float64]{f2, 4.5} if got, want := f1.Largest(), 13.5; got != want { - panic(fmt.Sprintf("got %f, want %f", got, want)) + panic(fmt.Sprintf("got %f, want %f", got, want)) } s3 := &_List[string]{nil, "dd"} s2 := &_List[string]{s3, "aa"} s1 := &_List[string]{s2, "bb"} if got, want := s1.Largest(), "dd"; got != want { - panic(fmt.Sprintf("got %s, want %s", got, want)) + panic(fmt.Sprintf("got %s, want %s", got, want)) } j3 := &_ListNum[int]{nil, 1} j2 := &_ListNum[int]{j3, 32} j1 := &_ListNum[int]{j2, 2} if got, want := j1.ClippedLargest(), 2; got != want { - panic(fmt.Sprintf("got %d, want %d", got, want)) + panic(fmt.Sprintf("got %d, want %d", got, want)) } g3 := &_ListNum[float64]{nil, 13.5} g2 := &_ListNum[float64]{g3, 1.2} g1 := &_ListNum[float64]{g2, 4.5} if got, want := g1.ClippedLargest(), 4.5; got != want { - panic(fmt.Sprintf("got %f, want %f", got, want)) + panic(fmt.Sprintf("got %f, want %f", got, want)) } } diff --git a/test/typeparam/list2.go b/test/typeparam/list2.go index 32023cf319d..e7f346c78e1 100644 --- a/test/typeparam/list2.go +++ b/test/typeparam/list2.go @@ -50,7 +50,7 @@ func (e *_Element[T]) Prev() *_Element[T] { // The zero value for _List is an empty list ready to use. type _List[T any] struct { root _Element[T] // sentinel list element, only &root, root.prev, and root.next are used - len int // current list length excluding (this) sentinel element + len int // current list length excluding (this) sentinel element } // Init initializes or clears list l. @@ -594,7 +594,6 @@ func TestTransform() { checkList(l2, []interface{}{"1", "2"}) } - func main() { TestList() TestExtending() @@ -607,4 +606,3 @@ func main() { TestInsertAfterUnknownMark() TestTransform() } - diff --git a/test/typeparam/listimp.dir/a.go b/test/typeparam/listimp.dir/a.go index 2b5b23cde33..bf1641af9c3 100644 --- a/test/typeparam/listimp.dir/a.go +++ b/test/typeparam/listimp.dir/a.go @@ -5,49 +5,49 @@ package a type Ordered interface { - ~int | ~int8 | ~int16 | ~int32 | ~int64 | - ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | - ~float32 | ~float64 | - ~string + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string } // List is a linked list of ordered values of type T. type List[T Ordered] struct { - Next *List[T] - Val T + Next *List[T] + Val T } func (l *List[T]) Largest() T { - var max T - for p := l; p != nil; p = p.Next { - if p.Val > max { - max = p.Val - } - } - return max + var max T + for p := l; p != nil; p = p.Next { + if p.Val > max { + max = p.Val + } + } + return max } type OrderedNum interface { - ~int | ~int8 | ~int16 | ~int32 | ~int64 | - ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | - ~float32 | ~float64 + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 } // ListNum is a linked _List of ordered numeric values of type T. type ListNum[T OrderedNum] struct { - Next *ListNum[T] - Val T + Next *ListNum[T] + Val T } const Clip = 5 // clippedLargest returns the largest in the list of OrderNums, but a max of 5. func (l *ListNum[T]) ClippedLargest() T { - var max T - for p := l; p != nil; p = p.Next { - if p.Val > max && p.Val < Clip { - max = p.Val - } - } - return max + var max T + for p := l; p != nil; p = p.Next { + if p.Val > max && p.Val < Clip { + max = p.Val + } + } + return max } diff --git a/test/typeparam/listimp.dir/main.go b/test/typeparam/listimp.dir/main.go index d43ad508be5..985ff59a189 100644 --- a/test/typeparam/listimp.dir/main.go +++ b/test/typeparam/listimp.dir/main.go @@ -10,43 +10,43 @@ import ( ) func main() { - i3 := &a.List[int]{nil, 1} - i2 := &a.List[int]{i3, 3} - i1 := &a.List[int]{i2, 2} - if got, want := i1.Largest(), 3; got != want { - panic(fmt.Sprintf("got %d, want %d", got, want)) - } + i3 := &a.List[int]{nil, 1} + i2 := &a.List[int]{i3, 3} + i1 := &a.List[int]{i2, 2} + if got, want := i1.Largest(), 3; got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } - b3 := &a.List[byte]{nil, byte(1)} - b2 := &a.List[byte]{b3, byte(3)} - b1 := &a.List[byte]{b2, byte(2)} - if got, want := b1.Largest(), byte(3); got != want { - panic(fmt.Sprintf("got %d, want %d", got, want)) - } + b3 := &a.List[byte]{nil, byte(1)} + b2 := &a.List[byte]{b3, byte(3)} + b1 := &a.List[byte]{b2, byte(2)} + if got, want := b1.Largest(), byte(3); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } - f3 := &a.List[float64]{nil, 13.5} - f2 := &a.List[float64]{f3, 1.2} - f1 := &a.List[float64]{f2, 4.5} - if got, want := f1.Largest(), 13.5; got != want { - panic(fmt.Sprintf("got %f, want %f", got, want)) - } + f3 := &a.List[float64]{nil, 13.5} + f2 := &a.List[float64]{f3, 1.2} + f1 := &a.List[float64]{f2, 4.5} + if got, want := f1.Largest(), 13.5; got != want { + panic(fmt.Sprintf("got %f, want %f", got, want)) + } - s3 := &a.List[string]{nil, "dd"} - s2 := &a.List[string]{s3, "aa"} - s1 := &a.List[string]{s2, "bb"} - if got, want := s1.Largest(), "dd"; got != want { - panic(fmt.Sprintf("got %s, want %s", got, want)) - } - j3 := &a.ListNum[int]{nil, 1} - j2 := &a.ListNum[int]{j3, 32} - j1 := &a.ListNum[int]{j2, 2} - if got, want := j1.ClippedLargest(), 2; got != want { - panic(fmt.Sprintf("got %d, want %d", got, want)) - } - g3 := &a.ListNum[float64]{nil, 13.5} - g2 := &a.ListNum[float64]{g3, 1.2} - g1 := &a.ListNum[float64]{g2, 4.5} - if got, want := g1.ClippedLargest(), 4.5; got != want { - panic(fmt.Sprintf("got %f, want %f", got, want)) - } + s3 := &a.List[string]{nil, "dd"} + s2 := &a.List[string]{s3, "aa"} + s1 := &a.List[string]{s2, "bb"} + if got, want := s1.Largest(), "dd"; got != want { + panic(fmt.Sprintf("got %s, want %s", got, want)) + } + j3 := &a.ListNum[int]{nil, 1} + j2 := &a.ListNum[int]{j3, 32} + j1 := &a.ListNum[int]{j2, 2} + if got, want := j1.ClippedLargest(), 2; got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + g3 := &a.ListNum[float64]{nil, 13.5} + g2 := &a.ListNum[float64]{g3, 1.2} + g1 := &a.ListNum[float64]{g2, 4.5} + if got, want := g1.ClippedLargest(), 4.5; got != want { + panic(fmt.Sprintf("got %f, want %f", got, want)) + } } diff --git a/test/typeparam/listimp2.dir/a.go b/test/typeparam/listimp2.dir/a.go index 76ad669767a..3a7dfc3999a 100644 --- a/test/typeparam/listimp2.dir/a.go +++ b/test/typeparam/listimp2.dir/a.go @@ -44,7 +44,7 @@ func (e *Element[T]) Prev() *Element[T] { // The zero value for List is an empty list ready to use. type List[T any] struct { root Element[T] // sentinel list element, only &root, root.prev, and root.next are used - len int // current list length excluding (this) sentinel element + len int // current list length excluding (this) sentinel element } // Init initializes or clears list l. diff --git a/test/typeparam/listimp2.dir/main.go b/test/typeparam/listimp2.dir/main.go index 0c2c38e3995..226e1a9a571 100644 --- a/test/typeparam/listimp2.dir/main.go +++ b/test/typeparam/listimp2.dir/main.go @@ -301,7 +301,6 @@ func TestTransform() { checkList(l2, []interface{}{"1", "2"}) } - func main() { TestList() TestExtending() diff --git a/test/typeparam/lockable.go b/test/typeparam/lockable.go index 9372c76b4db..9b20d87bb77 100644 --- a/test/typeparam/lockable.go +++ b/test/typeparam/lockable.go @@ -11,7 +11,7 @@ import "sync" // A Lockable is a value that may be safely simultaneously accessed // from multiple goroutines via the Get and Set methods. type Lockable[T any] struct { - x T + x T mu sync.Mutex } diff --git a/test/typeparam/mapimp.dir/a.go b/test/typeparam/mapimp.dir/a.go index 6835e214b8d..cbfa80ac6b1 100644 --- a/test/typeparam/mapimp.dir/a.go +++ b/test/typeparam/mapimp.dir/a.go @@ -7,9 +7,9 @@ package a // Map calls the function f on every element of the slice s, // returning a new slice of the results. func Mapper[F, T any](s []F, f func(F) T) []T { - r := make([]T, len(s)) - for i, v := range s { - r[i] = f(v) - } - return r + r := make([]T, len(s)) + for i, v := range s { + r[i] = f(v) + } + return r } diff --git a/test/typeparam/mincheck.dir/a.go b/test/typeparam/mincheck.dir/a.go index 7d42492b741..fa0f249e615 100644 --- a/test/typeparam/mincheck.dir/a.go +++ b/test/typeparam/mincheck.dir/a.go @@ -5,12 +5,12 @@ package a type Ordered interface { - int | int64 | float64 + int | int64 | float64 } func Min[T Ordered](x, y T) T { - if x < y { - return x - } - return y + if x < y { + return x + } + return y } diff --git a/test/typeparam/minimp.dir/a.go b/test/typeparam/minimp.dir/a.go index 6c3e0eba363..fabde62c5d7 100644 --- a/test/typeparam/minimp.dir/a.go +++ b/test/typeparam/minimp.dir/a.go @@ -5,12 +5,12 @@ package a type Ordered interface { - ~int | ~int64 | ~float64 | ~string + ~int | ~int64 | ~float64 | ~string } func Min[T Ordered](x, y T) T { - if x < y { - return x - } - return y + if x < y { + return x + } + return y } diff --git a/test/typeparam/mutualimp.dir/a.go b/test/typeparam/mutualimp.dir/a.go index 56ca57cea5e..5b924d3ce5d 100644 --- a/test/typeparam/mutualimp.dir/a.go +++ b/test/typeparam/mutualimp.dir/a.go @@ -5,7 +5,8 @@ package a type X int + func (x X) M() X { return x } func F[T interface{ M() U }, U interface{ M() T }]() {} -func G() { F[X, X]() } +func G() { F[X, X]() } diff --git a/test/typeparam/ordered.go b/test/typeparam/ordered.go index 699505ec75b..0f539d659c3 100644 --- a/test/typeparam/ordered.go +++ b/test/typeparam/ordered.go @@ -13,15 +13,15 @@ import ( ) type Ordered interface { - ~int | ~int8 | ~int16 | ~int32 | ~int64 | - ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | - ~float32 | ~float64 | - ~string + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string } type orderedSlice[Elem Ordered] []Elem -func (s orderedSlice[Elem]) Len() int { return len(s) } +func (s orderedSlice[Elem]) Len() int { return len(s) } func (s orderedSlice[Elem]) Less(i, j int) bool { if s[i] < s[j] { return true @@ -32,7 +32,7 @@ func (s orderedSlice[Elem]) Less(i, j int) bool { } return false } -func (s orderedSlice[Elem]) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s orderedSlice[Elem]) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func _OrderedSlice[Elem Ordered](s []Elem) { sort.Sort(orderedSlice[Elem](s)) @@ -68,7 +68,7 @@ func testOrdered[Elem Ordered](name string, s []Elem, sorter func([]Elem)) bool } for i := len(s1) - 1; i > 0; i-- { if s1[i] < s1[i-1] { - fmt.Printf("%s: element %d (%v) < element %d (%v)", name, i, s1[i], i - 1, s1[i - 1]) + fmt.Printf("%s: element %d (%v) < element %d (%v)", name, i, s1[i], i-1, s1[i-1]) ok = false } } diff --git a/test/typeparam/orderedmap.go b/test/typeparam/orderedmap.go index 6a895bd3960..1f077333b8f 100644 --- a/test/typeparam/orderedmap.go +++ b/test/typeparam/orderedmap.go @@ -15,10 +15,10 @@ import ( ) type Ordered interface { - ~int | ~int8 | ~int16 | ~int32 | ~int64 | - ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | - ~float32 | ~float64 | - ~string + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string } // _Map is an ordered map. @@ -230,7 +230,7 @@ func _Ranger[Elem any]() (*_Sender[Elem], *_Receiver[Elem]) { values: c, done: d, } - r := &_Receiver[Elem] { + r := &_Receiver[Elem]{ values: c, done: d, } diff --git a/test/typeparam/orderedmapsimp.dir/a.go b/test/typeparam/orderedmapsimp.dir/a.go index 37fc3e79b9f..d6a2de5d7b3 100644 --- a/test/typeparam/orderedmapsimp.dir/a.go +++ b/test/typeparam/orderedmapsimp.dir/a.go @@ -10,10 +10,10 @@ import ( ) type Ordered interface { - ~int | ~int8 | ~int16 | ~int32 | ~int64 | - ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | - ~float32 | ~float64 | - ~string + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string } // Map is an ordered map. @@ -170,7 +170,7 @@ func Ranger[Elem any]() (*Sender[Elem], *Receiver[Elem]) { values: c, done: d, } - r := &Receiver[Elem] { + r := &Receiver[Elem]{ values: c, done: d, } diff --git a/test/typeparam/orderedmapsimp.dir/main.go b/test/typeparam/orderedmapsimp.dir/main.go index ac4cee6a781..978f1e763c0 100644 --- a/test/typeparam/orderedmapsimp.dir/main.go +++ b/test/typeparam/orderedmapsimp.dir/main.go @@ -17,7 +17,7 @@ func TestMap() { panic(fmt.Sprintf("unexpectedly found %q in empty map", []byte("a"))) } - for _, c := range []int{ 'a', 'c', 'b' } { + for _, c := range []int{'a', 'c', 'b'} { if !m.Insert([]byte(string(c)), c) { panic(fmt.Sprintf("key %q unexpectedly already present", []byte(string(c)))) } diff --git a/test/typeparam/pair.go b/test/typeparam/pair.go index 57742022b10..c1427b9c52c 100644 --- a/test/typeparam/pair.go +++ b/test/typeparam/pair.go @@ -25,7 +25,10 @@ func main() { panic(fmt.Sprintf("unexpected f2 size == %d, want %d", got, want)) } - type mypair struct { f1 int32; f2 int64 } + type mypair struct { + f1 int32 + f2 int64 + } mp := mypair(p) if mp.f1 != 1 || mp.f2 != 2 { panic(fmt.Sprintf("mp == %#v, want %#v", mp, mypair{1, 2})) diff --git a/test/typeparam/pairimp.dir/a.go b/test/typeparam/pairimp.dir/a.go index 27b2412961b..a984fba37b6 100644 --- a/test/typeparam/pairimp.dir/a.go +++ b/test/typeparam/pairimp.dir/a.go @@ -5,6 +5,6 @@ package a type Pair[F1, F2 any] struct { - Field1 F1 - Field2 F2 + Field1 F1 + Field2 F2 } diff --git a/test/typeparam/pairimp.dir/main.go b/test/typeparam/pairimp.dir/main.go index fc2face81df..027fdd9ce76 100644 --- a/test/typeparam/pairimp.dir/main.go +++ b/test/typeparam/pairimp.dir/main.go @@ -11,17 +11,20 @@ import ( ) func main() { - p := a.Pair[int32, int64]{1, 2} - if got, want := unsafe.Sizeof(p.Field1), uintptr(4); got != want { - panic(fmt.Sprintf("unexpected f1 size == %d, want %d", got, want)) - } - if got, want := unsafe.Sizeof(p.Field2), uintptr(8); got != want { - panic(fmt.Sprintf("unexpected f2 size == %d, want %d", got, want)) - } + p := a.Pair[int32, int64]{1, 2} + if got, want := unsafe.Sizeof(p.Field1), uintptr(4); got != want { + panic(fmt.Sprintf("unexpected f1 size == %d, want %d", got, want)) + } + if got, want := unsafe.Sizeof(p.Field2), uintptr(8); got != want { + panic(fmt.Sprintf("unexpected f2 size == %d, want %d", got, want)) + } - type mypair struct { Field1 int32; Field2 int64 } - mp := mypair(p) - if mp.Field1 != 1 || mp.Field2 != 2 { - panic(fmt.Sprintf("mp == %#v, want %#v", mp, mypair{1, 2})) - } + type mypair struct { + Field1 int32 + Field2 int64 + } + mp := mypair(p) + if mp.Field1 != 1 || mp.Field2 != 2 { + panic(fmt.Sprintf("mp == %#v, want %#v", mp, mypair{1, 2})) + } } diff --git a/test/typeparam/sets.go b/test/typeparam/sets.go index 258514489e1..4f07b590e36 100644 --- a/test/typeparam/sets.go +++ b/test/typeparam/sets.go @@ -160,7 +160,7 @@ func TestSet() { vals := s1.Values() sort.Ints(vals) w1 := []int{1, 2, 3, 4} - if !_SliceEqual(vals, w1) { + if !_SliceEqual(vals, w1) { panic(fmt.Sprintf("(%v).Values() == %v, want %v", s1, vals, w1)) } } diff --git a/test/typeparam/settable.go b/test/typeparam/settable.go index d0b831b5333..99455e93fa1 100644 --- a/test/typeparam/settable.go +++ b/test/typeparam/settable.go @@ -44,7 +44,6 @@ func fromStrings1a[T any, PT Setter[T]](s []string) []PT { return result } - // Takes one type parameter and a set function func fromStrings2[T any](s []string, set func(*T, string)) []T { results := make([]T, len(s)) diff --git a/test/typeparam/sliceimp.dir/a.go b/test/typeparam/sliceimp.dir/a.go index 61b1b17a982..da12e9f9fc9 100644 --- a/test/typeparam/sliceimp.dir/a.go +++ b/test/typeparam/sliceimp.dir/a.go @@ -5,26 +5,26 @@ package a type Ordered interface { - ~int | ~int8 | ~int16 | ~int32 | ~int64 | - ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | - ~float32 | ~float64 | - ~string + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string } // Max returns the maximum of two values of some ordered type. func Max[T Ordered](a, b T) T { - if a > b { - return a - } - return b + if a > b { + return a + } + return b } // Min returns the minimum of two values of some ordered type. func Min[T Ordered](a, b T) T { - if a < b { - return a - } - return b + if a < b { + return a + } + return b } // Equal reports whether two slices are equal: the same length and all @@ -121,7 +121,7 @@ func Append[T any](s []T, t ...T) []T { if tot <= cap(s) { s = s[:tot] } else { - news := make([]T, tot, tot + tot/2) + news := make([]T, tot, tot+tot/2) Copy(news, s) s = news } diff --git a/test/typeparam/sliceimp.dir/main.go b/test/typeparam/sliceimp.dir/main.go index 2d4d3b28318..0f79e10018b 100644 --- a/test/typeparam/sliceimp.dir/main.go +++ b/test/typeparam/sliceimp.dir/main.go @@ -12,42 +12,42 @@ import ( ) type Integer interface { - ~int | ~int8 | ~int16 | ~int32 | ~int64 | - ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr } func TestEqual() { - s1 := []int{1, 2, 3} - if !a.Equal(s1, s1) { - panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", s1, s1)) - } - s2 := []int{1, 2, 3} - if !a.Equal(s1, s2) { - panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", s1, s2)) - } - s2 = append(s2, 4) - if a.Equal(s1, s2) { - panic(fmt.Sprintf("a.Equal(%v, %v) = true, want false", s1, s2)) - } + s1 := []int{1, 2, 3} + if !a.Equal(s1, s1) { + panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", s1, s1)) + } + s2 := []int{1, 2, 3} + if !a.Equal(s1, s2) { + panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", s1, s2)) + } + s2 = append(s2, 4) + if a.Equal(s1, s2) { + panic(fmt.Sprintf("a.Equal(%v, %v) = true, want false", s1, s2)) + } - s3 := []float64{1, 2, math.NaN()} - if !a.Equal(s3, s3) { - panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", s3, s3)) - } + s3 := []float64{1, 2, math.NaN()} + if !a.Equal(s3, s3) { + panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", s3, s3)) + } - if a.Equal(s1, nil) { - panic(fmt.Sprintf("a.Equal(%v, nil) = true, want false", s1)) - } - if a.Equal(nil, s1) { - panic(fmt.Sprintf("a.Equal(nil, %v) = true, want false", s1)) - } - if !a.Equal(s1[:0], nil) { - panic(fmt.Sprintf("a.Equal(%v, nil = false, want true", s1[:0])) - } + if a.Equal(s1, nil) { + panic(fmt.Sprintf("a.Equal(%v, nil) = true, want false", s1)) + } + if a.Equal(nil, s1) { + panic(fmt.Sprintf("a.Equal(nil, %v) = true, want false", s1)) + } + if !a.Equal(s1[:0], nil) { + panic(fmt.Sprintf("a.Equal(%v, nil = false, want true", s1[:0])) + } } func offByOne[Elem Integer](a, b Elem) bool { - return a == b + 1 || a == b - 1 + return a == b+1 || a == b-1 } func TestEqualFn() { @@ -92,12 +92,12 @@ func TestMap() { func TestReduce() { s1 := []int{1, 2, 3} - r := a.Reduce(s1, 0, func(f float64, i int) float64 { return float64(i) * 2.5 + f }) + r := a.Reduce(s1, 0, func(f float64, i int) float64 { return float64(i)*2.5 + f }) if want := 15.0; r != want { panic(fmt.Sprintf("a.Reduce(%v, 0, ...) = %v, want %v", s1, r, want)) } - if got := a.Reduce(nil, 0, func(i, j int) int { return i + j}); got != 0 { + if got := a.Reduce(nil, 0, func(i, j int) int { return i + j }); got != 0 { panic(fmt.Sprintf("a.Reduce(nil, 0, add) = %v, want 0", got)) } } diff --git a/test/typeparam/slices.go b/test/typeparam/slices.go index 50783a5439b..b5e8e0c6063 100644 --- a/test/typeparam/slices.go +++ b/test/typeparam/slices.go @@ -15,31 +15,31 @@ import ( ) type Ordered interface { - ~int | ~int8 | ~int16 | ~int32 | ~int64 | - ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | - ~float32 | ~float64 | - ~string + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string } type Integer interface { - ~int | ~int8 | ~int16 | ~int32 | ~int64 | - ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr } // Max returns the maximum of two values of some ordered type. func _Max[T Ordered](a, b T) T { - if a > b { - return a - } - return b + if a > b { + return a + } + return b } // Min returns the minimum of two values of some ordered type. func _Min[T Ordered](a, b T) T { - if a < b { - return a - } - return b + if a < b { + return a + } + return b } // _Equal reports whether two slices are equal: the same length and all @@ -136,7 +136,7 @@ func _Append[T any](s []T, t ...T) []T { if tot <= cap(s) { s = s[:tot] } else { - news := make([]T, tot, tot + tot/2) + news := make([]T, tot, tot+tot/2) _Copy(news, s) s = news } @@ -156,37 +156,37 @@ func _Copy[T any](s, t []T) int { } func TestEqual() { - s1 := []int{1, 2, 3} - if !_Equal(s1, s1) { - panic(fmt.Sprintf("_Equal(%v, %v) = false, want true", s1, s1)) - } - s2 := []int{1, 2, 3} - if !_Equal(s1, s2) { - panic(fmt.Sprintf("_Equal(%v, %v) = false, want true", s1, s2)) - } - s2 = append(s2, 4) - if _Equal(s1, s2) { - panic(fmt.Sprintf("_Equal(%v, %v) = true, want false", s1, s2)) - } + s1 := []int{1, 2, 3} + if !_Equal(s1, s1) { + panic(fmt.Sprintf("_Equal(%v, %v) = false, want true", s1, s1)) + } + s2 := []int{1, 2, 3} + if !_Equal(s1, s2) { + panic(fmt.Sprintf("_Equal(%v, %v) = false, want true", s1, s2)) + } + s2 = append(s2, 4) + if _Equal(s1, s2) { + panic(fmt.Sprintf("_Equal(%v, %v) = true, want false", s1, s2)) + } - s3 := []float64{1, 2, math.NaN()} - if !_Equal(s3, s3) { - panic(fmt.Sprintf("_Equal(%v, %v) = false, want true", s3, s3)) - } + s3 := []float64{1, 2, math.NaN()} + if !_Equal(s3, s3) { + panic(fmt.Sprintf("_Equal(%v, %v) = false, want true", s3, s3)) + } - if _Equal(s1, nil) { - panic(fmt.Sprintf("_Equal(%v, nil) = true, want false", s1)) - } - if _Equal(nil, s1) { - panic(fmt.Sprintf("_Equal(nil, %v) = true, want false", s1)) - } - if !_Equal(s1[:0], nil) { - panic(fmt.Sprintf("_Equal(%v, nil = false, want true", s1[:0])) - } + if _Equal(s1, nil) { + panic(fmt.Sprintf("_Equal(%v, nil) = true, want false", s1)) + } + if _Equal(nil, s1) { + panic(fmt.Sprintf("_Equal(nil, %v) = true, want false", s1)) + } + if !_Equal(s1[:0], nil) { + panic(fmt.Sprintf("_Equal(%v, nil = false, want true", s1[:0])) + } } func offByOne[Elem Integer](a, b Elem) bool { - return a == b + 1 || a == b - 1 + return a == b+1 || a == b-1 } func TestEqualFn() { @@ -231,12 +231,12 @@ func TestMap() { func TestReduce() { s1 := []int{1, 2, 3} - r := _Reduce(s1, 0, func(f float64, i int) float64 { return float64(i) * 2.5 + f }) + r := _Reduce(s1, 0, func(f float64, i int) float64 { return float64(i)*2.5 + f }) if want := 15.0; r != want { panic(fmt.Sprintf("_Reduce(%v, 0, ...) = %v, want %v", s1, r, want)) } - if got := _Reduce(nil, 0, func(i, j int) int { return i + j}); got != 0 { + if got := _Reduce(nil, 0, func(i, j int) int { return i + j }); got != 0 { panic(fmt.Sprintf("_Reduce(nil, 0, add) = %v, want 0", got)) } } diff --git a/test/typeparam/smallest.go b/test/typeparam/smallest.go index 3fead6a0671..af1d72d8992 100644 --- a/test/typeparam/smallest.go +++ b/test/typeparam/smallest.go @@ -11,10 +11,10 @@ import ( ) type Ordered interface { - ~int | ~int8 | ~int16 | ~int32 | ~int64 | - ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | - ~float32 | ~float64 | - ~string + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string } func Smallest[T Ordered](s []T) T { diff --git a/test/typeparam/smoketest.go b/test/typeparam/smoketest.go index d92e02713d7..eeda25964f4 100644 --- a/test/typeparam/smoketest.go +++ b/test/typeparam/smoketest.go @@ -29,8 +29,8 @@ type _ T2[int, string, struct{}] type _ T3[bool] // methods -func (T1[P]) m1() {} -func (T1[_]) m2() {} +func (T1[P]) m1() {} +func (T1[_]) m2() {} func (x T2[P1, P2, P3]) m() {} // type lists diff --git a/test/typeparam/stringable.go b/test/typeparam/stringable.go index 20da012cb87..855a1edb3bf 100644 --- a/test/typeparam/stringable.go +++ b/test/typeparam/stringable.go @@ -38,9 +38,9 @@ func (a myint) String() string { } func main() { - v := StringableList[myint]{ myint(1), myint(2) } + v := StringableList[myint]{myint(1), myint(2)} if got, want := v.String(), "1, 2"; got != want { - panic(fmt.Sprintf("got %s, want %s", got, want)) + panic(fmt.Sprintf("got %s, want %s", got, want)) } } diff --git a/test/typeparam/struct.go b/test/typeparam/struct.go index 093f6935e69..ad1b41ddac4 100644 --- a/test/typeparam/struct.go +++ b/test/typeparam/struct.go @@ -35,15 +35,15 @@ type S3 struct { func main() { s1 := S1{Eint{2}, "foo"} if got, want := s1.E.v, 2; got != want { - panic(fmt.Sprintf("got %d, want %d", got, want)) + panic(fmt.Sprintf("got %d, want %d", got, want)) } s2 := S2{Eint{3}, Ebool{true}, "foo"} if got, want := s2.Eint.v, 3; got != want { - panic(fmt.Sprintf("got %d, want %d", got, want)) + panic(fmt.Sprintf("got %d, want %d", got, want)) } var s3 S3 s3.E = &Eint{4} if got, want := s3.E.v, 4; got != want { - panic(fmt.Sprintf("got %d, want %d", got, want)) + panic(fmt.Sprintf("got %d, want %d", got, want)) } } diff --git a/test/typeparam/subdict.go b/test/typeparam/subdict.go index c899af6d0d6..b4e84baf8a7 100644 --- a/test/typeparam/subdict.go +++ b/test/typeparam/subdict.go @@ -4,7 +4,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Test cases where a main dictionary is needed inside a generic function/method, because +// Test cases where a main dictionary is needed inside a generic function/method, because // we are calling a method on a fully-instantiated type or a fully-instantiated function. // (probably not common situations, of course) @@ -33,7 +33,6 @@ func (v *value[T]) get(def T) T { } } - func main() { var s value[string] if got, want := s.get("ab"), ""; got != want { diff --git a/test/typeparam/sum.go b/test/typeparam/sum.go index 53e6face11a..d444e007a3a 100644 --- a/test/typeparam/sum.go +++ b/test/typeparam/sum.go @@ -40,11 +40,11 @@ func main() { fwant := vec2[0] + vec2[1] fgot := Sum[float64](vec2) - if Abs(fgot - fwant) > 1e-10 { + if Abs(fgot-fwant) > 1e-10 { panic(fmt.Sprintf("got %f, want %f", fgot, fwant)) } fgot = Sum(vec2) - if Abs(fgot - fwant) > 1e-10 { + if Abs(fgot-fwant) > 1e-10 { panic(fmt.Sprintf("got %f, want %f", fgot, fwant)) } } diff --git a/test/typeparam/tparam1.go b/test/typeparam/tparam1.go index 2bcc4af3dba..a196caf976b 100644 --- a/test/typeparam/tparam1.go +++ b/test/typeparam/tparam1.go @@ -10,18 +10,18 @@ package tparam1 // The predeclared identifier "any" is only visible as a constraint // in a type parameter list. -var _ any // ERROR "cannot use any outside constraint position" +var _ any // ERROR "cannot use any outside constraint position" func _(_ any) // ERROR "cannot use any outside constraint position" -type _[_ any /* ok here */ ] struct{} +type _[_ any /* ok here */] struct{} const N = 10 type ( - _[] struct{} // slice - _[N] struct{} // array - _[T any] struct{} - _[T, T any] struct{} // ERROR "T redeclared" - _[T1, T2 any, T3 any] struct{} + _ []struct{} // slice + _ [N]struct{} // array + _[T any] struct{} + _[T, T any] struct{} // ERROR "T redeclared" + _[T1, T2 any, T3 any] struct{} ) func _[T any]() @@ -36,7 +36,7 @@ func _[T C]() func _[T struct{}]() // ERROR "not an interface" func _[T interface{ m() T }]() func _[T1 interface{ m() T2 }, T2 interface{ m() T1 }]() { - var _ T1 + var _ T1 } // TODO(gri) expand this diff --git a/test/typeparam/typelist.go b/test/typeparam/typelist.go index 5c51c9c4617..3d035bf4572 100644 --- a/test/typeparam/typelist.go +++ b/test/typeparam/typelist.go @@ -10,19 +10,19 @@ package p // Assignability of an unnamed pointer type to a type parameter that // has a matching underlying type. -func _[T interface{}, PT interface{type *T}] (x T) PT { - return &x +func _[T interface{}, PT interface{ type *T }](x T) PT { + return &x } // Indexing of generic types containing type parameters in their type list: func at[T interface{ type []E }, E any](x T, i int) E { - return x[i] + return x[i] } // A generic type inside a function acts like a named type. Its underlying // type is itself, its "operational type" is defined by the type list in // the tybe bound, if any. -func _[T interface{type int}](x T) { +func _[T interface{ type int }](x T) { type myint int var _ int = int(x) var _ T = 42 @@ -30,7 +30,7 @@ func _[T interface{type int}](x T) { } // Indexing a generic type which has a structural contraints to be an array. -func _[T interface { type [10]int }](x T) { +func _[T interface{ type [10]int }](x T) { _ = x[9] // ok } @@ -44,7 +44,7 @@ func _[T interface{ type *int }](p T) int { func _[T interface{ type chan int }](ch T) int { // This would deadlock if executed (but ok for a compile test) ch <- 0 - return <- ch + return <-ch } // Calling of a generic type which has a structural constraint to be a function. @@ -59,11 +59,10 @@ func _[T interface{ type func(string) int }](f T) int { } // Map access of a generic type which has a structural constraint to be a map. -func _[V any, T interface { type map[string]V }](p T) V { +func _[V any, T interface{ type map[string]V }](p T) V { return p["test"] } - // Testing partial and full type inference, including the case where the types can // be inferred without needing the types of the function arguments. @@ -86,7 +85,7 @@ func _() { } */ -func f2[A any, B interface{type []A}](_ A, _ B) +func f2[A any, B interface{ type []A }](_ A, _ B) func _() { f := f2[byte] f(byte(0), []byte{}) @@ -106,7 +105,7 @@ func _() { } */ -func f4[A any, B interface{type []C}, C interface{type *A}](_ A, _ B, c C) +func f4[A any, B interface{ type []C }, C interface{ type *A }](_ A, _ B, c C) func _() { f := f4[int] var x int @@ -114,15 +113,20 @@ func _() { f4(x, []*int{}, &x) } -func f5[A interface{type struct{b B; c C}}, B any, C interface{type *B}](x B) A +func f5[A interface { + type struct { + b B + c C + } +}, B any, C interface{ type *B }](x B) A func _() { x := f5(1.2) var _ float64 = x.b var _ float64 = *x.c } -func f6[A any, B interface{type struct{f []A}}](B) A +func f6[A any, B interface{ type struct{ f []A } }](B) A func _() { - x := f6(struct{f []string}{}) + x := f6(struct{ f []string }{}) var _ string = x } diff --git a/test/typeparam/valimp.dir/a.go b/test/typeparam/valimp.dir/a.go index 5aa5ebfa976..2ed0063cfd6 100644 --- a/test/typeparam/valimp.dir/a.go +++ b/test/typeparam/valimp.dir/a.go @@ -5,7 +5,7 @@ package a type Value[T any] struct { - val T + val T } // The noinline directive should survive across import, and prevent instantiations @@ -13,20 +13,20 @@ type Value[T any] struct { //go:noinline func Get[T any](v *Value[T]) T { - return v.val + return v.val } //go:noinline func Set[T any](v *Value[T], val T) { - v.val = val + v.val = val } //go:noinline func (v *Value[T]) Set(val T) { - v.val = val + v.val = val } //go:noinline func (v *Value[T]) Get() T { - return v.val + return v.val } diff --git a/test/typeparam/valimp.dir/main.go b/test/typeparam/valimp.dir/main.go index 925fb1e6994..606ff2273af 100644 --- a/test/typeparam/valimp.dir/main.go +++ b/test/typeparam/valimp.dir/main.go @@ -10,47 +10,46 @@ import ( ) func main() { - var v1 a.Value[int] + var v1 a.Value[int] - a.Set(&v1, 1) - if got, want := a.Get(&v1), 1; got != want { - panic(fmt.Sprintf("Get() == %d, want %d", got, want)) - } - v1.Set(2) - if got, want := v1.Get(), 2; got != want { - panic(fmt.Sprintf("Get() == %d, want %d", got, want)) - } - v1p := new(a.Value[int]) - a.Set(v1p, 3) - if got, want := a.Get(v1p), 3; got != want { - panic(fmt.Sprintf("Get() == %d, want %d", got, want)) - } + a.Set(&v1, 1) + if got, want := a.Get(&v1), 1; got != want { + panic(fmt.Sprintf("Get() == %d, want %d", got, want)) + } + v1.Set(2) + if got, want := v1.Get(), 2; got != want { + panic(fmt.Sprintf("Get() == %d, want %d", got, want)) + } + v1p := new(a.Value[int]) + a.Set(v1p, 3) + if got, want := a.Get(v1p), 3; got != want { + panic(fmt.Sprintf("Get() == %d, want %d", got, want)) + } - v1p.Set(4) - if got, want := v1p.Get(), 4; got != want { - panic(fmt.Sprintf("Get() == %d, want %d", got, want)) - } + v1p.Set(4) + if got, want := v1p.Get(), 4; got != want { + panic(fmt.Sprintf("Get() == %d, want %d", got, want)) + } - var v2 a.Value[string] - a.Set(&v2, "a") - if got, want := a.Get(&v2), "a"; got != want { - panic(fmt.Sprintf("Get() == %q, want %q", got, want)) - } + var v2 a.Value[string] + a.Set(&v2, "a") + if got, want := a.Get(&v2), "a"; got != want { + panic(fmt.Sprintf("Get() == %q, want %q", got, want)) + } - v2.Set("b") - if got, want := a.Get(&v2), "b"; got != want { - panic(fmt.Sprintf("Get() == %q, want %q", got, want)) - } + v2.Set("b") + if got, want := a.Get(&v2), "b"; got != want { + panic(fmt.Sprintf("Get() == %q, want %q", got, want)) + } - v2p := new(a.Value[string]) - a.Set(v2p, "c") - if got, want := a.Get(v2p), "c"; got != want { - panic(fmt.Sprintf("Get() == %d, want %d", got, want)) - } + v2p := new(a.Value[string]) + a.Set(v2p, "c") + if got, want := a.Get(v2p), "c"; got != want { + panic(fmt.Sprintf("Get() == %d, want %d", got, want)) + } - v2p.Set("d") - if got, want := v2p.Get(), "d"; got != want { - panic(fmt.Sprintf("Get() == %d, want %d", got, want)) - } + v2p.Set("d") + if got, want := v2p.Get(), "d"; got != want { + panic(fmt.Sprintf("Get() == %d, want %d", got, want)) + } } - From adedf54288e826bd93ccf22ad104f768d42289d4 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 28 Jul 2021 12:59:14 -0700 Subject: [PATCH 805/940] [dev.typeparams] test: rename blank functions This CL renames blank functions in the test/ directory so that they don't rely on the compiler doing anything more than typechecking them. In particular, I ran this search to find files that used blank functions and methods: $ git grep -l '^func.*\b_(' | xargs grep -n '^' | grep '\.go:1:' | grep -v '// errorcheck$' I then skipped updating a few files: * blank.go * fixedbugs/issue11699.go * fixedbugs/issue29870.go These tests specifically check that blank functions/methods work. * interface/fail.go Not sure the motivation for the blank method here, but it's empty anyway. * typeparam/tparam1.go Type-checking test, but uses "-G" (to use types2 instead of typecheck). Updates #47446. Change-Id: I9ec1714f499808768bd0dcd7ae6016fb2b078e5e Reviewed-on: https://go-review.googlesource.com/c/go/+/338094 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- test/escape5.go | 4 ++-- test/escape_goto.go | 6 +++--- test/fixedbugs/bug267.go | 2 +- test/fixedbugs/issue22076.go | 4 ++-- test/fixedbugs/issue27557.go | 6 +++--- test/fixedbugs/issue45258.go | 2 +- test/fixedbugs/issue8042.go | 6 +++--- test/fixedbugs/issue8761.go | 6 +++--- test/inline.go | 4 ++-- test/typeparam/issue45547.go | 2 +- test/typeparam/typelist.go | 14 +++++++------- 11 files changed, 28 insertions(+), 28 deletions(-) diff --git a/test/escape5.go b/test/escape5.go index 97aaf23b2d1..089130dad5c 100644 --- a/test/escape5.go +++ b/test/escape5.go @@ -173,13 +173,13 @@ type U int func (*U) M() {} func (_ *U) N() {} -func _() { +func fbad24305a() { var u U u.M() u.N() } -func fbad24305() { +func fbad24305b() { var u U (*U).M(&u) (*U).N(&u) diff --git a/test/escape_goto.go b/test/escape_goto.go index f024a9afe37..90da5a21512 100644 --- a/test/escape_goto.go +++ b/test/escape_goto.go @@ -10,7 +10,7 @@ package escape var x bool -func _() { +func f1() { var p *int loop: if x { @@ -22,7 +22,7 @@ loop: _ = p } -func _() { +func f2() { var p *int if x { loop: @@ -33,7 +33,7 @@ func _() { _ = p } -func _() { +func f3() { var p *int if x { loop: diff --git a/test/fixedbugs/bug267.go b/test/fixedbugs/bug267.go index cf8bf841f8b..b61216a9d5a 100644 --- a/test/fixedbugs/bug267.go +++ b/test/fixedbugs/bug267.go @@ -10,7 +10,7 @@ type T []int var a []bool -func _() { +func f1() { if a[T{42}[0]] { } // if (a[T{42}[0]]) {} // this compiles diff --git a/test/fixedbugs/issue22076.go b/test/fixedbugs/issue22076.go index 5d628b96bd3..b383a674e2f 100644 --- a/test/fixedbugs/issue22076.go +++ b/test/fixedbugs/issue22076.go @@ -13,12 +13,12 @@ import . "bytes" var _ Reader // use "bytes" import -func _() { +func f1() { Buffer := 0 _ = Buffer } -func _() { +func f2() { for Buffer := range []int{} { _ = Buffer } diff --git a/test/fixedbugs/issue27557.go b/test/fixedbugs/issue27557.go index e35ab5a1690..f609b27faa5 100644 --- a/test/fixedbugs/issue27557.go +++ b/test/fixedbugs/issue27557.go @@ -8,19 +8,19 @@ package p var sink interface{} -func _() { +func f1() { var t T f := t.noescape // ERROR "t.noescape does not escape" f() } -func _() { +func f2() { var t T // ERROR "moved to heap" f := t.escape // ERROR "t.escape does not escape" f() } -func _() { +func f3() { var t T // ERROR "moved to heap" f := t.returns // ERROR "t.returns does not escape" sink = f() diff --git a/test/fixedbugs/issue45258.go b/test/fixedbugs/issue45258.go index f4d6fccf17d..b026c0c8f53 100644 --- a/test/fixedbugs/issue45258.go +++ b/test/fixedbugs/issue45258.go @@ -22,7 +22,7 @@ func (r *impl) Foo() Barer { func (r *impl) Bar() {} -func _() { +func f1() { var r Fooer = &impl{} r.Foo().Bar() } diff --git a/test/fixedbugs/issue8042.go b/test/fixedbugs/issue8042.go index 5639f97bb89..be15ef06cd2 100644 --- a/test/fixedbugs/issue8042.go +++ b/test/fixedbugs/issue8042.go @@ -9,7 +9,7 @@ package p -func _() { +func f1() { goto L1 const x = 0 L1: @@ -18,7 +18,7 @@ L1: L2: } -func _() { +func f2() { { goto L1 } @@ -31,7 +31,7 @@ L1: L2: } -func _(d int) { +func f3(d int) { if d > 0 { goto L1 } else { diff --git a/test/fixedbugs/issue8761.go b/test/fixedbugs/issue8761.go index 7f458f7f033..e5130e1ff5c 100644 --- a/test/fixedbugs/issue8761.go +++ b/test/fixedbugs/issue8761.go @@ -10,17 +10,17 @@ package p -func _() { +func f1() { type C chan int _ = [1][]C{[]C{make(chan int)}} } -func _() { +func f2() { type C interface{} _ = [1][]C{[]C{recover()}} } -func _() { +func f3() { type C *int _ = [1][]C{[]C{new(int)}} } diff --git a/test/inline.go b/test/inline.go index 2cda07b2da9..a73c0ba7b1d 100644 --- a/test/inline.go +++ b/test/inline.go @@ -49,7 +49,7 @@ func j(x int) int { // ERROR "can inline j" } } -func _() int { // ERROR "can inline _" +func f2() int { // ERROR "can inline f2" tmp1 := h tmp2 := tmp1 return tmp2(0) // ERROR "inlining call to h" @@ -167,7 +167,7 @@ func (T) meth(int, int) {} // ERROR "can inline T.meth" func k() (T, int, int) { return T{}, 0, 0 } // ERROR "can inline k" -func _() { // ERROR "can inline _" +func f3() { // ERROR "can inline f3" T.meth(k()) // ERROR "inlining call to k" "inlining call to T.meth" // ERRORAUTO "inlining call to T.meth" } diff --git a/test/typeparam/issue45547.go b/test/typeparam/issue45547.go index 0a08d66b70e..b354d4d7f64 100644 --- a/test/typeparam/issue45547.go +++ b/test/typeparam/issue45547.go @@ -11,7 +11,7 @@ func f[T any]() (f, g T) { return f, g } // Tests for generic function instantiation on the right hande side of multi-value // assignments. -func _() { +func g() { // Multi-value assignment within a function var _, _ = f[int]() } diff --git a/test/typeparam/typelist.go b/test/typeparam/typelist.go index 3d035bf4572..a68ae1b5cd0 100644 --- a/test/typeparam/typelist.go +++ b/test/typeparam/typelist.go @@ -69,14 +69,14 @@ func _[V any, T interface{ type map[string]V }](p T) V { // Cannot embed stand-alone type parameters. Disabled for now. /* func f0[A any, B interface{type C}, C interface{type D}, D interface{type A}](A, B, C, D) -func _() { +func f0x() { f := f0[string] f("a", "b", "c", "d") f0("a", "b", "c", "d") } func f1[A any, B interface{type A}](A, B) -func _() { +func f1x() { f := f1[int] f(int(0), int(0)) f1(int(0), int(0)) @@ -86,7 +86,7 @@ func _() { */ func f2[A any, B interface{ type []A }](_ A, _ B) -func _() { +func f2x() { f := f2[byte] f(byte(0), []byte{}) f2(byte(0), []byte{}) @@ -97,7 +97,7 @@ func _() { // Cannot embed stand-alone type parameters. Disabled for now. /* func f3[A any, B interface{type C}, C interface{type *A}](a A, _ B, c C) -func _() { +func f3x() { f := f3[int] var x int f(x, &x, &x) @@ -106,7 +106,7 @@ func _() { */ func f4[A any, B interface{ type []C }, C interface{ type *A }](_ A, _ B, c C) -func _() { +func f4x() { f := f4[int] var x int f(x, []*int{}, &x) @@ -119,14 +119,14 @@ func f5[A interface { c C } }, B any, C interface{ type *B }](x B) A -func _() { +func f5x() { x := f5(1.2) var _ float64 = x.b var _ float64 = *x.c } func f6[A any, B interface{ type struct{ f []A } }](B) A -func _() { +func f6x() { x := f6(struct{ f []string }{}) var _ string = x } From 506fd520d5cd6ea075ac82e79a23c502c1540170 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 28 Jul 2021 13:17:32 -0700 Subject: [PATCH 806/940] [dev.typeparams] cmd/compile: don't compile blank functions After typechecking a blank function, we can clear out its body and skip applying middle-end optimizations (inlining, escape analysis). We already skip sending them through SSA, and the previous CL updated inlining and escape analysis regress tests to not depend on compiling blank functions. Updates #47446. Change-Id: Ie678763b0e6ff13dd606ce14906b1ccf1bbccaae Reviewed-on: https://go-review.googlesource.com/c/go/+/338095 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/typecheck/typecheck.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go index 8f3d6cf4bb5..db1b11c4cfd 100644 --- a/src/cmd/compile/internal/typecheck/typecheck.go +++ b/src/cmd/compile/internal/typecheck/typecheck.go @@ -51,8 +51,8 @@ func FuncBody(n *ir.Func) { Stmts(n.Body) CheckUnused(n) CheckReturn(n) - if base.Errors() > errorsBefore { - n.Body = nil // type errors; do not compile + if ir.IsBlank(n.Nname) || base.Errors() > errorsBefore { + n.Body = nil // blank function or type errors; do not compile } } From 4a47e40a14c2051656d4ff4b768fe21a5fc308fa Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 28 Jul 2021 13:17:56 -0700 Subject: [PATCH 807/940] [dev.typeparams] cmd/compile: don't export blank functions in unified IR After the previous two CLs, there's no need for unified IR to write/read blank functions anymore: types2 has already checked that they're valid, and the compiler backend is going to ignore them. Allows dropping code for worrying about blank methods and will probably simplify some of the object handling code eventually too. Fixes #47446. Change-Id: I03cb722793d676a246b1ab768b5cf0d3d2578b12 Reviewed-on: https://go-review.googlesource.com/c/go/+/338096 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/noder/writer.go | 25 +++++------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go index bf60246d64b..7b2285556ed 100644 --- a/src/cmd/compile/internal/noder/writer.go +++ b/src/cmd/compile/internal/noder/writer.go @@ -550,25 +550,6 @@ func (w *writer) doObj(obj types2.Object) codeObj { assert(ok) sig := obj.Type().(*types2.Signature) - // Rewrite blank methods into blank functions. - // They aren't included in the receiver type's method set, - // and we still want to write them out to be compiled - // for regression tests. - // TODO(mdempsky): Change regress tests to avoid relying - // on blank functions/methods, so we can just ignore them - // altogether. - if recv := sig.Recv(); recv != nil { - assert(obj.Name() == "_") - assert(sig.TParams() == nil) - - params := make([]*types2.Var, 1+sig.Params().Len()) - params[0] = recv - for i := 0; i < sig.Params().Len(); i++ { - params[1+i] = sig.Params().At(i) - } - sig = types2.NewSignature(nil, types2.NewTuple(params...), sig.Results(), sig.Variadic()) - } - w.pos(obj) w.typeParamNames(sig.TParams()) w.signature(sig) @@ -1683,6 +1664,10 @@ func (w *writer) pkgDecl(decl syntax.Decl) { w.pkgObjs(decl.NameList...) case *syntax.FuncDecl: + if decl.Name.Value == "_" { + break // skip blank functions + } + obj := w.p.info.Defs[decl.Name].(*types2.Func) sig := obj.Type().(*types2.Signature) @@ -1690,7 +1675,7 @@ func (w *writer) pkgDecl(decl syntax.Decl) { break // skip generic functions } - if recv := sig.Recv(); recv != nil && obj.Name() != "_" { + if recv := sig.Recv(); recv != nil { w.code(declMethod) w.typ(recvBase(recv)) w.selector(obj) From 70fd4e47d73b92fe90e44ac785e2f98f9df0ab67 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 28 Jul 2021 21:09:31 -0700 Subject: [PATCH 808/940] runtime: avoid possible preemption when returning from Go to C When returning from Go to C, it was possible for the goroutine to be preempted after calling unlockOSThread. This could happen when there a context function installed by SetCgoTraceback set a non-zero context, leading to a defer call in cgocallbackg1. The defer function wrapper, introduced in 1.17 as part of the regabi support, was not nosplit, and hence was a potential preemption point. If it did get preempted, the G would move to a new M. It would then attempt to return to C code on a different stack, typically leading to a SIGSEGV. Fix this in a simple way by postponing the unlockOSThread until after the other defer. Also check for the failure condition and fail early, rather than waiting for a SIGSEGV. Without the fix to cgocall.go, the test case fails about 50% of the time on my laptop. Fixes #47441 Change-Id: Ib8ca13215bd36cddc2a49e86698824a29c6a68ba Reviewed-on: https://go-review.googlesource.com/c/go/+/338197 Trust: Ian Lance Taylor Reviewed-by: Keith Randall Reviewed-by: Cherry Mui --- src/runtime/cgocall.go | 20 +++++++---- src/runtime/crash_cgo_test.go | 9 +++++ .../testdata/testprogcgo/tracebackctxt.go | 33 +++++++++++++++++-- .../testdata/testprogcgo/tracebackctxt_c.c | 14 +++++++- 4 files changed, 67 insertions(+), 9 deletions(-) diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go index 8ffb48a888e..2626216f958 100644 --- a/src/runtime/cgocall.go +++ b/src/runtime/cgocall.go @@ -212,6 +212,8 @@ func cgocallbackg(fn, frame unsafe.Pointer, ctxt uintptr) { // a different M. The call to unlockOSThread is in unwindm. lockOSThread() + checkm := gp.m + // Save current syscall parameters, so m.syscall can be // used again if callback decide to make syscall. syscall := gp.m.syscall @@ -227,15 +229,20 @@ func cgocallbackg(fn, frame unsafe.Pointer, ctxt uintptr) { osPreemptExtExit(gp.m) - cgocallbackg1(fn, frame, ctxt) + cgocallbackg1(fn, frame, ctxt) // will call unlockOSThread // At this point unlockOSThread has been called. // The following code must not change to a different m. // This is enforced by checking incgo in the schedule function. + gp.m.incgo = true + + if gp.m != checkm { + throw("m changed unexpectedly in cgocallbackg") + } + osPreemptExtEnter(gp.m) - gp.m.incgo = true // going back to cgo call reentersyscall(savedpc, uintptr(savedsp)) @@ -244,6 +251,11 @@ func cgocallbackg(fn, frame unsafe.Pointer, ctxt uintptr) { func cgocallbackg1(fn, frame unsafe.Pointer, ctxt uintptr) { gp := getg() + + // When we return, undo the call to lockOSThread in cgocallbackg. + // We must still stay on the same m. + defer unlockOSThread() + if gp.m.needextram || atomic.Load(&extraMWaiters) > 0 { gp.m.needextram = false systemstack(newextram) @@ -323,10 +335,6 @@ func unwindm(restore *bool) { releasem(mp) } - - // Undo the call to lockOSThread in cgocallbackg. - // We must still stay on the same m. - unlockOSThread() } // called from assembly diff --git a/src/runtime/crash_cgo_test.go b/src/runtime/crash_cgo_test.go index 7d25c51aa2a..5729942cee3 100644 --- a/src/runtime/crash_cgo_test.go +++ b/src/runtime/crash_cgo_test.go @@ -282,6 +282,15 @@ func TestCgoTracebackContext(t *testing.T) { } } +func TestCgoTracebackContextPreemption(t *testing.T) { + t.Parallel() + got := runTestProg(t, "testprogcgo", "TracebackContextPreemption") + want := "OK\n" + if got != want { + t.Errorf("expected %q got %v", want, got) + } +} + func testCgoPprof(t *testing.T, buildArg, runArg, top, bottom string) { t.Parallel() if runtime.GOOS != "linux" || (runtime.GOARCH != "amd64" && runtime.GOARCH != "ppc64le") { diff --git a/src/runtime/testdata/testprogcgo/tracebackctxt.go b/src/runtime/testdata/testprogcgo/tracebackctxt.go index 51fa4ad25c3..62ff8eccd67 100644 --- a/src/runtime/testdata/testprogcgo/tracebackctxt.go +++ b/src/runtime/testdata/testprogcgo/tracebackctxt.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// The __attribute__((weak)) used below doesn't seem to work on Windows. - package main // Test the context argument to SetCgoTraceback. @@ -14,20 +12,24 @@ package main extern void C1(void); extern void C2(void); extern void tcContext(void*); +extern void tcContextSimple(void*); extern void tcTraceback(void*); extern void tcSymbolizer(void*); extern int getContextCount(void); +extern void TracebackContextPreemptionCallGo(int); */ import "C" import ( "fmt" "runtime" + "sync" "unsafe" ) func init() { register("TracebackContext", TracebackContext) + register("TracebackContextPreemption", TracebackContextPreemption) } var tracebackOK bool @@ -105,3 +107,30 @@ wantLoop: tracebackOK = false } } + +// Issue 47441. +func TracebackContextPreemption() { + runtime.SetCgoTraceback(0, unsafe.Pointer(C.tcTraceback), unsafe.Pointer(C.tcContextSimple), unsafe.Pointer(C.tcSymbolizer)) + + const funcs = 10 + const calls = 1e5 + var wg sync.WaitGroup + for i := 0; i < funcs; i++ { + wg.Add(1) + go func(i int) { + defer wg.Done() + for j := 0; j < calls; j++ { + C.TracebackContextPreemptionCallGo(C.int(i*calls + j)) + } + }(i) + } + wg.Wait() + + fmt.Println("OK") +} + +//export TracebackContextPreemptionGoFunction +func TracebackContextPreemptionGoFunction(i C.int) { + // Do some busy work. + fmt.Sprintf("%d\n", i) +} diff --git a/src/runtime/testdata/testprogcgo/tracebackctxt_c.c b/src/runtime/testdata/testprogcgo/tracebackctxt_c.c index 900cada0d3d..910cb7b8997 100644 --- a/src/runtime/testdata/testprogcgo/tracebackctxt_c.c +++ b/src/runtime/testdata/testprogcgo/tracebackctxt_c.c @@ -11,6 +11,7 @@ // Functions exported from Go. extern void G1(void); extern void G2(void); +extern void TracebackContextPreemptionGoFunction(int); void C1() { G1(); @@ -62,10 +63,17 @@ void tcContext(void* parg) { } } +void tcContextSimple(void* parg) { + struct cgoContextArg* arg = (struct cgoContextArg*)(parg); + if (arg->context == 0) { + arg->context = 1; + } +} + void tcTraceback(void* parg) { int base, i; struct cgoTracebackArg* arg = (struct cgoTracebackArg*)(parg); - if (arg->context == 0) { + if (arg->context == 0 && arg->sigContext == 0) { // This shouldn't happen in this program. abort(); } @@ -89,3 +97,7 @@ void tcSymbolizer(void *parg) { arg->func = "cFunction"; arg->lineno = arg->pc + (arg->more << 16); } + +void TracebackContextPreemptionCallGo(int i) { + TracebackContextPreemptionGoFunction(i); +} From f4f503e0a3ac7fbf9f57c7fe34cecc8df383e334 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 26 Jul 2021 17:41:02 -0700 Subject: [PATCH 809/940] [dev.typeparams] cmd/compile: implement generic .(T) operations Introduce new dynamic dottype operations which take a dynamic instead of static type to convert to. Change-Id: I5824a1fea056fe811b1226ce059e1e8da1baa335 Reviewed-on: https://go-review.googlesource.com/c/go/+/337609 Trust: Keith Randall Trust: Dan Scales Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/escape/expr.go | 4 + src/cmd/compile/internal/ir/expr.go | 23 ++++ src/cmd/compile/internal/ir/node.go | 4 + src/cmd/compile/internal/ir/node_gen.go | 28 +++++ src/cmd/compile/internal/ir/op_string.go | 16 +-- src/cmd/compile/internal/noder/stencil.go | 43 +++++++- src/cmd/compile/internal/ssagen/ssa.go | 122 ++++++++++++++-------- src/cmd/compile/internal/walk/expr.go | 11 ++ src/cmd/compile/internal/walk/order.go | 4 + test/typeparam/dottype.go | 5 + test/typeparam/dottype.out | 2 + 11 files changed, 209 insertions(+), 53 deletions(-) diff --git a/src/cmd/compile/internal/escape/expr.go b/src/cmd/compile/internal/escape/expr.go index b7423e114ad..4a6304d47a6 100644 --- a/src/cmd/compile/internal/escape/expr.go +++ b/src/cmd/compile/internal/escape/expr.go @@ -74,6 +74,10 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) { case ir.ODOTTYPE, ir.ODOTTYPE2: n := n.(*ir.TypeAssertExpr) e.expr(k.dotType(n.Type(), n, "dot"), n.X) + case ir.ODYNAMICDOTTYPE, ir.ODYNAMICDOTTYPE2: + n := n.(*ir.DynamicTypeAssertExpr) + e.expr(k.dotType(n.Type(), n, "dot"), n.X) + // n.T doesn't need to be tracked; it always points to read-only storage. case ir.OINDEX: n := n.(*ir.IndexExpr) if n.X.Type().IsArray() { diff --git a/src/cmd/compile/internal/ir/expr.go b/src/cmd/compile/internal/ir/expr.go index 86323e6b8f8..9c5fbbc9aa8 100644 --- a/src/cmd/compile/internal/ir/expr.go +++ b/src/cmd/compile/internal/ir/expr.go @@ -677,6 +677,29 @@ func (n *TypeAssertExpr) SetOp(op Op) { } } +// A DynamicTypeAssertExpr asserts that X is of dynamic type T. +type DynamicTypeAssertExpr struct { + miniExpr + X Node + // N = not an interface + // E = empty interface + // I = nonempty interface + // For E->N, T is a *runtime.type for N + // For I->N, T is a *runtime.itab for N+I + // For E->I, T is a *runtime.type for I + // For I->I, ditto + // For I->E, T is a *runtime.type for interface{} (unnecessary, but just to fill in the slot) + // For E->E, ditto + T Node +} + +func NewDynamicTypeAssertExpr(pos src.XPos, op Op, x, t Node) *DynamicTypeAssertExpr { + n := &DynamicTypeAssertExpr{X: x, T: t} + n.pos = pos + n.op = op + return n +} + // A UnaryExpr is a unary expression Op X, // or Op(X) for a builtin function that does not end up being a call. type UnaryExpr struct { diff --git a/src/cmd/compile/internal/ir/node.go b/src/cmd/compile/internal/ir/node.go index 0fbc867c1d9..e5f0c38f861 100644 --- a/src/cmd/compile/internal/ir/node.go +++ b/src/cmd/compile/internal/ir/node.go @@ -319,6 +319,10 @@ const ( OINLMARK // start of an inlined body, with file/line of caller. Xoffset is an index into the inline tree. OLINKSYMOFFSET // offset within a name + // opcodes for generics + ODYNAMICDOTTYPE + ODYNAMICDOTTYPE2 + // arch-specific opcodes OTAILCALL // tail call to another function OGETG // runtime.getg() (read g pointer) diff --git a/src/cmd/compile/internal/ir/node_gen.go b/src/cmd/compile/internal/ir/node_gen.go index 9a4858d0371..56db6bb9cf7 100644 --- a/src/cmd/compile/internal/ir/node_gen.go +++ b/src/cmd/compile/internal/ir/node_gen.go @@ -463,6 +463,34 @@ func (n *Decl) editChildren(edit func(Node) Node) { } } +func (n *DynamicTypeAssertExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) } +func (n *DynamicTypeAssertExpr) copy() Node { + c := *n + c.init = copyNodes(c.init) + return &c +} +func (n *DynamicTypeAssertExpr) doChildren(do func(Node) bool) bool { + if doNodes(n.init, do) { + return true + } + if n.X != nil && do(n.X) { + return true + } + if n.T != nil && do(n.T) { + return true + } + return false +} +func (n *DynamicTypeAssertExpr) editChildren(edit func(Node) Node) { + editNodes(n.init, edit) + if n.X != nil { + n.X = edit(n.X).(Node) + } + if n.T != nil { + n.T = edit(n.T).(Node) + } +} + func (n *ForStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) } func (n *ForStmt) copy() Node { c := *n diff --git a/src/cmd/compile/internal/ir/op_string.go b/src/cmd/compile/internal/ir/op_string.go index 0235d5eab39..7b08ee287a7 100644 --- a/src/cmd/compile/internal/ir/op_string.go +++ b/src/cmd/compile/internal/ir/op_string.go @@ -162,16 +162,18 @@ func _() { _ = x[ORESULT-151] _ = x[OINLMARK-152] _ = x[OLINKSYMOFFSET-153] - _ = x[OTAILCALL-154] - _ = x[OGETG-155] - _ = x[OGETCALLERPC-156] - _ = x[OGETCALLERSP-157] - _ = x[OEND-158] + _ = x[ODYNAMICDOTTYPE-154] + _ = x[ODYNAMICDOTTYPE2-155] + _ = x[OTAILCALL-156] + _ = x[OGETG-157] + _ = x[OGETCALLERPC-158] + _ = x[OGETCALLERSP-159] + _ = x[OEND-160] } -const _Op_name = "XXXNAMENONAMETYPEPACKLITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVIDATACONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFUNSAFEADDUNSAFESLICEMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWFUNCINSTTCHANTMAPTSTRUCTTINTERTFUNCTARRAYTSLICEINLCALLEFACEITABIDATASPTRCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKLINKSYMOFFSETTAILCALLGETGGETCALLERPCGETCALLERSPEND" +const _Op_name = "XXXNAMENONAMETYPEPACKLITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVIDATACONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFUNSAFEADDUNSAFESLICEMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWFUNCINSTTCHANTMAPTSTRUCTTINTERTFUNCTARRAYTSLICEINLCALLEFACEITABIDATASPTRCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKLINKSYMOFFSETDYNAMICDOTTYPEDYNAMICDOTTYPE2TAILCALLGETGGETCALLERPCGETCALLERSPEND" -var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 37, 39, 42, 48, 52, 58, 64, 73, 85, 94, 103, 115, 124, 136, 138, 141, 151, 158, 165, 172, 176, 180, 188, 196, 205, 208, 213, 220, 227, 233, 242, 250, 258, 264, 268, 277, 286, 293, 297, 300, 307, 315, 322, 328, 331, 337, 344, 352, 356, 363, 371, 373, 375, 377, 379, 381, 383, 388, 393, 401, 404, 413, 416, 420, 428, 435, 444, 457, 460, 463, 466, 469, 472, 475, 481, 484, 487, 493, 497, 500, 504, 509, 514, 520, 525, 529, 534, 542, 550, 556, 565, 576, 583, 592, 596, 603, 611, 615, 619, 623, 630, 637, 645, 651, 660, 671, 679, 688, 693, 698, 702, 710, 715, 719, 722, 730, 734, 736, 741, 743, 748, 754, 760, 766, 772, 780, 785, 789, 796, 802, 807, 813, 819, 826, 831, 835, 840, 844, 849, 857, 863, 870, 877, 883, 890, 903, 911, 915, 926, 937, 940} +var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 37, 39, 42, 48, 52, 58, 64, 73, 85, 94, 103, 115, 124, 136, 138, 141, 151, 158, 165, 172, 176, 180, 188, 196, 205, 208, 213, 220, 227, 233, 242, 250, 258, 264, 268, 277, 286, 293, 297, 300, 307, 315, 322, 328, 331, 337, 344, 352, 356, 363, 371, 373, 375, 377, 379, 381, 383, 388, 393, 401, 404, 413, 416, 420, 428, 435, 444, 457, 460, 463, 466, 469, 472, 475, 481, 484, 487, 493, 497, 500, 504, 509, 514, 520, 525, 529, 534, 542, 550, 556, 565, 576, 583, 592, 596, 603, 611, 615, 619, 623, 630, 637, 645, 651, 660, 671, 679, 688, 693, 698, 702, 710, 715, 719, 722, 730, 734, 736, 741, 743, 748, 754, 760, 766, 772, 780, 785, 789, 796, 802, 807, 813, 819, 826, 831, 835, 840, 844, 849, 857, 863, 870, 877, 883, 890, 903, 917, 932, 940, 944, 955, 966, 969} func (i Op) String() string { if i >= Op(len(_Op_index)-1) { diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 02a380e63f9..70a2c7b97fc 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -1039,6 +1039,7 @@ func (subst *subster) checkDictionary(name *ir.Name, targs []*types.Type) (code d.SetTypecheck(1) d = ir.NewConvExpr(pos, ir.OCONVNOP, types.NewArray(types.Types[types.TUINTPTR], int64(len(targs))).PtrTo(), d) d.SetTypecheck(1) + types.CheckSize(d.Type().Elem()) // Check that each type entry in the dictionary is correct. for i, t := range targs { @@ -1079,6 +1080,7 @@ func getDictionaryEntry(pos src.XPos, dict *ir.Name, i int, size int) ir.Node { d.SetTypecheck(1) d = ir.NewConvExpr(pos, ir.OCONVNOP, types.NewArray(types.Types[types.TUINTPTR], int64(size)).PtrTo(), d) d.SetTypecheck(1) + types.CheckSize(d.Type().Elem()) // Load entry i out of the dictionary. deref := ir.NewStarExpr(pos, d) @@ -1367,7 +1369,31 @@ func (subst *subster) node(n ir.Node) ir.Node { m = subst.convertUsingDictionary(m.Pos(), m.(*ir.ConvExpr).X, x, m.Type(), x.X.Type()) } case ir.ODOTTYPE, ir.ODOTTYPE2: - m.SetType(subst.unshapifyTyp(m.Type())) + dt := m.(*ir.TypeAssertExpr) + var rt ir.Node + if dt.Type().IsInterface() || dt.X.Type().IsEmptyInterface() { + ix := subst.findDictType(x.Type()) + assert(ix >= 0) + rt = subst.getDictionaryType(dt.Pos(), ix) + } else { + // nonempty interface to noninterface. Need an itab. + ix := -1 + for i, ic := range subst.info.gfInfo.itabConvs { + if ic == x { + ix = subst.info.startItabConv + i + break + } + } + assert(ix >= 0) + rt = getDictionaryEntry(dt.Pos(), subst.info.dictParam, ix, subst.info.dictLen) + } + op := ir.ODYNAMICDOTTYPE + if x.Op() == ir.ODOTTYPE2 { + op = ir.ODYNAMICDOTTYPE2 + } + m = ir.NewDynamicTypeAssertExpr(dt.Pos(), op, dt.X, rt) + m.SetType(dt.Type()) + m.SetTypecheck(1) case ir.OMETHEXPR: se := m.(*ir.SelectorExpr) @@ -1696,7 +1722,8 @@ func (g *irgen) finalizeSyms() { // Emit an entry for each itab for _, n := range info.itabConvs { var srctype, dsttype *types.Type - if n.Op() == ir.OXDOT { + switch n.Op() { + case ir.OXDOT: se := n.(*ir.SelectorExpr) srctype = subst.Typ(se.X.Type()) dsttype = subst.Typ(se.X.Type().Bound()) @@ -1712,10 +1739,14 @@ func (g *irgen) finalizeSyms() { } } assert(found) - } else { - assert(n.Op() == ir.OCONVIFACE) + case ir.ODOTTYPE, ir.ODOTTYPE2: + srctype = subst.Typ(n.(*ir.TypeAssertExpr).Type()) + dsttype = subst.Typ(n.(*ir.TypeAssertExpr).X.Type()) + case ir.OCONVIFACE: srctype = subst.Typ(n.(*ir.ConvExpr).X.Type()) dsttype = subst.Typ(n.Type()) + default: + base.Fatalf("itab entry with unknown op %s", n.Op()) } itabLsym := reflectdata.ITabLsym(srctype, dsttype) d.off = objw.SymPtr(lsym, d.off, itabLsym, 0) @@ -1859,6 +1890,10 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo { infoPrint(" Itab for interface conv: %v\n", n) info.itabConvs = append(info.itabConvs, n) } + if (n.Op() == ir.ODOTTYPE || n.Op() == ir.ODOTTYPE2) && !n.(*ir.TypeAssertExpr).Type().IsInterface() && !n.(*ir.TypeAssertExpr).X.Type().IsEmptyInterface() { + infoPrint(" Itab for dot type: %v\n", n) + info.itabConvs = append(info.itabConvs, n) + } if n.Op() == ir.OCLOSURE { // Visit the closure body and add all relevant entries to the // dictionary of the outer function (closure will just use diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index d2e0d57b28c..7e2f6a7471c 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -1423,7 +1423,12 @@ func (s *state) stmt(n ir.Node) { case ir.OAS2DOTTYPE: n := n.(*ir.AssignListStmt) - res, resok := s.dottype(n.Rhs[0].(*ir.TypeAssertExpr), true) + var res, resok *ssa.Value + if n.Rhs[0].Op() == ir.ODOTTYPE2 { + res, resok = s.dottype(n.Rhs[0].(*ir.TypeAssertExpr), true) + } else { + res, resok = s.dynamicDottype(n.Rhs[0].(*ir.DynamicTypeAssertExpr), true) + } deref := false if !TypeOK(n.Rhs[0].Type()) { if res.Op != ssa.OpLoad { @@ -2680,6 +2685,11 @@ func (s *state) expr(n ir.Node) *ssa.Value { res, _ := s.dottype(n, false) return res + case ir.ODYNAMICDOTTYPE: + n := n.(*ir.DynamicTypeAssertExpr) + res, _ := s.dynamicDottype(n, false) + return res + // binary ops case ir.OLT, ir.OEQ, ir.ONE, ir.OLE, ir.OGE, ir.OGT: n := n.(*ir.BinaryExpr) @@ -5147,9 +5157,13 @@ func (s *state) addr(n ir.Node) *ssa.Value { case ir.OCALLFUNC, ir.OCALLINTER: n := n.(*ir.CallExpr) return s.callAddr(n, callNormal) - case ir.ODOTTYPE: - n := n.(*ir.TypeAssertExpr) - v, _ := s.dottype(n, false) + case ir.ODOTTYPE, ir.ODYNAMICDOTTYPE: + var v *ssa.Value + if n.Op() == ir.ODOTTYPE { + v, _ = s.dottype(n.(*ir.TypeAssertExpr), false) + } else { + v, _ = s.dynamicDottype(n.(*ir.DynamicTypeAssertExpr), false) + } if v.Op != ssa.OpLoad { s.Fatalf("dottype of non-load") } @@ -6043,14 +6057,38 @@ func (s *state) floatToUint(cvttab *f2uCvtTab, n ir.Node, x *ssa.Value, ft, tt * func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Value) { iface := s.expr(n.X) // input interface target := s.reflectType(n.Type()) // target type - byteptr := s.f.Config.Types.BytePtr + var targetItab *ssa.Value + if n.Itab != nil { + targetItab = s.expr(n.Itab) + } + return s.dottype1(n.Pos(), n.X.Type(), n.Type(), iface, target, targetItab, commaok) +} - if n.Type().IsInterface() { - if n.Type().IsEmptyInterface() { +func (s *state) dynamicDottype(n *ir.DynamicTypeAssertExpr, commaok bool) (res, resok *ssa.Value) { + iface := s.expr(n.X) + target := s.expr(n.T) + var itab *ssa.Value + if !n.X.Type().IsEmptyInterface() && !n.Type().IsInterface() { + byteptr := s.f.Config.Types.BytePtr + itab = target + target = s.load(byteptr, s.newValue1I(ssa.OpOffPtr, byteptr, int64(types.PtrSize), itab)) // itab.typ + } + return s.dottype1(n.Pos(), n.X.Type(), n.Type(), iface, target, itab, commaok) +} + +// dottype1 implements a x.(T) operation. iface is the argument (x), dst is the type we're asserting to (T) +// and src is the type we're asserting from. +// target is the *runtime._type of dst. +// If src is a nonempty interface and dst is not an interface, targetItab is an itab representing (dst, src). Otherwise it is nil. +// commaok is true if the caller wants a boolean success value. Otherwise, the generated code panics if the conversion fails. +func (s *state) dottype1(pos src.XPos, src, dst *types.Type, iface, target, targetItab *ssa.Value, commaok bool) (res, resok *ssa.Value) { + byteptr := s.f.Config.Types.BytePtr + if dst.IsInterface() { + if dst.IsEmptyInterface() { // Converting to an empty interface. // Input could be an empty or nonempty interface. if base.Debug.TypeAssert > 0 { - base.WarnfAt(n.Pos(), "type assertion inlined") + base.WarnfAt(pos, "type assertion inlined") } // Get itab/type field from input. @@ -6058,7 +6096,7 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val // Conversion succeeds iff that field is not nil. cond := s.newValue2(ssa.OpNeqPtr, types.Types[types.TBOOL], itab, s.constNil(byteptr)) - if n.X.Type().IsEmptyInterface() && commaok { + if src.IsEmptyInterface() && commaok { // Converting empty interface to empty interface with ,ok is just a nil check. return iface, cond } @@ -6080,7 +6118,7 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val // On success, return (perhaps modified) input interface. s.startBlock(bOk) - if n.X.Type().IsEmptyInterface() { + if src.IsEmptyInterface() { res = iface // Use input interface unchanged. return } @@ -6088,7 +6126,7 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val off := s.newValue1I(ssa.OpOffPtr, byteptr, int64(types.PtrSize), itab) typ := s.load(byteptr, off) idata := s.newValue1(ssa.OpIData, byteptr, iface) - res = s.newValue2(ssa.OpIMake, n.Type(), typ, idata) + res = s.newValue2(ssa.OpIMake, dst, typ, idata) return } @@ -6110,62 +6148,62 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val bFail.AddEdgeTo(bEnd) s.startBlock(bEnd) idata := s.newValue1(ssa.OpIData, byteptr, iface) - res = s.newValue2(ssa.OpIMake, n.Type(), s.variable(typVar, byteptr), idata) + res = s.newValue2(ssa.OpIMake, dst, s.variable(typVar, byteptr), idata) resok = cond delete(s.vars, typVar) return } // converting to a nonempty interface needs a runtime call. if base.Debug.TypeAssert > 0 { - base.WarnfAt(n.Pos(), "type assertion not inlined") + base.WarnfAt(pos, "type assertion not inlined") } if !commaok { fn := ir.Syms.AssertI2I - if n.X.Type().IsEmptyInterface() { + if src.IsEmptyInterface() { fn = ir.Syms.AssertE2I } data := s.newValue1(ssa.OpIData, types.Types[types.TUNSAFEPTR], iface) tab := s.newValue1(ssa.OpITab, byteptr, iface) tab = s.rtcall(fn, true, []*types.Type{byteptr}, target, tab)[0] - return s.newValue2(ssa.OpIMake, n.Type(), tab, data), nil + return s.newValue2(ssa.OpIMake, dst, tab, data), nil } fn := ir.Syms.AssertI2I2 - if n.X.Type().IsEmptyInterface() { + if src.IsEmptyInterface() { fn = ir.Syms.AssertE2I2 } - res = s.rtcall(fn, true, []*types.Type{n.Type()}, target, iface)[0] - resok = s.newValue2(ssa.OpNeqInter, types.Types[types.TBOOL], res, s.constInterface(n.Type())) + res = s.rtcall(fn, true, []*types.Type{dst}, target, iface)[0] + resok = s.newValue2(ssa.OpNeqInter, types.Types[types.TBOOL], res, s.constInterface(dst)) return } if base.Debug.TypeAssert > 0 { - base.WarnfAt(n.Pos(), "type assertion inlined") + base.WarnfAt(pos, "type assertion inlined") } // Converting to a concrete type. - direct := types.IsDirectIface(n.Type()) + direct := types.IsDirectIface(dst) itab := s.newValue1(ssa.OpITab, byteptr, iface) // type word of interface if base.Debug.TypeAssert > 0 { - base.WarnfAt(n.Pos(), "type assertion inlined") + base.WarnfAt(pos, "type assertion inlined") } - var targetITab *ssa.Value - if n.X.Type().IsEmptyInterface() { + var wantedFirstWord *ssa.Value + if src.IsEmptyInterface() { // Looking for pointer to target type. - targetITab = target + wantedFirstWord = target } else { // Looking for pointer to itab for target type and source interface. - targetITab = s.expr(n.Itab) + wantedFirstWord = targetItab } var tmp ir.Node // temporary for use with large types var addr *ssa.Value // address of tmp - if commaok && !TypeOK(n.Type()) { + if commaok && !TypeOK(dst) { // unSSAable type, use temporary. // TODO: get rid of some of these temporaries. - tmp, addr = s.temp(n.Pos(), n.Type()) + tmp, addr = s.temp(pos, dst) } - cond := s.newValue2(ssa.OpEqPtr, types.Types[types.TBOOL], itab, targetITab) + cond := s.newValue2(ssa.OpEqPtr, types.Types[types.TBOOL], itab, wantedFirstWord) b := s.endBlock() b.Kind = ssa.BlockIf b.SetControl(cond) @@ -6179,8 +6217,8 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val if !commaok { // on failure, panic by calling panicdottype s.startBlock(bFail) - taddr := s.reflectType(n.X.Type()) - if n.X.Type().IsEmptyInterface() { + taddr := s.reflectType(src) + if src.IsEmptyInterface() { s.rtcall(ir.Syms.PanicdottypeE, false, nil, itab, target, taddr) } else { s.rtcall(ir.Syms.PanicdottypeI, false, nil, itab, target, taddr) @@ -6189,10 +6227,10 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val // on success, return data from interface s.startBlock(bOk) if direct { - return s.newValue1(ssa.OpIData, n.Type(), iface), nil + return s.newValue1(ssa.OpIData, dst, iface), nil } - p := s.newValue1(ssa.OpIData, types.NewPtr(n.Type()), iface) - return s.load(n.Type(), p), nil + p := s.newValue1(ssa.OpIData, types.NewPtr(dst), iface) + return s.load(dst, p), nil } // commaok is the more complicated case because we have @@ -6206,14 +6244,14 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val s.startBlock(bOk) if tmp == nil { if direct { - s.vars[valVar] = s.newValue1(ssa.OpIData, n.Type(), iface) + s.vars[valVar] = s.newValue1(ssa.OpIData, dst, iface) } else { - p := s.newValue1(ssa.OpIData, types.NewPtr(n.Type()), iface) - s.vars[valVar] = s.load(n.Type(), p) + p := s.newValue1(ssa.OpIData, types.NewPtr(dst), iface) + s.vars[valVar] = s.load(dst, p) } } else { - p := s.newValue1(ssa.OpIData, types.NewPtr(n.Type()), iface) - s.move(n.Type(), addr, p) + p := s.newValue1(ssa.OpIData, types.NewPtr(dst), iface) + s.move(dst, addr, p) } s.vars[okVar] = s.constBool(true) s.endBlock() @@ -6222,9 +6260,9 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val // type assertion failed s.startBlock(bFail) if tmp == nil { - s.vars[valVar] = s.zeroVal(n.Type()) + s.vars[valVar] = s.zeroVal(dst) } else { - s.zero(n.Type(), addr) + s.zero(dst, addr) } s.vars[okVar] = s.constBool(false) s.endBlock() @@ -6233,10 +6271,10 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val // merge point s.startBlock(bEnd) if tmp == nil { - res = s.variable(valVar, n.Type()) + res = s.variable(valVar, dst) delete(s.vars, valVar) } else { - res = s.load(n.Type(), addr) + res = s.load(dst, addr) s.vars[memVar] = s.newValue1A(ssa.OpVarKill, types.TypeMem, tmp.(*ir.Name), s.mem()) } resok = s.variable(okVar, types.Types[types.TBOOL]) diff --git a/src/cmd/compile/internal/walk/expr.go b/src/cmd/compile/internal/walk/expr.go index f0d37198d37..f95b6f4639f 100644 --- a/src/cmd/compile/internal/walk/expr.go +++ b/src/cmd/compile/internal/walk/expr.go @@ -136,6 +136,10 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node { n := n.(*ir.TypeAssertExpr) return walkDotType(n, init) + case ir.ODYNAMICDOTTYPE, ir.ODYNAMICDOTTYPE2: + n := n.(*ir.DynamicTypeAssertExpr) + return walkDynamicDotType(n, init) + case ir.OLEN, ir.OCAP: n := n.(*ir.UnaryExpr) return walkLenCap(n, init) @@ -669,6 +673,13 @@ func walkDotType(n *ir.TypeAssertExpr, init *ir.Nodes) ir.Node { return n } +// walkDynamicdotType walks an ODYNAMICDOTTYPE or ODYNAMICDOTTYPE2 node. +func walkDynamicDotType(n *ir.DynamicTypeAssertExpr, init *ir.Nodes) ir.Node { + n.X = walkExpr(n.X, init) + n.T = walkExpr(n.T, init) + return n +} + // walkIndex walks an OINDEX node. func walkIndex(n *ir.IndexExpr, init *ir.Nodes) ir.Node { n.X = walkExpr(n.X, init) diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go index fe6ae3fda00..c5fd0c1e1da 100644 --- a/src/cmd/compile/internal/walk/order.go +++ b/src/cmd/compile/internal/walk/order.go @@ -686,6 +686,10 @@ func (o *orderState) stmt(n ir.Node) { case ir.ODOTTYPE2: r := r.(*ir.TypeAssertExpr) r.X = o.expr(r.X, nil) + case ir.ODYNAMICDOTTYPE2: + r := r.(*ir.DynamicTypeAssertExpr) + r.X = o.expr(r.X, nil) + r.T = o.expr(r.T, nil) case ir.ORECV: r := r.(*ir.UnaryExpr) r.X = o.expr(r.X, nil) diff --git a/test/typeparam/dottype.go b/test/typeparam/dottype.go index 89a9b021119..c9c900c0962 100644 --- a/test/typeparam/dottype.go +++ b/test/typeparam/dottype.go @@ -69,6 +69,11 @@ func main() { println(h[int](struct{ a, b int }{3, 5}).a) println(k[int](mybar(3)).bar()) + + type large struct {a,b,c,d,e,f int} + println(f[large](large{}).a) + l2, ok := f2[large](large{}) + println(l2.a, ok) } func shouldpanic(x func()) { defer func() { diff --git a/test/typeparam/dottype.out b/test/typeparam/dottype.out index 058c923a5ce..8e6a3c25526 100644 --- a/test/typeparam/dottype.out +++ b/test/typeparam/dottype.out @@ -6,3 +6,5 @@ 0 false 3 3 +0 +0 true From 2fa8f00915893670964e05e14be7202f6f97760b Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 27 Jul 2021 19:14:30 -0700 Subject: [PATCH 810/940] [dev.typeparams] cmd/compile/internal/types2: implement type terms Type terms will be used to represent a type set as a list of type terms. Eventually, a type term may also include a method set. Groundwork for the implementation of lazily computed type sets for union expressions. Change-Id: Ic88750af21f697ce0b52a2259eff40bee115964c Reviewed-on: https://go-review.googlesource.com/c/go/+/338049 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/typeterm.go | 166 ++++++++++++++ .../compile/internal/types2/typeterm_test.go | 205 ++++++++++++++++++ 2 files changed, 371 insertions(+) create mode 100644 src/cmd/compile/internal/types2/typeterm.go create mode 100644 src/cmd/compile/internal/types2/typeterm_test.go diff --git a/src/cmd/compile/internal/types2/typeterm.go b/src/cmd/compile/internal/types2/typeterm.go new file mode 100644 index 00000000000..59a89cb004c --- /dev/null +++ b/src/cmd/compile/internal/types2/typeterm.go @@ -0,0 +1,166 @@ +// Copyright 2021 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 types2 + +// TODO(gri) use a different symbol instead of ⊤ for the set of all types +// (⊤ is hard to distinguish from T in some fonts) + +// A term describes elementary type sets: +// +// ∅: (*term)(nil) == ∅ // set of no types (empty set) +// ⊤: &term{} == ⊤ // set of all types +// T: &term{false, T} == {T} // set of type T +// ~t: &term{true, t} == {t' | under(t') == t} // set of types with underlying type t +// +type term struct { + tilde bool // valid if typ != nil + typ Type +} + +func (x *term) String() string { + switch { + case x == nil: + return "∅" + case x.typ == nil: + return "⊤" + case x.tilde: + return "~" + x.typ.String() + default: + return x.typ.String() + } +} + +// equal reports whether x and y represent the same type set. +func (x *term) equal(y *term) bool { + // easy cases + switch { + case x == nil || y == nil: + return x == y + case x.typ == nil || y.typ == nil: + return x.typ == y.typ + } + // ∅ ⊂ x, y ⊂ ⊤ + + return x.tilde == y.tilde && Identical(x.typ, y.typ) +} + +// union returns the union x ∪ y: zero, one, or two non-nil terms. +func (x *term) union(y *term) (_, _ *term) { + // easy cases + switch { + case x == nil && y == nil: + return nil, nil // ∅ ∪ ∅ == ∅ + case x == nil: + return y, nil // ∅ ∪ y == y + case y == nil: + return x, nil // x ∪ ∅ == x + case x.typ == nil: + return x, nil // ⊤ ∪ y == ⊤ + case y.typ == nil: + return y, nil // x ∪ ⊤ == ⊤ + } + // ∅ ⊂ x, y ⊂ ⊤ + + if x.disjoint(y) { + return x, y // x ∪ y == (x, y) if x ∩ y == ∅ + } + // x.typ == y.typ + + // ~t ∪ ~t == ~t + // ~t ∪ T == ~t + // T ∪ ~t == ~t + // T ∪ T == T + if x.tilde || !y.tilde { + return x, nil + } + return y, nil +} + +// intersect returns the intersection x ∩ y. +func (x *term) intersect(y *term) *term { + // easy cases + switch { + case x == nil || y == nil: + return nil // ∅ ∩ y == ∅ and ∩ ∅ == ∅ + case x.typ == nil: + return y // ⊤ ∩ y == y + case y.typ == nil: + return x // x ∩ ⊤ == x + } + // ∅ ⊂ x, y ⊂ ⊤ + + if x.disjoint(y) { + return nil // x ∩ y == ∅ if x ∩ y == ∅ + } + // x.typ == y.typ + + // ~t ∩ ~t == ~t + // ~t ∩ T == T + // T ∩ ~t == T + // T ∩ T == T + if !x.tilde || y.tilde { + return x + } + return y +} + +// includes reports whether t ∈ x. +func (x *term) includes(t Type) bool { + // easy cases + switch { + case x == nil: + return false // t ∈ ∅ == false + case x.typ == nil: + return true // t ∈ ⊤ == true + } + // ∅ ⊂ x ⊂ ⊤ + + u := t + if x.tilde { + u = under(u) + } + return Identical(x.typ, u) +} + +// subsetOf reports whether x ⊆ y. +func (x *term) subsetOf(y *term) bool { + // easy cases + switch { + case x == nil: + return true // ∅ ⊆ y == true + case y == nil: + return false // x ⊆ ∅ == false since x != ∅ + case y.typ == nil: + return true // x ⊆ ⊤ == true + case x.typ == nil: + return false // ⊤ ⊆ y == false since y != ⊤ + } + // ∅ ⊂ x, y ⊂ ⊤ + + if x.disjoint(y) { + return false // x ⊆ y == false if x ∩ y == ∅ + } + // x.typ == y.typ + + // ~t ⊆ ~t == true + // ~t ⊆ T == false + // T ⊆ ~t == true + // T ⊆ T == true + return !x.tilde || y.tilde +} + +// disjoint reports whether x ∩ y == ∅. +// x.typ and y.typ must not be nil. +func (x *term) disjoint(y *term) bool { + ux := x.typ + if y.tilde { + ux = under(ux) + } + uy := y.typ + if x.tilde { + uy = under(uy) + } + return !Identical(ux, uy) +} diff --git a/src/cmd/compile/internal/types2/typeterm_test.go b/src/cmd/compile/internal/types2/typeterm_test.go new file mode 100644 index 00000000000..4676fb04373 --- /dev/null +++ b/src/cmd/compile/internal/types2/typeterm_test.go @@ -0,0 +1,205 @@ +// Copyright 2021 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 types2 + +import ( + "strings" + "testing" +) + +var testTerms = map[string]*term{ + "∅": nil, + "⊤": &term{}, + "int": &term{false, Typ[Int]}, + "~int": &term{true, Typ[Int]}, + "string": &term{false, Typ[String]}, + "~string": &term{true, Typ[String]}, + // TODO(gri) add a defined type +} + +func TestTermString(t *testing.T) { + for want, x := range testTerms { + if got := x.String(); got != want { + t.Errorf("%v.String() == %v; want %v", x, got, want) + } + } +} + +func split(s string, n int) []string { + r := strings.Split(s, " ") + if len(r) != n { + panic("invalid test case: " + s) + } + return r +} + +func testTerm(name string) *term { + r, ok := testTerms[name] + if !ok { + panic("invalid test argument: " + name) + } + return r +} + +func TestTermEqual(t *testing.T) { + for _, test := range []string{ + "∅ ∅ T", + "⊤ ⊤ T", + "int int T", + "~int ~int T", + "∅ ⊤ F", + "∅ int F", + "∅ ~int F", + "⊤ int F", + "⊤ ~int F", + "int ~int F", + } { + args := split(test, 3) + x := testTerm(args[0]) + y := testTerm(args[1]) + want := args[2] == "T" + if got := x.equal(y); got != want { + t.Errorf("%v.equal(%v) = %v; want %v", x, y, got, want) + } + // equal is symmetric + x, y = y, x + if got := x.equal(y); got != want { + t.Errorf("%v.equal(%v) = %v; want %v", x, y, got, want) + } + } +} + +func TestTermUnion(t *testing.T) { + for _, test := range []string{ + "∅ ∅ ∅ ∅", + "∅ ⊤ ⊤ ∅", + "∅ int int ∅", + "∅ ~int ~int ∅", + "⊤ ⊤ ⊤ ∅", + "⊤ int ⊤ ∅", + "⊤ ~int ⊤ ∅", + "int int int ∅", + "int ~int ~int ∅", + "int string int string", + "int ~string int ~string", + "~int ~string ~int ~string", + + // union is symmetric, but the result order isn't - repeat symmetric cases explictly + "⊤ ∅ ⊤ ∅", + "int ∅ int ∅", + "~int ∅ ~int ∅", + "int ⊤ ⊤ ∅", + "~int ⊤ ⊤ ∅", + "~int int ~int ∅", + "string int string int", + "~string int ~string int", + "~string ~int ~string ~int", + } { + args := split(test, 4) + x := testTerm(args[0]) + y := testTerm(args[1]) + want1 := testTerm(args[2]) + want2 := testTerm(args[3]) + if got1, got2 := x.union(y); !got1.equal(want1) || !got2.equal(want2) { + t.Errorf("%v.union(%v) = %v, %v; want %v, %v", x, y, got1, got2, want1, want2) + } + } +} + +func TestTermIntersection(t *testing.T) { + for _, test := range []string{ + "∅ ∅ ∅", + "∅ ⊤ ∅", + "∅ int ∅", + "∅ ~int ∅", + "⊤ ⊤ ⊤", + "⊤ int int", + "⊤ ~int ~int", + "int int int", + "int ~int int", + "int string ∅", + "int ~string ∅", + "~int ~string ∅", + } { + args := split(test, 3) + x := testTerm(args[0]) + y := testTerm(args[1]) + want := testTerm(args[2]) + if got := x.intersect(y); !got.equal(want) { + t.Errorf("%v.intersect(%v) = %v; want %v", x, y, got, want) + } + // intersect is symmetric + x, y = y, x + if got := x.intersect(y); !got.equal(want) { + t.Errorf("%v.intersect(%v) = %v; want %v", x, y, got, want) + } + } +} + +func TestTermIncludes(t *testing.T) { + for _, test := range []string{ + "∅ int F", + "⊤ int T", + "int int T", + "~int int T", + "string int F", + "~string int F", + } { + args := split(test, 3) + x := testTerm(args[0]) + y := testTerm(args[1]).typ + want := args[2] == "T" + if got := x.includes(y); got != want { + t.Errorf("%v.includes(%v) = %v; want %v", x, y, got, want) + } + } +} + +func TestTermSubsetOf(t *testing.T) { + for _, test := range []string{ + "∅ ∅ T", + "⊤ ⊤ T", + "int int T", + "~int ~int T", + "∅ ⊤ T", + "∅ int T", + "∅ ~int T", + "⊤ int F", + "⊤ ~int F", + "int ~int T", + } { + args := split(test, 3) + x := testTerm(args[0]) + y := testTerm(args[1]) + want := args[2] == "T" + if got := x.subsetOf(y); got != want { + t.Errorf("%v.subsetOf(%v) = %v; want %v", x, y, got, want) + } + } +} + +func TestTermDisjoint(t *testing.T) { + for _, test := range []string{ + "int int F", + "~int ~int F", + "int ~int F", + "int string T", + "int ~string T", + "~int ~string T", + } { + args := split(test, 3) + x := testTerm(args[0]) + y := testTerm(args[1]) + want := args[2] == "T" + if got := x.disjoint(y); got != want { + t.Errorf("%v.disjoint(%v) = %v; want %v", x, y, got, want) + } + // disjoint is symmetric + x, y = y, x + if got := x.disjoint(y); got != want { + t.Errorf("%v.disjoint(%v) = %v; want %v", x, y, got, want) + } + } +} From ff0c0dbca6a7a3a3d6528481829679be4c9d7e94 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 27 Jul 2021 19:13:26 -0700 Subject: [PATCH 811/940] [dev.typeparams] cmd/compile/internal/types2: use type terms to represent unions This is just an internal representation change for now. Change-Id: I7e0126e9b17850ec020c2a60db13582761557bea Reviewed-on: https://go-review.googlesource.com/c/go/+/338092 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/infer.go | 18 ++- src/cmd/compile/internal/types2/interface.go | 6 +- src/cmd/compile/internal/types2/operand.go | 6 +- src/cmd/compile/internal/types2/predicates.go | 16 +-- .../compile/internal/types2/sizeof_test.go | 3 +- src/cmd/compile/internal/types2/subst.go | 22 +++- .../types2/testdata/examples/constraints.go2 | 6 +- src/cmd/compile/internal/types2/type.go | 2 +- src/cmd/compile/internal/types2/typeset.go | 7 ++ src/cmd/compile/internal/types2/typestring.go | 6 +- src/cmd/compile/internal/types2/union.go | 117 +++++++++++------- 11 files changed, 130 insertions(+), 79 deletions(-) diff --git a/src/cmd/compile/internal/types2/infer.go b/src/cmd/compile/internal/types2/infer.go index 6e7a2177094..00548b402e8 100644 --- a/src/cmd/compile/internal/types2/infer.go +++ b/src/cmd/compile/internal/types2/infer.go @@ -308,7 +308,7 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { } case *Union: - return w.isParameterizedList(t.types) + return w.isParameterizedTermList(t.terms) case *Signature: // t.tparams may not be nil if we are looking at a signature @@ -336,7 +336,7 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { return w.isParameterized(t.elem) case *Named: - return w.isParameterizedList(t.targs) + return w.isParameterizedTypeList(t.targs) case *TypeParam: // t must be one of w.tparams @@ -349,7 +349,7 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { return false } -func (w *tpWalker) isParameterizedList(list []Type) bool { +func (w *tpWalker) isParameterizedTypeList(list []Type) bool { for _, t := range list { if w.isParameterized(t) { return true @@ -358,6 +358,15 @@ func (w *tpWalker) isParameterizedList(list []Type) bool { return false } +func (w *tpWalker) isParameterizedTermList(list []*term) bool { + for _, t := range list { + if w.isParameterized(t.typ) { + return true + } + } + return false +} + // inferB returns the list of actual type arguments inferred from the type parameters' // bounds and an initial set of type arguments. If type inference is impossible because // unification fails, an error is reported if report is set to true, the resulting types @@ -466,7 +475,8 @@ func (check *Checker) structuralType(constraint Type) Type { if u, _ := types.(*Union); u != nil { if u.NumTerms() == 1 { // TODO(gri) do we need to respect tilde? - return u.types[0] + t, _ := u.Term(0) + return t } return nil } diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go index cf8ec1a5e23..fc1f5ffe00d 100644 --- a/src/cmd/compile/internal/types2/interface.go +++ b/src/cmd/compile/internal/types2/interface.go @@ -30,7 +30,7 @@ func (t *Interface) is(f func(Type, bool) bool) bool { // TODO(gri) should settle on top or nil to represent this case return false // we must have at least one type! (was bug) case *Union: - return t.is(func(typ Type, tilde bool) bool { return f(typ, tilde) }) + return t.is(func(t *term) bool { return f(t.typ, t.tilde) }) default: return f(t, false) } @@ -260,8 +260,8 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType sortMethods(ityp.methods) // Compute type set with a non-nil *Checker as soon as possible - // to report any errors. Subsequent uses of type sets should be - // using this computed type set and won't need to pass in a *Checker. + // to report any errors. Subsequent uses of type sets will use + // this computed type set and won't need to pass in a *Checker. check.later(func() { computeTypeSet(check, iface.Pos(), ityp) }) } diff --git a/src/cmd/compile/internal/types2/operand.go b/src/cmd/compile/internal/types2/operand.go index 83cc239d931..01c720d1f78 100644 --- a/src/cmd/compile/internal/types2/operand.go +++ b/src/cmd/compile/internal/types2/operand.go @@ -270,13 +270,13 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er // x is an untyped value representable by a value of type T. if isUntyped(Vu) { if t, ok := Tu.(*Union); ok { - return t.is(func(t Type, tilde bool) bool { + return t.is(func(t *term) bool { // TODO(gri) this could probably be more efficient - if tilde { + if t.tilde { // TODO(gri) We need to check assignability // for the underlying type of x. } - ok, _ := x.assignableTo(check, t, reason) + ok, _ := x.assignableTo(check, t.typ, reason) return ok }), _IncompatibleAssign } diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go index e448ade9e57..cd9fa3f5643 100644 --- a/src/cmd/compile/internal/types2/predicates.go +++ b/src/cmd/compile/internal/types2/predicates.go @@ -238,20 +238,8 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { // types - each type appears exactly once. Thus, two union types // must contain the same number of types to have chance of // being equal. - if y, ok := y.(*Union); ok && x.NumTerms() == y.NumTerms() { - // Every type in x.types must be in y.types. - // Quadratic algorithm, but probably good enough for now. - // TODO(gri) we need a fast quick type ID/hash for all types. - L: - for i, xt := range x.types { - for j, yt := range y.types { - if Identical(xt, yt) && x.tilde[i] == y.tilde[j] { - continue L // x is in y.types - } - } - return false // x is not in y.types - } - return true + if y, ok := y.(*Union); ok { + return identicalTerms(x.terms, y.terms) } case *Interface: diff --git a/src/cmd/compile/internal/types2/sizeof_test.go b/src/cmd/compile/internal/types2/sizeof_test.go index a62b7cb3e25..70cf3709e5e 100644 --- a/src/cmd/compile/internal/types2/sizeof_test.go +++ b/src/cmd/compile/internal/types2/sizeof_test.go @@ -27,12 +27,13 @@ func TestSizeof(t *testing.T) { {Pointer{}, 8, 16}, {Tuple{}, 12, 24}, {Signature{}, 44, 88}, - {Union{}, 24, 48}, + {Union{}, 12, 24}, {Interface{}, 40, 80}, {Map{}, 16, 32}, {Chan{}, 12, 24}, {Named{}, 88, 168}, {TypeParam{}, 28, 48}, + {term{}, 12, 24}, {top{}, 0, 0}, // Objects diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index 87e3e3018ed..fc713434318 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -145,12 +145,12 @@ func (subst *subster) typ(typ Type) Type { } case *Union: - types, copied := subst.typeList(t.types) + terms, copied := subst.termList(t.terms) if copied { // TODO(gri) Remove duplicates that may have crept in after substitution // (unlikely but possible). This matters for the Identical // predicate on unions. - return newUnion(types, t.tilde) + return &Union{terms} } case *Interface: @@ -386,3 +386,21 @@ func (subst *subster) typeList(in []Type) (out []Type, copied bool) { } return } + +func (subst *subster) termList(in []*term) (out []*term, copied bool) { + out = in + for i, t := range in { + if u := subst.typ(t.typ); u != t.typ { + if !copied { + // first function that got substituted => allocate new out slice + // and copy all functions + new := make([]*term, len(in)) + copy(new, out) + out = new + copied = true + } + out[i] = &term{t.tilde, u} + } + } + return +} diff --git a/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 b/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 index d9805fe6940..28aa19bb12c 100644 --- a/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 +++ b/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 @@ -31,9 +31,9 @@ type ( _ interface{int|~ /* ERROR duplicate term int */ int } _ interface{~int|~ /* ERROR duplicate term int */ int } - // For now we do not permit interfaces with ~ or in unions. - _ interface{~ /* ERROR cannot use interface */ interface{}} - _ interface{int|interface /* ERROR cannot use interface */ {}} + // For now we do not permit interfaces with methods in unions. + _ interface{~ /* ERROR invalid use of ~ */ interface{}} + _ interface{int|interface /* ERROR cannot use .* in union */ { m() }} ) type ( diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index b41b50393dc..80054372bcc 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -60,7 +60,7 @@ func optype(typ Type) Type { // If we have a union with a single entry, ignore // any tilde because under(~t) == under(t). if u, _ := a.(*Union); u != nil && u.NumTerms() == 1 { - a = u.types[0] + a, _ = u.Term(0) } if a != typ { // a != typ and a is a type parameter => under(a) != typ, so this is ok diff --git a/src/cmd/compile/internal/types2/typeset.go b/src/cmd/compile/internal/types2/typeset.go index cc28625070a..5a334b2f533 100644 --- a/src/cmd/compile/internal/types2/typeset.go +++ b/src/cmd/compile/internal/types2/typeset.go @@ -42,6 +42,13 @@ func (s *TypeSet) IsComparable() bool { return s.comparable && tcomparable } +// TODO(gri) IsTypeSet is not a great name. Find a better one. + +// IsTypeSet reports whether the type set s is represented by a finite set of underlying types. +func (s *TypeSet) IsTypeSet() bool { + return !s.comparable && len(s.methods) == 0 +} + // NumMethods returns the number of methods available. func (s *TypeSet) NumMethods() int { return len(s.methods) } diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go index 74d2f1dc519..1da3f7f8ed8 100644 --- a/src/cmd/compile/internal/types2/typestring.go +++ b/src/cmd/compile/internal/types2/typestring.go @@ -162,14 +162,14 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { buf.WriteString("⊥") break } - for i, e := range t.types { + for i, t := range t.terms { if i > 0 { buf.WriteByte('|') } - if t.tilde[i] { + if t.tilde { buf.WriteByte('~') } - writeType(buf, e, qf, visited) + writeType(buf, t.typ, qf, visited) } case *Interface: diff --git a/src/cmd/compile/internal/types2/union.go b/src/cmd/compile/internal/types2/union.go index 5983a73ec69..1215ef90577 100644 --- a/src/cmd/compile/internal/types2/union.go +++ b/src/cmd/compile/internal/types2/union.go @@ -10,10 +10,8 @@ import "cmd/compile/internal/syntax" // API // A Union represents a union of terms. -// A term is a type with a ~ (tilde) flag. type Union struct { - types []Type // types are unique - tilde []bool // if tilde[i] is set, terms[i] is of the form ~T + terms []*term } // NewUnion returns a new Union type with the given terms (types[i], tilde[i]). @@ -21,9 +19,9 @@ type Union struct { // of no types. func NewUnion(types []Type, tilde []bool) *Union { return newUnion(types, tilde) } -func (u *Union) IsEmpty() bool { return len(u.types) == 0 } -func (u *Union) NumTerms() int { return len(u.types) } -func (u *Union) Term(i int) (Type, bool) { return u.types[i], u.tilde[i] } +func (u *Union) IsEmpty() bool { return len(u.terms) == 0 } +func (u *Union) NumTerms() int { return len(u.terms) } +func (u *Union) Term(i int) (Type, bool) { t := u.terms[i]; return t.typ, t.tilde } func (u *Union) Underlying() Type { return u } func (u *Union) String() string { return TypeString(u, nil) } @@ -39,18 +37,20 @@ func newUnion(types []Type, tilde []bool) *Union { return emptyUnion } t := new(Union) - t.types = types - t.tilde = tilde + t.terms = make([]*term, len(types)) + for i, typ := range types { + t.terms[i] = &term{tilde[i], typ} + } return t } -// is reports whether f returned true for all terms (type, tilde) of u. -func (u *Union) is(f func(Type, bool) bool) bool { +// is reports whether f returns true for all terms of u. +func (u *Union) is(f func(*term) bool) bool { if u.IsEmpty() { return false } - for i, t := range u.types { - if !f(t, u.tilde[i]) { + for _, t := range u.terms { + if !f(t) { return false } } @@ -62,8 +62,8 @@ func (u *Union) underIs(f func(Type) bool) bool { if u.IsEmpty() { return false } - for _, t := range u.types { - if !f(under(t)) { + for _, t := range u.terms { + if !f(under(t.typ)) { return false } } @@ -83,7 +83,7 @@ func parseUnion(check *Checker, tlist []syntax.Expr) Type { } // Ensure that each type is only present once in the type list. - // It's ok to do this check at the end because it's not a requirement + // It's ok to do this check later because it's not a requirement // for correctness of the code. // Note: This is a quadratic algorithm, but unions tend to be short. check.later(func() { @@ -96,7 +96,7 @@ func parseUnion(check *Checker, tlist []syntax.Expr) Type { x := tlist[i] pos := syntax.StartPos(x) // We may not know the position of x if it was a typechecker- - // introduced ~T type of a type list entry T. Use the position + // introduced ~T term for a type list entry T. Use the position // of T instead. // TODO(gri) remove this test once we don't support type lists anymore if !pos.IsKnown() { @@ -106,13 +106,24 @@ func parseUnion(check *Checker, tlist []syntax.Expr) Type { } u := under(t) - if tilde[i] && !Identical(u, t) { - check.errorf(x, "invalid use of ~ (underlying type of %s is %s)", t, u) - continue // don't report another error for t + f, _ := u.(*Interface) + if tilde[i] { + if f != nil { + check.errorf(x, "invalid use of ~ (%s is an interface)", t) + continue // don't report another error for t + } + + if !Identical(u, t) { + check.errorf(x, "invalid use of ~ (underlying type of %s is %s)", t, u) + continue // don't report another error for t + } } - if _, ok := u.(*Interface); ok { - // A single type with a ~ is a single-term union. - check.errorf(pos, "cannot use interface %s with ~ or inside a union (implementation restriction)", t) + + // Stand-alone embedded interfaces are ok and are handled by the single-type case + // in the beginning. Embedded interfaces with tilde are excluded above. If we reach + // here, we must have at least two terms in the union. + if f != nil && !f.typeSet().IsTypeSet() { + check.errorf(pos, "cannot use %s in union (interface contains methods)", t) continue // don't report another error for t } @@ -164,25 +175,7 @@ func intersect(x, y Type) (r Type) { yu, _ := y.(*Union) switch { case xu != nil && yu != nil: - // Quadratic algorithm, but good enough for now. - // TODO(gri) fix asymptotic performance - var types []Type - var tilde []bool - for j, y := range yu.types { - yt := yu.tilde[j] - if r, rt := xu.intersect(y, yt); r != nil { - // Terms x[i] and y[j] match: Select the one that - // is not a ~t because that is the intersection - // type. If both are ~t, they are identical: - // T ∩ T = T - // T ∩ ~t = T - // ~t ∩ T = T - // ~t ∩ ~t = ~t - types = append(types, r) - tilde = append(tilde, rt) - } - } - return newUnion(types, tilde) + return &Union{intersectTerms(xu.terms, yu.terms)} case xu != nil: if r, _ := xu.intersect(y, false); r != nil { @@ -216,14 +209,16 @@ func includes(list []Type, typ Type) bool { // intersect computes the intersection of the union u and term (y, yt) // and returns the intersection term, if any. Otherwise the result is // (nil, false). +// TODO(gri) this needs to cleaned up/removed once we switch to lazy +// union type set computation. func (u *Union) intersect(y Type, yt bool) (Type, bool) { under_y := under(y) - for i, x := range u.types { - xt := u.tilde[i] + for _, x := range u.terms { + xt := x.tilde // determine which types xx, yy to compare - xx := x + xx := x.typ if yt { - xx = under(x) + xx = under(xx) } yy := y if xt { @@ -239,3 +234,35 @@ func (u *Union) intersect(y Type, yt bool) (Type, bool) { } return nil, false } + +func identicalTerms(list1, list2 []*term) bool { + if len(list1) != len(list2) { + return false + } + // Every term in list1 must be in list2. + // Quadratic algorithm, but probably good enough for now. + // TODO(gri) we need a fast quick type ID/hash for all types. +L: + for _, x := range list1 { + for _, y := range list2 { + if x.equal(y) { + continue L // x is in list2 + } + } + return false + } + return true +} + +func intersectTerms(list1, list2 []*term) (list []*term) { + // Quadratic algorithm, but good enough for now. + // TODO(gri) fix asymptotic performance + for _, x := range list1 { + for _, y := range list2 { + if r := x.intersect(y); r != nil { + list = append(list, r) + } + } + } + return +} From c079b6baaa781e71a48661c05063d1d2754937f8 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 28 Jul 2021 13:50:09 -0700 Subject: [PATCH 812/940] [dev.typeparams] cmd/compile/internal/types2: trigger verification while resolving instance This is a straight port of CL 335978 with minor adjustements to white space and an error message. Change-Id: Icfcb562f75802a119ce5d02427bffecf7e279b2f Reviewed-on: https://go-review.googlesource.com/c/go/+/338097 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/instance.go | 2 +- .../compile/internal/types2/instantiate.go | 59 +++++++++++-------- .../internal/types2/testdata/check/issues.go2 | 4 +- 3 files changed, 37 insertions(+), 28 deletions(-) diff --git a/src/cmd/compile/internal/types2/instance.go b/src/cmd/compile/internal/types2/instance.go index df0fc17ba7a..711d7de53ca 100644 --- a/src/cmd/compile/internal/types2/instance.go +++ b/src/cmd/compile/internal/types2/instance.go @@ -26,7 +26,7 @@ func (n *Named) expand() { // tparams. This is done implicitly by the call to n.TParams, but making it // explicit is harmless: load is idempotent. n.load() - inst := n.check.instantiate(n.instance.pos, n.orig.underlying, n.TParams(), n.targs, n.instance.posList, n.instance.verify) + inst := n.check.instantiate(n.instance.pos, n.orig.underlying, n.TParams(), n.targs, n.instance.posList) n.underlying = inst n.fromRHS = inst n.instance = nil diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go index 1294b08490d..7a40cea8894 100644 --- a/src/cmd/compile/internal/types2/instantiate.go +++ b/src/cmd/compile/internal/types2/instantiate.go @@ -54,10 +54,15 @@ func (check *Checker) Instantiate(pos syntax.Pos, typ Type, targs []Type, posLis // only types and functions can be generic panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) } - return check.instantiate(pos, typ, tparams, targs, posList, verify) + + inst := check.instantiate(pos, typ, tparams, targs, posList) + if verify && len(tparams) == len(targs) { + check.verify(pos, tparams, targs, posList) + } + return inst } -func (check *Checker) instantiate(pos syntax.Pos, typ Type, tparams []*TypeName, targs []Type, posList []syntax.Pos, verify bool) (res Type) { +func (check *Checker) instantiate(pos syntax.Pos, typ Type, tparams []*TypeName, targs []Type, posList []syntax.Pos) (res Type) { // the number of supplied types must match the number of type parameters if len(targs) != len(tparams) { // TODO(gri) provide better error message @@ -67,9 +72,6 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, tparams []*TypeName, } panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, len(targs), len(tparams))) } - if verify && check == nil { - panic("cannot have nil receiver if verify is set") - } if check != nil && check.conf.Trace { check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs)) @@ -93,24 +95,7 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, tparams []*TypeName, return typ // nothing to do (minor optimization) } - smap := makeSubstMap(tparams, targs) - - // check bounds - if verify { - for i, tname := range tparams { - // best position for error reporting - pos := pos - if i < len(posList) { - pos = posList[i] - } - // stop checking bounds after the first failure - if !check.satisfies(pos, targs[i], tname.typ.(*TypeParam), smap) { - break - } - } - } - - return check.subst(pos, typ, smap) + return check.subst(pos, typ, makeSubstMap(tparams, targs)) } // InstantiateLazy is like Instantiate, but avoids actually @@ -120,10 +105,16 @@ func (check *Checker) InstantiateLazy(pos syntax.Pos, typ Type, targs []Type, po // Don't use asNamed here: we don't want to expand the base during lazy // instantiation. base := typ.(*Named) - if base == nil { panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) } + + if verify && len(base.tparams) == len(targs) { + check.later(func() { + check.verify(pos, base.tparams, targs, posList) + }) + } + h := instantiatedHash(base, targs) if check != nil { // typ may already have been instantiated with identical type arguments. In @@ -148,6 +139,26 @@ func (check *Checker) InstantiateLazy(pos syntax.Pos, typ Type, targs []Type, po return named } +func (check *Checker) verify(pos syntax.Pos, tparams []*TypeName, targs []Type, posList []syntax.Pos) { + if check == nil { + panic("cannot have nil Checker if verifying constraints") + } + + smap := makeSubstMap(tparams, targs) + for i, tname := range tparams { + // best position for error reporting + pos := pos + if i < len(posList) { + pos = posList[i] + } + + // stop checking bounds after the first failure + if !check.satisfies(pos, targs[i], tname.typ.(*TypeParam), smap) { + break + } + } +} + // satisfies reports whether the type argument targ satisfies the constraint of type parameter // parameter tpar (after any of its type parameters have been substituted through smap). // A suitable error is reported if the result is false. diff --git a/src/cmd/compile/internal/types2/testdata/check/issues.go2 b/src/cmd/compile/internal/types2/testdata/check/issues.go2 index e29357de0b8..1ede383ebe5 100644 --- a/src/cmd/compile/internal/types2/testdata/check/issues.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/issues.go2 @@ -74,10 +74,8 @@ func (u T2[U]) Add1() U { return u.s + 1 } -// TODO(rfindley): we should probably report an error here as well, not -// just when the type is first instantiated. func NewT2[U any]() T2[U /* ERROR U has no constraints */ ] { - return T2[U]{} + return T2[U /* ERROR U has no constraints */ ]{} } func _() { From af903261e7e6af8ce932433cf87a60381781bfb9 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 28 Jul 2021 14:01:06 -0700 Subject: [PATCH 813/940] [dev.typeparams] go/types, types2: remove instance.verify field (cleanup) This field is not needed anymore. Follow-up on CL 335978 and CL 338097. Change-Id: I8032e5153ba65c6a4aaf6575ac6d5a15a61f1b81 Reviewed-on: https://go-review.googlesource.com/c/go/+/338098 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/instance.go | 1 - src/cmd/compile/internal/types2/instantiate.go | 8 ++------ src/go/types/instance.go | 1 - src/go/types/instantiate.go | 8 ++------ 4 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/cmd/compile/internal/types2/instance.go b/src/cmd/compile/internal/types2/instance.go index 711d7de53ca..e18688771cc 100644 --- a/src/cmd/compile/internal/types2/instance.go +++ b/src/cmd/compile/internal/types2/instance.go @@ -15,7 +15,6 @@ import "cmd/compile/internal/syntax" type instance struct { pos syntax.Pos // position of type instantiation; for error reporting only posList []syntax.Pos // position of each targ; for error reporting only - verify bool // if set, check constraint satisfaction upon instantiation } // expand ensures that the underlying type of n is instantiated. diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go index 7a40cea8894..ee790ba6d6b 100644 --- a/src/cmd/compile/internal/types2/instantiate.go +++ b/src/cmd/compile/internal/types2/instantiate.go @@ -127,15 +127,11 @@ func (check *Checker) InstantiateLazy(pos syntax.Pos, typ Type, targs []Type, po tname := NewTypeName(pos, base.obj.pkg, base.obj.name, nil) named := check.newNamed(tname, base, nil, nil, nil) // methods and tparams are set when named is loaded. named.targs = targs - named.instance = &instance{ - pos: pos, - posList: posList, - verify: verify, - } - + named.instance = &instance{pos, posList} if check != nil { check.typMap[h] = named } + return named } diff --git a/src/go/types/instance.go b/src/go/types/instance.go index 7e158ea3521..5e0447b4341 100644 --- a/src/go/types/instance.go +++ b/src/go/types/instance.go @@ -14,7 +14,6 @@ type instance struct { check *Checker pos token.Pos // position of type instantiation; for error reporting only posList []token.Pos // position of each targ; for error reporting only - verify bool // if set, constraint satisfaction is verified } // complete ensures that the underlying type of n is instantiated. diff --git a/src/go/types/instantiate.go b/src/go/types/instantiate.go index 7e2f3173c3f..1d3bbc26671 100644 --- a/src/go/types/instantiate.go +++ b/src/go/types/instantiate.go @@ -124,15 +124,11 @@ func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type, pos tname := NewTypeName(pos, base.obj.pkg, base.obj.name, nil) named := check.newNamed(tname, base, nil, base.TParams(), base.methods) // methods are instantiated lazily named.targs = targs - named.instance = &instance{ - check: check, - pos: pos, - posList: posList, - verify: verify, - } + named.instance = &instance{check, pos, posList} if check != nil { check.typMap[h] = named } + return named } From 27552e9172c5a9f7bbd8428c6e30eac14bb5e0b0 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 28 Jul 2021 15:29:19 -0700 Subject: [PATCH 814/940] [dev.typeparams] cmd/compile: set type parameter indices when they are bound This is a port of CL 336249 with adjustments due to slightly different handling of type parameter declaration in types2. The CL also contains adjustments to the compiler front-end. With this change it is not necessary to export type parameter indices. Filed issue #47451 so we don't forget. Change-Id: I2834f7be313fcb4763dff2a9058f1983ee6a81b3 Reviewed-on: https://go-review.googlesource.com/c/go/+/338192 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/importer/iimport.go | 7 ++- src/cmd/compile/internal/noder/decl.go | 6 +-- src/cmd/compile/internal/noder/expr.go | 2 +- src/cmd/compile/internal/noder/reader2.go | 2 +- src/cmd/compile/internal/noder/types.go | 10 ++-- src/cmd/compile/internal/noder/writer.go | 26 +++++++---- src/cmd/compile/internal/types2/api_test.go | 2 +- .../compile/internal/types2/assignments.go | 2 +- src/cmd/compile/internal/types2/builtins.go | 3 +- src/cmd/compile/internal/types2/call.go | 20 ++++---- src/cmd/compile/internal/types2/decl.go | 12 ++--- src/cmd/compile/internal/types2/index.go | 2 +- src/cmd/compile/internal/types2/instance.go | 2 +- .../compile/internal/types2/instantiate.go | 10 ++-- src/cmd/compile/internal/types2/lookup.go | 22 ++++----- src/cmd/compile/internal/types2/named.go | 12 ++--- src/cmd/compile/internal/types2/object.go | 4 +- src/cmd/compile/internal/types2/predicates.go | 2 +- src/cmd/compile/internal/types2/signature.go | 31 +++++++------ .../compile/internal/types2/sizeof_test.go | 4 +- src/cmd/compile/internal/types2/subst.go | 4 +- src/cmd/compile/internal/types2/typeparam.go | 46 +++++++++++++++++-- src/cmd/compile/internal/types2/typestring.go | 4 +- 23 files changed, 142 insertions(+), 93 deletions(-) diff --git a/src/cmd/compile/internal/importer/iimport.go b/src/cmd/compile/internal/importer/iimport.go index 453fa40f2d6..999b2aa1dc1 100644 --- a/src/cmd/compile/internal/importer/iimport.go +++ b/src/cmd/compile/internal/importer/iimport.go @@ -368,10 +368,13 @@ func (r *importReader) obj(name string) { if r.p.exportVersion < iexportVersionGenerics { errorf("unexpected type param type") } - index := int(r.int64()) + // Type parameter indices are lazily "allocated". + // There's no need to export them anymore. + // TODO change the export format accordingly + _ = int(r.int64()) name0, sub := parseSubscript(name) tn := types2.NewTypeName(pos, r.currPkg, name0, nil) - t := (*types2.Checker)(nil).NewTypeParam(tn, index, nil) + t := (*types2.Checker)(nil).NewTypeParam(tn, nil) if sub == 0 { errorf("missing subscript") } diff --git a/src/cmd/compile/internal/noder/decl.go b/src/cmd/compile/internal/noder/decl.go index 96abbe66ae1..2416d1a49e2 100644 --- a/src/cmd/compile/internal/noder/decl.go +++ b/src/cmd/compile/internal/noder/decl.go @@ -167,10 +167,10 @@ func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) { ntyp.SetUnderlying(g.typeExpr(decl.Type)) tparams := otyp.(*types2.Named).TParams() - if len(tparams) > 0 { - rparams := make([]*types.Type, len(tparams)) + if n := tparams.Len(); n > 0 { + rparams := make([]*types.Type, n) for i := range rparams { - rparams[i] = g.typ(tparams[i].Type()) + rparams[i] = g.typ(tparams.At(i).Type()) } // This will set hasTParam flag if any rparams are not concrete types. ntyp.SetRParams(rparams) diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go index 131ee89cbb9..a0d3cad6994 100644 --- a/src/cmd/compile/internal/noder/expr.go +++ b/src/cmd/compile/internal/noder/expr.go @@ -337,7 +337,7 @@ func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.Selecto if wantPtr { recvType2Base = types2.AsPointer(recvType2).Elem() } - if len(types2.AsNamed(recvType2Base).TParams()) > 0 { + if types2.AsNamed(recvType2Base).TParams().Len() > 0 { // recvType2 is the original generic type that is // instantiated for this method call. // selinfo.Recv() is the instantiated type diff --git a/src/cmd/compile/internal/noder/reader2.go b/src/cmd/compile/internal/noder/reader2.go index 297fa59439a..3e310e26c43 100644 --- a/src/cmd/compile/internal/noder/reader2.go +++ b/src/cmd/compile/internal/noder/reader2.go @@ -481,7 +481,7 @@ func (r *reader2) typeParamNames() []*types2.TypeName { pkg, name := r.localIdent() names[i] = types2.NewTypeName(pos, pkg, name, nil) - r.dict.tparams[i] = r.p.check.NewTypeParam(names[i], i, nil) + r.dict.tparams[i] = r.p.check.NewTypeParam(names[i], nil) } for i, bound := range r.dict.bounds { diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go index d073526adaf..3f7280a823e 100644 --- a/src/cmd/compile/internal/noder/types.go +++ b/src/cmd/compile/internal/noder/types.go @@ -304,9 +304,9 @@ func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) { } else { meth2 = ir.NewNameAt(meth.Pos(), newsym) rparams := types2.AsSignature(m.Type()).RParams() - tparams := make([]*types.Type, len(rparams)) - for i, rparam := range rparams { - tparams[i] = g.typ1(rparam.Type()) + tparams := make([]*types.Type, rparams.Len()) + for i := range tparams { + tparams[i] = g.typ1(rparams.At(i).Type()) } assert(len(tparams) == len(targs)) ts := typecheck.Tsubster{ @@ -336,9 +336,9 @@ func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) { func (g *irgen) signature(recv *types.Field, sig *types2.Signature) *types.Type { tparams2 := sig.TParams() - tparams := make([]*types.Field, len(tparams2)) + tparams := make([]*types.Field, tparams2.Len()) for i := range tparams { - tp := tparams2[i] + tp := tparams2.At(i) tparams[i] = types.NewField(g.pos(tp), g.sym(tp), g.typ1(tp.Type())) } diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go index 7b2285556ed..0fc7e4f38ce 100644 --- a/src/cmd/compile/internal/noder/writer.go +++ b/src/cmd/compile/internal/noder/writer.go @@ -299,7 +299,7 @@ func (pw *pkgWriter) typIdx(typ types2.Type, dict *writerDict) typeInfo { // Type aliases can refer to uninstantiated generic types, so we // might see len(TParams) != 0 && len(TArgs) == 0 here. // TODO(mdempsky): Revisit after #46477 is resolved. - assert(len(typ.TParams()) == len(typ.TArgs()) || len(typ.TArgs()) == 0) + assert(typ.TParams().Len() == len(typ.TArgs()) || len(typ.TArgs()) == 0) // TODO(mdempsky): Why do we need to loop here? orig := typ @@ -615,9 +615,10 @@ func (w *writer) objDict(obj types2.Object, dict *writerDict) { w.len(len(dict.implicits)) tparams := objTypeParams(obj) - w.len(len(tparams)) - for _, tparam := range tparams { - w.typ(tparam.Type().(*types2.TypeParam).Bound()) + ntparams := tparams.Len() + w.len(ntparams) + for i := 0; i < ntparams; i++ { + w.typ(tparams.At(i).Type().(*types2.TypeParam).Bound()) } nderived := len(dict.derived) @@ -641,10 +642,12 @@ func (w *writer) objDict(obj types2.Object, dict *writerDict) { assert(len(dict.funcs) == nfuncs) } -func (w *writer) typeParamNames(tparams []*types2.TypeName) { +func (w *writer) typeParamNames(tparams *types2.TypeParams) { w.sync(syncTypeParamNames) - for _, tparam := range tparams { + ntparams := tparams.Len() + for i := 0; i < ntparams; i++ { + tparam := tparams.At(i) w.pos(tparam) w.localIdent(tparam) } @@ -1468,13 +1471,16 @@ type declCollector struct { func (c *declCollector) withTParams(obj types2.Object) *declCollector { tparams := objTypeParams(obj) - if len(tparams) == 0 { + n := tparams.Len() + if n == 0 { return c } copy := *c copy.implicits = copy.implicits[:len(copy.implicits):len(copy.implicits)] - copy.implicits = append(copy.implicits, objTypeParams(obj)...) + for i := 0; i < n; i++ { + copy.implicits = append(copy.implicits, tparams.At(i)) + } return © } @@ -1705,7 +1711,7 @@ func (w *writer) pkgDecl(decl syntax.Decl) { // TODO(mdempsky): Revisit after #46477 is resolved. if name.IsAlias() { named, ok := name.Type().(*types2.Named) - if ok && len(named.TParams()) != 0 && len(named.TArgs()) == 0 { + if ok && named.TParams().Len() != 0 && len(named.TArgs()) == 0 { break } } @@ -1851,7 +1857,7 @@ func fieldIndex(info *types2.Info, str *types2.Struct, key *syntax.Name) int { } // objTypeParams returns the type parameters on the given object. -func objTypeParams(obj types2.Object) []*types2.TypeName { +func objTypeParams(obj types2.Object) *types2.TypeParams { switch obj := obj.(type) { case *types2.Func: sig := obj.Type().(*types2.Signature) diff --git a/src/cmd/compile/internal/types2/api_test.go b/src/cmd/compile/internal/types2/api_test.go index 74e3da3fe13..1d3347a6dea 100644 --- a/src/cmd/compile/internal/types2/api_test.go +++ b/src/cmd/compile/internal/types2/api_test.go @@ -1857,7 +1857,7 @@ func TestInstantiate(t *testing.T) { // type T should have one type parameter T := pkg.Scope().Lookup("T").Type().(*Named) - if n := len(T.TParams()); n != 1 { + if n := T.TParams().Len(); n != 1 { t.Fatalf("expected 1 type parameter; found %d", n) } diff --git a/src/cmd/compile/internal/types2/assignments.go b/src/cmd/compile/internal/types2/assignments.go index 583118c8b23..6184fc2ea50 100644 --- a/src/cmd/compile/internal/types2/assignments.go +++ b/src/cmd/compile/internal/types2/assignments.go @@ -68,7 +68,7 @@ func (check *Checker) assignment(x *operand, T Type, context string) { // x.typ is typed // A generic (non-instantiated) function value cannot be assigned to a variable. - if sig := asSignature(x.typ); sig != nil && len(sig.tparams) > 0 { + if sig := asSignature(x.typ); sig != nil && sig.TParams().Len() > 0 { check.errorf(x, "cannot use generic function %s without instantiation in %s", x, context) } diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index b9fcf3c898b..7ef9e7be639 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -837,7 +837,8 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { // type param is placed in the current package so export/import // works as expected. tpar := NewTypeName(nopos, check.pkg, "", nil) - ptyp := check.NewTypeParam(tpar, tp.index, &emptyInterface) // assigns type to tpar as a side-effect + ptyp := check.NewTypeParam(tpar, &emptyInterface) // assigns type to tpar as a side-effect + ptyp.index = tp.index tsum := newUnion(rtypes, tildes) ptyp.bound = &Interface{complete: true, tset: &TypeSet{types: tsum}} diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index 0d9637e696b..dee49b44a44 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -26,7 +26,7 @@ func (check *Checker) funcInst(x *operand, inst *syntax.IndexExpr) { // check number of type arguments (got) vs number of type parameters (want) sig := x.typ.(*Signature) - got, want := len(targs), len(sig.tparams) + got, want := len(targs), sig.TParams().Len() if !useConstraintTypeInference && got != want || got > want { check.errorf(xlist[got-1], "got %d type arguments but want %d", got, want) x.mode = invalid @@ -37,7 +37,7 @@ func (check *Checker) funcInst(x *operand, inst *syntax.IndexExpr) { // if we don't have enough type arguments, try type inference inferred := false if got < want { - targs = check.infer(inst.Pos(), sig.tparams, targs, nil, nil, true) + targs = check.infer(inst.Pos(), sig.TParams().list(), targs, nil, nil, true) if targs == nil { // error was already reported x.mode = invalid @@ -155,7 +155,7 @@ func (check *Checker) callExpr(x *operand, call *syntax.CallExpr) exprKind { assert(len(targs) == len(xlist)) // check number of type arguments (got) vs number of type parameters (want) - got, want := len(targs), len(sig.tparams) + got, want := len(targs), sig.TParams().Len() if got > want { check.errorf(xlist[want], "got %d type arguments but want %d", got, want) check.use(call.ArgList...) @@ -189,7 +189,7 @@ func (check *Checker) callExpr(x *operand, call *syntax.CallExpr) exprKind { // if type inference failed, a parametrized result must be invalidated // (operands cannot have a parametrized type) - if x.mode == value && len(sig.tparams) > 0 && isParameterized(sig.tparams, x.typ) { + if x.mode == value && sig.TParams().Len() > 0 && isParameterized(sig.TParams().list(), x.typ) { x.mode = invalid } @@ -317,10 +317,10 @@ func (check *Checker) arguments(call *syntax.CallExpr, sig *Signature, targs []T } // infer type arguments and instantiate signature if necessary - if len(sig.tparams) > 0 { + if sig.TParams().Len() > 0 { // TODO(gri) provide position information for targs so we can feed // it to the instantiate call for better error reporting - targs = check.infer(call.Pos(), sig.tparams, targs, sigParams, args, true) + targs := check.infer(call.Pos(), sig.TParams().list(), targs, sigParams, args, true) if targs == nil { return // error already reported } @@ -334,7 +334,7 @@ func (check *Checker) arguments(call *syntax.CallExpr, sig *Signature, targs []T // need to compute it from the adjusted list; otherwise we can // simply use the result signature's parameter list. if adjusted { - sigParams = check.subst(call.Pos(), sigParams, makeSubstMap(sig.tparams, targs)).(*Tuple) + sigParams = check.subst(call.Pos(), sigParams, makeSubstMap(sig.TParams().list(), targs)).(*Tuple) } else { sigParams = rsig.params } @@ -516,7 +516,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) { // the signature accordingly. // TODO(gri) factor this code out sig := m.typ.(*Signature) - if len(sig.rparams) > 0 { + if sig.RParams().Len() > 0 { // For inference to work, we must use the receiver type // matching the receiver in the actual method declaration. // If the method is embedded, the matching receiver is the @@ -545,7 +545,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) { // the receiver type arguments here, the receiver must be be otherwise invalid // and an error has been reported elsewhere. arg := operand{mode: variable, expr: x.expr, typ: recv} - targs := check.infer(m.pos, sig.rparams, nil, NewTuple(sig.recv), []*operand{&arg}, false /* no error reporting */) + targs := check.infer(m.pos, sig.RParams().list(), nil, NewTuple(sig.recv), []*operand{&arg}, false /* no error reporting */) //check.dump("### inferred targs = %s", targs) if targs == nil { // We may reach here if there were other errors (see issue #40056). @@ -555,7 +555,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) { // (If we modify m, some tests will fail; possibly because the m is in use.) // TODO(gri) investigate and provide a correct explanation here copy := *m - copy.typ = check.subst(e.Pos(), m.typ, makeSubstMap(sig.rparams, targs)) + copy.typ = check.subst(e.Pos(), m.typ, makeSubstMap(sig.RParams().list(), targs)) obj = © } // TODO(gri) we also need to do substitution for parameterized interface methods diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go index 6ca8f75e9a9..c867d87603c 100644 --- a/src/cmd/compile/internal/types2/decl.go +++ b/src/cmd/compile/internal/types2/decl.go @@ -575,20 +575,20 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named named.underlying = under(named) // If the RHS is a type parameter, it must be from this type declaration. - if tpar, _ := named.underlying.(*TypeParam); tpar != nil && tparamIndex(named.tparams, tpar) < 0 { + if tpar, _ := named.underlying.(*TypeParam); tpar != nil && tparamIndex(named.tparams.list(), tpar) < 0 { check.errorf(tdecl.Type, "cannot use function type parameter %s as RHS in type declaration", tpar) named.underlying = Typ[Invalid] } } -func (check *Checker) collectTypeParams(list []*syntax.Field) []*TypeName { +func (check *Checker) collectTypeParams(list []*syntax.Field) *TypeParams { tparams := make([]*TypeName, len(list)) // Declare type parameters up-front. // The scope of type parameters starts at the beginning of the type parameter // list (so we can have mutually recursive parameterized type bounds). for i, f := range list { - tparams[i] = check.declareTypeParam(i, f.Name) + tparams[i] = check.declareTypeParam(f.Name) } var bound Type @@ -602,12 +602,12 @@ func (check *Checker) collectTypeParams(list []*syntax.Field) []*TypeName { tparams[i].typ.(*TypeParam).bound = bound } - return tparams + return bindTParams(tparams) } -func (check *Checker) declareTypeParam(index int, name *syntax.Name) *TypeName { +func (check *Checker) declareTypeParam(name *syntax.Name) *TypeName { tpar := NewTypeName(name.Pos(), check.pkg, name.Value, nil) - check.NewTypeParam(tpar, index, nil) // assigns type to tpar as a side-effect + check.NewTypeParam(tpar, nil) // assigns type to tpar as a side-effect check.declare(check.scope, name, tpar, check.scope.pos) // TODO(gri) check scope position return tpar } diff --git a/src/cmd/compile/internal/types2/index.go b/src/cmd/compile/internal/types2/index.go index d3e0c71f05d..e8755a1a68e 100644 --- a/src/cmd/compile/internal/types2/index.go +++ b/src/cmd/compile/internal/types2/index.go @@ -32,7 +32,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo return false case value: - if sig := asSignature(x.typ); sig != nil && len(sig.tparams) > 0 { + if sig := asSignature(x.typ); sig != nil && sig.TParams().Len() > 0 { // function instantiation return true } diff --git a/src/cmd/compile/internal/types2/instance.go b/src/cmd/compile/internal/types2/instance.go index e18688771cc..40e89289a26 100644 --- a/src/cmd/compile/internal/types2/instance.go +++ b/src/cmd/compile/internal/types2/instance.go @@ -25,7 +25,7 @@ func (n *Named) expand() { // tparams. This is done implicitly by the call to n.TParams, but making it // explicit is harmless: load is idempotent. n.load() - inst := n.check.instantiate(n.instance.pos, n.orig.underlying, n.TParams(), n.targs, n.instance.posList) + inst := n.check.instantiate(n.instance.pos, n.orig.underlying, n.TParams().list(), n.targs, n.instance.posList) n.underlying = inst n.fromRHS = inst n.instance = nil diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go index ee790ba6d6b..9f9f8a7f5d3 100644 --- a/src/cmd/compile/internal/types2/instantiate.go +++ b/src/cmd/compile/internal/types2/instantiate.go @@ -29,9 +29,9 @@ func (check *Checker) Instantiate(pos syntax.Pos, typ Type, targs []Type, posLis var tparams []*TypeName switch t := typ.(type) { case *Named: - tparams = t.TParams() + tparams = t.TParams().list() case *Signature: - tparams = t.tparams + tparams = t.TParams().list() defer func() { // If we had an unexpected failure somewhere don't panic below when // asserting res.(*Signature). Check for *Signature in case Typ[Invalid] @@ -109,9 +109,9 @@ func (check *Checker) InstantiateLazy(pos syntax.Pos, typ Type, targs []Type, po panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) } - if verify && len(base.tparams) == len(targs) { + if verify && base.TParams().Len() == len(targs) { check.later(func() { - check.verify(pos, base.tparams, targs, posList) + check.verify(pos, base.tparams.list(), targs, posList) }) } @@ -125,7 +125,7 @@ func (check *Checker) InstantiateLazy(pos syntax.Pos, typ Type, targs []Type, po } tname := NewTypeName(pos, base.obj.pkg, base.obj.name, nil) - named := check.newNamed(tname, base, nil, nil, nil) // methods and tparams are set when named is loaded. + named := check.newNamed(tname, base, nil, nil, nil) // methods and tparams are set when named is loaded named.targs = targs named.instance = &instance{pos, posList} if check != nil { diff --git a/src/cmd/compile/internal/types2/lookup.go b/src/cmd/compile/internal/types2/lookup.go index 9e9d6dfb29b..3819a9ffb86 100644 --- a/src/cmd/compile/internal/types2/lookup.go +++ b/src/cmd/compile/internal/types2/lookup.go @@ -315,10 +315,10 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // both methods must have the same number of type parameters ftyp := f.typ.(*Signature) mtyp := m.typ.(*Signature) - if len(ftyp.tparams) != len(mtyp.tparams) { + if ftyp.TParams().Len() != mtyp.TParams().Len() { return m, f } - if !acceptMethodTypeParams && len(ftyp.tparams) > 0 { + if !acceptMethodTypeParams && ftyp.TParams().Len() > 0 { panic("internal error: method with type parameters") } @@ -328,7 +328,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // TODO(gri) is this always correct? what about type bounds? // (Alternative is to rename/subst type parameters and compare.) u := newUnifier(true) - u.x.init(ftyp.tparams) + u.x.init(ftyp.TParams().list()) if !u.unify(ftyp, mtyp) { return m, f } @@ -367,10 +367,10 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // both methods must have the same number of type parameters ftyp := f.typ.(*Signature) mtyp := m.typ.(*Signature) - if len(ftyp.tparams) != len(mtyp.tparams) { + if ftyp.TParams().Len() != mtyp.TParams().Len() { return m, f } - if !acceptMethodTypeParams && len(ftyp.tparams) > 0 { + if !acceptMethodTypeParams && ftyp.TParams().Len() > 0 { panic("internal error: method with type parameters") } @@ -381,17 +381,17 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // In order to compare the signatures, substitute the receiver // type parameters of ftyp with V's instantiation type arguments. // This lazily instantiates the signature of method f. - if Vn != nil && len(Vn.TParams()) > 0 { + if Vn != nil && Vn.TParams().Len() > 0 { // Be careful: The number of type arguments may not match // the number of receiver parameters. If so, an error was // reported earlier but the length discrepancy is still // here. Exit early in this case to prevent an assertion // failure in makeSubstMap. // TODO(gri) Can we avoid this check by fixing the lengths? - if len(ftyp.rparams) != len(Vn.targs) { + if len(ftyp.RParams().list()) != len(Vn.targs) { return } - ftyp = check.subst(nopos, ftyp, makeSubstMap(ftyp.rparams, Vn.targs)).(*Signature) + ftyp = check.subst(nopos, ftyp, makeSubstMap(ftyp.RParams().list(), Vn.targs)).(*Signature) } // If the methods have type parameters we don't care whether they @@ -400,7 +400,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // TODO(gri) is this always correct? what about type bounds? // (Alternative is to rename/subst type parameters and compare.) u := newUnifier(true) - if len(ftyp.tparams) > 0 { + if ftyp.TParams().Len() > 0 { // We reach here only if we accept method type parameters. // In this case, unification must consider any receiver // and method type parameters as "free" type parameters. @@ -410,9 +410,9 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // unimplemented call so that we test this code if we // enable method type parameters. unimplemented() - u.x.init(append(ftyp.rparams, ftyp.tparams...)) + u.x.init(append(ftyp.RParams().list(), ftyp.TParams().list()...)) } else { - u.x.init(ftyp.rparams) + u.x.init(ftyp.RParams().list()) } if !u.unify(ftyp, mtyp) { return m, f diff --git a/src/cmd/compile/internal/types2/named.go b/src/cmd/compile/internal/types2/named.go index a88aeb00779..96f2db1429d 100644 --- a/src/cmd/compile/internal/types2/named.go +++ b/src/cmd/compile/internal/types2/named.go @@ -17,7 +17,7 @@ type Named struct { fromRHS Type // type (on RHS of declaration) this *Named type is derived from (for cycle reporting) underlying Type // possibly a *Named during setup; never a *Named once set up completely instance *instance // position information for lazy instantiation, or nil - tparams []*TypeName // type parameters, or nil + tparams *TypeParams // type parameters, or nil targs []Type // type arguments (after instantiation), or nil methods []*Func // methods declared for this type (not the method set of this type); signatures are type-checked lazily @@ -69,7 +69,7 @@ func (t *Named) load() *Named { panic("invalid underlying type") } - t.tparams = tparams + t.tparams = bindTParams(tparams) t.underlying = underlying t.methods = methods }) @@ -77,7 +77,7 @@ func (t *Named) load() *Named { } // newNamed is like NewNamed but with a *Checker receiver and additional orig argument. -func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams []*TypeName, methods []*Func) *Named { +func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams *TypeParams, methods []*Func) *Named { typ := &Named{check: check, obj: obj, orig: orig, fromRHS: underlying, underlying: underlying, tparams: tparams, methods: methods} if typ.orig == nil { typ.orig = typ @@ -117,12 +117,10 @@ func (t *Named) Orig() *Named { return t.orig } // TParams returns the type parameters of the named type t, or nil. // The result is non-nil for an (originally) parameterized type even if it is instantiated. -func (t *Named) TParams() []*TypeName { - return t.load().tparams -} +func (t *Named) TParams() *TypeParams { return t.load().tparams } // SetTParams sets the type parameters of the named type t. -func (t *Named) SetTParams(tparams []*TypeName) { t.load().tparams = tparams } +func (t *Named) SetTParams(tparams []*TypeName) { t.load().tparams = bindTParams(tparams) } // TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated. func (t *Named) TArgs() []Type { return t.targs } diff --git a/src/cmd/compile/internal/types2/object.go b/src/cmd/compile/internal/types2/object.go index 48fd1e44de1..8263ccae0cb 100644 --- a/src/cmd/compile/internal/types2/object.go +++ b/src/cmd/compile/internal/types2/object.go @@ -475,8 +475,8 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) { if _, ok := typ.(*Basic); ok { return } - if named, _ := typ.(*Named); named != nil && len(named.tparams) > 0 { - writeTParamList(buf, named.tparams, qf, nil) + if named, _ := typ.(*Named); named != nil && named.TParams().Len() > 0 { + writeTParamList(buf, named.TParams().list(), qf, nil) } if tname.IsAlias() { buf.WriteString(" =") diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go index cd9fa3f5643..f3aeafcbb70 100644 --- a/src/cmd/compile/internal/types2/predicates.go +++ b/src/cmd/compile/internal/types2/predicates.go @@ -227,7 +227,7 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { // parameter names. if y, ok := y.(*Signature); ok { return x.variadic == y.variadic && - identicalTParams(x.tparams, y.tparams, cmpTags, p) && + identicalTParams(x.TParams().list(), y.TParams().list(), cmpTags, p) && identical(x.params, y.params, cmpTags, p) && identical(x.results, y.results, cmpTags, p) } diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go index fa5c3f7a9b8..832f37a6af4 100644 --- a/src/cmd/compile/internal/types2/signature.go +++ b/src/cmd/compile/internal/types2/signature.go @@ -19,8 +19,8 @@ type Signature struct { // and store it in the Func Object) because when type-checking a function // literal we call the general type checker which returns a general Type. // We then unpack the *Signature and use the scope for the literal body. - rparams []*TypeName // receiver type parameters from left to right; or nil - tparams []*TypeName // type parameters from left to right; or nil + rparams *TypeParams // receiver type parameters from left to right, or nil + tparams *TypeParams // type parameters from left to right, or nil scope *Scope // function scope, present for package-local signatures recv *Var // nil if not a method params *Tuple // (incoming) parameters from left to right; or nil @@ -54,16 +54,16 @@ func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature { func (s *Signature) Recv() *Var { return s.recv } // TParams returns the type parameters of signature s, or nil. -func (s *Signature) TParams() []*TypeName { return s.tparams } - -// RParams returns the receiver type params of signature s, or nil. -func (s *Signature) RParams() []*TypeName { return s.rparams } +func (s *Signature) TParams() *TypeParams { return s.tparams } // SetTParams sets the type parameters of signature s. -func (s *Signature) SetTParams(tparams []*TypeName) { s.tparams = tparams } +func (s *Signature) SetTParams(tparams []*TypeName) { s.tparams = bindTParams(tparams) } + +// RParams returns the receiver type parameters of signature s, or nil. +func (s *Signature) RParams() *TypeParams { return s.rparams } // SetRParams sets the receiver type params of signature s. -func (s *Signature) SetRParams(rparams []*TypeName) { s.rparams = rparams } +func (s *Signature) SetRParams(rparams []*TypeName) { s.rparams = bindTParams(rparams) } // Params returns the parameters of signature s, or nil. func (s *Signature) Params() *Tuple { return s.params } @@ -119,10 +119,11 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams [] // blank identifiers were found => use rewritten receiver type recvTyp = isubst(recvPar.Type, smap) } - sig.rparams = make([]*TypeName, len(rparams)) + rlist := make([]*TypeName, len(rparams)) for i, rparam := range rparams { - sig.rparams[i] = check.declareTypeParam(i, rparam) + rlist[i] = check.declareTypeParam(rparam) } + sig.rparams = bindTParams(rlist) // determine receiver type to get its type parameters // and the respective type parameter bounds var recvTParams []*TypeName @@ -132,19 +133,19 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams [] // again when we type-check the signature. // TODO(gri) maybe the receiver should be marked as invalid instead? if recv := asNamed(check.genericType(rname, false)); recv != nil { - recvTParams = recv.TParams() + recvTParams = recv.TParams().list() } } // provide type parameter bounds // - only do this if we have the right number (otherwise an error is reported elsewhere) - if len(sig.rparams) == len(recvTParams) { + if sig.RParams().Len() == len(recvTParams) { // We have a list of *TypeNames but we need a list of Types. - list := make([]Type, len(sig.rparams)) - for i, t := range sig.rparams { + list := make([]Type, sig.RParams().Len()) + for i, t := range sig.RParams().list() { list[i] = t.typ } smap := makeSubstMap(recvTParams, list) - for i, tname := range sig.rparams { + for i, tname := range sig.RParams().list() { bound := recvTParams[i].typ.(*TypeParam).bound // bound is (possibly) parameterized in the context of the // receiver type declaration. Substitute parameters for the diff --git a/src/cmd/compile/internal/types2/sizeof_test.go b/src/cmd/compile/internal/types2/sizeof_test.go index 70cf3709e5e..8255e6ded4f 100644 --- a/src/cmd/compile/internal/types2/sizeof_test.go +++ b/src/cmd/compile/internal/types2/sizeof_test.go @@ -26,12 +26,12 @@ func TestSizeof(t *testing.T) { {Struct{}, 24, 48}, {Pointer{}, 8, 16}, {Tuple{}, 12, 24}, - {Signature{}, 44, 88}, + {Signature{}, 28, 56}, {Union{}, 12, 24}, {Interface{}, 40, 80}, {Map{}, 16, 32}, {Chan{}, 12, 24}, - {Named{}, 88, 168}, + {Named{}, 80, 152}, {TypeParam{}, 28, 48}, {term{}, 12, 24}, {top{}, 0, 0}, diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index fc713434318..54cd005640d 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -197,7 +197,7 @@ func (subst *subster) typ(typ Type) Type { if len(t.targs) > 0 { // already instantiated dump(">>> %s already instantiated", t) - assert(len(t.targs) == len(t.TParams())) + assert(len(t.targs) == t.TParams().Len()) // For each (existing) type argument targ, determine if it needs // to be substituted; i.e., if it is or contains a type parameter // that has a type argument for it. @@ -207,7 +207,7 @@ func (subst *subster) typ(typ Type) Type { if new_targ != targ { dump(">>> substituted %d targ %s => %s", i, targ, new_targ) if new_targs == nil { - new_targs = make([]Type, len(t.TParams())) + new_targs = make([]Type, t.TParams().Len()) copy(new_targs, t.targs) } new_targs[i] = new_targ diff --git a/src/cmd/compile/internal/types2/typeparam.go b/src/cmd/compile/internal/types2/typeparam.go index b66256cf00d..aff03a5f042 100644 --- a/src/cmd/compile/internal/types2/typeparam.go +++ b/src/cmd/compile/internal/types2/typeparam.go @@ -28,15 +28,19 @@ type TypeParam struct { // Obj returns the type name for the type parameter t. func (t *TypeParam) Obj() *TypeName { return t.obj } -// NewTypeParam returns a new TypeParam. bound can be nil (and set later). -func (check *Checker) NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam { +// NewTypeParam returns a new TypeParam. Type parameters may be set on a Named +// or Signature type by calling SetTParams. Setting a type parameter on more +// than one type will result in a panic. +// +// The bound argument can be nil, and set later via SetBound. +func (check *Checker) NewTypeParam(obj *TypeName, bound Type) *TypeParam { // Always increment lastID, even if it is not used. id := nextID() if check != nil { check.nextID++ id = check.nextID } - typ := &TypeParam{check: check, id: id, obj: obj, index: index, bound: bound} + typ := &TypeParam{check: check, id: id, obj: obj, index: -1, bound: bound} if obj.typ == nil { obj.typ = typ } @@ -88,6 +92,42 @@ func (t *TypeParam) SetBound(bound Type) { func (t *TypeParam) Underlying() Type { return t } func (t *TypeParam) String() string { return TypeString(t, nil) } +// TypeParams holds a list of type parameters bound to a type. +type TypeParams struct{ tparams []*TypeName } + +// Len returns the number of type parameters in the list. +// It is safe to call on a nil receiver. +func (tps *TypeParams) Len() int { + return len(tps.list()) +} + +// At returns the i'th type parameter in the list. +// It is safe to call on a nil receiver. +func (tps *TypeParams) At(i int) *TypeName { + return tps.list()[i] +} + +func (tps *TypeParams) list() []*TypeName { + if tps == nil { + return nil + } + return tps.tparams +} + +func bindTParams(list []*TypeName) *TypeParams { + if len(list) == 0 { + return nil + } + for i, tp := range list { + typ := tp.Type().(*TypeParam) + if typ.index >= 0 { + panic("internal error: type parameter bound more than once") + } + typ.index = i + } + return &TypeParams{tparams: list} +} + // ---------------------------------------------------------------------------- // Implementation diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go index 1da3f7f8ed8..7a8b5a6eeeb 100644 --- a/src/cmd/compile/internal/types2/typestring.go +++ b/src/cmd/compile/internal/types2/typestring.go @@ -280,7 +280,7 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { buf.WriteByte(']') } else if t.TParams() != nil { // parameterized type - writeTParamList(buf, t.TParams(), qf, visited) + writeTParamList(buf, t.TParams().list(), qf, visited) } case *TypeParam: @@ -426,7 +426,7 @@ func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) { func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) { if sig.tparams != nil { - writeTParamList(buf, sig.tparams, qf, visited) + writeTParamList(buf, sig.TParams().list(), qf, visited) } writeTuple(buf, sig.params, sig.variadic, qf, visited) From 46cc68638143770206e0894add7021990a9bec52 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 28 Jul 2021 15:38:28 -0700 Subject: [PATCH 815/940] [dev.typeparams] cmd/compile/internal/types2: use the TParams API consistently This is a clean port of CL 336251. Change-Id: I08415c3e9b6cef33594e7d56c4115ddde8030381 Reviewed-on: https://go-review.googlesource.com/c/go/+/338193 Trust: Robert Griesemer Run-TryBot: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/call.go | 4 ++-- src/cmd/compile/internal/types2/decl.go | 2 +- src/cmd/compile/internal/types2/subst.go | 2 +- src/cmd/compile/internal/types2/typestring.go | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index dee49b44a44..e1acf50213a 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -57,7 +57,7 @@ func (check *Checker) funcInst(x *operand, inst *syntax.IndexExpr) { // instantiate function signature res := check.Instantiate(x.Pos(), sig, targs, poslist, true).(*Signature) - assert(res.tparams == nil) // signature is not generic anymore + assert(res.TParams().Len() == 0) // signature is not generic anymore if inferred { check.recordInferred(inst, targs, res) } @@ -327,7 +327,7 @@ func (check *Checker) arguments(call *syntax.CallExpr, sig *Signature, targs []T // compute result signature rsig = check.Instantiate(call.Pos(), sig, targs, nil, true).(*Signature) - assert(rsig.tparams == nil) // signature is not generic anymore + assert(rsig.TParams().Len() == 0) // signature is not generic anymore check.recordInferred(call, targs, rsig) // Optimization: Only if the parameter list was adjusted do we diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go index c867d87603c..cf4d4c95a7e 100644 --- a/src/cmd/compile/internal/types2/decl.go +++ b/src/cmd/compile/internal/types2/decl.go @@ -575,7 +575,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named named.underlying = under(named) // If the RHS is a type parameter, it must be from this type declaration. - if tpar, _ := named.underlying.(*TypeParam); tpar != nil && tparamIndex(named.tparams.list(), tpar) < 0 { + if tpar, _ := named.underlying.(*TypeParam); tpar != nil && tparamIndex(named.TParams().list(), tpar) < 0 { check.errorf(tdecl.Type, "cannot use function type parameter %s as RHS in type declaration", tpar) named.underlying = Typ[Invalid] } diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index 54cd005640d..e497e174636 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -187,7 +187,7 @@ func (subst *subster) typ(typ Type) Type { } } - if t.TParams() == nil { + if t.TParams().Len() == 0 { dump(">>> %s is not parameterized", t) return t // type is not parameterized } diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go index 7a8b5a6eeeb..b7e32c9860b 100644 --- a/src/cmd/compile/internal/types2/typestring.go +++ b/src/cmd/compile/internal/types2/typestring.go @@ -278,7 +278,7 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { buf.WriteByte('[') writeTypeList(buf, t.targs, qf, visited) buf.WriteByte(']') - } else if t.TParams() != nil { + } else if t.TParams().Len() != 0 { // parameterized type writeTParamList(buf, t.TParams().list(), qf, visited) } @@ -425,7 +425,7 @@ func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) { } func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) { - if sig.tparams != nil { + if sig.TParams().Len() != 0 { writeTParamList(buf, sig.TParams().list(), qf, visited) } From 5ecbd811b54f478244b7e54a621f32b5b8e3ea95 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 28 Jul 2021 16:58:57 -0700 Subject: [PATCH 816/940] [dev.typeparams] cmd/compile/internal/types2: (TypeParam) SetBound -> SetConstraint This matches the accessor named Constraint, and any documentation we have so far. Use iface instead of Bound internally to types2; keep Bound because of two external uses but mark it as deprecated. Adjust clients. Change-Id: Id1a2c2f28259a16082e875eee0534d46cf157336 Reviewed-on: https://go-review.googlesource.com/c/go/+/338196 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/importer/iimport.go | 2 +- src/cmd/compile/internal/noder/reader2.go | 2 +- src/cmd/compile/internal/types2/builtins.go | 2 +- src/cmd/compile/internal/types2/call.go | 2 +- .../compile/internal/types2/instantiate.go | 6 ++--- src/cmd/compile/internal/types2/lookup.go | 2 +- src/cmd/compile/internal/types2/predicates.go | 2 +- src/cmd/compile/internal/types2/type.go | 2 +- src/cmd/compile/internal/types2/typeparam.go | 26 ++++++++++++------- 9 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/cmd/compile/internal/importer/iimport.go b/src/cmd/compile/internal/importer/iimport.go index 999b2aa1dc1..3dd28033a1a 100644 --- a/src/cmd/compile/internal/importer/iimport.go +++ b/src/cmd/compile/internal/importer/iimport.go @@ -384,7 +384,7 @@ func (r *importReader) obj(name string) { id := ident{r.currPkg.Name(), name} r.p.tparamIndex[id] = t - t.SetBound(r.typ()) + t.SetConstraint(r.typ()) case 'V': typ := r.typ() diff --git a/src/cmd/compile/internal/noder/reader2.go b/src/cmd/compile/internal/noder/reader2.go index 3e310e26c43..d1839349002 100644 --- a/src/cmd/compile/internal/noder/reader2.go +++ b/src/cmd/compile/internal/noder/reader2.go @@ -485,7 +485,7 @@ func (r *reader2) typeParamNames() []*types2.TypeName { } for i, bound := range r.dict.bounds { - r.dict.tparams[i].SetBound(r.p.typIdx(bound, r.dict)) + r.dict.tparams[i].SetConstraint(r.p.typIdx(bound, r.dict)) } return names diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index 7ef9e7be639..7b2c92bfa86 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -817,7 +817,7 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { // type and collect possible result types at the same time. var rtypes []Type var tildes []bool - if !tp.Bound().is(func(typ Type, tilde bool) bool { + if !tp.iface().is(func(typ Type, tilde bool) bool { if r := f(typ); r != nil { rtypes = append(rtypes, r) tildes = append(tildes, tilde) diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index e1acf50213a..049d80dd9e7 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -479,7 +479,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) { var why string if tpar := asTypeParam(x.typ); tpar != nil { // Type parameter bounds don't specify fields, so don't mention "field". - if tname := tpar.Bound().obj; tname != nil { + if tname := tpar.iface().obj; tname != nil { why = check.sprintf("interface %s has no method %s", tname.name, sel) } else { why = check.sprintf("type bound for %s has no method %s", x.typ, sel) diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go index 9f9f8a7f5d3..357f041c466 100644 --- a/src/cmd/compile/internal/types2/instantiate.go +++ b/src/cmd/compile/internal/types2/instantiate.go @@ -160,7 +160,7 @@ func (check *Checker) verify(pos syntax.Pos, tparams []*TypeName, targs []Type, // A suitable error is reported if the result is false. // TODO(gri) This should be a method of interfaces or type sets. func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap *substMap) bool { - iface := tpar.Bound() + iface := tpar.iface() if iface.Empty() { return true // no type bound } @@ -174,7 +174,7 @@ func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap // if iface is comparable, targ must be comparable // TODO(gri) the error messages needs to be better, here if iface.IsComparable() && !Comparable(targ) { - if tpar := asTypeParam(targ); tpar != nil && tpar.Bound().typeSet().IsTop() { + if tpar := asTypeParam(targ); tpar != nil && tpar.iface().typeSet().IsTop() { check.softErrorf(pos, "%s has no constraints", targ) return false } @@ -219,7 +219,7 @@ func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap // If targ is itself a type parameter, each of its possible types, but at least one, must be in the // list of iface types (i.e., the targ type list must be a non-empty subset of the iface types). if targ := asTypeParam(targ); targ != nil { - targBound := targ.Bound() + targBound := targ.iface() if targBound.typeSet().types == nil { check.softErrorf(pos, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ) return false diff --git a/src/cmd/compile/internal/types2/lookup.go b/src/cmd/compile/internal/types2/lookup.go index 3819a9ffb86..41e5bc7811a 100644 --- a/src/cmd/compile/internal/types2/lookup.go +++ b/src/cmd/compile/internal/types2/lookup.go @@ -186,7 +186,7 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o } case *TypeParam: - if i, m := t.Bound().typeSet().LookupMethod(pkg, name); m != nil { + if i, m := t.iface().typeSet().LookupMethod(pkg, name); m != nil { assert(m.typ != nil) index = concat(e.index, i) if obj != nil || e.multiples { diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go index f3aeafcbb70..84342b2796a 100644 --- a/src/cmd/compile/internal/types2/predicates.go +++ b/src/cmd/compile/internal/types2/predicates.go @@ -113,7 +113,7 @@ func comparable(T Type, seen map[Type]bool) bool { case *Array: return comparable(t.elem, seen) case *TypeParam: - return t.Bound().IsComparable() + return t.iface().IsComparable() } return false } diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index 80054372bcc..a9439261899 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -56,7 +56,7 @@ func optype(typ Type) Type { // for a type parameter list of the form: // (type T interface { type T }). // See also issue #39680. - if a := t.Bound().typeSet().types; a != nil { + if a := t.iface().typeSet().types; a != nil { // If we have a union with a single entry, ignore // any tilde because under(~t) == under(t). if u, _ := a.(*Union); u != nil && u.NumTerms() == 1 { diff --git a/src/cmd/compile/internal/types2/typeparam.go b/src/cmd/compile/internal/types2/typeparam.go index aff03a5f042..9f8c921bf17 100644 --- a/src/cmd/compile/internal/types2/typeparam.go +++ b/src/cmd/compile/internal/types2/typeparam.go @@ -72,21 +72,27 @@ func (t *TypeParam) Constraint() Type { return t.bound } -// Bound returns the underlying type of the type parameter's -// constraint. -// Deprecated for external use. Use Constraint instead. -func (t *TypeParam) Bound() *Interface { +// SetConstraint sets the type constraint for t. +func (t *TypeParam) SetConstraint(bound Type) { + if bound == nil { + panic("types2.TypeParam.SetConstraint: bound must not be nil") + } + t.bound = bound +} + +// iface returns the constraint interface of t. +func (t *TypeParam) iface() *Interface { if iface, _ := under(t.Constraint()).(*Interface); iface != nil { return iface } return &emptyInterface } -func (t *TypeParam) SetBound(bound Type) { - if bound == nil { - panic("types2.TypeParam.SetBound: bound must not be nil") - } - t.bound = bound +// Bound returns the constraint interface of t. +// Deprecated. Only here for the compiler. +// TODO(gri) remove in favor of uses of Constraint. +func (t *TypeParam) Bound() *Interface { + return t.iface() } func (t *TypeParam) Underlying() Type { return t } @@ -132,5 +138,5 @@ func bindTParams(list []*TypeName) *TypeParams { // Implementation func (t *TypeParam) underIs(f func(Type) bool) bool { - return t.Bound().typeSet().underIs(f) + return t.iface().typeSet().underIs(f) } From 600b7b431bd546841c04a27d4ac73af1e4f2fcc4 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Mon, 26 Jul 2021 19:25:40 -0700 Subject: [PATCH 817/940] [dev.typeparams] cmd/compile: handle meth expressions on typeparams Rewrite a method expression such as 'T.String' (where T is type param and String is part of its type bound Stringer) as: func(rcvr T, other params...) { return Stringer(rcvr).String(other params...) } New function buildClosure2 to create the needed closure. The conversion Stringer(rcvr) uses the dictionary in the outer function. For a method expression like 'Test[T].finish' (where finish is a method of Test[T]), we can already deal with this in buildClosure(). We just need fix transformDot() to allow the method lookup to fail, since shapes have no methods on them. That's fine, since for any instantiated receiver type, we always use the methods on the generic base type. Also removed the OMETHEXPR case in the main switch of node(), which isn't needed any (and removes one more potential unshapify). Also, fixed two small bugs with handling closures that have generic params or generic captured variables. Need to set the instInfo for the closure in the subst struct when descending into a closure during genericSubst() and was missing initializing the startItabConv and gfInfo fields in the closure info. Change-Id: I6dadedd1378477936a27c9c544c014cd2083cfb7 Reviewed-on: https://go-review.googlesource.com/c/go/+/338129 Trust: Dan Scales Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/noder/stencil.go | 214 +++++++++++++------- src/cmd/compile/internal/noder/transform.go | 6 +- test/typeparam/boundmethod.go | 54 ++++- 3 files changed, 198 insertions(+), 76 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 70a2c7b97fc..83abee1dd20 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -357,8 +357,7 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { // } // Make a new internal function. - fn := ir.NewClosureFunc(pos, outer != nil) - ir.NameClosure(fn.OClosure, outer) + fn, formalParams, formalResults := startClosure(pos, outer, typ) // This is the dictionary we want to use. // It may be a constant, or it may be a dictionary acquired from the outer function's dictionary. @@ -395,38 +394,6 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { outer.Dcl = append(outer.Dcl, rcvrVar) } - // Build formal argument and return lists. - var formalParams []*types.Field // arguments of closure - var formalResults []*types.Field // returns of closure - for i := 0; i < typ.NumParams(); i++ { - t := typ.Params().Field(i).Type - arg := ir.NewNameAt(pos, typecheck.LookupNum("a", i)) - arg.Class = ir.PPARAM - typed(t, arg) - arg.Curfn = fn - fn.Dcl = append(fn.Dcl, arg) - f := types.NewField(pos, arg.Sym(), t) - f.Nname = arg - formalParams = append(formalParams, f) - } - for i := 0; i < typ.NumResults(); i++ { - t := typ.Results().Field(i).Type - result := ir.NewNameAt(pos, typecheck.LookupNum("r", i)) // TODO: names not needed? - result.Class = ir.PPARAMOUT - typed(t, result) - result.Curfn = fn - fn.Dcl = append(fn.Dcl, result) - f := types.NewField(pos, result.Sym(), t) - f.Nname = result - formalResults = append(formalResults, f) - } - - // Build an internal function with the right signature. - closureType := types.NewSignature(x.Type().Pkg(), nil, nil, formalParams, formalResults) - typed(closureType, fn.Nname) - typed(x.Type(), fn.OClosure) - fn.SetTypecheck(1) - // Build body of closure. This involves just calling the wrapped function directly // with the additional dictionary argument. @@ -1092,14 +1059,15 @@ func getDictionaryEntry(pos src.XPos, dict *ir.Name, i int, size int) ir.Node { return r } -// getDictionaryType returns a *runtime._type from the dictionary entry i -// (which refers to a type param or a derived type that uses type params). -func (subst *subster) getDictionaryType(pos src.XPos, i int) ir.Node { - if i < 0 || i >= subst.info.startSubDict { +// getDictionaryType returns a *runtime._type from the dictionary entry i (which +// refers to a type param or a derived type that uses type params). It uses the +// specified dictionary dictParam, rather than the one in info.dictParam. +func getDictionaryType(info *instInfo, dictParam *ir.Name, pos src.XPos, i int) ir.Node { + if i < 0 || i >= info.startSubDict { base.Fatalf(fmt.Sprintf("bad dict index %d", i)) } - r := getDictionaryEntry(pos, subst.info.dictParam, i, subst.info.startSubDict) + r := getDictionaryEntry(pos, info.dictParam, i, info.startSubDict) // change type of retrieved dictionary entry to *byte, which is the // standard typing of a *runtime._type in the compiler typed(types.Types[types.TUINT8].PtrTo(), r) @@ -1235,9 +1203,9 @@ func (subst *subster) node(n ir.Node) ir.Node { // The only dot on a shape type value are methods. if mse.X.Op() == ir.OTYPE { // Method expression T.M - // Fall back from shape type to concrete type. - src = subst.unshapifyTyp(src) - mse.X = ir.TypeNode(src) + m = subst.g.buildClosure2(subst.newf, subst.info, m, x) + // No need for transformDot - buildClosure2 has already + // transformed to OCALLINTER/ODOTINTER. } else { // Implement x.M as a conversion-to-bound-interface // 1) convert x to the bound interface @@ -1247,12 +1215,11 @@ func (subst *subster) node(n ir.Node) ir.Node { if dst.HasTParam() { dst = subst.ts.Typ(dst) } - mse.X = subst.convertUsingDictionary(m.Pos(), mse.X, x, dst, gsrc) + mse.X = convertUsingDictionary(subst.info, subst.info.dictParam, m.Pos(), mse.X, x, dst, gsrc) + transformDot(mse, false) } - } - transformDot(mse, false) - if mse.Op() == ir.OMETHEXPR && mse.X.Type().HasShape() { - mse.X = ir.TypeNodeAt(mse.X.Pos(), subst.unshapifyTyp(mse.X.Type())) + } else { + transformDot(mse, false) } m.SetTypecheck(1) @@ -1341,11 +1308,14 @@ func (subst *subster) node(n ir.Node) ir.Node { // outer function. Since the dictionary is shared, use the // same entries for startSubDict, dictLen, dictEntryMap. cinfo := &instInfo{ - fun: newfn, - dictParam: cdict, - startSubDict: subst.info.startSubDict, - dictLen: subst.info.dictLen, - dictEntryMap: subst.info.dictEntryMap, + fun: newfn, + dictParam: cdict, + gf: subst.info.gf, + gfInfo: subst.info.gfInfo, + startSubDict: subst.info.startSubDict, + startItabConv: subst.info.startItabConv, + dictLen: subst.info.dictLen, + dictEntryMap: subst.info.dictEntryMap, } subst.g.instInfoMap[newfn.Nname.Sym()] = cinfo @@ -1353,8 +1323,11 @@ func (subst *subster) node(n ir.Node) ir.Node { typed(newfn.Nname.Type(), newfn.OClosure) newfn.SetTypecheck(1) + outerinfo := subst.info + subst.info = cinfo // Make sure type of closure function is set before doing body. newfn.Body = subst.list(oldfn.Body) + subst.info = outerinfo subst.newf = saveNewf ir.CurFunc = saveNewf @@ -1366,15 +1339,15 @@ func (subst *subster) node(n ir.Node) ir.Node { // Note: x's argument is still typed as a type parameter. // m's argument now has an instantiated type. if x.X.Type().HasTParam() { - m = subst.convertUsingDictionary(m.Pos(), m.(*ir.ConvExpr).X, x, m.Type(), x.X.Type()) + m = convertUsingDictionary(subst.info, subst.info.dictParam, m.Pos(), m.(*ir.ConvExpr).X, x, m.Type(), x.X.Type()) } case ir.ODOTTYPE, ir.ODOTTYPE2: dt := m.(*ir.TypeAssertExpr) var rt ir.Node if dt.Type().IsInterface() || dt.X.Type().IsEmptyInterface() { - ix := subst.findDictType(x.Type()) + ix := findDictType(subst.info, x.Type()) assert(ix >= 0) - rt = subst.getDictionaryType(dt.Pos(), ix) + rt = getDictionaryType(subst.info, subst.info.dictParam, dt.Pos(), ix) } else { // nonempty interface to noninterface. Need an itab. ix := -1 @@ -1395,9 +1368,6 @@ func (subst *subster) node(n ir.Node) ir.Node { m.SetType(dt.Type()) m.SetTypecheck(1) - case ir.OMETHEXPR: - se := m.(*ir.SelectorExpr) - se.X = ir.TypeNodeAt(se.X.Pos(), subst.unshapifyTyp(se.X.Type())) case ir.OFUNCINST: inst := m.(*ir.InstExpr) targs2 := make([]ir.Node, len(inst.Targs)) @@ -1414,17 +1384,17 @@ func (subst *subster) node(n ir.Node) ir.Node { } // findDictType looks for type t in the typeparams or derived types in the generic -// function info subst.info.gfInfo. This will indicate the dictionary entry with the +// function info.gfInfo. This will indicate the dictionary entry with the // correct concrete type for the associated instantiated function. -func (subst *subster) findDictType(t *types.Type) int { - for i, dt := range subst.info.gfInfo.tparams { +func findDictType(info *instInfo, t *types.Type) int { + for i, dt := range info.gfInfo.tparams { if dt == t { return i } } - for i, dt := range subst.info.gfInfo.derivedTypes { + for i, dt := range info.gfInfo.derivedTypes { if types.Identical(dt, t) { - return i + len(subst.info.gfInfo.tparams) + return i + len(info.gfInfo.tparams) } } return -1 @@ -1435,7 +1405,7 @@ func (subst *subster) findDictType(t *types.Type) int { // is the generic (not shape) type, and gn is the original generic node of the // CONVIFACE node or XDOT node (for a bound method call) that is causing the // conversion. -func (subst *subster) convertUsingDictionary(pos src.XPos, v ir.Node, gn ir.Node, dst, src *types.Type) ir.Node { +func convertUsingDictionary(info *instInfo, dictParam *ir.Name, pos src.XPos, v ir.Node, gn ir.Node, dst, src *types.Type) ir.Node { assert(src.HasTParam()) assert(dst.IsInterface()) @@ -1445,19 +1415,19 @@ func (subst *subster) convertUsingDictionary(pos src.XPos, v ir.Node, gn ir.Node // will be more efficient than converting to an empty interface first // and then type asserting to dst. ix := -1 - for i, ic := range subst.info.gfInfo.itabConvs { + for i, ic := range info.gfInfo.itabConvs { if ic == gn { - ix = subst.info.startItabConv + i + ix = info.startItabConv + i break } } assert(ix >= 0) - rt = getDictionaryEntry(pos, subst.info.dictParam, ix, subst.info.dictLen) + rt = getDictionaryEntry(pos, dictParam, ix, info.dictLen) } else { - ix := subst.findDictType(src) + ix := findDictType(info, src) assert(ix >= 0) // Load the actual runtime._type of the type parameter from the dictionary. - rt = subst.getDictionaryType(pos, ix) + rt = getDictionaryType(info, dictParam, pos, ix) } // Figure out what the data field of the interface will be. @@ -1670,7 +1640,7 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) case ir.OXDOT: selExpr := n.(*ir.SelectorExpr) - subtargs := selExpr.X.Type().RParams() + subtargs := deref(selExpr.X.Type()).RParams() s2targs := make([]*types.Type, len(subtargs)) for i, t := range subtargs { s2targs[i] = subst.Typ(t) @@ -1842,7 +1812,7 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo { } } else if n.Op() == ir.OXDOT && !n.(*ir.SelectorExpr).Implicit() && n.(*ir.SelectorExpr).Selection != nil && - len(n.(*ir.SelectorExpr).X.Type().RParams()) > 0 { + len(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) > 0 { if n.(*ir.SelectorExpr).X.Op() == ir.OTYPE { infoPrint(" Closure&subdictionary required at generic meth expr %v\n", n) } else { @@ -2017,3 +1987,105 @@ func parameterizedBy1(t *types.Type, params []*types.Type, visited map[*types.Ty return true } } + +// startClosures starts creation of a closure that has the function type typ. It +// creates all the formal params and results according to the type typ. On return, +// the body and closure variables of the closure must still be filled in, and +// ir.UseClosure() called. +func startClosure(pos src.XPos, outer *ir.Func, typ *types.Type) (*ir.Func, []*types.Field, []*types.Field) { + // Make a new internal function. + fn := ir.NewClosureFunc(pos, outer != nil) + ir.NameClosure(fn.OClosure, outer) + + // Build formal argument and return lists. + var formalParams []*types.Field // arguments of closure + var formalResults []*types.Field // returns of closure + for i := 0; i < typ.NumParams(); i++ { + t := typ.Params().Field(i).Type + arg := ir.NewNameAt(pos, typecheck.LookupNum("a", i)) + arg.Class = ir.PPARAM + typed(t, arg) + arg.Curfn = fn + fn.Dcl = append(fn.Dcl, arg) + f := types.NewField(pos, arg.Sym(), t) + f.Nname = arg + formalParams = append(formalParams, f) + } + for i := 0; i < typ.NumResults(); i++ { + t := typ.Results().Field(i).Type + result := ir.NewNameAt(pos, typecheck.LookupNum("r", i)) // TODO: names not needed? + result.Class = ir.PPARAMOUT + typed(t, result) + result.Curfn = fn + fn.Dcl = append(fn.Dcl, result) + f := types.NewField(pos, result.Sym(), t) + f.Nname = result + formalResults = append(formalResults, f) + } + + // Build an internal function with the right signature. + closureType := types.NewSignature(typ.Pkg(), nil, nil, formalParams, formalResults) + typed(closureType, fn.Nname) + typed(typ, fn.OClosure) + fn.SetTypecheck(1) + return fn, formalParams, formalResults + +} + +// buildClosure2 makes a closure to implement a method expression m (generic form x) +// which has a shape type as receiver. If the receiver is exactly a shape (i.e. from +// a typeparam), then the body of the closure converts the first argument (the +// receiver) to the interface bound type, and makes an interface call with the +// remaining arguments. +// +// The returned closure is fully substituted and has already has any needed +// transformations done. +func (g *irgen) buildClosure2(outer *ir.Func, info *instInfo, m, x ir.Node) ir.Node { + pos := m.Pos() + typ := m.Type() // type of the closure + + fn, formalParams, formalResults := startClosure(pos, outer, typ) + + // Capture dictionary calculated in the outer function + dictVar := ir.CaptureName(pos, fn, info.dictParam) + typed(types.Types[types.TUINTPTR], dictVar) + + // Build arguments to call inside the closure. + var args []ir.Node + for i := 0; i < typ.NumParams(); i++ { + args = append(args, formalParams[i].Nname.(*ir.Name)) + } + + // Build call itself. This involves converting the first argument to the + // bound type (an interface) using the dictionary, and then making an + // interface call with the remaining arguments. + var innerCall ir.Node + rcvr := args[0] + args = args[1:] + assert(m.(*ir.SelectorExpr).X.Type().IsShape()) + rcvr = convertUsingDictionary(info, dictVar, pos, rcvr, x, x.(*ir.SelectorExpr).X.Type().Bound(), x.(*ir.SelectorExpr).X.Type()) + dot := ir.NewSelectorExpr(pos, ir.ODOTINTER, rcvr, x.(*ir.SelectorExpr).Sel) + dot.Selection = typecheck.Lookdot1(dot, dot.Sel, dot.X.Type(), dot.X.Type().AllMethods(), 1) + + typed(x.(*ir.SelectorExpr).Selection.Type, dot) + innerCall = ir.NewCallExpr(pos, ir.OCALLINTER, dot, args) + t := m.Type() + if t.NumResults() == 0 { + innerCall.SetTypecheck(1) + } else if t.NumResults() == 1 { + typed(t.Results().Field(0).Type, innerCall) + } else { + typed(t.Results(), innerCall) + } + if len(formalResults) > 0 { + innerCall = ir.NewReturnStmt(pos, []ir.Node{innerCall}) + innerCall.SetTypecheck(1) + } + fn.Body = []ir.Node{innerCall} + + // We're all done with the captured dictionary + ir.FinishCaptureNames(pos, outer, fn) + + // Do final checks on closure and return it. + return ir.UseClosure(fn.OClosure, g.target) +} diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go index 2fe55a6852f..9c791d8a7bb 100644 --- a/src/cmd/compile/internal/noder/transform.go +++ b/src/cmd/compile/internal/noder/transform.go @@ -664,7 +664,11 @@ func transformMethodExpr(n *ir.SelectorExpr) (res ir.Node) { s := n.Sel m := typecheck.Lookdot1(n, s, t, ms, 0) - assert(m != nil) + if !t.HasShape() { + // It's OK to not find the method if t is instantiated by shape types, + // because we will use the methods on the generic type anyway. + assert(m != nil) + } n.SetOp(ir.OMETHEXPR) n.Selection = m diff --git a/test/typeparam/boundmethod.go b/test/typeparam/boundmethod.go index 3deabbcdcef..22f416422da 100644 --- a/test/typeparam/boundmethod.go +++ b/test/typeparam/boundmethod.go @@ -29,32 +29,78 @@ type Stringer interface { func stringify[T Stringer](s []T) (ret []string) { for _, v := range s { + // Test normal bounds method call on type param + x1 := v.String() + + // Test converting type param to its bound interface first + v1 := Stringer(v) + x2 := v1.String() + + // Test method expression with type param type + f1 := T.String + x3 := f1(v) + + // Test creating and calling closure equivalent to the method expression + f2 := func(v1 T) string { + return Stringer(v1).String() + } + x4 := f2(v) + + if x1 != x2 || x2 != x3 || x3 != x4 { + panic(fmt.Sprintf("Mismatched values %v, %v, %v, %v\n", x1, x2, x3, x4)) + } + ret = append(ret, v.String()) } return ret } -type StringInt[T any] T +type Ints interface { + ~int32 | ~int +} + +type StringInt[T Ints] T //go:noinline func (m StringInt[T]) String() string { - return "aa" + return strconv.Itoa(int(m)) +} + +type StringStruct[T Ints] struct { + f T +} + +func (m StringStruct[T]) String() string { + return strconv.Itoa(int(m.f)) } func main() { x := []myint{myint(1), myint(2), myint(3)} + // stringify on a normal type, whose bound method is associated with the base type. got := stringify(x) want := []string{"1", "2", "3"} if !reflect.DeepEqual(got, want) { panic(fmt.Sprintf("got %s, want %s", got, want)) } - x2 := []StringInt[myint]{StringInt[myint](1), StringInt[myint](2), StringInt[myint](3)} + x2 := []StringInt[myint]{StringInt[myint](5), StringInt[myint](7), StringInt[myint](6)} + // stringify on an instantiated type, whose bound method is associated with + // the generic type StringInt[T], which maps directly to T. got2 := stringify(x2) - want2 := []string{"aa", "aa", "aa"} + want2 := []string{ "5", "7", "6" } if !reflect.DeepEqual(got2, want2) { panic(fmt.Sprintf("got %s, want %s", got2, want2)) } + + // stringify on an instantiated type, whose bound method is associated with + // the generic type StringStruct[T], which maps to a struct containing T. + x3 := []StringStruct[myint]{StringStruct[myint]{f: 11}, StringStruct[myint]{f: 10}, StringStruct[myint]{f: 9}} + + got3 := stringify(x3) + want3 := []string{ "11", "10", "9" } + if !reflect.DeepEqual(got3, want3) { + panic(fmt.Sprintf("got %s, want %s", got3, want3)) + } } From 35dbdda2feecd04fde8d44441fef58aabaf0a78a Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Thu, 29 Jul 2021 07:27:35 -0700 Subject: [PATCH 818/940] [dev.typeparams] cmd/compile: remove remaining uses of Unshapify The other uses of Unshapify were really only there to allow for the dictionary checking code at the beginning of generic functions/methods. But that will go away as soon as we start combining real shapes. If we get rid of that code, we can get rid of the unshapify calls elsewhere. The only tricky part is that getInstantiation now gets targs that may each either be a shape or concrete type, and it must translate any concrete types to shapes, while leaving the already existing shapes. Change-Id: Ib2b9072b921f8e064958548a1078d82f1d040c9f Reviewed-on: https://go-review.googlesource.com/c/go/+/338289 Trust: Dan Scales Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/noder/stencil.go | 97 ++++++++--------------- 1 file changed, 35 insertions(+), 62 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 83abee1dd20..037f309a82b 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -768,38 +768,49 @@ func checkFetchBody(nameNode *ir.Name) { } // getInstantiation gets the instantiantion and dictionary of the function or method nameNode -// with the type arguments targs. If the instantiated function is not already +// with the type arguments shapes. If the instantiated function is not already // cached, then it calls genericSubst to create the new instantiation. -func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth bool) *ir.Func { +func (g *irgen) getInstantiation(nameNode *ir.Name, shapes []*types.Type, isMeth bool) *ir.Func { checkFetchBody(nameNode) - // Convert type arguments to their shape, so we can reduce the number - // of instantiations we have to generate. - shapes := typecheck.ShapifyList(targs) + // Convert any non-shape type arguments to their shape, so we can reduce the + // number of instantiations we have to generate. You can actually have a mix + // of shape and non-shape arguments, because of inferred or explicitly + // specified concrete type args. + var s1 []*types.Type + for i, t := range shapes { + if !t.HasShape() { + if s1 == nil { + s1 = make([]*types.Type, len(shapes)) + for j := 0; j < i; j++ { + s1[j] = shapes[j] + } + } + s1[i] = typecheck.Shapify(t) + } else if s1 != nil { + s1[i] = shapes[i] + } + } + if s1 != nil { + shapes = s1 + } sym := typecheck.MakeInstName(nameNode.Sym(), shapes, isMeth) info := g.instInfoMap[sym] if info == nil { - if false { - // Testing out gcshapeType() and gcshapeName() - for i, t := range targs { - gct, gcs := gcshapeType(t) - fmt.Printf("targ %d: %v %v %v\n", i, gcs, gct, gct.Underlying()) - } - } // If instantiation doesn't exist yet, create it and add // to the list of decls. gfInfo := g.getGfInfo(nameNode) info = &instInfo{ gf: nameNode, gfInfo: gfInfo, - startSubDict: len(targs) + len(gfInfo.derivedTypes), - startItabConv: len(targs) + len(gfInfo.derivedTypes) + len(gfInfo.subDictCalls), - dictLen: len(targs) + len(gfInfo.derivedTypes) + len(gfInfo.subDictCalls) + len(gfInfo.itabConvs), + startSubDict: len(shapes) + len(gfInfo.derivedTypes), + startItabConv: len(shapes) + len(gfInfo.derivedTypes) + len(gfInfo.subDictCalls), + dictLen: len(shapes) + len(gfInfo.derivedTypes) + len(gfInfo.subDictCalls) + len(gfInfo.itabConvs), dictEntryMap: make(map[ir.Node]int), } // genericSubst fills in info.dictParam and info.dictEntryMap. - st := g.genericSubst(sym, nameNode, shapes, targs, isMeth, info) + st := g.genericSubst(sym, nameNode, shapes, isMeth, info) info.fun = st g.instInfoMap[sym] = info // This ensures that the linker drops duplicates of this instantiation. @@ -821,23 +832,15 @@ type subster struct { newf *ir.Func // Func node for the new stenciled function ts typecheck.Tsubster info *instInfo // Place to put extra info in the instantiation - - // unshapeify maps from shape types to the concrete types they represent. - // TODO: remove when we no longer need it. - unshapify typecheck.Tsubster - - // TODO: some sort of map from to index in the - // dictionary where a *runtime.itab for the corresponding pair resides. } // genericSubst returns a new function with name newsym. The function is an // instantiation of a generic function or method specified by namedNode with type -// args targs. For a method with a generic receiver, it returns an instantiated -// function type where the receiver becomes the first parameter. Otherwise the -// instantiated method would still need to be transformed by later compiler -// phases. genericSubst fills in info.dictParam and info.dictEntryMap. -func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, shapes, targs []*types.Type, isMethod bool, info *instInfo) *ir.Func { +// args shapes. For a method with a generic receiver, it returns an instantiated +// function type where the receiver becomes the first parameter. For either a generic +// method or function, a dictionary parameter is the added as the very first +// parameter. genericSubst fills in info.dictParam and info.dictEntryMap. +func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, shapes []*types.Type, isMethod bool, info *instInfo) *ir.Func { var tparams []*types.Type if isMethod { // Get the type params from the method receiver (after skipping @@ -852,11 +855,6 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, shapes, targs tparams[i] = f.Type } } - for i := range targs { - if targs[i].HasShape() { - base.Fatalf("generiSubst shape %s %+v %+v\n", newsym.Name, shapes[i], targs[i]) - } - } gf := nameNode.Func // Pos of the instantiated function is same as the generic function newf := ir.NewFunc(gf.Pos()) @@ -871,7 +869,6 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, shapes, targs ir.CurFunc = newf assert(len(tparams) == len(shapes)) - assert(len(tparams) == len(targs)) subst := &subster{ g: g, @@ -883,11 +880,6 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, shapes, targs Targs: shapes, Vars: make(map[*ir.Name]*ir.Name), }, - unshapify: typecheck.Tsubster{ - Tparams: shapes, - Targs: targs, - Vars: make(map[*ir.Name]*ir.Name), - }, } newf.Dcl = make([]*ir.Name, 0, len(gf.Dcl)+1) @@ -935,14 +927,14 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, shapes, targs newf.Body = subst.list(gf.Body) // Add code to check that the dictionary is correct. - // TODO: must go away when we move to many->1 shape to concrete mapping. - newf.Body.Prepend(subst.checkDictionary(dictionaryName, targs)...) + // TODO: must be adjusted to deal with shapes, but will go away soon when we move + // to many->1 shape to concrete mapping. + // newf.Body.Prepend(subst.checkDictionary(dictionaryName, shapes)...) ir.CurFunc = savef // Add any new, fully instantiated types seen during the substitution to // g.instTypeList. g.instTypeList = append(g.instTypeList, subst.ts.InstTypeList...) - g.instTypeList = append(g.instTypeList, subst.unshapify.InstTypeList...) if doubleCheck { okConvs := map[ir.Node]bool{} @@ -967,12 +959,6 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, shapes, targs return newf } -func (subst *subster) unshapifyTyp(t *types.Type) *types.Type { - res := subst.unshapify.Typ(t) - types.CheckSize(res) - return res -} - // localvar creates a new name node for the specified local variable and enters it // in subst.vars. It substitutes type arguments for type parameters in the type of // name as needed. @@ -1012,10 +998,7 @@ func (subst *subster) checkDictionary(name *ir.Name, targs []*types.Type) (code for i, t := range targs { if t.HasShape() { // Check the concrete type, not the shape type. - // TODO: can this happen? - //t = subst.unshapify.Typ(t) base.Fatalf("shape type in dictionary %s %+v\n", name.Sym().Name, t) - continue } want := reflectdata.TypePtr(t) typed(types.Types[types.TUINTPTR], want) @@ -1239,7 +1222,6 @@ func (subst *subster) node(n ir.Node) ir.Node { // transform the call. call.X.(*ir.SelectorExpr).SetOp(ir.OXDOT) transformDot(call.X.(*ir.SelectorExpr), true) - call.X.SetType(subst.unshapifyTyp(call.X.Type())) transformCall(call) case ir.ODOT, ir.ODOTPTR: @@ -1367,15 +1349,6 @@ func (subst *subster) node(n ir.Node) ir.Node { m = ir.NewDynamicTypeAssertExpr(dt.Pos(), op, dt.X, rt) m.SetType(dt.Type()) m.SetTypecheck(1) - - case ir.OFUNCINST: - inst := m.(*ir.InstExpr) - targs2 := make([]ir.Node, len(inst.Targs)) - for i, n := range inst.Targs { - targs2[i] = ir.TypeNodeAt(n.Pos(), subst.unshapifyTyp(n.Type())) - // TODO: need an ir.Name node? - } - inst.Targs = targs2 } return m } From 1d35d8ffa5561d1b69ede515c94c2785eaf29e1f Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 29 Jul 2021 15:58:13 -0700 Subject: [PATCH 819/940] [dev.typeparams] cmd/compile: switch unified IR from TypeParam.Bound to TypeParam.Constraint Change-Id: Id68d41f09e78343953167cb1e38fb1ebc41a34d4 Reviewed-on: https://go-review.googlesource.com/c/go/+/338429 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky Reviewed-by: Robert Griesemer TryBot-Result: Go Bot --- src/cmd/compile/internal/noder/writer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go index 0fc7e4f38ce..07d4363f898 100644 --- a/src/cmd/compile/internal/noder/writer.go +++ b/src/cmd/compile/internal/noder/writer.go @@ -618,7 +618,7 @@ func (w *writer) objDict(obj types2.Object, dict *writerDict) { ntparams := tparams.Len() w.len(ntparams) for i := 0; i < ntparams; i++ { - w.typ(tparams.At(i).Type().(*types2.TypeParam).Bound()) + w.typ(tparams.At(i).Type().(*types2.TypeParam).Constraint()) } nderived := len(dict.derived) From 3e7571f6ffb65a7d45c8035f7f8d2409bfda3307 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 29 Jul 2021 16:01:30 -0700 Subject: [PATCH 820/940] [dev.typeparams] go/types,cmd/compile/internal/types2: fix TypeParams.At docs Presumably the "It is safe to call on a nil receiver" comment was mistakenly copied from TypeParams.Len, which is actually safe to call on a nil receiver. Change-Id: Iec5ae32c98dc91ce84a6207b47f2b1e530bdbfe2 Reviewed-on: https://go-review.googlesource.com/c/go/+/338430 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types2/typeparam.go | 1 - src/go/types/typeparam.go | 1 - 2 files changed, 2 deletions(-) diff --git a/src/cmd/compile/internal/types2/typeparam.go b/src/cmd/compile/internal/types2/typeparam.go index 9f8c921bf17..2614f467b15 100644 --- a/src/cmd/compile/internal/types2/typeparam.go +++ b/src/cmd/compile/internal/types2/typeparam.go @@ -108,7 +108,6 @@ func (tps *TypeParams) Len() int { } // At returns the i'th type parameter in the list. -// It is safe to call on a nil receiver. func (tps *TypeParams) At(i int) *TypeName { return tps.list()[i] } diff --git a/src/go/types/typeparam.go b/src/go/types/typeparam.go index 8c18b52a9a9..a3d60c16486 100644 --- a/src/go/types/typeparam.go +++ b/src/go/types/typeparam.go @@ -98,7 +98,6 @@ func (tps *TypeParams) Len() int { } // At returns the i'th type parameter in the list. -// It is safe to call on a nil receiver. func (tps *TypeParams) At(i int) *TypeName { return tps.list()[i] } From 27283d208f1757f388ac84d2989e24ee3edcb869 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Thu, 29 Jul 2021 13:36:36 -0700 Subject: [PATCH 821/940] [dev.typeparams] cmd/compile: remove now-unneeded check for '==' method for comparable type Comparable type no longer has a special method '=='. Change-Id: I152f324d83343a66300050479181a6607fb7ca26 Reviewed-on: https://go-review.googlesource.com/c/go/+/338409 Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall Trust: Dan Scales --- src/runtime/iface.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/runtime/iface.go b/src/runtime/iface.go index 71bd2d2f072..79a49c0dffb 100644 --- a/src/runtime/iface.go +++ b/src/runtime/iface.go @@ -214,16 +214,6 @@ imethods: if ipkg == "" { ipkg = inter.pkgpath.name() } - if iname == "==" { - // Don't need '==' method right now (from comparable), - // just fill in with a random pointer for now. - if k == 0 { - fun0 = unsafe.Pointer(m) - } else { - methods[k] = unsafe.Pointer(m) - } - continue imethods - } for ; j < nt; j++ { t := &xmhdr[j] tname := typ.nameOff(t.name) From 4480e3b11ab6dcd8d4c6a1e87388f573ff49f429 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 29 Jul 2021 16:39:49 -0400 Subject: [PATCH 822/940] [dev.typeparams] go/types: backport lazy loading changes from CL 336252 When CL 336252 was created (itself a port of CL 335929), types2 tests revealed that lazy expansion of instances was not behaving correctly with respect to lazy loading of Named types. This CL ports the fixes from CL 336252 back to go/types. Change-Id: Iffc6c84a708449633153b800dfb98ff57402893c Reviewed-on: https://go-review.googlesource.com/c/go/+/338369 Trust: Robert Findley Trust: Robert Griesemer Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/decl.go | 4 +-- src/go/types/instance.go | 29 ++++++++++++---------- src/go/types/instantiate.go | 11 ++++++--- src/go/types/lookup.go | 2 +- src/go/types/named.go | 49 +++++++++++++++++++++---------------- src/go/types/predicates.go | 2 +- src/go/types/sizeof_test.go | 2 +- src/go/types/subst.go | 2 +- src/go/types/typestring.go | 3 +++ 9 files changed, 61 insertions(+), 43 deletions(-) diff --git a/src/go/types/decl.go b/src/go/types/decl.go index ad88c302820..831b1da5896 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -317,7 +317,7 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo { } case *Named: - t.complete() + t.expand() // don't touch the type if it is from a different package or the Universe scope // (doing so would lead to a race condition - was issue #35049) if t.obj.pkg != check.pkg { @@ -747,7 +747,7 @@ func (check *Checker) collectMethods(obj *TypeName) { } if base != nil { - base.expand() // TODO(mdempsky): Probably unnecessary. + base.load() // TODO(mdempsky): Probably unnecessary. base.methods = append(base.methods, m) } } diff --git a/src/go/types/instance.go b/src/go/types/instance.go index 5e0447b4341..1223c9f6f18 100644 --- a/src/go/types/instance.go +++ b/src/go/types/instance.go @@ -8,34 +8,37 @@ package types import "go/token" -// instance holds a Checker along with syntactic information -// information, for use in lazy instantiation. +// instance holds position information for use in lazy instantiation. +// +// TODO(rfindley): come up with a better name for this type, now that its usage +// has changed. type instance struct { - check *Checker pos token.Pos // position of type instantiation; for error reporting only posList []token.Pos // position of each targ; for error reporting only } -// complete ensures that the underlying type of n is instantiated. +// expand ensures that the underlying type of n is instantiated. // The underlying type will be Typ[Invalid] if there was an error. // TODO(rfindley): expand would be a better name for this method, but conflicts // with the existing concept of lazy expansion. Need to reconcile this. -func (n *Named) complete() { - if n.instance != nil && len(n.targs) > 0 && n.underlying == nil { - check := n.instance.check - inst := check.instantiate(n.instance.pos, n.orig.underlying, n.TParams().list(), n.targs, n.instance.posList) +func (n *Named) expand() { + if n.instance != nil { + // n must be loaded before instantiation, in order to have accurate + // tparams. This is done implicitly by the call to n.TParams, but making it + // explicit is harmless: load is idempotent. + n.load() + inst := n.check.instantiate(n.instance.pos, n.orig.underlying, n.TParams().list(), n.targs, n.instance.posList) n.underlying = inst n.fromRHS = inst - n.methods = n.orig.methods + n.instance = nil } } -// expand expands a type instance into its instantiated -// type and leaves all other types alone. expand does -// not recurse. +// expand expands uninstantiated named types and leaves all other types alone. +// expand does not recurse. func expand(typ Type) Type { if t, _ := typ.(*Named); t != nil { - t.complete() + t.expand() } return typ } diff --git a/src/go/types/instantiate.go b/src/go/types/instantiate.go index 1d3bbc26671..28d68cad0ef 100644 --- a/src/go/types/instantiate.go +++ b/src/go/types/instantiate.go @@ -105,7 +105,9 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, tparams []*TypeName, // instantiating the type until needed. typ must be a *Named // type. func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type, posList []token.Pos, verify bool) Type { - base := asNamed(typ) + // Don't use asNamed here: we don't want to expand the base during lazy + // instantiation. + base := typ.(*Named) if base == nil { panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) } @@ -116,15 +118,18 @@ func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type, pos } h := instantiatedHash(base, targs) if check != nil { + // typ may already have been instantiated with identical type arguments. In + // that case, re-use the existing instance. if named := check.typMap[h]; named != nil { return named } } tname := NewTypeName(pos, base.obj.pkg, base.obj.name, nil) - named := check.newNamed(tname, base, nil, base.TParams(), base.methods) // methods are instantiated lazily + named := check.newNamed(tname, base, nil, nil, nil) // methods and tparams are set when named is loaded. named.targs = targs - named.instance = &instance{check, pos, posList} + named.instance = &instance{pos, posList} + if check != nil { check.typMap[h] = named } diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go index 8b1d70a9784..07baf2a48b6 100644 --- a/src/go/types/lookup.go +++ b/src/go/types/lookup.go @@ -121,7 +121,7 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o seen[named] = true // look for a matching attached method - named.expand() + named.load() if i, m := lookupMethod(named.methods, pkg, name); m != nil { // potential match // caution: method may not have a proper signature yet diff --git a/src/go/types/named.go b/src/go/types/named.go index 03af3fbc5aa..87eaa3179e8 100644 --- a/src/go/types/named.go +++ b/src/go/types/named.go @@ -10,12 +10,13 @@ import "sync" // A Named represents a named (defined) type. type Named struct { - instance *instance // syntactic information for lazy instantiation + check *Checker info typeInfo // for cycle detection obj *TypeName // corresponding declared object orig *Named // original, uninstantiated type fromRHS Type // type (on RHS of declaration) this *Named type is derived of (for cycle reporting) underlying Type // possibly a *Named during setup; never a *Named once set up completely + instance *instance // syntactic information for lazy instantiation tparams *TypeParams // type parameters, or nil targs []Type // type arguments (after instantiation), or nil methods []*Func // methods declared for this type (not the method set of this type); signatures are type-checked lazily @@ -34,7 +35,19 @@ func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named { return (*Checker)(nil).newNamed(obj, nil, underlying, nil, methods) } -func (t *Named) expand() *Named { +func (t *Named) load() *Named { + // If t is an instantiated type, it derives its methods and tparams from its + // base type. Since we expect type parameters and methods to be set after a + // call to load, we must load the base and copy here. + // + // underlying is set when t is expanded. + // + // By convention, a type instance is loaded iff its tparams are set. + if len(t.targs) > 0 && t.tparams == nil { + t.orig.load() + t.tparams = t.orig.tparams + t.methods = t.orig.methods + } if t.resolve == nil { return t } @@ -65,13 +78,7 @@ func (t *Named) expand() *Named { // newNamed is like NewNamed but with a *Checker receiver and additional orig argument. func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams *TypeParams, methods []*Func) *Named { - var inst *instance - if check != nil { - inst = &instance{ - check: check, - } - } - typ := &Named{instance: inst, obj: obj, orig: orig, fromRHS: underlying, underlying: underlying, tparams: tparams, methods: methods} + typ := &Named{check: check, obj: obj, orig: orig, fromRHS: underlying, underlying: underlying, tparams: tparams, methods: methods} if typ.orig == nil { typ.orig = typ } @@ -92,7 +99,7 @@ func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tpar case *Named: panic("internal error: unexpanded underlying type") } - typ.instance = nil + typ.check = nil }) } return typ @@ -110,10 +117,10 @@ func (t *Named) _Orig() *Named { return t.orig } // TParams returns the type parameters of the named type t, or nil. // The result is non-nil for an (originally) parameterized type even if it is instantiated. -func (t *Named) TParams() *TypeParams { return t.expand().tparams } +func (t *Named) TParams() *TypeParams { return t.load().tparams } // SetTParams sets the type parameters of the named type t. -func (t *Named) SetTParams(tparams []*TypeName) { t.expand().tparams = bindTParams(tparams) } +func (t *Named) SetTParams(tparams []*TypeName) { t.load().tparams = bindTParams(tparams) } // TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated. func (t *Named) TArgs() []Type { return t.targs } @@ -122,10 +129,10 @@ func (t *Named) TArgs() []Type { return t.targs } func (t *Named) SetTArgs(args []Type) { t.targs = args } // NumMethods returns the number of explicit methods whose receiver is named type t. -func (t *Named) NumMethods() int { return len(t.expand().methods) } +func (t *Named) NumMethods() int { return len(t.load().methods) } // Method returns the i'th method of named type t for 0 <= i < t.NumMethods(). -func (t *Named) Method(i int) *Func { return t.expand().methods[i] } +func (t *Named) Method(i int) *Func { return t.load().methods[i] } // SetUnderlying sets the underlying type and marks t as complete. func (t *Named) SetUnderlying(underlying Type) { @@ -135,18 +142,18 @@ func (t *Named) SetUnderlying(underlying Type) { if _, ok := underlying.(*Named); ok { panic("types.Named.SetUnderlying: underlying type must not be *Named") } - t.expand().underlying = underlying + t.load().underlying = underlying } // AddMethod adds method m unless it is already in the method list. func (t *Named) AddMethod(m *Func) { - t.expand() + t.load() if i, _ := lookupMethod(t.methods, m.pkg, m.name); i < 0 { t.methods = append(t.methods, m) } } -func (t *Named) Underlying() Type { return t.expand().underlying } +func (t *Named) Underlying() Type { return t.load().underlying } func (t *Named) String() string { return TypeString(t, nil) } // ---------------------------------------------------------------------------- @@ -159,7 +166,7 @@ func (t *Named) String() string { return TypeString(t, nil) } // is detected, the result is Typ[Invalid]. If a cycle is detected and // n0.check != nil, the cycle is reported. func (n0 *Named) under() Type { - n0.complete() + n0.expand() u := n0.Underlying() @@ -180,13 +187,13 @@ func (n0 *Named) under() Type { // handled below } - if n0.instance == nil || n0.instance.check == nil { + if n0.check == nil { panic("internal error: Named.check == nil but type is incomplete") } // Invariant: after this point n0 as well as any named types in its // underlying chain should be set up when this function exits. - check := n0.instance.check + check := n0.check // If we can't expand u at this point, it is invalid. n := asNamed(u) @@ -207,7 +214,7 @@ func (n0 *Named) under() Type { var n1 *Named switch u1 := u.(type) { case *Named: - u1.complete() + u1.expand() n1 = u1 } if n1 == nil { diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index 181e2fcfc54..41e0c25d6bc 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -21,7 +21,7 @@ func isNamed(typ Type) bool { func isGeneric(typ Type) bool { // A parameterized type is only instantiated if it doesn't have an instantiation already. named, _ := typ.(*Named) - return named != nil && named.obj != nil && named.TParams() != nil && named.targs == nil + return named != nil && named.obj != nil && named.targs == nil && named.TParams() != nil } func is(typ Type, what BasicInfo) bool { diff --git a/src/go/types/sizeof_test.go b/src/go/types/sizeof_test.go index 29e298103bf..c8758663ec0 100644 --- a/src/go/types/sizeof_test.go +++ b/src/go/types/sizeof_test.go @@ -30,7 +30,7 @@ func TestSizeof(t *testing.T) { {Interface{}, 40, 80}, {Map{}, 16, 32}, {Chan{}, 12, 24}, - {Named{}, 76, 144}, + {Named{}, 80, 152}, {TypeParam{}, 28, 48}, {top{}, 0, 0}, diff --git a/src/go/types/subst.go b/src/go/types/subst.go index 60fc7ae8192..c05e51d4250 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -244,7 +244,7 @@ func (subst *subster) typ(typ Type) Type { named := subst.check.newNamed(tname, t, t.Underlying(), t.TParams(), t.methods) // method signatures are updated lazily named.targs = newTargs subst.typMap[h] = named - t.complete() // must happen after typMap update to avoid infinite recursion + t.expand() // must happen after typMap update to avoid infinite recursion // do the substitution dump(">>> subst %s with %s (new: %s)", t.underlying, subst.smap, newTargs) diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go index 6a9e7f2ac89..74b18a9ec83 100644 --- a/src/go/types/typestring.go +++ b/src/go/types/typestring.go @@ -270,6 +270,9 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { } case *Named: + if t.instance != nil { + buf.WriteByte(instanceMarker) + } writeTypeName(buf, t.obj, qf) if t.targs != nil { // instantiated type From b7a85e0003cedb1b48a1fd3ae5b746ec6330102e Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Wed, 7 Jul 2021 16:34:34 -0700 Subject: [PATCH 823/940] net/http/httputil: close incoming ReverseProxy request body Reading from an incoming request body after the request handler aborts with a panic can cause a panic, becuse http.Server does not (contrary to its documentation) close the request body in this case. Always close the incoming request body in ReverseProxy.ServeHTTP to ensure that any in-flight outgoing requests using the body do not read from it. Updates #46866 Fixes CVE-2021-36221 Change-Id: I310df269200ad8732c5d9f1a2b00de68725831df Reviewed-on: https://go-review.googlesource.com/c/go/+/333191 Trust: Damien Neil Reviewed-by: Brad Fitzpatrick Reviewed-by: Filippo Valsorda --- src/net/http/httputil/reverseproxy.go | 9 +++++ src/net/http/httputil/reverseproxy_test.go | 39 ++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/net/http/httputil/reverseproxy.go b/src/net/http/httputil/reverseproxy.go index 5d39955d62d..8b63368386f 100644 --- a/src/net/http/httputil/reverseproxy.go +++ b/src/net/http/httputil/reverseproxy.go @@ -235,6 +235,15 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { if req.ContentLength == 0 { outreq.Body = nil // Issue 16036: nil Body for http.Transport retries } + if outreq.Body != nil { + // Reading from the request body after returning from a handler is not + // allowed, and the RoundTrip goroutine that reads the Body can outlive + // this handler. This can lead to a crash if the handler panics (see + // Issue 46866). Although calling Close doesn't guarantee there isn't + // any Read in flight after the handle returns, in practice it's safe to + // read after closing it. + defer outreq.Body.Close() + } if outreq.Header == nil { outreq.Header = make(http.Header) // Issue 33142: historical behavior was to always allocate } diff --git a/src/net/http/httputil/reverseproxy_test.go b/src/net/http/httputil/reverseproxy_test.go index 1898ed8b8af..4b6ad77a294 100644 --- a/src/net/http/httputil/reverseproxy_test.go +++ b/src/net/http/httputil/reverseproxy_test.go @@ -1122,6 +1122,45 @@ func TestReverseProxy_PanicBodyError(t *testing.T) { rproxy.ServeHTTP(httptest.NewRecorder(), req) } +// Issue #46866: panic without closing incoming request body causes a panic +func TestReverseProxy_PanicClosesIncomingBody(t *testing.T) { + backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + out := "this call was relayed by the reverse proxy" + // Coerce a wrong content length to induce io.ErrUnexpectedEOF + w.Header().Set("Content-Length", fmt.Sprintf("%d", len(out)*2)) + fmt.Fprintln(w, out) + })) + defer backend.Close() + backendURL, err := url.Parse(backend.URL) + if err != nil { + t.Fatal(err) + } + proxyHandler := NewSingleHostReverseProxy(backendURL) + proxyHandler.ErrorLog = log.New(io.Discard, "", 0) // quiet for tests + frontend := httptest.NewServer(proxyHandler) + defer frontend.Close() + frontendClient := frontend.Client() + + var wg sync.WaitGroup + for i := 0; i < 2; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for j := 0; j < 10; j++ { + const reqLen = 6 * 1024 * 1024 + req, _ := http.NewRequest("POST", frontend.URL, &io.LimitedReader{R: neverEnding('x'), N: reqLen}) + req.ContentLength = reqLen + resp, _ := frontendClient.Transport.RoundTrip(req) + if resp != nil { + io.Copy(io.Discard, resp.Body) + resp.Body.Close() + } + } + }() + } + wg.Wait() +} + func TestSelectFlushInterval(t *testing.T) { tests := []struct { name string From ea94e5d3c57fadea088cdc5002e014b3c7ef4bc1 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 23 Jul 2021 15:03:00 -0400 Subject: [PATCH 824/940] [dev.typeparams] runtime: use func() for deferred functions Prior to regabi, a deferred function could have any signature, so the runtime always manipulated them as funcvals. Now, a deferred function is always func(). Hence, this CL makes the runtime's manipulation of deferred functions more type-safe by using func() directly instead of *funcval. Change-Id: Ib55f38ed49107f74149725c65044e4690761971d Reviewed-on: https://go-review.googlesource.com/c/go/+/337650 Trust: Austin Clements Run-TryBot: Austin Clements TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/runtime/asm_amd64.s | 2 +- src/runtime/asm_riscv64.s | 2 +- src/runtime/heapdump.go | 5 +++-- src/runtime/panic.go | 28 +++++++++------------------- src/runtime/runtime2.go | 8 ++++---- src/runtime/stubs.go | 2 +- 6 files changed, 19 insertions(+), 28 deletions(-) diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index 50ffa30ac56..0f719b2664a 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -662,7 +662,7 @@ TEXT ·publicationBarrier(SB),NOSPLIT,$0-0 // compile barrier. RET -// func jmpdefer(fv *funcval, argp uintptr) +// func jmpdefer(fv func(), argp uintptr) // argp is a caller SP. // called from deferreturn. // 1. pop the caller diff --git a/src/runtime/asm_riscv64.s b/src/runtime/asm_riscv64.s index 69ab88f1d2c..9957ae201bc 100644 --- a/src/runtime/asm_riscv64.s +++ b/src/runtime/asm_riscv64.s @@ -248,7 +248,7 @@ TEXT gogo<>(SB), NOSPLIT|NOFRAME, $0 MOV gobuf_pc(T0), T0 JALR ZERO, T0 -// func jmpdefer(fv *funcval, argp uintptr) +// func jmpdefer(fv func(), argp uintptr) // called from deferreturn // 1. grab stored return address from the caller's frame // 2. sub 8 bytes to get back to JAL deferreturn diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go index 18e4666fa40..8fb30d95b9b 100644 --- a/src/runtime/heapdump.go +++ b/src/runtime/heapdump.go @@ -381,12 +381,13 @@ func dumpgoroutine(gp *g) { dumpint(uint64(uintptr(unsafe.Pointer(gp)))) dumpint(uint64(d.sp)) dumpint(uint64(d.pc)) - dumpint(uint64(uintptr(unsafe.Pointer(d.fn)))) + fn := *(**funcval)(unsafe.Pointer(&d.fn)) + dumpint(uint64(uintptr(unsafe.Pointer(fn)))) if d.fn == nil { // d.fn can be nil for open-coded defers dumpint(uint64(0)) } else { - dumpint(uint64(uintptr(unsafe.Pointer(d.fn.fn)))) + dumpint(uint64(uintptr(unsafe.Pointer(fn.fn)))) } dumpint(uint64(uintptr(unsafe.Pointer(d.link)))) } diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 85d39b92508..35f3b44a4d5 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -227,7 +227,7 @@ func panicmemAddr(addr uintptr) { // Create a new deferred function fn, which has no arguments and results. // The compiler turns a defer statement into a call to this. -func deferproc(fn *funcval) { // TODO: Make deferproc just take a func(). +func deferproc(fn func()) { gp := getg() if gp.m.curg != gp { // go code on the system stack can't defer @@ -303,16 +303,6 @@ func deferprocStack(d *_defer) { // been set and must not be clobbered. } -// deferFunc returns d's deferred function. This is temporary while we -// support both modes of GOEXPERIMENT=regabidefer. Once we commit to -// that experiment, we should change the type of d.fn. -//go:nosplit -func deferFunc(d *_defer) func() { - var fn func() - *(**funcval)(unsafe.Pointer(&fn)) = d.fn - return fn -} - // Each P holds a pool for defers. // Allocate a Defer, usually using per-P pool. @@ -470,9 +460,8 @@ func deferreturn() { // If the defer function pointer is nil, force the seg fault to happen // here rather than in jmpdefer. gentraceback() throws an error if it is // called with a callback on an LR architecture and jmpdefer is on the - // stack, because the stack trace can be incorrect in that case - see - // issue #8153). - _ = fn.fn + // stack, because jmpdefer manipulates SP (see issue #8153). + _ = **(**funcval)(unsafe.Pointer(&fn)) jmpdefer(fn, argp) } @@ -536,7 +525,7 @@ func Goexit() { } else { // Save the pc/sp in deferCallSave(), so we can "recover" back to this // loop if necessary. - deferCallSave(&p, deferFunc(d)) + deferCallSave(&p, d.fn) } if p.aborted { // We had a recursive panic in the defer d we started, and @@ -728,12 +717,14 @@ func runOpenDeferFrame(gp *g, d *_defer) bool { if deferBits&(1< Date: Mon, 26 Jul 2021 12:04:36 -0400 Subject: [PATCH 825/940] [dev.typeparams] runtime: remove unnecessary split-prevention from defer code Prior to regabi, the compiler passed defer arguments to the runtime as untyped values on the stack. This meant a lot of defer-related runtime functions had to be very careful not to grow the stack or allow preemption since the stack could not be safely scanned or moved. However, with regabi, every defer is now simply a func() from the runtime's perspective, which means we no longer have untyped values on the stack when we enter defer-related runtime code. Hence, this CL removes a lot of the now-unnecessary carefulness in the defer implementation. Specifically, deferreturn no longer needs to be nosplit because it doesn't copy untyped defer arguments to its caller's frame (we also update some stale comments in deferreturn). freedefer no longer needs to be nosplit because it's none of its callers are deeply nosplit. And newdefer and freedefer no longer need to switch to the systemstack on their slow paths to avoid stack growth. deferprocStack is the only function that still needs to be nosplit, but that's because the compiler calls it with uninitialized live pointer slots on the stack (maybe we should change that, but that's a very different fix). Change-Id: I1156ec90bff2613fe4b48b84b375943349ce637d Reviewed-on: https://go-review.googlesource.com/c/go/+/337651 Trust: Austin Clements Run-TryBot: Austin Clements TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/runtime/panic.go | 84 +++++++++++++++----------------------------- 1 file changed, 29 insertions(+), 55 deletions(-) diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 35f3b44a4d5..e66fe27be0b 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -261,10 +261,8 @@ func deferproc(fn func()) { // deferprocStack queues a new deferred function with a defer record on the stack. // The defer record must have its fn field initialized. // All other fields can contain junk. -// The defer record must be immediately followed in memory by -// the arguments of the defer. -// Nosplit because the arguments on the stack won't be scanned -// until the defer record is spliced into the gp._defer list. +// Nosplit because of the uninitialized pointer fields on the stack. +// //go:nosplit func deferprocStack(d *_defer) { gp := getg() @@ -313,18 +311,14 @@ func newdefer() *_defer { gp := getg() pp := gp.m.p.ptr() if len(pp.deferpool) == 0 && sched.deferpool != nil { - // Take the slow path on the system stack so - // we don't grow newdefer's stack. - systemstack(func() { - lock(&sched.deferlock) - for len(pp.deferpool) < cap(pp.deferpool)/2 && sched.deferpool != nil { - d := sched.deferpool - sched.deferpool = d.link - d.link = nil - pp.deferpool = append(pp.deferpool, d) - } - unlock(&sched.deferlock) - }) + lock(&sched.deferlock) + for len(pp.deferpool) < cap(pp.deferpool)/2 && sched.deferpool != nil { + d := sched.deferpool + sched.deferpool = d.link + d.link = nil + pp.deferpool = append(pp.deferpool, d) + } + unlock(&sched.deferlock) } if n := len(pp.deferpool); n > 0 { d = pp.deferpool[n-1] @@ -341,11 +335,6 @@ func newdefer() *_defer { // Free the given defer. // The defer cannot be used after this call. -// -// This must not grow the stack because there may be a frame without a -// stack map when this is called. -// -//go:nosplit func freedefer(d *_defer) { if d._panic != nil { freedeferpanic() @@ -359,28 +348,23 @@ func freedefer(d *_defer) { pp := getg().m.p.ptr() if len(pp.deferpool) == cap(pp.deferpool) { // Transfer half of local cache to the central cache. - // - // Take this slow path on the system stack so - // we don't grow freedefer's stack. - systemstack(func() { - var first, last *_defer - for len(pp.deferpool) > cap(pp.deferpool)/2 { - n := len(pp.deferpool) - d := pp.deferpool[n-1] - pp.deferpool[n-1] = nil - pp.deferpool = pp.deferpool[:n-1] - if first == nil { - first = d - } else { - last.link = d - } - last = d + var first, last *_defer + for len(pp.deferpool) > cap(pp.deferpool)/2 { + n := len(pp.deferpool) + d := pp.deferpool[n-1] + pp.deferpool[n-1] = nil + pp.deferpool = pp.deferpool[:n-1] + if first == nil { + first = d + } else { + last.link = d } - lock(&sched.deferlock) - last.link = sched.deferpool - sched.deferpool = first - unlock(&sched.deferlock) - }) + last = d + } + lock(&sched.deferlock) + last.link = sched.deferpool + sched.deferpool = first + unlock(&sched.deferlock) } // These lines used to be simply `*d = _defer{}` but that @@ -420,12 +404,6 @@ func freedeferfn() { // to have been called by the caller of deferreturn at the point // just before deferreturn was called. The effect is that deferreturn // is called again and again until there are no more deferred functions. -// -// Declared as nosplit, because the function should not be preempted once we start -// modifying the caller's frame in order to reuse the frame to call the deferred -// function. -// -//go:nosplit func deferreturn() { gp := getg() d := gp._defer @@ -446,13 +424,6 @@ func deferreturn() { return } - // Moving arguments around. - // - // Everything called after this point must be recursively - // nosplit because the garbage collector won't know the form - // of the arguments until the jmpdefer can flip the PC over to - // fn. - argp := getcallersp() + sys.MinFrameSize fn := d.fn d.fn = nil gp._defer = d.link @@ -462,6 +433,9 @@ func deferreturn() { // called with a callback on an LR architecture and jmpdefer is on the // stack, because jmpdefer manipulates SP (see issue #8153). _ = **(**funcval)(unsafe.Pointer(&fn)) + // We must not split the stack between computing argp and + // calling jmpdefer because argp is a uintptr stack pointer. + argp := getcallersp() + sys.MinFrameSize jmpdefer(fn, argp) } From fd0011dca5b35ec07ff53df4c3231a2a119796a9 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Mon, 26 Jul 2021 15:44:22 -0400 Subject: [PATCH 826/940] [dev.typeparams] runtime,cmd/compile,cmd/link: replace jmpdefer with a loop Currently, deferreturn runs deferred functions by backing up its return PC to the deferreturn call, and then effectively tail-calling the deferred function (via jmpdefer). The effect of this is that the deferred function appears to be called directly from the deferee, and when it returns, the deferee calls deferreturn again so it can run the next deferred function if necessary. This unusual flow control leads to a large number of special cases and complications all over the tool chain. This used to be necessary because deferreturn copied the deferred function's argument frame directly into its caller's frame and then had to invoke that call as if it had been called from its caller's frame so it could access it arguments. But now that we've simplified defer processing so the runtime only deals with argument-less closures, this approach is no longer necessary. This CL simplifies all of this by making deferreturn simply call deferred functions in a loop. This eliminates the need for jmpdefer, so we can delete a bunch of per-architecture assembly code. This eliminates several special cases on Wasm, since it couldn't support these calling shenanigans directly and thus had to simulate the loop a different way. Now Wasm can largely work the way the other platforms do. This eliminates the per-architecture Ginsnopdefer operation. On PPC64, this was necessary to reload the TOC pointer after the tail call (since TOC pointers in general make tail calls impossible). The tail call is gone, and in the case where we do force a jump to the deferreturn call when recovering from an open-coded defer, we go through gogo (via runtime.recovery), which handles the TOC. On other platforms, we needed a NOP so traceback didn't get confused by seeing the return to the CALL instruction, rather than the usual return to the instruction following the CALL instruction. Now we don't inject a return to the CALL instruction at all, so this NOP is also unnecessary. The one potential effect of this is that deferreturn could now appear in stack traces from deferred functions. However, this could already happen from open-coded defers, so we've long since marked deferreturn as a "wrapper" so it gets elided not only from printed stack traces, but from runtime.Callers*. Change-Id: Ie9f700cd3fb774f498c9edce363772a868407bf7 Reviewed-on: https://go-review.googlesource.com/c/go/+/337652 Trust: Austin Clements Run-TryBot: Austin Clements TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/cmd/compile/internal/amd64/galign.go | 1 - src/cmd/compile/internal/arm/galign.go | 1 - src/cmd/compile/internal/arm64/galign.go | 1 - src/cmd/compile/internal/mips/galign.go | 1 - src/cmd/compile/internal/mips64/galign.go | 1 - src/cmd/compile/internal/ppc64/galign.go | 1 - src/cmd/compile/internal/ppc64/ggen.go | 27 ---------- src/cmd/compile/internal/riscv64/galign.go | 1 - src/cmd/compile/internal/s390x/galign.go | 1 - src/cmd/compile/internal/ssagen/arch.go | 3 +- src/cmd/compile/internal/ssagen/ssa.go | 12 ----- src/cmd/compile/internal/wasm/ssa.go | 7 ++- src/cmd/compile/internal/x86/galign.go | 1 - src/cmd/internal/obj/arm/asm5.go | 11 ++-- src/cmd/internal/obj/wasm/wasmobj.go | 36 -------------- src/cmd/internal/obj/x86/asm6.go | 1 - src/cmd/internal/objabi/funcid.go | 2 - src/cmd/link/internal/ld/pcln.go | 9 ++-- src/runtime/asm_386.s | 20 -------- src/runtime/asm_amd64.s | 15 ------ src/runtime/asm_arm.s | 14 ------ src/runtime/asm_arm64.s | 17 ------- src/runtime/asm_mips64x.s | 16 ------ src/runtime/asm_mipsx.s | 16 ------ src/runtime/asm_ppc64x.s | 28 ----------- src/runtime/asm_riscv64.s | 15 ------ src/runtime/asm_s390x.s | 15 ------ src/runtime/asm_wasm.s | 29 ----------- src/runtime/panic.go | 58 ++++++++++------------ src/runtime/stubs.go | 2 - src/runtime/symtab.go | 1 - 31 files changed, 39 insertions(+), 324 deletions(-) diff --git a/src/cmd/compile/internal/amd64/galign.go b/src/cmd/compile/internal/amd64/galign.go index 3b13e123a74..ca44263afc4 100644 --- a/src/cmd/compile/internal/amd64/galign.go +++ b/src/cmd/compile/internal/amd64/galign.go @@ -18,7 +18,6 @@ func Init(arch *ssagen.ArchInfo) { arch.ZeroRange = zerorange arch.Ginsnop = ginsnop - arch.Ginsnopdefer = ginsnop arch.SSAMarkMoves = ssaMarkMoves arch.SSAGenValue = ssaGenValue diff --git a/src/cmd/compile/internal/arm/galign.go b/src/cmd/compile/internal/arm/galign.go index d68500280d0..23e52bacbf2 100644 --- a/src/cmd/compile/internal/arm/galign.go +++ b/src/cmd/compile/internal/arm/galign.go @@ -18,7 +18,6 @@ func Init(arch *ssagen.ArchInfo) { arch.SoftFloat = buildcfg.GOARM == 5 arch.ZeroRange = zerorange arch.Ginsnop = ginsnop - arch.Ginsnopdefer = ginsnop arch.SSAMarkMoves = func(s *ssagen.State, b *ssa.Block) {} arch.SSAGenValue = ssaGenValue diff --git a/src/cmd/compile/internal/arm64/galign.go b/src/cmd/compile/internal/arm64/galign.go index 2a61b9dd997..3ebd860de8f 100644 --- a/src/cmd/compile/internal/arm64/galign.go +++ b/src/cmd/compile/internal/arm64/galign.go @@ -18,7 +18,6 @@ func Init(arch *ssagen.ArchInfo) { arch.PadFrame = padframe arch.ZeroRange = zerorange arch.Ginsnop = ginsnop - arch.Ginsnopdefer = ginsnop arch.SSAMarkMoves = func(s *ssagen.State, b *ssa.Block) {} arch.SSAGenValue = ssaGenValue diff --git a/src/cmd/compile/internal/mips/galign.go b/src/cmd/compile/internal/mips/galign.go index f892923ba03..4e6897042ec 100644 --- a/src/cmd/compile/internal/mips/galign.go +++ b/src/cmd/compile/internal/mips/galign.go @@ -21,7 +21,6 @@ func Init(arch *ssagen.ArchInfo) { arch.SoftFloat = (buildcfg.GOMIPS == "softfloat") arch.ZeroRange = zerorange arch.Ginsnop = ginsnop - arch.Ginsnopdefer = ginsnop arch.SSAMarkMoves = func(s *ssagen.State, b *ssa.Block) {} arch.SSAGenValue = ssaGenValue arch.SSAGenBlock = ssaGenBlock diff --git a/src/cmd/compile/internal/mips64/galign.go b/src/cmd/compile/internal/mips64/galign.go index af81366e51b..412bc71aab2 100644 --- a/src/cmd/compile/internal/mips64/galign.go +++ b/src/cmd/compile/internal/mips64/galign.go @@ -21,7 +21,6 @@ func Init(arch *ssagen.ArchInfo) { arch.SoftFloat = buildcfg.GOMIPS64 == "softfloat" arch.ZeroRange = zerorange arch.Ginsnop = ginsnop - arch.Ginsnopdefer = ginsnop arch.SSAMarkMoves = func(s *ssagen.State, b *ssa.Block) {} arch.SSAGenValue = ssaGenValue diff --git a/src/cmd/compile/internal/ppc64/galign.go b/src/cmd/compile/internal/ppc64/galign.go index 590290fa371..bff3e38f42d 100644 --- a/src/cmd/compile/internal/ppc64/galign.go +++ b/src/cmd/compile/internal/ppc64/galign.go @@ -20,7 +20,6 @@ func Init(arch *ssagen.ArchInfo) { arch.ZeroRange = zerorange arch.Ginsnop = ginsnop - arch.Ginsnopdefer = ginsnopdefer arch.SSAMarkMoves = ssaMarkMoves arch.SSAGenValue = ssaGenValue diff --git a/src/cmd/compile/internal/ppc64/ggen.go b/src/cmd/compile/internal/ppc64/ggen.go index c76962cfb81..3ae6422bf9e 100644 --- a/src/cmd/compile/internal/ppc64/ggen.go +++ b/src/cmd/compile/internal/ppc64/ggen.go @@ -53,30 +53,3 @@ func ginsnop(pp *objw.Progs) *obj.Prog { p.To.Reg = ppc64.REG_R0 return p } - -func ginsnopdefer(pp *objw.Progs) *obj.Prog { - // On PPC64 two nops are required in the defer case. - // - // (see gc/cgen.go, gc/plive.go -- copy of comment below) - // - // On ppc64, when compiling Go into position - // independent code on ppc64le we insert an - // instruction to reload the TOC pointer from the - // stack as well. See the long comment near - // jmpdefer in runtime/asm_ppc64.s for why. - // If the MOVD is not needed, insert a hardware NOP - // so that the same number of instructions are used - // on ppc64 in both shared and non-shared modes. - - ginsnop(pp) - if base.Ctxt.Flag_shared { - p := pp.Prog(ppc64.AMOVD) - p.From.Type = obj.TYPE_MEM - p.From.Offset = 24 - p.From.Reg = ppc64.REGSP - p.To.Type = obj.TYPE_REG - p.To.Reg = ppc64.REG_R2 - return p - } - return ginsnop(pp) -} diff --git a/src/cmd/compile/internal/riscv64/galign.go b/src/cmd/compile/internal/riscv64/galign.go index 338248a7cf2..846ed8fb380 100644 --- a/src/cmd/compile/internal/riscv64/galign.go +++ b/src/cmd/compile/internal/riscv64/galign.go @@ -16,7 +16,6 @@ func Init(arch *ssagen.ArchInfo) { arch.MAXWIDTH = 1 << 50 arch.Ginsnop = ginsnop - arch.Ginsnopdefer = ginsnop arch.ZeroRange = zeroRange arch.SSAMarkMoves = ssaMarkMoves diff --git a/src/cmd/compile/internal/s390x/galign.go b/src/cmd/compile/internal/s390x/galign.go index b004a2db0a3..d880834c220 100644 --- a/src/cmd/compile/internal/s390x/galign.go +++ b/src/cmd/compile/internal/s390x/galign.go @@ -16,7 +16,6 @@ func Init(arch *ssagen.ArchInfo) { arch.ZeroRange = zerorange arch.Ginsnop = ginsnop - arch.Ginsnopdefer = ginsnop arch.SSAMarkMoves = ssaMarkMoves arch.SSAGenValue = ssaGenValue diff --git a/src/cmd/compile/internal/ssagen/arch.go b/src/cmd/compile/internal/ssagen/arch.go index 957fb3e84a9..483e45cad43 100644 --- a/src/cmd/compile/internal/ssagen/arch.go +++ b/src/cmd/compile/internal/ssagen/arch.go @@ -29,8 +29,7 @@ type ArchInfo struct { // at function entry, and it is ok to clobber registers. ZeroRange func(*objw.Progs, *obj.Prog, int64, int64, *uint32) *obj.Prog - Ginsnop func(*objw.Progs) *obj.Prog - Ginsnopdefer func(*objw.Progs) *obj.Prog // special ginsnop for deferreturn + Ginsnop func(*objw.Progs) *obj.Prog // SSAMarkMoves marks any MOVXconst ops that need to avoid clobbering flags. SSAMarkMoves func(*State, *ssa.Block) diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 7e2f6a7471c..161469ea67c 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -7335,18 +7335,6 @@ func (s *State) PrepareCall(v *ssa.Value) { call, ok := v.Aux.(*ssa.AuxCall) - if ok && call.Fn == ir.Syms.Deferreturn { - // Deferred calls will appear to be returning to - // the CALL deferreturn(SB) that we are about to emit. - // However, the stack trace code will show the line - // of the instruction byte before the return PC. - // To avoid that being an unrelated instruction, - // insert an actual hardware NOP that will have the right line number. - // This is different from obj.ANOP, which is a virtual no-op - // that doesn't make it into the instruction stream. - Arch.Ginsnopdefer(s.pp) - } - if ok { // Record call graph information for nowritebarrierrec // analysis. diff --git a/src/cmd/compile/internal/wasm/ssa.go b/src/cmd/compile/internal/wasm/ssa.go index 31b09016eb9..0b2ca3fdbb8 100644 --- a/src/cmd/compile/internal/wasm/ssa.go +++ b/src/cmd/compile/internal/wasm/ssa.go @@ -24,7 +24,6 @@ func Init(arch *ssagen.ArchInfo) { arch.ZeroRange = zeroRange arch.Ginsnop = ginsnop - arch.Ginsnopdefer = ginsnop arch.SSAMarkMoves = ssaMarkMoves arch.SSAGenValue = ssaGenValue @@ -126,7 +125,11 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { case ssa.OpWasmLoweredStaticCall, ssa.OpWasmLoweredClosureCall, ssa.OpWasmLoweredInterCall: s.PrepareCall(v) if call, ok := v.Aux.(*ssa.AuxCall); ok && call.Fn == ir.Syms.Deferreturn { - // add a resume point before call to deferreturn so it can be called again via jmpdefer + // The runtime needs to inject jumps to + // deferreturn calls using the address in + // _func.deferreturn. Hence, the call to + // deferreturn must itself be a resumption + // point so it gets a target PC. s.Prog(wasm.ARESUMEPOINT) } if v.Op == ssa.OpWasmLoweredClosureCall { diff --git a/src/cmd/compile/internal/x86/galign.go b/src/cmd/compile/internal/x86/galign.go index 00a20e429f1..5565bd32c76 100644 --- a/src/cmd/compile/internal/x86/galign.go +++ b/src/cmd/compile/internal/x86/galign.go @@ -34,7 +34,6 @@ func Init(arch *ssagen.ArchInfo) { arch.ZeroRange = zerorange arch.Ginsnop = ginsnop - arch.Ginsnopdefer = ginsnop arch.SSAMarkMoves = ssaMarkMoves } diff --git a/src/cmd/internal/obj/arm/asm5.go b/src/cmd/internal/obj/arm/asm5.go index ccf5f9e7f8d..7b1682776e5 100644 --- a/src/cmd/internal/obj/arm/asm5.go +++ b/src/cmd/internal/obj/arm/asm5.go @@ -355,11 +355,10 @@ var oprange [ALAST & obj.AMask][]Optab var xcmp [C_GOK + 1][C_GOK + 1]bool var ( - deferreturn *obj.LSym - symdiv *obj.LSym - symdivu *obj.LSym - symmod *obj.LSym - symmodu *obj.LSym + symdiv *obj.LSym + symdivu *obj.LSym + symmod *obj.LSym + symmodu *obj.LSym ) // Note about encoding: Prog.scond holds the condition encoding, @@ -1219,8 +1218,6 @@ func buildop(ctxt *obj.Link) { return } - deferreturn = ctxt.LookupABI("runtime.deferreturn", obj.ABIInternal) - symdiv = ctxt.Lookup("runtime._div") symdivu = ctxt.Lookup("runtime._divu") symmod = ctxt.Lookup("runtime._mod") diff --git a/src/cmd/internal/obj/wasm/wasmobj.go b/src/cmd/internal/obj/wasm/wasmobj.go index ceeae7a257c..4d276db6780 100644 --- a/src/cmd/internal/obj/wasm/wasmobj.go +++ b/src/cmd/internal/obj/wasm/wasmobj.go @@ -129,8 +129,6 @@ var ( morestackNoCtxt *obj.LSym gcWriteBarrier *obj.LSym sigpanic *obj.LSym - deferreturn *obj.LSym - jmpdefer *obj.LSym ) const ( @@ -143,10 +141,6 @@ func instinit(ctxt *obj.Link) { morestackNoCtxt = ctxt.Lookup("runtime.morestack_noctxt") gcWriteBarrier = ctxt.LookupABI("runtime.gcWriteBarrier", obj.ABIInternal) sigpanic = ctxt.LookupABI("runtime.sigpanic", obj.ABIInternal) - deferreturn = ctxt.LookupABI("runtime.deferreturn", obj.ABIInternal) - // jmpdefer is defined in assembly as ABI0. The compiler will - // generate a direct ABI0 call from Go, so look for that. - jmpdefer = ctxt.LookupABI(`"".jmpdefer`, obj.ABI0) } func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) { @@ -423,12 +417,6 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) { pcAfterCall-- // sigpanic expects to be called without advancing the pc } - // jmpdefer manipulates the return address on the stack so deferreturn gets called repeatedly. - // Model this in WebAssembly with a loop. - if call.To.Sym == deferreturn { - p = appendp(p, ALoop) - } - // SP -= 8 p = appendp(p, AGet, regAddr(REG_SP)) p = appendp(p, AI32Const, constAddr(8)) @@ -479,15 +467,6 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) { break } - // jmpdefer removes the frame of deferreturn from the Go stack. - // However, its WebAssembly function still returns normally, - // so we need to return from deferreturn without removing its - // stack frame (no RET), because the frame is already gone. - if call.To.Sym == jmpdefer { - p = appendp(p, AReturn) - break - } - // return value of call is on the top of the stack, indicating whether to unwind the WebAssembly stack if call.As == ACALLNORESUME && call.To.Sym != sigpanic { // sigpanic unwinds the stack, but it never resumes // trying to unwind WebAssembly stack but call has no resume point, terminate with error @@ -500,21 +479,6 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) { unwindExitBranches = append(unwindExitBranches, p) } - // jump to before the call if jmpdefer has reset the return address to the call's PC - if call.To.Sym == deferreturn { - // get PC_B from -8(SP) - p = appendp(p, AGet, regAddr(REG_SP)) - p = appendp(p, AI32Const, constAddr(8)) - p = appendp(p, AI32Sub) - p = appendp(p, AI32Load16U, constAddr(0)) - p = appendp(p, ATee, regAddr(REG_PC_B)) - - p = appendp(p, AI32Const, constAddr(call.Pc)) - p = appendp(p, AI32Eq) - p = appendp(p, ABrIf, constAddr(0)) - p = appendp(p, AEnd) // end of Loop - } - case obj.ARET, ARETUNWIND: ret := *p p.As = obj.ANOP diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go index 17fa76727e6..331a98dfef9 100644 --- a/src/cmd/internal/obj/x86/asm6.go +++ b/src/cmd/internal/obj/x86/asm6.go @@ -43,7 +43,6 @@ import ( var ( plan9privates *obj.LSym - deferreturn *obj.LSym ) // Instruction layout. diff --git a/src/cmd/internal/objabi/funcid.go b/src/cmd/internal/objabi/funcid.go index d881cdd0618..68f6a26a76c 100644 --- a/src/cmd/internal/objabi/funcid.go +++ b/src/cmd/internal/objabi/funcid.go @@ -34,7 +34,6 @@ const ( FuncID_gogo FuncID_gopanic FuncID_handleAsyncEvent - FuncID_jmpdefer FuncID_mcall FuncID_morestack FuncID_mstart @@ -60,7 +59,6 @@ var funcIDs = map[string]FuncID{ "gogo": FuncID_gogo, "gopanic": FuncID_gopanic, "handleAsyncEvent": FuncID_handleAsyncEvent, - "jmpdefer": FuncID_jmpdefer, "main": FuncID_runtime_main, "mcall": FuncID_mcall, "morestack": FuncID_morestack, diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go index 05fd3023694..70e3e1284b9 100644 --- a/src/cmd/link/internal/ld/pcln.go +++ b/src/cmd/link/internal/ld/pcln.go @@ -129,11 +129,10 @@ func computeDeferReturn(ctxt *Link, deferReturnSym, s loader.Sym) uint32 { for ri := 0; ri < relocs.Count(); ri++ { r := relocs.At(ri) if target.IsWasm() && r.Type() == objabi.R_ADDR { - // Wasm does not have a live variable set at the deferreturn - // call itself. Instead it has one identified by the - // resumption point immediately preceding the deferreturn. - // The wasm code has a R_ADDR relocation which is used to - // set the resumption point to PC_B. + // wasm/ssa.go generates an ARESUMEPOINT just + // before the deferreturn call. The "PC" of + // the deferreturn call is stored in the + // R_ADDR relocation on the ARESUMEPOINT. lastWasmAddr = uint32(r.Add()) } if r.Type().IsDirectCall() && (r.Sym() == deferReturnSym || ldr.IsDeferReturnTramp(r.Sym())) { diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s index dd2ea458cc5..11c60309f4e 100644 --- a/src/runtime/asm_386.s +++ b/src/runtime/asm_386.s @@ -582,26 +582,6 @@ TEXT ·publicationBarrier(SB),NOSPLIT,$0-0 // compile barrier. RET -// void jmpdefer(fn, sp); -// called from deferreturn. -// 1. pop the caller -// 2. sub 5 bytes (the length of CALL & a 32 bit displacement) from the callers -// return (when building for shared libraries, subtract 16 bytes -- 5 bytes -// for CALL & displacement to call __x86.get_pc_thunk.cx, 6 bytes for the -// LEAL to load the offset into BX, and finally 5 for the call & displacement) -// 3. jmp to the argument -TEXT runtime·jmpdefer(SB), NOSPLIT, $0-8 - MOVL fv+0(FP), DX // fn - MOVL argp+4(FP), BX // caller sp - LEAL -4(BX), SP // caller sp after CALL -#ifdef GOBUILDMODE_shared - SUBL $16, (SP) // return to CALL again -#else - SUBL $5, (SP) // return to CALL again -#endif - MOVL 0(DX), BX - JMP BX // but first run the deferred function - // Save state of caller into g->sched, // but using fake PC from systemstack_switch. // Must only be called from functions with no locals ($0) diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index 0f719b2664a..2d8f4c24120 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -662,21 +662,6 @@ TEXT ·publicationBarrier(SB),NOSPLIT,$0-0 // compile barrier. RET -// func jmpdefer(fv func(), argp uintptr) -// argp is a caller SP. -// called from deferreturn. -// 1. pop the caller -// 2. sub 5 bytes from the callers return -// 3. jmp to the argument -TEXT runtime·jmpdefer(SB), NOSPLIT, $0-16 - MOVQ fv+0(FP), DX // fn - MOVQ argp+8(FP), BX // caller sp - LEAQ -8(BX), SP // caller sp after CALL - MOVQ -8(SP), BP // restore BP as if deferreturn returned (harmless if framepointers not in use) - SUBQ $5, (SP) // return to CALL again - MOVQ 0(DX), BX - JMP BX // but first run the deferred function - // Save state of caller into g->sched, // but using fake PC from systemstack_switch. // Must only be called from functions with no locals ($0) diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index 5c2bc00fe81..a1164781d2e 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -506,20 +506,6 @@ CALLFN(·call268435456, 268435456) CALLFN(·call536870912, 536870912) CALLFN(·call1073741824, 1073741824) -// void jmpdefer(fn, sp); -// called from deferreturn. -// 1. grab stored LR for caller -// 2. sub 4 bytes to get back to BL deferreturn -// 3. B to fn -TEXT runtime·jmpdefer(SB),NOSPLIT,$0-8 - MOVW 0(R13), LR - MOVW $-4(LR), LR // BL deferreturn - MOVW fv+0(FP), R7 - MOVW argp+4(FP), R13 - MOVW $-4(R13), R13 // SP is 4 below argp, due to saved LR - MOVW 0(R7), R1 - B (R1) - // Save state of caller into g->sched, // but using fake PC from systemstack_switch. // Must only be called from functions with no locals ($0) diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s index e7c5fa32252..e51ce2f8316 100644 --- a/src/runtime/asm_arm64.s +++ b/src/runtime/asm_arm64.s @@ -982,23 +982,6 @@ again: CBNZ R0, again RET -// void jmpdefer(fv, sp); -// called from deferreturn. -// 1. grab stored LR for caller -// 2. sub 4 bytes to get back to BL deferreturn -// 3. BR to fn -TEXT runtime·jmpdefer(SB), NOSPLIT|NOFRAME, $0-16 - MOVD 0(RSP), R0 - SUB $4, R0 - MOVD R0, LR - - MOVD fv+0(FP), R26 - MOVD argp+8(FP), R0 - MOVD R0, RSP - SUB $8, RSP - MOVD 0(R26), R3 - B (R3) - // Save state of caller into g->sched, // but using fake PC from systemstack_switch. // Must only be called from functions with no locals ($0) diff --git a/src/runtime/asm_mips64x.s b/src/runtime/asm_mips64x.s index f3ac453d998..b2e2384c368 100644 --- a/src/runtime/asm_mips64x.s +++ b/src/runtime/asm_mips64x.s @@ -384,22 +384,6 @@ CALLFN(·call1073741824, 1073741824) TEXT runtime·procyield(SB),NOSPLIT,$0-0 RET -// void jmpdefer(fv, sp); -// called from deferreturn. -// 1. grab stored LR for caller -// 2. sub 8 bytes to get back to JAL deferreturn -// 3. JMP to fn -TEXT runtime·jmpdefer(SB), NOSPLIT|NOFRAME, $0-16 - MOVV 0(R29), R31 - ADDV $-8, R31 - - MOVV fv+0(FP), REGCTXT - MOVV argp+8(FP), R29 - ADDV $-8, R29 - NOR R0, R0 // prevent scheduling - MOVV 0(REGCTXT), R4 - JMP (R4) - // Save state of caller into g->sched, // but using fake PC from systemstack_switch. // Must only be called from functions with no locals ($0) diff --git a/src/runtime/asm_mipsx.s b/src/runtime/asm_mipsx.s index 4dc165849e2..87a1344e8f6 100644 --- a/src/runtime/asm_mipsx.s +++ b/src/runtime/asm_mipsx.s @@ -382,22 +382,6 @@ CALLFN(·call1073741824, 1073741824) TEXT runtime·procyield(SB),NOSPLIT,$0-4 RET -// void jmpdefer(fv, sp); -// called from deferreturn. -// 1. grab stored LR for caller -// 2. sub 8 bytes to get back to JAL deferreturn -// 3. JMP to fn -TEXT runtime·jmpdefer(SB),NOSPLIT,$0-8 - MOVW 0(R29), R31 - ADDU $-8, R31 - - MOVW fv+0(FP), REGCTXT - MOVW argp+4(FP), R29 - ADDU $-4, R29 - NOR R0, R0 // prevent scheduling - MOVW 0(REGCTXT), R4 - JMP (R4) - // Save state of caller into g->sched, // but using fake PC from systemstack_switch. // Must only be called from functions with no locals ($0) diff --git a/src/runtime/asm_ppc64x.s b/src/runtime/asm_ppc64x.s index a789d041e43..5dc96c59473 100644 --- a/src/runtime/asm_ppc64x.s +++ b/src/runtime/asm_ppc64x.s @@ -503,34 +503,6 @@ again: OR R6, R6, R6 // Set PPR priority back to medium-low RET -// void jmpdefer(fv, sp); -// called from deferreturn. -// 1. grab stored LR for caller -// 2. sub 8 bytes to get back to either nop or toc reload before deferreturn -// 3. BR to fn -// When dynamically linking Go, it is not sufficient to rewind to the BL -// deferreturn -- we might be jumping between modules and so we need to reset -// the TOC pointer in r2. To do this, codegen inserts MOVD 24(R1), R2 *before* -// the BL deferreturn and jmpdefer rewinds to that. -TEXT runtime·jmpdefer(SB), NOSPLIT|NOFRAME, $0-16 - MOVD 0(R1), R31 - SUB $8, R31 - MOVD R31, LR - - MOVD fv+0(FP), R11 - MOVD argp+8(FP), R1 - SUB $FIXED_FRAME, R1 -#ifdef GOOS_aix - // AIX won't trigger a SIGSEGV if R11 = nil - // So it manually triggers it - CMP R0, R11 - BNE 2(PC) - MOVD R0, 0(R0) -#endif - MOVD 0(R11), R12 - MOVD R12, CTR - BR (CTR) - // Save state of caller into g->sched, // but using fake PC from systemstack_switch. // Must only be called from functions with no locals ($0) diff --git a/src/runtime/asm_riscv64.s b/src/runtime/asm_riscv64.s index 9957ae201bc..9927a817f72 100644 --- a/src/runtime/asm_riscv64.s +++ b/src/runtime/asm_riscv64.s @@ -248,21 +248,6 @@ TEXT gogo<>(SB), NOSPLIT|NOFRAME, $0 MOV gobuf_pc(T0), T0 JALR ZERO, T0 -// func jmpdefer(fv func(), argp uintptr) -// called from deferreturn -// 1. grab stored return address from the caller's frame -// 2. sub 8 bytes to get back to JAL deferreturn -// 3. JMP to fn -TEXT runtime·jmpdefer(SB), NOSPLIT|NOFRAME, $0-16 - MOV 0(X2), RA - ADD $-8, RA - - MOV fv+0(FP), CTXT - MOV argp+8(FP), X2 - ADD $-8, X2 - MOV 0(CTXT), T0 - JALR ZERO, T0 - // func procyield(cycles uint32) TEXT runtime·procyield(SB),NOSPLIT,$0-0 RET diff --git a/src/runtime/asm_s390x.s b/src/runtime/asm_s390x.s index 534cb6112c6..d4110d563f4 100644 --- a/src/runtime/asm_s390x.s +++ b/src/runtime/asm_s390x.s @@ -480,21 +480,6 @@ TEXT callfnMVC<>(SB),NOSPLIT|NOFRAME,$0-0 TEXT runtime·procyield(SB),NOSPLIT,$0-0 RET -// void jmpdefer(fv, sp); -// called from deferreturn. -// 1. grab stored LR for caller -// 2. sub 6 bytes to get back to BL deferreturn (size of BRASL instruction) -// 3. BR to fn -TEXT runtime·jmpdefer(SB),NOSPLIT|NOFRAME,$0-16 - MOVD 0(R15), R1 - SUB $6, R1, LR - - MOVD fv+0(FP), R12 - MOVD argp+8(FP), R15 - SUB $8, R15 - MOVD 0(R12), R3 - BR (R3) - // Save state of caller into g->sched, // but using fake PC from systemstack_switch. // Must only be called from functions with no locals ($0) diff --git a/src/runtime/asm_wasm.s b/src/runtime/asm_wasm.s index 53c271aa708..d885da6e70f 100644 --- a/src/runtime/asm_wasm.s +++ b/src/runtime/asm_wasm.s @@ -193,35 +193,6 @@ TEXT runtime·return0(SB), NOSPLIT, $0-0 MOVD $0, RET0 RET -TEXT runtime·jmpdefer(SB), NOSPLIT, $0-16 - MOVD fv+0(FP), CTXT - - Get CTXT - I64Eqz - If - CALLNORESUME runtime·sigpanic(SB) - End - - // caller sp after CALL - I64Load argp+8(FP) - I64Const $8 - I64Sub - I32WrapI64 - Set SP - - // decrease PC_B by 1 to CALL again - Get SP - I32Load16U (SP) - I32Const $1 - I32Sub - I32Store16 $0 - - // but first run the deferred function - Get CTXT - I32WrapI64 - I64Load $0 - JMP - TEXT runtime·asminit(SB), NOSPLIT, $0-0 // No per-thread init. RET diff --git a/src/runtime/panic.go b/src/runtime/panic.go index e66fe27be0b..4b8bca6c566 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -396,47 +396,39 @@ func freedeferfn() { throw("freedefer with d.fn != nil") } -// Run a deferred function if there is one. +// deferreturn runs deferred functions for the caller's frame. // The compiler inserts a call to this at the end of any // function which calls defer. -// If there is a deferred function, this will call runtime·jmpdefer, -// which will jump to the deferred function such that it appears -// to have been called by the caller of deferreturn at the point -// just before deferreturn was called. The effect is that deferreturn -// is called again and again until there are no more deferred functions. func deferreturn() { gp := getg() - d := gp._defer - if d == nil { - return - } - sp := getcallersp() - if d.sp != sp { - return - } - if d.openDefer { - done := runOpenDeferFrame(gp, d) - if !done { - throw("unfinished open-coded defers in deferreturn") + for { + d := gp._defer + if d == nil { + return } + sp := getcallersp() + if d.sp != sp { + return + } + if d.openDefer { + done := runOpenDeferFrame(gp, d) + if !done { + throw("unfinished open-coded defers in deferreturn") + } + gp._defer = d.link + freedefer(d) + // If this frame uses open defers, then this + // must be the only defer record for the + // frame, so we can just return. + return + } + + fn := d.fn + d.fn = nil gp._defer = d.link freedefer(d) - return + fn() } - - fn := d.fn - d.fn = nil - gp._defer = d.link - freedefer(d) - // If the defer function pointer is nil, force the seg fault to happen - // here rather than in jmpdefer. gentraceback() throws an error if it is - // called with a callback on an LR architecture and jmpdefer is on the - // stack, because jmpdefer manipulates SP (see issue #8153). - _ = **(**funcval)(unsafe.Pointer(&fn)) - // We must not split the stack between computing argp and - // calling jmpdefer because argp is a uintptr stack pointer. - argp := getcallersp() + sys.MinFrameSize - jmpdefer(fn, argp) } // Goexit terminates the goroutine that calls it. No other goroutine is affected. diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index b94acdea1f6..fc29a1bac31 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -176,8 +176,6 @@ func cgocallback(fn, frame, ctxt uintptr) func gogo(buf *gobuf) -//go:noescape -func jmpdefer(fv func(), argp uintptr) func asminit() func setg(gg *g) func breakpoint() diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index 44ea0710c65..d08aa0b3204 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -331,7 +331,6 @@ const ( funcID_gogo funcID_gopanic funcID_handleAsyncEvent - funcID_jmpdefer funcID_mcall funcID_morestack funcID_mstart From 40e561d9337afbae221b34d6d0811761f32412f6 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Fri, 30 Jul 2021 09:06:38 -0700 Subject: [PATCH 827/940] [dev.typeparams] cmd/compile: allow types with the same underlying type to have the same shape First baby step to sharing the underlying implementation among several types. Change-Id: I6a156176d2b7f0131a87285a03b881ce380c26ed Reviewed-on: https://go-review.googlesource.com/c/go/+/338610 Trust: Keith Randall Trust: Dan Scales Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Dan Scales --- .../compile/internal/reflectdata/reflect.go | 2 +- src/cmd/compile/internal/typecheck/subr.go | 22 +++++-------- test/typeparam/shape1.go | 33 +++++++++++++++++++ test/typeparam/shape1.out | 2 ++ 4 files changed, 44 insertions(+), 15 deletions(-) create mode 100644 test/typeparam/shape1.go create mode 100644 test/typeparam/shape1.out diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index 3bf248a7ade..dca8de74f30 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -1920,7 +1920,7 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy // Target method uses shaped names. targs2 := make([]*types.Type, len(targs)) for i, t := range targs { - targs2[i] = typecheck.Shaped[t] + targs2[i] = typecheck.Shapify(t) } targs = targs2 diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index 53221bc1cdf..e2f0a57e713 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -1348,32 +1348,26 @@ func Shapify(t *types.Type) *types.Type { if t.IsShape() { return t // TODO: is this right? } - if s := Shaped[t]; s != nil { + // Map all types with the same underlying type to the same shape. + u := t.Underlying() + + if s := shaped[u]; s != nil { return s //TODO: keep? } - // For now, there is a 1-1 mapping between regular types and shape types. sym := Lookup(fmt.Sprintf(".shape%d", snum)) snum++ - name := ir.NewDeclNameAt(t.Pos(), ir.OTYPE, sym) + name := ir.NewDeclNameAt(u.Pos(), ir.OTYPE, sym) s := types.NewNamed(name) - s.SetUnderlying(t.Underlying()) + s.SetUnderlying(u) s.SetIsShape(true) name.SetType(s) name.SetTypecheck(1) // TODO: add methods to s that the bound has? - Shaped[t] = s + shaped[u] = s return s } var snum int -var Shaped = map[*types.Type]*types.Type{} - -func ShapifyList(targs []*types.Type) []*types.Type { - r := make([]*types.Type, len(targs)) - for i, t := range targs { - r[i] = Shapify(t) - } - return r -} +var shaped = map[*types.Type]*types.Type{} diff --git a/test/typeparam/shape1.go b/test/typeparam/shape1.go new file mode 100644 index 00000000000..3c9e71ea63d --- /dev/null +++ b/test/typeparam/shape1.go @@ -0,0 +1,33 @@ +// run -gcflags=-G=3 + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type I interface { + foo() int +} + +// There should be a single instantiation of f in this program. +func f[T I](x T) int { + return x.foo() +} + +type squarer int + +func (x squarer) foo() int { + return int(x*x) +} + +type doubler int + +func (x doubler) foo() int { + return int(2*x) +} + +func main() { + println(f(squarer(5))) + println(f(doubler(5))) +} diff --git a/test/typeparam/shape1.out b/test/typeparam/shape1.out new file mode 100644 index 00000000000..28391fde667 --- /dev/null +++ b/test/typeparam/shape1.out @@ -0,0 +1,2 @@ +25 +10 From e3e9f0bb2d6cc15b201fe2e0a0ac095d62cf4b8c Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 30 Jul 2021 16:40:17 -0400 Subject: [PATCH 828/940] [dev.typeparams] Revert "[dev.typeparams] runtime,cmd/compile,cmd/link: replace jmpdefer with a loop" This reverts CL 227652. I'm reverting CL 337651 and this builds on top of it. Change-Id: I03ce363be44c2a3defff2e43e7b1aad83386820d Reviewed-on: https://go-review.googlesource.com/c/go/+/338709 Trust: Austin Clements Run-TryBot: Austin Clements TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/cmd/compile/internal/amd64/galign.go | 1 + src/cmd/compile/internal/arm/galign.go | 1 + src/cmd/compile/internal/arm64/galign.go | 1 + src/cmd/compile/internal/mips/galign.go | 1 + src/cmd/compile/internal/mips64/galign.go | 1 + src/cmd/compile/internal/ppc64/galign.go | 1 + src/cmd/compile/internal/ppc64/ggen.go | 27 ++++++++++ src/cmd/compile/internal/riscv64/galign.go | 1 + src/cmd/compile/internal/s390x/galign.go | 1 + src/cmd/compile/internal/ssagen/arch.go | 3 +- src/cmd/compile/internal/ssagen/ssa.go | 12 +++++ src/cmd/compile/internal/wasm/ssa.go | 7 +-- src/cmd/compile/internal/x86/galign.go | 1 + src/cmd/internal/obj/arm/asm5.go | 11 ++-- src/cmd/internal/obj/wasm/wasmobj.go | 36 ++++++++++++++ src/cmd/internal/obj/x86/asm6.go | 1 + src/cmd/internal/objabi/funcid.go | 2 + src/cmd/link/internal/ld/pcln.go | 9 ++-- src/runtime/asm_386.s | 20 ++++++++ src/runtime/asm_amd64.s | 15 ++++++ src/runtime/asm_arm.s | 14 ++++++ src/runtime/asm_arm64.s | 17 +++++++ src/runtime/asm_mips64x.s | 16 ++++++ src/runtime/asm_mipsx.s | 16 ++++++ src/runtime/asm_ppc64x.s | 28 +++++++++++ src/runtime/asm_riscv64.s | 15 ++++++ src/runtime/asm_s390x.s | 15 ++++++ src/runtime/asm_wasm.s | 29 +++++++++++ src/runtime/panic.go | 58 ++++++++++++---------- src/runtime/stubs.go | 2 + src/runtime/symtab.go | 1 + 31 files changed, 324 insertions(+), 39 deletions(-) diff --git a/src/cmd/compile/internal/amd64/galign.go b/src/cmd/compile/internal/amd64/galign.go index ca44263afc4..3b13e123a74 100644 --- a/src/cmd/compile/internal/amd64/galign.go +++ b/src/cmd/compile/internal/amd64/galign.go @@ -18,6 +18,7 @@ func Init(arch *ssagen.ArchInfo) { arch.ZeroRange = zerorange arch.Ginsnop = ginsnop + arch.Ginsnopdefer = ginsnop arch.SSAMarkMoves = ssaMarkMoves arch.SSAGenValue = ssaGenValue diff --git a/src/cmd/compile/internal/arm/galign.go b/src/cmd/compile/internal/arm/galign.go index 23e52bacbf2..d68500280d0 100644 --- a/src/cmd/compile/internal/arm/galign.go +++ b/src/cmd/compile/internal/arm/galign.go @@ -18,6 +18,7 @@ func Init(arch *ssagen.ArchInfo) { arch.SoftFloat = buildcfg.GOARM == 5 arch.ZeroRange = zerorange arch.Ginsnop = ginsnop + arch.Ginsnopdefer = ginsnop arch.SSAMarkMoves = func(s *ssagen.State, b *ssa.Block) {} arch.SSAGenValue = ssaGenValue diff --git a/src/cmd/compile/internal/arm64/galign.go b/src/cmd/compile/internal/arm64/galign.go index 3ebd860de8f..2a61b9dd997 100644 --- a/src/cmd/compile/internal/arm64/galign.go +++ b/src/cmd/compile/internal/arm64/galign.go @@ -18,6 +18,7 @@ func Init(arch *ssagen.ArchInfo) { arch.PadFrame = padframe arch.ZeroRange = zerorange arch.Ginsnop = ginsnop + arch.Ginsnopdefer = ginsnop arch.SSAMarkMoves = func(s *ssagen.State, b *ssa.Block) {} arch.SSAGenValue = ssaGenValue diff --git a/src/cmd/compile/internal/mips/galign.go b/src/cmd/compile/internal/mips/galign.go index 4e6897042ec..f892923ba03 100644 --- a/src/cmd/compile/internal/mips/galign.go +++ b/src/cmd/compile/internal/mips/galign.go @@ -21,6 +21,7 @@ func Init(arch *ssagen.ArchInfo) { arch.SoftFloat = (buildcfg.GOMIPS == "softfloat") arch.ZeroRange = zerorange arch.Ginsnop = ginsnop + arch.Ginsnopdefer = ginsnop arch.SSAMarkMoves = func(s *ssagen.State, b *ssa.Block) {} arch.SSAGenValue = ssaGenValue arch.SSAGenBlock = ssaGenBlock diff --git a/src/cmd/compile/internal/mips64/galign.go b/src/cmd/compile/internal/mips64/galign.go index 412bc71aab2..af81366e51b 100644 --- a/src/cmd/compile/internal/mips64/galign.go +++ b/src/cmd/compile/internal/mips64/galign.go @@ -21,6 +21,7 @@ func Init(arch *ssagen.ArchInfo) { arch.SoftFloat = buildcfg.GOMIPS64 == "softfloat" arch.ZeroRange = zerorange arch.Ginsnop = ginsnop + arch.Ginsnopdefer = ginsnop arch.SSAMarkMoves = func(s *ssagen.State, b *ssa.Block) {} arch.SSAGenValue = ssaGenValue diff --git a/src/cmd/compile/internal/ppc64/galign.go b/src/cmd/compile/internal/ppc64/galign.go index bff3e38f42d..590290fa371 100644 --- a/src/cmd/compile/internal/ppc64/galign.go +++ b/src/cmd/compile/internal/ppc64/galign.go @@ -20,6 +20,7 @@ func Init(arch *ssagen.ArchInfo) { arch.ZeroRange = zerorange arch.Ginsnop = ginsnop + arch.Ginsnopdefer = ginsnopdefer arch.SSAMarkMoves = ssaMarkMoves arch.SSAGenValue = ssaGenValue diff --git a/src/cmd/compile/internal/ppc64/ggen.go b/src/cmd/compile/internal/ppc64/ggen.go index 3ae6422bf9e..c76962cfb81 100644 --- a/src/cmd/compile/internal/ppc64/ggen.go +++ b/src/cmd/compile/internal/ppc64/ggen.go @@ -53,3 +53,30 @@ func ginsnop(pp *objw.Progs) *obj.Prog { p.To.Reg = ppc64.REG_R0 return p } + +func ginsnopdefer(pp *objw.Progs) *obj.Prog { + // On PPC64 two nops are required in the defer case. + // + // (see gc/cgen.go, gc/plive.go -- copy of comment below) + // + // On ppc64, when compiling Go into position + // independent code on ppc64le we insert an + // instruction to reload the TOC pointer from the + // stack as well. See the long comment near + // jmpdefer in runtime/asm_ppc64.s for why. + // If the MOVD is not needed, insert a hardware NOP + // so that the same number of instructions are used + // on ppc64 in both shared and non-shared modes. + + ginsnop(pp) + if base.Ctxt.Flag_shared { + p := pp.Prog(ppc64.AMOVD) + p.From.Type = obj.TYPE_MEM + p.From.Offset = 24 + p.From.Reg = ppc64.REGSP + p.To.Type = obj.TYPE_REG + p.To.Reg = ppc64.REG_R2 + return p + } + return ginsnop(pp) +} diff --git a/src/cmd/compile/internal/riscv64/galign.go b/src/cmd/compile/internal/riscv64/galign.go index 846ed8fb380..338248a7cf2 100644 --- a/src/cmd/compile/internal/riscv64/galign.go +++ b/src/cmd/compile/internal/riscv64/galign.go @@ -16,6 +16,7 @@ func Init(arch *ssagen.ArchInfo) { arch.MAXWIDTH = 1 << 50 arch.Ginsnop = ginsnop + arch.Ginsnopdefer = ginsnop arch.ZeroRange = zeroRange arch.SSAMarkMoves = ssaMarkMoves diff --git a/src/cmd/compile/internal/s390x/galign.go b/src/cmd/compile/internal/s390x/galign.go index d880834c220..b004a2db0a3 100644 --- a/src/cmd/compile/internal/s390x/galign.go +++ b/src/cmd/compile/internal/s390x/galign.go @@ -16,6 +16,7 @@ func Init(arch *ssagen.ArchInfo) { arch.ZeroRange = zerorange arch.Ginsnop = ginsnop + arch.Ginsnopdefer = ginsnop arch.SSAMarkMoves = ssaMarkMoves arch.SSAGenValue = ssaGenValue diff --git a/src/cmd/compile/internal/ssagen/arch.go b/src/cmd/compile/internal/ssagen/arch.go index 483e45cad43..957fb3e84a9 100644 --- a/src/cmd/compile/internal/ssagen/arch.go +++ b/src/cmd/compile/internal/ssagen/arch.go @@ -29,7 +29,8 @@ type ArchInfo struct { // at function entry, and it is ok to clobber registers. ZeroRange func(*objw.Progs, *obj.Prog, int64, int64, *uint32) *obj.Prog - Ginsnop func(*objw.Progs) *obj.Prog + Ginsnop func(*objw.Progs) *obj.Prog + Ginsnopdefer func(*objw.Progs) *obj.Prog // special ginsnop for deferreturn // SSAMarkMoves marks any MOVXconst ops that need to avoid clobbering flags. SSAMarkMoves func(*State, *ssa.Block) diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 161469ea67c..7e2f6a7471c 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -7335,6 +7335,18 @@ func (s *State) PrepareCall(v *ssa.Value) { call, ok := v.Aux.(*ssa.AuxCall) + if ok && call.Fn == ir.Syms.Deferreturn { + // Deferred calls will appear to be returning to + // the CALL deferreturn(SB) that we are about to emit. + // However, the stack trace code will show the line + // of the instruction byte before the return PC. + // To avoid that being an unrelated instruction, + // insert an actual hardware NOP that will have the right line number. + // This is different from obj.ANOP, which is a virtual no-op + // that doesn't make it into the instruction stream. + Arch.Ginsnopdefer(s.pp) + } + if ok { // Record call graph information for nowritebarrierrec // analysis. diff --git a/src/cmd/compile/internal/wasm/ssa.go b/src/cmd/compile/internal/wasm/ssa.go index 0b2ca3fdbb8..31b09016eb9 100644 --- a/src/cmd/compile/internal/wasm/ssa.go +++ b/src/cmd/compile/internal/wasm/ssa.go @@ -24,6 +24,7 @@ func Init(arch *ssagen.ArchInfo) { arch.ZeroRange = zeroRange arch.Ginsnop = ginsnop + arch.Ginsnopdefer = ginsnop arch.SSAMarkMoves = ssaMarkMoves arch.SSAGenValue = ssaGenValue @@ -125,11 +126,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { case ssa.OpWasmLoweredStaticCall, ssa.OpWasmLoweredClosureCall, ssa.OpWasmLoweredInterCall: s.PrepareCall(v) if call, ok := v.Aux.(*ssa.AuxCall); ok && call.Fn == ir.Syms.Deferreturn { - // The runtime needs to inject jumps to - // deferreturn calls using the address in - // _func.deferreturn. Hence, the call to - // deferreturn must itself be a resumption - // point so it gets a target PC. + // add a resume point before call to deferreturn so it can be called again via jmpdefer s.Prog(wasm.ARESUMEPOINT) } if v.Op == ssa.OpWasmLoweredClosureCall { diff --git a/src/cmd/compile/internal/x86/galign.go b/src/cmd/compile/internal/x86/galign.go index 5565bd32c76..00a20e429f1 100644 --- a/src/cmd/compile/internal/x86/galign.go +++ b/src/cmd/compile/internal/x86/galign.go @@ -34,6 +34,7 @@ func Init(arch *ssagen.ArchInfo) { arch.ZeroRange = zerorange arch.Ginsnop = ginsnop + arch.Ginsnopdefer = ginsnop arch.SSAMarkMoves = ssaMarkMoves } diff --git a/src/cmd/internal/obj/arm/asm5.go b/src/cmd/internal/obj/arm/asm5.go index 7b1682776e5..ccf5f9e7f8d 100644 --- a/src/cmd/internal/obj/arm/asm5.go +++ b/src/cmd/internal/obj/arm/asm5.go @@ -355,10 +355,11 @@ var oprange [ALAST & obj.AMask][]Optab var xcmp [C_GOK + 1][C_GOK + 1]bool var ( - symdiv *obj.LSym - symdivu *obj.LSym - symmod *obj.LSym - symmodu *obj.LSym + deferreturn *obj.LSym + symdiv *obj.LSym + symdivu *obj.LSym + symmod *obj.LSym + symmodu *obj.LSym ) // Note about encoding: Prog.scond holds the condition encoding, @@ -1218,6 +1219,8 @@ func buildop(ctxt *obj.Link) { return } + deferreturn = ctxt.LookupABI("runtime.deferreturn", obj.ABIInternal) + symdiv = ctxt.Lookup("runtime._div") symdivu = ctxt.Lookup("runtime._divu") symmod = ctxt.Lookup("runtime._mod") diff --git a/src/cmd/internal/obj/wasm/wasmobj.go b/src/cmd/internal/obj/wasm/wasmobj.go index 4d276db6780..ceeae7a257c 100644 --- a/src/cmd/internal/obj/wasm/wasmobj.go +++ b/src/cmd/internal/obj/wasm/wasmobj.go @@ -129,6 +129,8 @@ var ( morestackNoCtxt *obj.LSym gcWriteBarrier *obj.LSym sigpanic *obj.LSym + deferreturn *obj.LSym + jmpdefer *obj.LSym ) const ( @@ -141,6 +143,10 @@ func instinit(ctxt *obj.Link) { morestackNoCtxt = ctxt.Lookup("runtime.morestack_noctxt") gcWriteBarrier = ctxt.LookupABI("runtime.gcWriteBarrier", obj.ABIInternal) sigpanic = ctxt.LookupABI("runtime.sigpanic", obj.ABIInternal) + deferreturn = ctxt.LookupABI("runtime.deferreturn", obj.ABIInternal) + // jmpdefer is defined in assembly as ABI0. The compiler will + // generate a direct ABI0 call from Go, so look for that. + jmpdefer = ctxt.LookupABI(`"".jmpdefer`, obj.ABI0) } func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) { @@ -417,6 +423,12 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) { pcAfterCall-- // sigpanic expects to be called without advancing the pc } + // jmpdefer manipulates the return address on the stack so deferreturn gets called repeatedly. + // Model this in WebAssembly with a loop. + if call.To.Sym == deferreturn { + p = appendp(p, ALoop) + } + // SP -= 8 p = appendp(p, AGet, regAddr(REG_SP)) p = appendp(p, AI32Const, constAddr(8)) @@ -467,6 +479,15 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) { break } + // jmpdefer removes the frame of deferreturn from the Go stack. + // However, its WebAssembly function still returns normally, + // so we need to return from deferreturn without removing its + // stack frame (no RET), because the frame is already gone. + if call.To.Sym == jmpdefer { + p = appendp(p, AReturn) + break + } + // return value of call is on the top of the stack, indicating whether to unwind the WebAssembly stack if call.As == ACALLNORESUME && call.To.Sym != sigpanic { // sigpanic unwinds the stack, but it never resumes // trying to unwind WebAssembly stack but call has no resume point, terminate with error @@ -479,6 +500,21 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) { unwindExitBranches = append(unwindExitBranches, p) } + // jump to before the call if jmpdefer has reset the return address to the call's PC + if call.To.Sym == deferreturn { + // get PC_B from -8(SP) + p = appendp(p, AGet, regAddr(REG_SP)) + p = appendp(p, AI32Const, constAddr(8)) + p = appendp(p, AI32Sub) + p = appendp(p, AI32Load16U, constAddr(0)) + p = appendp(p, ATee, regAddr(REG_PC_B)) + + p = appendp(p, AI32Const, constAddr(call.Pc)) + p = appendp(p, AI32Eq) + p = appendp(p, ABrIf, constAddr(0)) + p = appendp(p, AEnd) // end of Loop + } + case obj.ARET, ARETUNWIND: ret := *p p.As = obj.ANOP diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go index 331a98dfef9..17fa76727e6 100644 --- a/src/cmd/internal/obj/x86/asm6.go +++ b/src/cmd/internal/obj/x86/asm6.go @@ -43,6 +43,7 @@ import ( var ( plan9privates *obj.LSym + deferreturn *obj.LSym ) // Instruction layout. diff --git a/src/cmd/internal/objabi/funcid.go b/src/cmd/internal/objabi/funcid.go index 68f6a26a76c..d881cdd0618 100644 --- a/src/cmd/internal/objabi/funcid.go +++ b/src/cmd/internal/objabi/funcid.go @@ -34,6 +34,7 @@ const ( FuncID_gogo FuncID_gopanic FuncID_handleAsyncEvent + FuncID_jmpdefer FuncID_mcall FuncID_morestack FuncID_mstart @@ -59,6 +60,7 @@ var funcIDs = map[string]FuncID{ "gogo": FuncID_gogo, "gopanic": FuncID_gopanic, "handleAsyncEvent": FuncID_handleAsyncEvent, + "jmpdefer": FuncID_jmpdefer, "main": FuncID_runtime_main, "mcall": FuncID_mcall, "morestack": FuncID_morestack, diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go index 70e3e1284b9..05fd3023694 100644 --- a/src/cmd/link/internal/ld/pcln.go +++ b/src/cmd/link/internal/ld/pcln.go @@ -129,10 +129,11 @@ func computeDeferReturn(ctxt *Link, deferReturnSym, s loader.Sym) uint32 { for ri := 0; ri < relocs.Count(); ri++ { r := relocs.At(ri) if target.IsWasm() && r.Type() == objabi.R_ADDR { - // wasm/ssa.go generates an ARESUMEPOINT just - // before the deferreturn call. The "PC" of - // the deferreturn call is stored in the - // R_ADDR relocation on the ARESUMEPOINT. + // Wasm does not have a live variable set at the deferreturn + // call itself. Instead it has one identified by the + // resumption point immediately preceding the deferreturn. + // The wasm code has a R_ADDR relocation which is used to + // set the resumption point to PC_B. lastWasmAddr = uint32(r.Add()) } if r.Type().IsDirectCall() && (r.Sym() == deferReturnSym || ldr.IsDeferReturnTramp(r.Sym())) { diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s index 11c60309f4e..dd2ea458cc5 100644 --- a/src/runtime/asm_386.s +++ b/src/runtime/asm_386.s @@ -582,6 +582,26 @@ TEXT ·publicationBarrier(SB),NOSPLIT,$0-0 // compile barrier. RET +// void jmpdefer(fn, sp); +// called from deferreturn. +// 1. pop the caller +// 2. sub 5 bytes (the length of CALL & a 32 bit displacement) from the callers +// return (when building for shared libraries, subtract 16 bytes -- 5 bytes +// for CALL & displacement to call __x86.get_pc_thunk.cx, 6 bytes for the +// LEAL to load the offset into BX, and finally 5 for the call & displacement) +// 3. jmp to the argument +TEXT runtime·jmpdefer(SB), NOSPLIT, $0-8 + MOVL fv+0(FP), DX // fn + MOVL argp+4(FP), BX // caller sp + LEAL -4(BX), SP // caller sp after CALL +#ifdef GOBUILDMODE_shared + SUBL $16, (SP) // return to CALL again +#else + SUBL $5, (SP) // return to CALL again +#endif + MOVL 0(DX), BX + JMP BX // but first run the deferred function + // Save state of caller into g->sched, // but using fake PC from systemstack_switch. // Must only be called from functions with no locals ($0) diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index 2d8f4c24120..0f719b2664a 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -662,6 +662,21 @@ TEXT ·publicationBarrier(SB),NOSPLIT,$0-0 // compile barrier. RET +// func jmpdefer(fv func(), argp uintptr) +// argp is a caller SP. +// called from deferreturn. +// 1. pop the caller +// 2. sub 5 bytes from the callers return +// 3. jmp to the argument +TEXT runtime·jmpdefer(SB), NOSPLIT, $0-16 + MOVQ fv+0(FP), DX // fn + MOVQ argp+8(FP), BX // caller sp + LEAQ -8(BX), SP // caller sp after CALL + MOVQ -8(SP), BP // restore BP as if deferreturn returned (harmless if framepointers not in use) + SUBQ $5, (SP) // return to CALL again + MOVQ 0(DX), BX + JMP BX // but first run the deferred function + // Save state of caller into g->sched, // but using fake PC from systemstack_switch. // Must only be called from functions with no locals ($0) diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index a1164781d2e..5c2bc00fe81 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -506,6 +506,20 @@ CALLFN(·call268435456, 268435456) CALLFN(·call536870912, 536870912) CALLFN(·call1073741824, 1073741824) +// void jmpdefer(fn, sp); +// called from deferreturn. +// 1. grab stored LR for caller +// 2. sub 4 bytes to get back to BL deferreturn +// 3. B to fn +TEXT runtime·jmpdefer(SB),NOSPLIT,$0-8 + MOVW 0(R13), LR + MOVW $-4(LR), LR // BL deferreturn + MOVW fv+0(FP), R7 + MOVW argp+4(FP), R13 + MOVW $-4(R13), R13 // SP is 4 below argp, due to saved LR + MOVW 0(R7), R1 + B (R1) + // Save state of caller into g->sched, // but using fake PC from systemstack_switch. // Must only be called from functions with no locals ($0) diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s index e51ce2f8316..e7c5fa32252 100644 --- a/src/runtime/asm_arm64.s +++ b/src/runtime/asm_arm64.s @@ -982,6 +982,23 @@ again: CBNZ R0, again RET +// void jmpdefer(fv, sp); +// called from deferreturn. +// 1. grab stored LR for caller +// 2. sub 4 bytes to get back to BL deferreturn +// 3. BR to fn +TEXT runtime·jmpdefer(SB), NOSPLIT|NOFRAME, $0-16 + MOVD 0(RSP), R0 + SUB $4, R0 + MOVD R0, LR + + MOVD fv+0(FP), R26 + MOVD argp+8(FP), R0 + MOVD R0, RSP + SUB $8, RSP + MOVD 0(R26), R3 + B (R3) + // Save state of caller into g->sched, // but using fake PC from systemstack_switch. // Must only be called from functions with no locals ($0) diff --git a/src/runtime/asm_mips64x.s b/src/runtime/asm_mips64x.s index b2e2384c368..f3ac453d998 100644 --- a/src/runtime/asm_mips64x.s +++ b/src/runtime/asm_mips64x.s @@ -384,6 +384,22 @@ CALLFN(·call1073741824, 1073741824) TEXT runtime·procyield(SB),NOSPLIT,$0-0 RET +// void jmpdefer(fv, sp); +// called from deferreturn. +// 1. grab stored LR for caller +// 2. sub 8 bytes to get back to JAL deferreturn +// 3. JMP to fn +TEXT runtime·jmpdefer(SB), NOSPLIT|NOFRAME, $0-16 + MOVV 0(R29), R31 + ADDV $-8, R31 + + MOVV fv+0(FP), REGCTXT + MOVV argp+8(FP), R29 + ADDV $-8, R29 + NOR R0, R0 // prevent scheduling + MOVV 0(REGCTXT), R4 + JMP (R4) + // Save state of caller into g->sched, // but using fake PC from systemstack_switch. // Must only be called from functions with no locals ($0) diff --git a/src/runtime/asm_mipsx.s b/src/runtime/asm_mipsx.s index 87a1344e8f6..4dc165849e2 100644 --- a/src/runtime/asm_mipsx.s +++ b/src/runtime/asm_mipsx.s @@ -382,6 +382,22 @@ CALLFN(·call1073741824, 1073741824) TEXT runtime·procyield(SB),NOSPLIT,$0-4 RET +// void jmpdefer(fv, sp); +// called from deferreturn. +// 1. grab stored LR for caller +// 2. sub 8 bytes to get back to JAL deferreturn +// 3. JMP to fn +TEXT runtime·jmpdefer(SB),NOSPLIT,$0-8 + MOVW 0(R29), R31 + ADDU $-8, R31 + + MOVW fv+0(FP), REGCTXT + MOVW argp+4(FP), R29 + ADDU $-4, R29 + NOR R0, R0 // prevent scheduling + MOVW 0(REGCTXT), R4 + JMP (R4) + // Save state of caller into g->sched, // but using fake PC from systemstack_switch. // Must only be called from functions with no locals ($0) diff --git a/src/runtime/asm_ppc64x.s b/src/runtime/asm_ppc64x.s index 5dc96c59473..a789d041e43 100644 --- a/src/runtime/asm_ppc64x.s +++ b/src/runtime/asm_ppc64x.s @@ -503,6 +503,34 @@ again: OR R6, R6, R6 // Set PPR priority back to medium-low RET +// void jmpdefer(fv, sp); +// called from deferreturn. +// 1. grab stored LR for caller +// 2. sub 8 bytes to get back to either nop or toc reload before deferreturn +// 3. BR to fn +// When dynamically linking Go, it is not sufficient to rewind to the BL +// deferreturn -- we might be jumping between modules and so we need to reset +// the TOC pointer in r2. To do this, codegen inserts MOVD 24(R1), R2 *before* +// the BL deferreturn and jmpdefer rewinds to that. +TEXT runtime·jmpdefer(SB), NOSPLIT|NOFRAME, $0-16 + MOVD 0(R1), R31 + SUB $8, R31 + MOVD R31, LR + + MOVD fv+0(FP), R11 + MOVD argp+8(FP), R1 + SUB $FIXED_FRAME, R1 +#ifdef GOOS_aix + // AIX won't trigger a SIGSEGV if R11 = nil + // So it manually triggers it + CMP R0, R11 + BNE 2(PC) + MOVD R0, 0(R0) +#endif + MOVD 0(R11), R12 + MOVD R12, CTR + BR (CTR) + // Save state of caller into g->sched, // but using fake PC from systemstack_switch. // Must only be called from functions with no locals ($0) diff --git a/src/runtime/asm_riscv64.s b/src/runtime/asm_riscv64.s index 9927a817f72..9957ae201bc 100644 --- a/src/runtime/asm_riscv64.s +++ b/src/runtime/asm_riscv64.s @@ -248,6 +248,21 @@ TEXT gogo<>(SB), NOSPLIT|NOFRAME, $0 MOV gobuf_pc(T0), T0 JALR ZERO, T0 +// func jmpdefer(fv func(), argp uintptr) +// called from deferreturn +// 1. grab stored return address from the caller's frame +// 2. sub 8 bytes to get back to JAL deferreturn +// 3. JMP to fn +TEXT runtime·jmpdefer(SB), NOSPLIT|NOFRAME, $0-16 + MOV 0(X2), RA + ADD $-8, RA + + MOV fv+0(FP), CTXT + MOV argp+8(FP), X2 + ADD $-8, X2 + MOV 0(CTXT), T0 + JALR ZERO, T0 + // func procyield(cycles uint32) TEXT runtime·procyield(SB),NOSPLIT,$0-0 RET diff --git a/src/runtime/asm_s390x.s b/src/runtime/asm_s390x.s index d4110d563f4..534cb6112c6 100644 --- a/src/runtime/asm_s390x.s +++ b/src/runtime/asm_s390x.s @@ -480,6 +480,21 @@ TEXT callfnMVC<>(SB),NOSPLIT|NOFRAME,$0-0 TEXT runtime·procyield(SB),NOSPLIT,$0-0 RET +// void jmpdefer(fv, sp); +// called from deferreturn. +// 1. grab stored LR for caller +// 2. sub 6 bytes to get back to BL deferreturn (size of BRASL instruction) +// 3. BR to fn +TEXT runtime·jmpdefer(SB),NOSPLIT|NOFRAME,$0-16 + MOVD 0(R15), R1 + SUB $6, R1, LR + + MOVD fv+0(FP), R12 + MOVD argp+8(FP), R15 + SUB $8, R15 + MOVD 0(R12), R3 + BR (R3) + // Save state of caller into g->sched, // but using fake PC from systemstack_switch. // Must only be called from functions with no locals ($0) diff --git a/src/runtime/asm_wasm.s b/src/runtime/asm_wasm.s index d885da6e70f..53c271aa708 100644 --- a/src/runtime/asm_wasm.s +++ b/src/runtime/asm_wasm.s @@ -193,6 +193,35 @@ TEXT runtime·return0(SB), NOSPLIT, $0-0 MOVD $0, RET0 RET +TEXT runtime·jmpdefer(SB), NOSPLIT, $0-16 + MOVD fv+0(FP), CTXT + + Get CTXT + I64Eqz + If + CALLNORESUME runtime·sigpanic(SB) + End + + // caller sp after CALL + I64Load argp+8(FP) + I64Const $8 + I64Sub + I32WrapI64 + Set SP + + // decrease PC_B by 1 to CALL again + Get SP + I32Load16U (SP) + I32Const $1 + I32Sub + I32Store16 $0 + + // but first run the deferred function + Get CTXT + I32WrapI64 + I64Load $0 + JMP + TEXT runtime·asminit(SB), NOSPLIT, $0-0 // No per-thread init. RET diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 4b8bca6c566..e66fe27be0b 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -396,39 +396,47 @@ func freedeferfn() { throw("freedefer with d.fn != nil") } -// deferreturn runs deferred functions for the caller's frame. +// Run a deferred function if there is one. // The compiler inserts a call to this at the end of any // function which calls defer. +// If there is a deferred function, this will call runtime·jmpdefer, +// which will jump to the deferred function such that it appears +// to have been called by the caller of deferreturn at the point +// just before deferreturn was called. The effect is that deferreturn +// is called again and again until there are no more deferred functions. func deferreturn() { gp := getg() - for { - d := gp._defer - if d == nil { - return + d := gp._defer + if d == nil { + return + } + sp := getcallersp() + if d.sp != sp { + return + } + if d.openDefer { + done := runOpenDeferFrame(gp, d) + if !done { + throw("unfinished open-coded defers in deferreturn") } - sp := getcallersp() - if d.sp != sp { - return - } - if d.openDefer { - done := runOpenDeferFrame(gp, d) - if !done { - throw("unfinished open-coded defers in deferreturn") - } - gp._defer = d.link - freedefer(d) - // If this frame uses open defers, then this - // must be the only defer record for the - // frame, so we can just return. - return - } - - fn := d.fn - d.fn = nil gp._defer = d.link freedefer(d) - fn() + return } + + fn := d.fn + d.fn = nil + gp._defer = d.link + freedefer(d) + // If the defer function pointer is nil, force the seg fault to happen + // here rather than in jmpdefer. gentraceback() throws an error if it is + // called with a callback on an LR architecture and jmpdefer is on the + // stack, because jmpdefer manipulates SP (see issue #8153). + _ = **(**funcval)(unsafe.Pointer(&fn)) + // We must not split the stack between computing argp and + // calling jmpdefer because argp is a uintptr stack pointer. + argp := getcallersp() + sys.MinFrameSize + jmpdefer(fn, argp) } // Goexit terminates the goroutine that calls it. No other goroutine is affected. diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index fc29a1bac31..b94acdea1f6 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -176,6 +176,8 @@ func cgocallback(fn, frame, ctxt uintptr) func gogo(buf *gobuf) +//go:noescape +func jmpdefer(fv func(), argp uintptr) func asminit() func setg(gg *g) func breakpoint() diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index d08aa0b3204..44ea0710c65 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -331,6 +331,7 @@ const ( funcID_gogo funcID_gopanic funcID_handleAsyncEvent + funcID_jmpdefer funcID_mcall funcID_morestack funcID_mstart From 7bed50e667cf1b4ba5b2ec7ca699c835c696e454 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 30 Jul 2021 16:41:11 -0400 Subject: [PATCH 829/940] [dev.typeparams] Revert "[dev.typeparams] runtime: remove unnecessary split-prevention from defer code" This reverts CL 337651. This causes `go test -count 1000 -run TestDeferHeapAndStack runtime` to fail with a SIGSEGV freedefer [https://build.golang.org/log/c113b366cc6d51146db02a07b4d7dd931133efd5] and possibly sometimes a GC bad pointer panic [https://build.golang.org/log/5b1cef7a9ad68704e9ef3ce3ad2fefca3ba86998]. Change-Id: Ie56c274b78603c81191213b302225ae19de27fb9 Reviewed-on: https://go-review.googlesource.com/c/go/+/338710 Trust: Austin Clements Run-TryBot: Austin Clements TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/runtime/panic.go | 84 +++++++++++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 29 deletions(-) diff --git a/src/runtime/panic.go b/src/runtime/panic.go index e66fe27be0b..35f3b44a4d5 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -261,8 +261,10 @@ func deferproc(fn func()) { // deferprocStack queues a new deferred function with a defer record on the stack. // The defer record must have its fn field initialized. // All other fields can contain junk. -// Nosplit because of the uninitialized pointer fields on the stack. -// +// The defer record must be immediately followed in memory by +// the arguments of the defer. +// Nosplit because the arguments on the stack won't be scanned +// until the defer record is spliced into the gp._defer list. //go:nosplit func deferprocStack(d *_defer) { gp := getg() @@ -311,14 +313,18 @@ func newdefer() *_defer { gp := getg() pp := gp.m.p.ptr() if len(pp.deferpool) == 0 && sched.deferpool != nil { - lock(&sched.deferlock) - for len(pp.deferpool) < cap(pp.deferpool)/2 && sched.deferpool != nil { - d := sched.deferpool - sched.deferpool = d.link - d.link = nil - pp.deferpool = append(pp.deferpool, d) - } - unlock(&sched.deferlock) + // Take the slow path on the system stack so + // we don't grow newdefer's stack. + systemstack(func() { + lock(&sched.deferlock) + for len(pp.deferpool) < cap(pp.deferpool)/2 && sched.deferpool != nil { + d := sched.deferpool + sched.deferpool = d.link + d.link = nil + pp.deferpool = append(pp.deferpool, d) + } + unlock(&sched.deferlock) + }) } if n := len(pp.deferpool); n > 0 { d = pp.deferpool[n-1] @@ -335,6 +341,11 @@ func newdefer() *_defer { // Free the given defer. // The defer cannot be used after this call. +// +// This must not grow the stack because there may be a frame without a +// stack map when this is called. +// +//go:nosplit func freedefer(d *_defer) { if d._panic != nil { freedeferpanic() @@ -348,23 +359,28 @@ func freedefer(d *_defer) { pp := getg().m.p.ptr() if len(pp.deferpool) == cap(pp.deferpool) { // Transfer half of local cache to the central cache. - var first, last *_defer - for len(pp.deferpool) > cap(pp.deferpool)/2 { - n := len(pp.deferpool) - d := pp.deferpool[n-1] - pp.deferpool[n-1] = nil - pp.deferpool = pp.deferpool[:n-1] - if first == nil { - first = d - } else { - last.link = d + // + // Take this slow path on the system stack so + // we don't grow freedefer's stack. + systemstack(func() { + var first, last *_defer + for len(pp.deferpool) > cap(pp.deferpool)/2 { + n := len(pp.deferpool) + d := pp.deferpool[n-1] + pp.deferpool[n-1] = nil + pp.deferpool = pp.deferpool[:n-1] + if first == nil { + first = d + } else { + last.link = d + } + last = d } - last = d - } - lock(&sched.deferlock) - last.link = sched.deferpool - sched.deferpool = first - unlock(&sched.deferlock) + lock(&sched.deferlock) + last.link = sched.deferpool + sched.deferpool = first + unlock(&sched.deferlock) + }) } // These lines used to be simply `*d = _defer{}` but that @@ -404,6 +420,12 @@ func freedeferfn() { // to have been called by the caller of deferreturn at the point // just before deferreturn was called. The effect is that deferreturn // is called again and again until there are no more deferred functions. +// +// Declared as nosplit, because the function should not be preempted once we start +// modifying the caller's frame in order to reuse the frame to call the deferred +// function. +// +//go:nosplit func deferreturn() { gp := getg() d := gp._defer @@ -424,6 +446,13 @@ func deferreturn() { return } + // Moving arguments around. + // + // Everything called after this point must be recursively + // nosplit because the garbage collector won't know the form + // of the arguments until the jmpdefer can flip the PC over to + // fn. + argp := getcallersp() + sys.MinFrameSize fn := d.fn d.fn = nil gp._defer = d.link @@ -433,9 +462,6 @@ func deferreturn() { // called with a callback on an LR architecture and jmpdefer is on the // stack, because jmpdefer manipulates SP (see issue #8153). _ = **(**funcval)(unsafe.Pointer(&fn)) - // We must not split the stack between computing argp and - // calling jmpdefer because argp is a uintptr stack pointer. - argp := getcallersp() + sys.MinFrameSize jmpdefer(fn, argp) } From 0b8a9ccb25cd9b8f78eb47b1934522af3fb4108f Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Fri, 30 Jul 2021 14:00:27 -0700 Subject: [PATCH 830/940] [dev.typeparams] cmd/compile: make all pointer types have the same shape Except unsafe.Pointer. It has a different Kind, which makes it trickier. Change-Id: I12582afb6e591bea35da9e43ac8d141ed19532a3 Reviewed-on: https://go-review.googlesource.com/c/go/+/338749 Trust: Keith Randall Trust: Dan Scales Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/typecheck/subr.go | 6 ++++++ src/cmd/compile/internal/types/identity.go | 2 +- test/typeparam/shape1.go | 19 ++++++++++++++++++- test/typeparam/shape1.out | 2 ++ 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index e2f0a57e713..5ee4152e1c9 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -1351,6 +1351,12 @@ func Shapify(t *types.Type) *types.Type { // Map all types with the same underlying type to the same shape. u := t.Underlying() + // All pointers have the same shape. + // TODO: Make unsafe.Pointer the same shape as normal pointers. + if u.Kind() == types.TPTR { + u = types.Types[types.TUINT8].PtrTo() + } + if s := shaped[u]; s != nil { return s //TODO: keep? } diff --git a/src/cmd/compile/internal/types/identity.go b/src/cmd/compile/internal/types/identity.go index 0a78092f078..dc39acced86 100644 --- a/src/cmd/compile/internal/types/identity.go +++ b/src/cmd/compile/internal/types/identity.go @@ -31,7 +31,7 @@ func identical(t1, t2 *Type, cmpTags bool, assumedEqual map[typePair]struct{}) b if t1.sym != nil || t2.sym != nil { if t1.HasShape() || t2.HasShape() { switch t1.kind { - case TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64, TUINT64, TINT, TUINT, TUINTPTR, TCOMPLEX64, TCOMPLEX128, TFLOAT32, TFLOAT64, TBOOL, TSTRING, TUNSAFEPTR: + case TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64, TUINT64, TINT, TUINT, TUINTPTR, TCOMPLEX64, TCOMPLEX128, TFLOAT32, TFLOAT64, TBOOL, TSTRING, TPTR, TUNSAFEPTR: return true } // fall through to unnamed type comparison for complex types. diff --git a/test/typeparam/shape1.go b/test/typeparam/shape1.go index 3c9e71ea63d..de1ea65ed22 100644 --- a/test/typeparam/shape1.go +++ b/test/typeparam/shape1.go @@ -10,7 +10,8 @@ type I interface { foo() int } -// There should be a single instantiation of f in this program. +// There should be one instantiation of f for both squarer and doubler. +// Similarly, there should be one instantiation of f for both *incrementer and *decrementer. func f[T I](x T) int { return x.foo() } @@ -27,7 +28,23 @@ func (x doubler) foo() int { return int(2*x) } +type incrementer int16 + +func (x *incrementer) foo() int { + return int(*x+1) +} + +type decrementer int32 + +func (x *decrementer) foo() int{ + return int(*x-1) +} + func main() { println(f(squarer(5))) println(f(doubler(5))) + var i incrementer = 5 + println(f(&i)) + var d decrementer = 5 + println(f(&d)) } diff --git a/test/typeparam/shape1.out b/test/typeparam/shape1.out index 28391fde667..da9a12ded55 100644 --- a/test/typeparam/shape1.out +++ b/test/typeparam/shape1.out @@ -1,2 +1,4 @@ 25 10 +6 +4 From b8ca6e59eda969c1d3aed9b0c5bd9e99cf0e7dfe Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Fri, 30 Jul 2021 11:04:36 -0700 Subject: [PATCH 831/940] all: gofmt Change-Id: Icfafcfb62a389d9fd2e7a4d17809486ed91f15c3 Reviewed-on: https://go-review.googlesource.com/c/go/+/338629 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/crypto/ed25519/internal/edwards25519/field/fe_amd64.go | 1 + src/runtime/export_debug_regabiargs_off_test.go | 3 +-- src/runtime/export_debug_regabiargs_on_test.go | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/crypto/ed25519/internal/edwards25519/field/fe_amd64.go b/src/crypto/ed25519/internal/edwards25519/field/fe_amd64.go index 44dc8e8caf9..8fe583939f1 100644 --- a/src/crypto/ed25519/internal/edwards25519/field/fe_amd64.go +++ b/src/crypto/ed25519/internal/edwards25519/field/fe_amd64.go @@ -1,5 +1,6 @@ // Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT. +//go:build amd64 && gc && !purego // +build amd64,gc,!purego package field diff --git a/src/runtime/export_debug_regabiargs_off_test.go b/src/runtime/export_debug_regabiargs_off_test.go index fce37ab4d19..5009003d27d 100644 --- a/src/runtime/export_debug_regabiargs_off_test.go +++ b/src/runtime/export_debug_regabiargs_off_test.go @@ -3,8 +3,7 @@ // license that can be found in the LICENSE file. //go:build amd64 && linux && !goexperiment.regabiargs -// +build amd64,linux -// +build !goexperiment.regabiargs +// +build amd64,linux,!goexperiment.regabiargs package runtime diff --git a/src/runtime/export_debug_regabiargs_on_test.go b/src/runtime/export_debug_regabiargs_on_test.go index 3c65127e560..e1b72efd0f7 100644 --- a/src/runtime/export_debug_regabiargs_on_test.go +++ b/src/runtime/export_debug_regabiargs_on_test.go @@ -3,8 +3,7 @@ // license that can be found in the LICENSE file. //go:build amd64 && linux && goexperiment.regabiargs -// +build amd64,linux -// +build goexperiment.regabiargs +// +build amd64,linux,goexperiment.regabiargs package runtime From aa3d54da07bea208cd7c5860875b2d3fbbfeb825 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 9 Jun 2021 20:01:12 -0400 Subject: [PATCH 832/940] [dev.typeparams] runtime: rewrite softfloat functions to avoid using floats Currently, most softfloat functions take uint32/64 arguments (for bit representation of float32/64) and operate on uint32/64. But there are exeptions where the function take float arguments and operate on float. So they are only actually softfloat if the helper functions themselves are translated (by the compiler's softfloat mode). These are mostly fine (besides being a bit convoluted). But with register ABIs this inconsistency adds complexity to the compiler to generate such calls, because it needs to be called with the right ABI. Rewrite the functions to operate on uint32/64 directly, using other helper functions. So they all take uint32/64 arguments and return uint32/64. Change-Id: Id9383b74bcbafee44160cc5b58ab245bffbbdfd2 Reviewed-on: https://go-review.googlesource.com/c/go/+/327273 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: David Chase --- src/runtime/softfloat64.go | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/runtime/softfloat64.go b/src/runtime/softfloat64.go index 13bee6c1d7a..084aa132d9c 100644 --- a/src/runtime/softfloat64.go +++ b/src/runtime/softfloat64.go @@ -562,36 +562,38 @@ func f64toint64(x uint64) int64 { return val } -func f64touint64(x float64) uint64 { - if x < float64(1<<63) { - return uint64(int64(x)) +func f64touint64(x uint64) uint64 { + var m uint64 = 0x43e0000000000000 // float64 1<<63 + if fgt64(m, x) { + return uint64(f64toint64(x)) } - y := x - float64(1<<63) - z := uint64(int64(y)) + y := fadd64(x, -m) + z := uint64(f64toint64(y)) return z | (1 << 63) } -func f32touint64(x float32) uint64 { - if x < float32(1<<63) { - return uint64(int64(x)) +func f32touint64(x uint32) uint64 { + var m uint32 = 0x5f000000 // float32 1<<63 + if fgt32(m, x) { + return uint64(f32toint64(x)) } - y := x - float32(1<<63) - z := uint64(int64(y)) + y := fadd32(x, -m) + z := uint64(f32toint64(y)) return z | (1 << 63) } -func fuint64to64(x uint64) float64 { +func fuint64to64(x uint64) uint64 { if int64(x) >= 0 { - return float64(int64(x)) + return fint64to64(int64(x)) } - // See ../cmd/compile/internal/gc/ssa.go:uint64Tofloat + // See ../cmd/compile/internal/ssagen/ssa.go:uint64Tofloat y := x & 1 z := x >> 1 z = z | y - r := float64(int64(z)) - return r + r + r := fint64to64(int64(z)) + return fadd64(r, r) } -func fuint64to32(x uint64) float32 { - return float32(fuint64to64(x)) +func fuint64to32(x uint64) uint32 { + return f64to32(fuint64to64(x)) } From 283991bd7fb5f0004a8d6c27a8b8038e4d448719 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 29 Jul 2021 11:14:54 -0700 Subject: [PATCH 833/940] [dev.typeparams] cmd/compile/internal/types2: print constraint info for type param operands Change-Id: Ic7a249fc150b526835db744431bef500c20fbd26 Reviewed-on: https://go-review.googlesource.com/c/go/+/338309 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/operand.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/cmd/compile/internal/types2/operand.go b/src/cmd/compile/internal/types2/operand.go index 01c720d1f78..34d35b25947 100644 --- a/src/cmd/compile/internal/types2/operand.go +++ b/src/cmd/compile/internal/types2/operand.go @@ -176,16 +176,20 @@ func operandString(x *operand, qf Qualifier) string { if hasType { if x.typ != Typ[Invalid] { var intro string - switch { - case isGeneric(x.typ): - intro = " of generic type " - case asTypeParam(x.typ) != nil: - intro = " of type parameter type " - default: + var tpar *TypeParam + if isGeneric(x.typ) { + intro = " of parameterized type " + } else if tpar = asTypeParam(x.typ); tpar != nil { + intro = " of type parameter " + } else { intro = " of type " } buf.WriteString(intro) WriteType(&buf, x.typ, qf) + if tpar != nil { + buf.WriteString(" constrained by ") + WriteType(&buf, tpar.bound, qf) // do not compute interface type sets here + } } else { buf.WriteString(" with invalid type") } From 8a7ee4c51e992174d432ce0f40d9387a32d6ee4a Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sat, 31 Jul 2021 15:39:08 -0700 Subject: [PATCH 834/940] io/fs: don't use absolute path in DirEntry.Name doc Fixes #47485 Change-Id: I64ac00905a403b7594c706141679051a93058a31 Reviewed-on: https://go-review.googlesource.com/c/go/+/338889 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Dmitri Shuralyov --- src/io/fs/fs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io/fs/fs.go b/src/io/fs/fs.go index e1be32478e0..e603afadb0b 100644 --- a/src/io/fs/fs.go +++ b/src/io/fs/fs.go @@ -86,7 +86,7 @@ type File interface { type DirEntry interface { // Name returns the name of the file (or subdirectory) described by the entry. // This name is only the final element of the path (the base name), not the entire path. - // For example, Name would return "hello.go" not "/home/gopher/hello.go". + // For example, Name would return "hello.go" not "home/gopher/hello.go". Name() string // IsDir reports whether the entry describes a directory. From 156eeb40a6d918bcac82871af1b8e428a5414159 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Sun, 1 Aug 2021 20:29:07 -0700 Subject: [PATCH 835/940] [dev.typeparams] cmd/compile: make HasShape() more efficient by implementing with a type flag Implement HasShape() similar to how HasTParam() is implemented. Fixes #47456 Change-Id: Icbd538574237faad2c4cd8c8e187725a1df47637 Reviewed-on: https://go-review.googlesource.com/c/go/+/339029 Reviewed-by: Keith Randall Trust: Dan Scales --- src/cmd/compile/internal/typecheck/subr.go | 1 + src/cmd/compile/internal/types/type.go | 106 ++++++++++----------- 2 files changed, 54 insertions(+), 53 deletions(-) diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index 5ee4152e1c9..968d7a0d6d7 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -1367,6 +1367,7 @@ func Shapify(t *types.Type) *types.Type { s := types.NewNamed(name) s.SetUnderlying(u) s.SetIsShape(true) + s.SetHasShape(true) name.SetType(s) name.SetTypecheck(1) // TODO: add methods to s that the bound has? diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index 58ac4db95a2..1f01498ca19 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -211,6 +211,7 @@ const ( typeRecur typeHasTParam // there is a typeparam somewhere in the type (generic function or type) typeIsShape // represents a set of closely related types, for generics + typeHasShape // there is a shape somewhere in the type ) func (t *Type) NotInHeap() bool { return t.flags&typeNotInHeap != 0 } @@ -220,17 +221,21 @@ func (t *Type) Deferwidth() bool { return t.flags&typeDeferwidth != 0 } func (t *Type) Recur() bool { return t.flags&typeRecur != 0 } func (t *Type) HasTParam() bool { return t.flags&typeHasTParam != 0 } func (t *Type) IsShape() bool { return t.flags&typeIsShape != 0 } +func (t *Type) HasShape() bool { return t.flags&typeHasShape != 0 } func (t *Type) SetNotInHeap(b bool) { t.flags.set(typeNotInHeap, b) } func (t *Type) SetBroke(b bool) { t.flags.set(typeBroke, b) } func (t *Type) SetNoalg(b bool) { t.flags.set(typeNoalg, b) } func (t *Type) SetDeferwidth(b bool) { t.flags.set(typeDeferwidth, b) } func (t *Type) SetRecur(b bool) { t.flags.set(typeRecur, b) } -func (t *Type) SetIsShape(b bool) { t.flags.set(typeIsShape, b) } // Generic types should never have alg functions. func (t *Type) SetHasTParam(b bool) { t.flags.set(typeHasTParam, b); t.flags.set(typeNoalg, b) } +// Should always do SetHasShape(true) when doing SeIsShape(true). +func (t *Type) SetIsShape(b bool) { t.flags.set(typeIsShape, b) } +func (t *Type) SetHasShape(b bool) { t.flags.set(typeHasShape, b) } + // Kind returns the kind of type t. func (t *Type) Kind() Kind { return t.kind } @@ -271,9 +276,6 @@ func (t *Type) SetRParams(rparams []*Type) { base.Fatalf("Setting nil or zero-length rparams") } t.rparams = &rparams - if t.HasTParam() { - return - } // HasTParam should be set if any rparam is or has a type param. This is // to handle the case of a generic type which doesn't reference any of its // type params (e.g. most commonly, an empty struct). @@ -282,6 +284,10 @@ func (t *Type) SetRParams(rparams []*Type) { t.SetHasTParam(true) break } + if rparam.HasShape() { + t.SetHasShape(true) + break + } } } @@ -624,6 +630,9 @@ func NewArray(elem *Type, bound int64) *Type { if elem.HasTParam() { t.SetHasTParam(true) } + if elem.HasShape() { + t.SetHasShape(true) + } return t } @@ -642,6 +651,9 @@ func NewSlice(elem *Type) *Type { if elem.HasTParam() { t.SetHasTParam(true) } + if elem.HasShape() { + t.SetHasShape(true) + } return t } @@ -654,6 +666,9 @@ func NewChan(elem *Type, dir ChanDir) *Type { if elem.HasTParam() { t.SetHasTParam(true) } + if elem.HasShape() { + t.SetHasShape(true) + } return t } @@ -664,6 +679,9 @@ func NewTuple(t1, t2 *Type) *Type { if t1.HasTParam() || t2.HasTParam() { t.SetHasTParam(true) } + if t1.HasShape() || t2.HasShape() { + t.SetHasShape(true) + } return t } @@ -695,6 +713,9 @@ func NewMap(k, v *Type) *Type { if k.HasTParam() || v.HasTParam() { t.SetHasTParam(true) } + if k.HasShape() || v.HasShape() { + t.SetHasShape(true) + } return t } @@ -719,6 +740,9 @@ func NewPtr(elem *Type) *Type { // when this entry was cached. t.SetHasTParam(true) } + if elem.HasShape() { + t.SetHasShape(true) + } return t } @@ -732,6 +756,9 @@ func NewPtr(elem *Type) *Type { if elem.HasTParam() { t.SetHasTParam(true) } + if elem.HasShape() { + t.SetHasShape(true) + } return t } @@ -1768,6 +1795,9 @@ func (t *Type) SetUnderlying(underlying *Type) { if underlying.HasTParam() { t.SetHasTParam(true) } + if underlying.HasShape() { + t.SetHasShape(true) + } // spec: "The declared type does not inherit any methods bound // to the existing type, but the method set of an interface @@ -1799,6 +1829,15 @@ func fieldsHasTParam(fields []*Field) bool { return false } +func fieldsHasShape(fields []*Field) bool { + for _, f := range fields { + if f.Type != nil && f.Type.HasShape() { + return true + } + } + return false +} + // NewBasic returns a new basic type of the given kind. func NewBasic(kind Kind, obj Object) *Type { t := New(kind) @@ -1818,6 +1857,10 @@ func NewInterface(pkg *Pkg, methods []*Field) *Type { t.SetHasTParam(true) break } + if f.Type != nil && f.Type.HasShape() { + t.SetHasShape(true) + break + } } if anyBroke(methods) { t.SetBroke(true) @@ -1923,6 +1966,9 @@ func NewSignature(pkg *Pkg, recv *Field, tparams, params, results []*Field) *Typ fieldsHasTParam(results) { t.SetHasTParam(true) } + if fieldsHasShape(recvs) || fieldsHasShape(params) || fieldsHasShape(results) { + t.SetHasShape(true) + } return t } @@ -1938,6 +1984,9 @@ func NewStruct(pkg *Pkg, fields []*Field) *Type { if fieldsHasTParam(fields) { t.SetHasTParam(true) } + if fieldsHasShape(fields) { + t.SetHasShape(true) + } return t } @@ -2150,52 +2199,3 @@ var ( ) var SimType [NTYPE]Kind - -// Reports whether t has a shape type anywere. -func (t *Type) HasShape() bool { - return t.HasShape1(map[*Type]bool{}) -} -func (t *Type) HasShape1(visited map[*Type]bool) bool { - if t.IsShape() { - return true - } - if visited[t] { - return false - } - visited[t] = true - if t.Sym() != nil { - for _, u := range t.RParams() { - if u.HasShape1(visited) { - return true - } - } - } - switch t.Kind() { - case TPTR, TARRAY, TSLICE, TCHAN: - return t.Elem().HasShape1(visited) - case TMAP: - return t.Elem().HasShape1(visited) || t.Key().HasShape1(visited) - case TSTRUCT: - for _, f := range t.FieldSlice() { - if f.Type.HasShape1(visited) { - return true - } - } - case TFUNC: - for _, a := range RecvsParamsResults { - for _, f := range a(t).FieldSlice() { - if f.Type.HasShape1(visited) { - return true - } - } - } - case TINTER: - for _, f := range t.Methods().Slice() { - if f.Type.HasShape1(visited) { - return true - } - } - return false - } - return false -} From c3c19731a9dd128b5b81c9062416804a5a4893d2 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 29 Jul 2021 22:24:37 -0700 Subject: [PATCH 836/940] [dev.typeparams] cmd/compile/internal/types2: move instance.go contents into named.go (cleanup) This just moves the code around the instance type into named.go where it belongs. While at it, also removed some left-over references to instance types (which are gone). Removed instance.go. Change-Id: I302a86ca50675b0be54f6138fa47f48f00f9c98f Reviewed-on: https://go-review.googlesource.com/c/go/+/338469 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/instance.go | 42 ------------------- src/cmd/compile/internal/types2/named.go | 38 ++++++++++++++++- src/cmd/compile/internal/types2/predicates.go | 6 --- src/cmd/compile/internal/types2/unify.go | 3 -- 4 files changed, 37 insertions(+), 52 deletions(-) delete mode 100644 src/cmd/compile/internal/types2/instance.go diff --git a/src/cmd/compile/internal/types2/instance.go b/src/cmd/compile/internal/types2/instance.go deleted file mode 100644 index 40e89289a26..00000000000 --- a/src/cmd/compile/internal/types2/instance.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2011 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 types2 - -// TODO(rfindley): move this code to named.go. - -import "cmd/compile/internal/syntax" - -// instance holds position information for use in lazy instantiation. -// -// TODO(rfindley): come up with a better name for this type, now that its usage -// has changed. -type instance struct { - pos syntax.Pos // position of type instantiation; for error reporting only - posList []syntax.Pos // position of each targ; for error reporting only -} - -// expand ensures that the underlying type of n is instantiated. -// The underlying type will be Typ[Invalid] if there was an error. -func (n *Named) expand() { - if n.instance != nil { - // n must be loaded before instantiation, in order to have accurate - // tparams. This is done implicitly by the call to n.TParams, but making it - // explicit is harmless: load is idempotent. - n.load() - inst := n.check.instantiate(n.instance.pos, n.orig.underlying, n.TParams().list(), n.targs, n.instance.posList) - n.underlying = inst - n.fromRHS = inst - n.instance = nil - } -} - -// expand expands uninstantiated named types and leaves all other types alone. -// expand does not recurse. -func expand(typ Type) Type { - if t, _ := typ.(*Named); t != nil { - t.expand() - } - return typ -} diff --git a/src/cmd/compile/internal/types2/named.go b/src/cmd/compile/internal/types2/named.go index 96f2db1429d..8ded197df5b 100644 --- a/src/cmd/compile/internal/types2/named.go +++ b/src/cmd/compile/internal/types2/named.go @@ -4,7 +4,10 @@ package types2 -import "sync" +import ( + "cmd/compile/internal/syntax" + "sync" +) // TODO(gri) Clean up Named struct below; specifically the fromRHS field (can we use underlying?). @@ -252,3 +255,36 @@ func (n *Named) setUnderlying(typ Type) { n.underlying = typ } } + +// instance holds position information for use in lazy instantiation. +// +// TODO(rfindley): come up with a better name for this type, now that its usage +// has changed. +type instance struct { + pos syntax.Pos // position of type instantiation; for error reporting only + posList []syntax.Pos // position of each targ; for error reporting only +} + +// expand ensures that the underlying type of n is instantiated. +// The underlying type will be Typ[Invalid] if there was an error. +func (n *Named) expand() { + if n.instance != nil { + // n must be loaded before instantiation, in order to have accurate + // tparams. This is done implicitly by the call to n.TParams, but making it + // explicit is harmless: load is idempotent. + n.load() + inst := n.check.instantiate(n.instance.pos, n.orig.underlying, n.TParams().list(), n.targs, n.instance.posList) + n.underlying = inst + n.fromRHS = inst + n.instance = nil + } +} + +// expand expands uninstantiated named types and leaves all other types alone. +// expand does not recurse. +func expand(typ Type) Type { + if t, _ := typ.(*Named); t != nil { + t.expand() + } + return typ +} diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go index 84342b2796a..bb7fedda3b2 100644 --- a/src/cmd/compile/internal/types2/predicates.go +++ b/src/cmd/compile/internal/types2/predicates.go @@ -57,9 +57,6 @@ func isNumericOrString(typ Type) bool { return is(typ, IsNumeric|IsString) } func isTyped(typ Type) bool { // isTyped is called with types that are not fully // set up. Must not call asBasic()! - // A *Named or *instance type is always typed, so - // we only need to check if we have a true *Basic - // type. t, _ := typ.(*Basic) return t == nil || t.info&IsUntyped == 0 } @@ -328,9 +325,6 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { case *TypeParam: // nothing to do (x and y being equal is caught in the very beginning of this function) - // case *instance: - // unreachable since types are expanded - case *top: // Either both types are theTop in which case the initial x == y check // will have caught them. Otherwise they are not identical. diff --git a/src/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go index 7221356354a..aa9a23d243b 100644 --- a/src/cmd/compile/internal/types2/unify.go +++ b/src/cmd/compile/internal/types2/unify.go @@ -459,9 +459,6 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool { // are identical if they originate in the same declaration. return x == y - // case *instance: - // unreachable since types are expanded - case nil: // avoid a crash in case of nil type From e56234a30544c043b45601ce01601e3a03e00d63 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Mon, 2 Aug 2021 11:07:45 -0700 Subject: [PATCH 837/940] [dev.typeparams] cmd/compile: simple shape cleanups - Changed some early returns to asserts (instantiateMethods and Shapify should never take a shape arg) - Added suggested change (by Ingo) to use copy() in getInstantiation() - Clarified that shape types never have methods in Shapify(), removed some TODO comments. Change-Id: Ia2164ffe670a777f7797bbb45c7ef5e6e9e15357 Reviewed-on: https://go-review.googlesource.com/c/go/+/338971 Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall Trust: Dan Scales --- src/cmd/compile/internal/noder/stencil.go | 9 ++------- src/cmd/compile/internal/typecheck/subr.go | 10 +++++----- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 037f309a82b..c006c4af446 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -474,10 +474,7 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { func (g *irgen) instantiateMethods() { for i := 0; i < len(g.instTypeList); i++ { typ := g.instTypeList[i] - if typ.HasShape() { - // Shape types should not have any methods. - continue - } + assert(!typ.HasShape()) // Mark runtime type as needed, since this ensures that the // compiler puts out the needed DWARF symbols, when this // instantiated type has a different package from the local @@ -782,9 +779,7 @@ func (g *irgen) getInstantiation(nameNode *ir.Name, shapes []*types.Type, isMeth if !t.HasShape() { if s1 == nil { s1 = make([]*types.Type, len(shapes)) - for j := 0; j < i; j++ { - s1[j] = shapes[j] - } + copy(s1[0:i], shapes[0:i]) } s1[i] = typecheck.Shapify(t) } else if s1 != nil { diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index 968d7a0d6d7..25db24259c3 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -1338,6 +1338,9 @@ func genericTypeName(sym *types.Sym) string { // Shapify takes a concrete type and returns a GCshape type that can // be used in place of the input type and still generate identical code. +// No methods are added - all methods calls directly on a shape should +// be done by converting to an interface using the dictionary. +// // TODO: this could take the generic function and base its decisions // on how that generic function uses this type argument. For instance, // if it doesn't use it as a function argument/return value, then @@ -1345,9 +1348,7 @@ func genericTypeName(sym *types.Sym) string { // differ in how they get passed as arguments). For now, we only // unify two different types if they are identical in every possible way. func Shapify(t *types.Type) *types.Type { - if t.IsShape() { - return t // TODO: is this right? - } + assert(!t.HasShape()) // Map all types with the same underlying type to the same shape. u := t.Underlying() @@ -1358,7 +1359,7 @@ func Shapify(t *types.Type) *types.Type { } if s := shaped[u]; s != nil { - return s //TODO: keep? + return s } sym := Lookup(fmt.Sprintf(".shape%d", snum)) @@ -1370,7 +1371,6 @@ func Shapify(t *types.Type) *types.Type { s.SetHasShape(true) name.SetType(s) name.SetTypecheck(1) - // TODO: add methods to s that the bound has? shaped[u] = s return s } From 1b193598b3a4ad3138626ca97bca752e9e63b21c Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 2 Aug 2021 18:01:46 -0700 Subject: [PATCH 838/940] [dev.typeparams] cmd/compile: fail early on unexpected types2.Invalid In unified IR, fail right away if we find a types2.Invalid while writing out the package. This provides a clearer error message for https://github.com/golang/go/issues/25838#issuecomment-448746670. Updates #25838. Change-Id: I6902fdd891fc31bbb832b6fdba00eca301282409 Reviewed-on: https://go-review.googlesource.com/c/go/+/338973 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/noder/writer.go | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go index 07d4363f898..eb1db623b4a 100644 --- a/src/cmd/compile/internal/noder/writer.go +++ b/src/cmd/compile/internal/noder/writer.go @@ -282,19 +282,23 @@ func (pw *pkgWriter) typIdx(typ types2.Type, dict *writerDict) typeInfo { base.Fatalf("unexpected type: %v (%T)", typ, typ) case *types2.Basic: - if kind := typ.Kind(); types2.Typ[kind] == typ { + switch kind := typ.Kind(); { + case kind == types2.Invalid: + base.Fatalf("unexpected types2.Invalid") + + case types2.Typ[kind] == typ: w.code(typeBasic) w.len(int(kind)) - break + + default: + // Handle "byte" and "rune" as references to their TypeName. + obj := types2.Universe.Lookup(typ.Name()) + assert(obj.Type() == typ) + + w.code(typeNamed) + w.obj(obj, nil) } - // Handle "byte" and "rune" as references to their TypeName. - obj := types2.Universe.Lookup(typ.Name()) - assert(obj.Type() == typ) - - w.code(typeNamed) - w.obj(obj, nil) - case *types2.Named: // Type aliases can refer to uninstantiated generic types, so we // might see len(TParams) != 0 && len(TArgs) == 0 here. From 656f0888b7de3b96792c1444bc15fe2e586ab5ef Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 9 Jun 2021 20:14:15 -0400 Subject: [PATCH 839/940] [dev.typeparams] cmd/compile: make softfloat mode work with register ABI Previously, softfloat mode does not work with register ABI, mainly because the compiler doesn't know how to pass floating point arguments and results. According to the ABI it should be passed in FP registers, but there isn't any in softfloat mode. This CL makes it work. When softfloat is used, we define the ABI as having 0 floating point registers (because there aren't any). The integer registers are unchanged. So floating point arguments and results are passed in memory. Another option is to pass (the bit representation of) floating point values in integer registers. But this complicates things because it'd need to reorder integer argument registers. Change-Id: Ibecbeccb658c10a868fa7f2dcf75138f719cc809 Reviewed-on: https://go-review.googlesource.com/c/go/+/327274 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: David Chase --- src/cmd/compile/internal/gc/main.go | 3 --- src/cmd/compile/internal/ssa/config.go | 6 ++++- src/cmd/compile/internal/ssa/expand_calls.go | 14 +++++++--- src/cmd/compile/internal/ssa/export_test.go | 2 +- src/cmd/compile/internal/ssa/softfloat.go | 1 + src/cmd/compile/internal/ssagen/ssa.go | 27 +++++++++++++++++--- test/fixedbugs/issue26163.go | 2 +- test/fixedbugs/issue28688.go | 2 +- 8 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 68017516dfd..6a373ce33d7 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -160,9 +160,6 @@ func Main(archInit func(*ssagen.ArchInfo)) { dwarf.EnableLogging(base.Debug.DwarfInl != 0) } if base.Debug.SoftFloat != 0 { - if buildcfg.Experiment.RegabiArgs { - log.Fatalf("softfloat mode with GOEXPERIMENT=regabiargs not implemented ") - } ssagen.Arch.SoftFloat = true } diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index b08a3943686..32e3a0860e3 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -171,7 +171,7 @@ type Frontend interface { } // NewConfig returns a new configuration object for the given architecture. -func NewConfig(arch string, types Types, ctxt *obj.Link, optimize bool) *Config { +func NewConfig(arch string, types Types, ctxt *obj.Link, optimize, softfloat bool) *Config { c := &Config{arch: arch, Types: types} c.useAvg = true c.useHmul = true @@ -320,6 +320,10 @@ func NewConfig(arch string, types Types, ctxt *obj.Link, optimize bool) *Config c.optimize = optimize c.useSSE = true c.UseFMA = true + c.SoftFloat = softfloat + if softfloat { + c.floatParamRegs = nil // no FP registers in softfloat mode + } c.ABI0 = abi.NewABIConfig(0, 0, ctxt.FixedFrameSize()) c.ABI1 = abi.NewABIConfig(len(c.intParamRegs), len(c.floatParamRegs), ctxt.FixedFrameSize()) diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index 7e973ab2059..a8c6c26dadc 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -215,7 +215,7 @@ func (x *expandState) isAlreadyExpandedAggregateType(t *types.Type) bool { return false } return t.IsStruct() || t.IsArray() || t.IsComplex() || t.IsInterface() || t.IsString() || t.IsSlice() || - t.Size() > x.regSize && t.IsInteger() + (t.Size() > x.regSize && (t.IsInteger() || (x.f.Config.SoftFloat && t.IsFloat()))) } // offsetFrom creates an offset from a pointer, simplifying chained offsets and offsets from SP @@ -380,6 +380,12 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, // The OpLoad was created to load the single field of the IData // This case removes that StructSelect. if leafType != selector.Type { + if x.f.Config.SoftFloat && selector.Type.IsFloat() { + if x.debug { + x.Printf("---OpLoad, break\n") + } + break // softfloat pass will take care of that + } x.f.Fatalf("Unexpected Load as selector, leaf=%s, selector=%s\n", leaf.LongString(), selector.LongString()) } leaf.copyOf(selector) @@ -525,11 +531,11 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, case OpComplexReal: ls := x.rewriteSelect(leaf, selector.Args[0], offset, regOffset) - locs = x.splitSlots(ls, ".real", 0, leafType) + locs = x.splitSlots(ls, ".real", 0, selector.Type) case OpComplexImag: - ls := x.rewriteSelect(leaf, selector.Args[0], offset+leafType.Width, regOffset+RO_complex_imag) // result is FloatNN, width of result is offset of imaginary part. - locs = x.splitSlots(ls, ".imag", leafType.Width, leafType) + ls := x.rewriteSelect(leaf, selector.Args[0], offset+selector.Type.Width, regOffset+RO_complex_imag) // result is FloatNN, width of result is offset of imaginary part. + locs = x.splitSlots(ls, ".imag", selector.Type.Width, selector.Type) case OpStringLen, OpSliceLen: ls := x.rewriteSelect(leaf, selector.Args[0], offset+x.ptrSize, regOffset+RO_slice_len) diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go index 8ed8a0c4a6e..6d3c0f3ccbd 100644 --- a/src/cmd/compile/internal/ssa/export_test.go +++ b/src/cmd/compile/internal/ssa/export_test.go @@ -39,7 +39,7 @@ func testConfigArch(tb testing.TB, arch string) *Conf { tb.Fatal("testTypes is 64-bit only") } c := &Conf{ - config: NewConfig(arch, testTypes, ctxt, true), + config: NewConfig(arch, testTypes, ctxt, true, false), tb: tb, } return c diff --git a/src/cmd/compile/internal/ssa/softfloat.go b/src/cmd/compile/internal/ssa/softfloat.go index a8a8f836294..351f824a9f5 100644 --- a/src/cmd/compile/internal/ssa/softfloat.go +++ b/src/cmd/compile/internal/ssa/softfloat.go @@ -63,6 +63,7 @@ func softfloat(f *Func) { v.Aux = f.Config.Types.UInt32 case 8: v.Aux = f.Config.Types.UInt64 + newInt64 = true default: v.Fatalf("bad float type with size %d", size) } diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 7e2f6a7471c..1a0a98f6aa1 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -87,8 +87,7 @@ func InitConfig() { _ = types.NewPtr(types.Types[types.TINT64]) // *int64 _ = types.NewPtr(types.ErrorType) // *error types.NewPtrCacheEnabled = false - ssaConfig = ssa.NewConfig(base.Ctxt.Arch.Name, *types_, base.Ctxt, base.Flag.N == 0) - ssaConfig.SoftFloat = Arch.SoftFloat + ssaConfig = ssa.NewConfig(base.Ctxt.Arch.Name, *types_, base.Ctxt, base.Flag.N == 0, Arch.SoftFloat) ssaConfig.Race = base.Flag.Race ssaCaches = make([]ssa.Cache, base.Flag.LowerC) @@ -3653,6 +3652,16 @@ func softfloatInit() { // TODO: do not emit sfcall if operation can be optimized to constant in later // opt phase func (s *state) sfcall(op ssa.Op, args ...*ssa.Value) (*ssa.Value, bool) { + f2i := func(t *types.Type) *types.Type { + switch t.Kind() { + case types.TFLOAT32: + return types.Types[types.TUINT32] + case types.TFLOAT64: + return types.Types[types.TUINT64] + } + return t + } + if callDef, ok := softFloatOps[op]; ok { switch op { case ssa.OpLess32F, @@ -3665,7 +3674,19 @@ func (s *state) sfcall(op ssa.Op, args ...*ssa.Value) (*ssa.Value, bool) { args[1] = s.newValue1(s.ssaOp(ir.ONEG, types.Types[callDef.rtype]), args[1].Type, args[1]) } - result := s.rtcall(callDef.rtfn, true, []*types.Type{types.Types[callDef.rtype]}, args...)[0] + // runtime functions take uints for floats and returns uints. + // Convert to uints so we use the right calling convention. + for i, a := range args { + if a.Type.IsFloat() { + args[i] = s.newValue1(ssa.OpCopy, f2i(a.Type), a) + } + } + + rt := types.Types[callDef.rtype] + result := s.rtcall(callDef.rtfn, true, []*types.Type{f2i(rt)}, args...)[0] + if rt.IsFloat() { + result = s.newValue1(ssa.OpCopy, rt, result) + } if op == ssa.OpNeq32F || op == ssa.OpNeq64F { result = s.newValue1(ssa.OpNot, result.Type, result) } diff --git a/test/fixedbugs/issue26163.go b/test/fixedbugs/issue26163.go index d141a2797d6..3f3d77859de 100644 --- a/test/fixedbugs/issue26163.go +++ b/test/fixedbugs/issue26163.go @@ -1,4 +1,4 @@ -// compile -N -d=softfloat -goexperiment noregabiargs +// compile -N -d=softfloat // Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/test/fixedbugs/issue28688.go b/test/fixedbugs/issue28688.go index 8ef0802812c..0d2000e1498 100644 --- a/test/fixedbugs/issue28688.go +++ b/test/fixedbugs/issue28688.go @@ -1,4 +1,4 @@ -// run -gcflags=-d=softfloat -goexperiment noregabiargs +// run -gcflags=-d=softfloat // Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style From fe73f28dc5e22ab6b54b7433dd6e63caf5c9da72 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 3 Aug 2021 10:37:33 -0700 Subject: [PATCH 840/940] [dev.typeparams] cmd/compile: set sym.Def to ir.Name for method value wrappers The code for generating method value wrappers is weird that it sets sym.Def to the generated ir.Func, whereas normally sym.Def points to ir.Name. While here, change methodValueWrapper to return the ir.Name too, since that's what the caller wants. Change-Id: I3da5320ca0bf4d32d7b420345454f19075d19a26 Reviewed-on: https://go-review.googlesource.com/c/go/+/339410 Trust: Matthew Dempsky Trust: Cuong Manh Le Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/noder/reader.go | 2 +- src/cmd/compile/internal/walk/closure.go | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 516bf8f1f74..83979a91c8a 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -2253,7 +2253,7 @@ func (r *reader) methodValueWrapper(tbase *types.Type, method *types.Field, targ pos := base.AutogeneratedPos fn := r.newWrapperFunc(pos, sym, nil, method) - sym.Def = fn + sym.Def = fn.Nname // Declare and initialize variable holding receiver. recv := ir.NewHiddenParam(pos, fn, typecheck.Lookup(".this"), recvType) diff --git a/src/cmd/compile/internal/walk/closure.go b/src/cmd/compile/internal/walk/closure.go index 2d0b2dcc0ee..902e01ef388 100644 --- a/src/cmd/compile/internal/walk/closure.go +++ b/src/cmd/compile/internal/walk/closure.go @@ -179,7 +179,7 @@ func walkMethodValue(n *ir.SelectorExpr, init *ir.Nodes) ir.Node { clos := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ), nil) clos.SetEsc(n.Esc()) - clos.List = []ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, methodValueWrapper(n).Nname), n.X} + clos.List = []ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, methodValueWrapper(n)), n.X} addr := typecheck.NodAddr(clos) addr.SetEsc(n.Esc()) @@ -199,11 +199,11 @@ func walkMethodValue(n *ir.SelectorExpr, init *ir.Nodes) ir.Node { return walkExpr(cfn, init) } -// methodValueWrapper returns the DCLFUNC node representing the +// methodValueWrapper returns the ONAME node representing the // wrapper function (*-fm) needed for the given method value. If the // wrapper function hasn't already been created yet, it's created and // added to typecheck.Target.Decls. -func methodValueWrapper(dot *ir.SelectorExpr) *ir.Func { +func methodValueWrapper(dot *ir.SelectorExpr) *ir.Name { if dot.Op() != ir.OMETHVALUE { base.Fatalf("methodValueWrapper: unexpected %v (%v)", dot, dot.Op()) } @@ -214,7 +214,7 @@ func methodValueWrapper(dot *ir.SelectorExpr) *ir.Func { sym := ir.MethodSymSuffix(rcvrtype, meth, "-fm") if sym.Uniq() { - return sym.Def.(*ir.Func) + return sym.Def.(*ir.Name) } sym.SetUniq(true) @@ -262,10 +262,10 @@ func methodValueWrapper(dot *ir.SelectorExpr) *ir.Func { // typecheckslice() requires that Curfn is set when processing an ORETURN. ir.CurFunc = fn typecheck.Stmts(fn.Body) - sym.Def = fn + sym.Def = fn.Nname typecheck.Target.Decls = append(typecheck.Target.Decls, fn) ir.CurFunc = savecurfn base.Pos = saveLineNo - return fn + return fn.Nname } From 7ab875402985ea5a31512fb9750dc0f809e06861 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 2 Aug 2021 23:56:13 -0700 Subject: [PATCH 841/940] [dev.typeparams] cmd/compile: avoid redundant method wrappers in unified IR Currently, unified IR takes a simple approach of generating method wrappers for every anonymous type that it sees. This is correct, but spends a lot of time in code generation and bloats the object files with duplicate method wrappers that the linker discards. This CL changes it to distinguish anonymous types that were found in imported packages vs the local package. The simple win here is that now we stop emitting wrappers for imported types; but by keeping track of them and marking them as "have" instead of "need", we can avoid emitting wrappers for types that appear in both the local package and imported packages. This can be improved further, but this is a simple first step that prevents large protobuf projects from blowing up build cache limits. Change-Id: Ia65e8981cb1f067eca2bd072b9bbb77c27b95207 Reviewed-on: https://go-review.googlesource.com/c/go/+/339411 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/noder/reader.go | 71 +++++++++++++------ .../compile/internal/reflectdata/reflect.go | 3 +- 2 files changed, 50 insertions(+), 24 deletions(-) diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 83979a91c8a..5481812b18d 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -2125,16 +2125,32 @@ func usedLocals(body []ir.Node) ir.NameSet { // method wrappers. var needWrapperTypes []*types.Type -func (r *reader) needWrapper(typ *types.Type) *types.Type { - // TODO(mdempsky): Be more judicious about generating wrappers. - // For now, generating all possible wrappers is simple and correct, - // but potentially wastes a lot of time/space. +// haveWrapperTypes lists types for which we know we already have +// method wrappers, because we found the type in an imported package. +var haveWrapperTypes []*types.Type +func (r *reader) needWrapper(typ *types.Type) *types.Type { if typ.IsPtr() { base.Fatalf("bad pointer type: %v", typ) } - needWrapperTypes = append(needWrapperTypes, typ) + // If a type was found in an imported package, then we can assume + // that package (or one of its transitive dependencies) already + // generated method wrappers for it. + // + // Exception: If we're instantiating an imported generic type or + // function, we might be instantiating it with type arguments not + // previously seen before. + // + // TODO(mdempsky): Distinguish when a generic function or type was + // instantiated in an imported package so that we can add types to + // haveWrapperTypes instead. + if r.p != localPkgReader && !r.hasTypeParams() { + haveWrapperTypes = append(haveWrapperTypes, typ) + } else { + needWrapperTypes = append(needWrapperTypes, typ) + } + return typ } @@ -2143,21 +2159,33 @@ func (r *reader) wrapTypes(target *ir.Package) { r.needWrapper(types.ErrorType) seen := make(map[string]*types.Type) - for _, typ := range needWrapperTypes { - if typ.Sym() == nil { - key := typ.LinkString() - if prev := seen[key]; prev != nil { - if !types.Identical(typ, prev) { - base.Fatalf("collision: types %v and %v have short string %q", typ, prev, key) - } - continue - } - seen[key] = typ + addType := func(typ *types.Type) bool { + if typ.Sym() != nil { + return true } - r.wrapType(typ, target) + key := typ.LinkString() + if prev := seen[key]; prev != nil { + if !types.Identical(typ, prev) { + base.Fatalf("collision: types %v and %v have short string %q", typ, prev, key) + } + return false + } + + seen[key] = typ + return true } + for _, typ := range haveWrapperTypes { + addType(typ) + } + haveWrapperTypes = nil + + for _, typ := range needWrapperTypes { + if addType(typ) { + r.wrapType(typ, target) + } + } needWrapperTypes = nil } @@ -2243,12 +2271,6 @@ func (r *reader) methodValueWrapper(tbase *types.Type, method *types.Field, targ assert(!sym.Uniq()) sym.SetUniq(true) - // TODO(mdempsky): Fix typecheck to not depend on creation of - // imported method value wrappers. - if false && !reflectdata.NeedEmit(tbase) { - return - } - // TODO(mdempsky): Use method.Pos instead? pos := base.AutogeneratedPos @@ -2258,6 +2280,11 @@ func (r *reader) methodValueWrapper(tbase *types.Type, method *types.Field, targ // Declare and initialize variable holding receiver. recv := ir.NewHiddenParam(pos, fn, typecheck.Lookup(".this"), recvType) + if !reflectdata.NeedEmit(tbase) { + typecheck.Func(fn) + return + } + addTailCall(pos, fn, recv, method) r.finishWrapperFunc(fn, target) diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index dca8de74f30..19cf2a0a125 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -1809,9 +1809,8 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy newnam.SetSiggen(true) // Except in quirks mode, unified IR creates its own wrappers. - // Complain loudly if it missed any. if base.Debug.Unified != 0 && base.Debug.UnifiedQuirks == 0 { - base.FatalfAt(method.Pos, "missing wrapper for %+v (%+v, %v) / %+v / %+v", rcvr, orig, types.IsDirectIface(orig), method.Sym, newnam) + return lsym } if !generic && types.Identical(rcvr, method.Type.Recv().Type) { From 077925e2b008a258f5204aab8a454294b9cdca96 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Mon, 26 Jul 2021 12:04:36 -0400 Subject: [PATCH 842/940] [dev.typeparams] runtime: remove unnecessary split-prevention from defer code Prior to regabi, the compiler passed defer arguments to the runtime as untyped values on the stack. This meant a lot of defer-related runtime functions had to be very careful not to grow the stack or allow preemption since the stack could not be safely scanned or moved. However, with regabi, every defer is now simply a func() from the runtime's perspective, which means we no longer have untyped values on the stack when we enter defer-related runtime code. Hence, this CL removes a lot of the now-unnecessary carefulness in the defer implementation. Specifically, deferreturn no longer needs to be nosplit because it doesn't copy untyped defer arguments to its caller's frame (we also update some stale comments in deferreturn). freedefer no longer needs to be nosplit because it's none of its callers are deeply nosplit. And newdefer and freedefer no longer need to switch to the systemstack on their slow paths to avoid stack growth. deferprocStack is the only function that still needs to be nosplit, but that's because the compiler calls it with uninitialized live pointer slots on the stack (maybe we should change that, but that's a very different fix). This is a retry of CL 337651, which was rolled back. This version disables preemption in newdefer and freedefer while they hold the current P. Change-Id: Ibf469addc0b69dc3ba9a3d1a5e0c2804b7b4b244 Reviewed-on: https://go-review.googlesource.com/c/go/+/339396 Trust: Austin Clements Run-TryBot: Austin Clements TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/runtime/panic.go | 98 ++++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 58 deletions(-) diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 35f3b44a4d5..b77376b5986 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -261,10 +261,8 @@ func deferproc(fn func()) { // deferprocStack queues a new deferred function with a defer record on the stack. // The defer record must have its fn field initialized. // All other fields can contain junk. -// The defer record must be immediately followed in memory by -// the arguments of the defer. -// Nosplit because the arguments on the stack won't be scanned -// until the defer record is spliced into the gp._defer list. +// Nosplit because of the uninitialized pointer fields on the stack. +// //go:nosplit func deferprocStack(d *_defer) { gp := getg() @@ -310,27 +308,26 @@ func deferprocStack(d *_defer) { // added to any defer chain yet. func newdefer() *_defer { var d *_defer - gp := getg() - pp := gp.m.p.ptr() + mp := acquirem() + pp := mp.p.ptr() if len(pp.deferpool) == 0 && sched.deferpool != nil { - // Take the slow path on the system stack so - // we don't grow newdefer's stack. - systemstack(func() { - lock(&sched.deferlock) - for len(pp.deferpool) < cap(pp.deferpool)/2 && sched.deferpool != nil { - d := sched.deferpool - sched.deferpool = d.link - d.link = nil - pp.deferpool = append(pp.deferpool, d) - } - unlock(&sched.deferlock) - }) + lock(&sched.deferlock) + for len(pp.deferpool) < cap(pp.deferpool)/2 && sched.deferpool != nil { + d := sched.deferpool + sched.deferpool = d.link + d.link = nil + pp.deferpool = append(pp.deferpool, d) + } + unlock(&sched.deferlock) } if n := len(pp.deferpool); n > 0 { d = pp.deferpool[n-1] pp.deferpool[n-1] = nil pp.deferpool = pp.deferpool[:n-1] } + releasem(mp) + mp, pp = nil, nil + if d == nil { // Allocate new defer. d = new(_defer) @@ -341,11 +338,6 @@ func newdefer() *_defer { // Free the given defer. // The defer cannot be used after this call. -// -// This must not grow the stack because there may be a frame without a -// stack map when this is called. -// -//go:nosplit func freedefer(d *_defer) { if d._panic != nil { freedeferpanic() @@ -356,31 +348,28 @@ func freedefer(d *_defer) { if !d.heap { return } - pp := getg().m.p.ptr() + + mp := acquirem() + pp := mp.p.ptr() if len(pp.deferpool) == cap(pp.deferpool) { // Transfer half of local cache to the central cache. - // - // Take this slow path on the system stack so - // we don't grow freedefer's stack. - systemstack(func() { - var first, last *_defer - for len(pp.deferpool) > cap(pp.deferpool)/2 { - n := len(pp.deferpool) - d := pp.deferpool[n-1] - pp.deferpool[n-1] = nil - pp.deferpool = pp.deferpool[:n-1] - if first == nil { - first = d - } else { - last.link = d - } - last = d + var first, last *_defer + for len(pp.deferpool) > cap(pp.deferpool)/2 { + n := len(pp.deferpool) + d := pp.deferpool[n-1] + pp.deferpool[n-1] = nil + pp.deferpool = pp.deferpool[:n-1] + if first == nil { + first = d + } else { + last.link = d } - lock(&sched.deferlock) - last.link = sched.deferpool - sched.deferpool = first - unlock(&sched.deferlock) - }) + last = d + } + lock(&sched.deferlock) + last.link = sched.deferpool + sched.deferpool = first + unlock(&sched.deferlock) } // These lines used to be simply `*d = _defer{}` but that @@ -398,6 +387,9 @@ func freedefer(d *_defer) { d.link = nil pp.deferpool = append(pp.deferpool, d) + + releasem(mp) + mp, pp = nil, nil } // Separate function so that it can split stack. @@ -420,12 +412,6 @@ func freedeferfn() { // to have been called by the caller of deferreturn at the point // just before deferreturn was called. The effect is that deferreturn // is called again and again until there are no more deferred functions. -// -// Declared as nosplit, because the function should not be preempted once we start -// modifying the caller's frame in order to reuse the frame to call the deferred -// function. -// -//go:nosplit func deferreturn() { gp := getg() d := gp._defer @@ -446,13 +432,6 @@ func deferreturn() { return } - // Moving arguments around. - // - // Everything called after this point must be recursively - // nosplit because the garbage collector won't know the form - // of the arguments until the jmpdefer can flip the PC over to - // fn. - argp := getcallersp() + sys.MinFrameSize fn := d.fn d.fn = nil gp._defer = d.link @@ -462,6 +441,9 @@ func deferreturn() { // called with a callback on an LR architecture and jmpdefer is on the // stack, because jmpdefer manipulates SP (see issue #8153). _ = **(**funcval)(unsafe.Pointer(&fn)) + // We must not split the stack between computing argp and + // calling jmpdefer because argp is a uintptr stack pointer. + argp := getcallersp() + sys.MinFrameSize jmpdefer(fn, argp) } From 1a0630aef474320e71595ed1a4a984fc7c7bbc0a Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Mon, 26 Jul 2021 15:44:22 -0400 Subject: [PATCH 843/940] [dev.typeparams] runtime,cmd/compile,cmd/link: replace jmpdefer with a loop Currently, deferreturn runs deferred functions by backing up its return PC to the deferreturn call, and then effectively tail-calling the deferred function (via jmpdefer). The effect of this is that the deferred function appears to be called directly from the deferee, and when it returns, the deferee calls deferreturn again so it can run the next deferred function if necessary. This unusual flow control leads to a large number of special cases and complications all over the tool chain. This used to be necessary because deferreturn copied the deferred function's argument frame directly into its caller's frame and then had to invoke that call as if it had been called from its caller's frame so it could access it arguments. But now that we've simplified defer processing so the runtime only deals with argument-less closures, this approach is no longer necessary. This CL simplifies all of this by making deferreturn simply call deferred functions in a loop. This eliminates the need for jmpdefer, so we can delete a bunch of per-architecture assembly code. This eliminates several special cases on Wasm, since it couldn't support these calling shenanigans directly and thus had to simulate the loop a different way. Now Wasm can largely work the way the other platforms do. This eliminates the per-architecture Ginsnopdefer operation. On PPC64, this was necessary to reload the TOC pointer after the tail call (since TOC pointers in general make tail calls impossible). The tail call is gone, and in the case where we do force a jump to the deferreturn call when recovering from an open-coded defer, we go through gogo (via runtime.recovery), which handles the TOC. On other platforms, we needed a NOP so traceback didn't get confused by seeing the return to the CALL instruction, rather than the usual return to the instruction following the CALL instruction. Now we don't inject a return to the CALL instruction at all, so this NOP is also unnecessary. The one potential effect of this is that deferreturn could now appear in stack traces from deferred functions. However, this could already happen from open-coded defers, so we've long since marked deferreturn as a "wrapper" so it gets elided not only from printed stack traces, but from runtime.Callers*. This is a retry of CL 337652 because we had to back out its parent. There are no changes in this version. Change-Id: I3f54b7fec1d7ccac71cc6cf6835c6a46b7e5fb6c Reviewed-on: https://go-review.googlesource.com/c/go/+/339397 Trust: Austin Clements Run-TryBot: Austin Clements TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/cmd/compile/internal/amd64/galign.go | 1 - src/cmd/compile/internal/arm/galign.go | 1 - src/cmd/compile/internal/arm64/galign.go | 1 - src/cmd/compile/internal/mips/galign.go | 1 - src/cmd/compile/internal/mips64/galign.go | 1 - src/cmd/compile/internal/ppc64/galign.go | 1 - src/cmd/compile/internal/ppc64/ggen.go | 27 ---------- src/cmd/compile/internal/riscv64/galign.go | 1 - src/cmd/compile/internal/s390x/galign.go | 1 - src/cmd/compile/internal/ssagen/arch.go | 3 +- src/cmd/compile/internal/ssagen/ssa.go | 12 ----- src/cmd/compile/internal/wasm/ssa.go | 7 ++- src/cmd/compile/internal/x86/galign.go | 1 - src/cmd/internal/obj/arm/asm5.go | 11 ++-- src/cmd/internal/obj/wasm/wasmobj.go | 36 -------------- src/cmd/internal/obj/x86/asm6.go | 1 - src/cmd/internal/objabi/funcid.go | 2 - src/cmd/link/internal/ld/pcln.go | 9 ++-- src/runtime/asm_386.s | 20 -------- src/runtime/asm_amd64.s | 15 ------ src/runtime/asm_arm.s | 14 ------ src/runtime/asm_arm64.s | 17 ------- src/runtime/asm_mips64x.s | 16 ------ src/runtime/asm_mipsx.s | 16 ------ src/runtime/asm_ppc64x.s | 28 ----------- src/runtime/asm_riscv64.s | 15 ------ src/runtime/asm_s390x.s | 15 ------ src/runtime/asm_wasm.s | 29 ----------- src/runtime/panic.go | 58 ++++++++++------------ src/runtime/stubs.go | 2 - src/runtime/symtab.go | 1 - 31 files changed, 39 insertions(+), 324 deletions(-) diff --git a/src/cmd/compile/internal/amd64/galign.go b/src/cmd/compile/internal/amd64/galign.go index 3b13e123a74..ca44263afc4 100644 --- a/src/cmd/compile/internal/amd64/galign.go +++ b/src/cmd/compile/internal/amd64/galign.go @@ -18,7 +18,6 @@ func Init(arch *ssagen.ArchInfo) { arch.ZeroRange = zerorange arch.Ginsnop = ginsnop - arch.Ginsnopdefer = ginsnop arch.SSAMarkMoves = ssaMarkMoves arch.SSAGenValue = ssaGenValue diff --git a/src/cmd/compile/internal/arm/galign.go b/src/cmd/compile/internal/arm/galign.go index d68500280d0..23e52bacbf2 100644 --- a/src/cmd/compile/internal/arm/galign.go +++ b/src/cmd/compile/internal/arm/galign.go @@ -18,7 +18,6 @@ func Init(arch *ssagen.ArchInfo) { arch.SoftFloat = buildcfg.GOARM == 5 arch.ZeroRange = zerorange arch.Ginsnop = ginsnop - arch.Ginsnopdefer = ginsnop arch.SSAMarkMoves = func(s *ssagen.State, b *ssa.Block) {} arch.SSAGenValue = ssaGenValue diff --git a/src/cmd/compile/internal/arm64/galign.go b/src/cmd/compile/internal/arm64/galign.go index 2a61b9dd997..3ebd860de8f 100644 --- a/src/cmd/compile/internal/arm64/galign.go +++ b/src/cmd/compile/internal/arm64/galign.go @@ -18,7 +18,6 @@ func Init(arch *ssagen.ArchInfo) { arch.PadFrame = padframe arch.ZeroRange = zerorange arch.Ginsnop = ginsnop - arch.Ginsnopdefer = ginsnop arch.SSAMarkMoves = func(s *ssagen.State, b *ssa.Block) {} arch.SSAGenValue = ssaGenValue diff --git a/src/cmd/compile/internal/mips/galign.go b/src/cmd/compile/internal/mips/galign.go index f892923ba03..4e6897042ec 100644 --- a/src/cmd/compile/internal/mips/galign.go +++ b/src/cmd/compile/internal/mips/galign.go @@ -21,7 +21,6 @@ func Init(arch *ssagen.ArchInfo) { arch.SoftFloat = (buildcfg.GOMIPS == "softfloat") arch.ZeroRange = zerorange arch.Ginsnop = ginsnop - arch.Ginsnopdefer = ginsnop arch.SSAMarkMoves = func(s *ssagen.State, b *ssa.Block) {} arch.SSAGenValue = ssaGenValue arch.SSAGenBlock = ssaGenBlock diff --git a/src/cmd/compile/internal/mips64/galign.go b/src/cmd/compile/internal/mips64/galign.go index af81366e51b..412bc71aab2 100644 --- a/src/cmd/compile/internal/mips64/galign.go +++ b/src/cmd/compile/internal/mips64/galign.go @@ -21,7 +21,6 @@ func Init(arch *ssagen.ArchInfo) { arch.SoftFloat = buildcfg.GOMIPS64 == "softfloat" arch.ZeroRange = zerorange arch.Ginsnop = ginsnop - arch.Ginsnopdefer = ginsnop arch.SSAMarkMoves = func(s *ssagen.State, b *ssa.Block) {} arch.SSAGenValue = ssaGenValue diff --git a/src/cmd/compile/internal/ppc64/galign.go b/src/cmd/compile/internal/ppc64/galign.go index 590290fa371..bff3e38f42d 100644 --- a/src/cmd/compile/internal/ppc64/galign.go +++ b/src/cmd/compile/internal/ppc64/galign.go @@ -20,7 +20,6 @@ func Init(arch *ssagen.ArchInfo) { arch.ZeroRange = zerorange arch.Ginsnop = ginsnop - arch.Ginsnopdefer = ginsnopdefer arch.SSAMarkMoves = ssaMarkMoves arch.SSAGenValue = ssaGenValue diff --git a/src/cmd/compile/internal/ppc64/ggen.go b/src/cmd/compile/internal/ppc64/ggen.go index c76962cfb81..3ae6422bf9e 100644 --- a/src/cmd/compile/internal/ppc64/ggen.go +++ b/src/cmd/compile/internal/ppc64/ggen.go @@ -53,30 +53,3 @@ func ginsnop(pp *objw.Progs) *obj.Prog { p.To.Reg = ppc64.REG_R0 return p } - -func ginsnopdefer(pp *objw.Progs) *obj.Prog { - // On PPC64 two nops are required in the defer case. - // - // (see gc/cgen.go, gc/plive.go -- copy of comment below) - // - // On ppc64, when compiling Go into position - // independent code on ppc64le we insert an - // instruction to reload the TOC pointer from the - // stack as well. See the long comment near - // jmpdefer in runtime/asm_ppc64.s for why. - // If the MOVD is not needed, insert a hardware NOP - // so that the same number of instructions are used - // on ppc64 in both shared and non-shared modes. - - ginsnop(pp) - if base.Ctxt.Flag_shared { - p := pp.Prog(ppc64.AMOVD) - p.From.Type = obj.TYPE_MEM - p.From.Offset = 24 - p.From.Reg = ppc64.REGSP - p.To.Type = obj.TYPE_REG - p.To.Reg = ppc64.REG_R2 - return p - } - return ginsnop(pp) -} diff --git a/src/cmd/compile/internal/riscv64/galign.go b/src/cmd/compile/internal/riscv64/galign.go index 338248a7cf2..846ed8fb380 100644 --- a/src/cmd/compile/internal/riscv64/galign.go +++ b/src/cmd/compile/internal/riscv64/galign.go @@ -16,7 +16,6 @@ func Init(arch *ssagen.ArchInfo) { arch.MAXWIDTH = 1 << 50 arch.Ginsnop = ginsnop - arch.Ginsnopdefer = ginsnop arch.ZeroRange = zeroRange arch.SSAMarkMoves = ssaMarkMoves diff --git a/src/cmd/compile/internal/s390x/galign.go b/src/cmd/compile/internal/s390x/galign.go index b004a2db0a3..d880834c220 100644 --- a/src/cmd/compile/internal/s390x/galign.go +++ b/src/cmd/compile/internal/s390x/galign.go @@ -16,7 +16,6 @@ func Init(arch *ssagen.ArchInfo) { arch.ZeroRange = zerorange arch.Ginsnop = ginsnop - arch.Ginsnopdefer = ginsnop arch.SSAMarkMoves = ssaMarkMoves arch.SSAGenValue = ssaGenValue diff --git a/src/cmd/compile/internal/ssagen/arch.go b/src/cmd/compile/internal/ssagen/arch.go index 957fb3e84a9..483e45cad43 100644 --- a/src/cmd/compile/internal/ssagen/arch.go +++ b/src/cmd/compile/internal/ssagen/arch.go @@ -29,8 +29,7 @@ type ArchInfo struct { // at function entry, and it is ok to clobber registers. ZeroRange func(*objw.Progs, *obj.Prog, int64, int64, *uint32) *obj.Prog - Ginsnop func(*objw.Progs) *obj.Prog - Ginsnopdefer func(*objw.Progs) *obj.Prog // special ginsnop for deferreturn + Ginsnop func(*objw.Progs) *obj.Prog // SSAMarkMoves marks any MOVXconst ops that need to avoid clobbering flags. SSAMarkMoves func(*State, *ssa.Block) diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 1a0a98f6aa1..b0f2585e3ab 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -7356,18 +7356,6 @@ func (s *State) PrepareCall(v *ssa.Value) { call, ok := v.Aux.(*ssa.AuxCall) - if ok && call.Fn == ir.Syms.Deferreturn { - // Deferred calls will appear to be returning to - // the CALL deferreturn(SB) that we are about to emit. - // However, the stack trace code will show the line - // of the instruction byte before the return PC. - // To avoid that being an unrelated instruction, - // insert an actual hardware NOP that will have the right line number. - // This is different from obj.ANOP, which is a virtual no-op - // that doesn't make it into the instruction stream. - Arch.Ginsnopdefer(s.pp) - } - if ok { // Record call graph information for nowritebarrierrec // analysis. diff --git a/src/cmd/compile/internal/wasm/ssa.go b/src/cmd/compile/internal/wasm/ssa.go index 31b09016eb9..0b2ca3fdbb8 100644 --- a/src/cmd/compile/internal/wasm/ssa.go +++ b/src/cmd/compile/internal/wasm/ssa.go @@ -24,7 +24,6 @@ func Init(arch *ssagen.ArchInfo) { arch.ZeroRange = zeroRange arch.Ginsnop = ginsnop - arch.Ginsnopdefer = ginsnop arch.SSAMarkMoves = ssaMarkMoves arch.SSAGenValue = ssaGenValue @@ -126,7 +125,11 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { case ssa.OpWasmLoweredStaticCall, ssa.OpWasmLoweredClosureCall, ssa.OpWasmLoweredInterCall: s.PrepareCall(v) if call, ok := v.Aux.(*ssa.AuxCall); ok && call.Fn == ir.Syms.Deferreturn { - // add a resume point before call to deferreturn so it can be called again via jmpdefer + // The runtime needs to inject jumps to + // deferreturn calls using the address in + // _func.deferreturn. Hence, the call to + // deferreturn must itself be a resumption + // point so it gets a target PC. s.Prog(wasm.ARESUMEPOINT) } if v.Op == ssa.OpWasmLoweredClosureCall { diff --git a/src/cmd/compile/internal/x86/galign.go b/src/cmd/compile/internal/x86/galign.go index 00a20e429f1..5565bd32c76 100644 --- a/src/cmd/compile/internal/x86/galign.go +++ b/src/cmd/compile/internal/x86/galign.go @@ -34,7 +34,6 @@ func Init(arch *ssagen.ArchInfo) { arch.ZeroRange = zerorange arch.Ginsnop = ginsnop - arch.Ginsnopdefer = ginsnop arch.SSAMarkMoves = ssaMarkMoves } diff --git a/src/cmd/internal/obj/arm/asm5.go b/src/cmd/internal/obj/arm/asm5.go index ccf5f9e7f8d..7b1682776e5 100644 --- a/src/cmd/internal/obj/arm/asm5.go +++ b/src/cmd/internal/obj/arm/asm5.go @@ -355,11 +355,10 @@ var oprange [ALAST & obj.AMask][]Optab var xcmp [C_GOK + 1][C_GOK + 1]bool var ( - deferreturn *obj.LSym - symdiv *obj.LSym - symdivu *obj.LSym - symmod *obj.LSym - symmodu *obj.LSym + symdiv *obj.LSym + symdivu *obj.LSym + symmod *obj.LSym + symmodu *obj.LSym ) // Note about encoding: Prog.scond holds the condition encoding, @@ -1219,8 +1218,6 @@ func buildop(ctxt *obj.Link) { return } - deferreturn = ctxt.LookupABI("runtime.deferreturn", obj.ABIInternal) - symdiv = ctxt.Lookup("runtime._div") symdivu = ctxt.Lookup("runtime._divu") symmod = ctxt.Lookup("runtime._mod") diff --git a/src/cmd/internal/obj/wasm/wasmobj.go b/src/cmd/internal/obj/wasm/wasmobj.go index ceeae7a257c..4d276db6780 100644 --- a/src/cmd/internal/obj/wasm/wasmobj.go +++ b/src/cmd/internal/obj/wasm/wasmobj.go @@ -129,8 +129,6 @@ var ( morestackNoCtxt *obj.LSym gcWriteBarrier *obj.LSym sigpanic *obj.LSym - deferreturn *obj.LSym - jmpdefer *obj.LSym ) const ( @@ -143,10 +141,6 @@ func instinit(ctxt *obj.Link) { morestackNoCtxt = ctxt.Lookup("runtime.morestack_noctxt") gcWriteBarrier = ctxt.LookupABI("runtime.gcWriteBarrier", obj.ABIInternal) sigpanic = ctxt.LookupABI("runtime.sigpanic", obj.ABIInternal) - deferreturn = ctxt.LookupABI("runtime.deferreturn", obj.ABIInternal) - // jmpdefer is defined in assembly as ABI0. The compiler will - // generate a direct ABI0 call from Go, so look for that. - jmpdefer = ctxt.LookupABI(`"".jmpdefer`, obj.ABI0) } func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) { @@ -423,12 +417,6 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) { pcAfterCall-- // sigpanic expects to be called without advancing the pc } - // jmpdefer manipulates the return address on the stack so deferreturn gets called repeatedly. - // Model this in WebAssembly with a loop. - if call.To.Sym == deferreturn { - p = appendp(p, ALoop) - } - // SP -= 8 p = appendp(p, AGet, regAddr(REG_SP)) p = appendp(p, AI32Const, constAddr(8)) @@ -479,15 +467,6 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) { break } - // jmpdefer removes the frame of deferreturn from the Go stack. - // However, its WebAssembly function still returns normally, - // so we need to return from deferreturn without removing its - // stack frame (no RET), because the frame is already gone. - if call.To.Sym == jmpdefer { - p = appendp(p, AReturn) - break - } - // return value of call is on the top of the stack, indicating whether to unwind the WebAssembly stack if call.As == ACALLNORESUME && call.To.Sym != sigpanic { // sigpanic unwinds the stack, but it never resumes // trying to unwind WebAssembly stack but call has no resume point, terminate with error @@ -500,21 +479,6 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) { unwindExitBranches = append(unwindExitBranches, p) } - // jump to before the call if jmpdefer has reset the return address to the call's PC - if call.To.Sym == deferreturn { - // get PC_B from -8(SP) - p = appendp(p, AGet, regAddr(REG_SP)) - p = appendp(p, AI32Const, constAddr(8)) - p = appendp(p, AI32Sub) - p = appendp(p, AI32Load16U, constAddr(0)) - p = appendp(p, ATee, regAddr(REG_PC_B)) - - p = appendp(p, AI32Const, constAddr(call.Pc)) - p = appendp(p, AI32Eq) - p = appendp(p, ABrIf, constAddr(0)) - p = appendp(p, AEnd) // end of Loop - } - case obj.ARET, ARETUNWIND: ret := *p p.As = obj.ANOP diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go index 17fa76727e6..331a98dfef9 100644 --- a/src/cmd/internal/obj/x86/asm6.go +++ b/src/cmd/internal/obj/x86/asm6.go @@ -43,7 +43,6 @@ import ( var ( plan9privates *obj.LSym - deferreturn *obj.LSym ) // Instruction layout. diff --git a/src/cmd/internal/objabi/funcid.go b/src/cmd/internal/objabi/funcid.go index d881cdd0618..68f6a26a76c 100644 --- a/src/cmd/internal/objabi/funcid.go +++ b/src/cmd/internal/objabi/funcid.go @@ -34,7 +34,6 @@ const ( FuncID_gogo FuncID_gopanic FuncID_handleAsyncEvent - FuncID_jmpdefer FuncID_mcall FuncID_morestack FuncID_mstart @@ -60,7 +59,6 @@ var funcIDs = map[string]FuncID{ "gogo": FuncID_gogo, "gopanic": FuncID_gopanic, "handleAsyncEvent": FuncID_handleAsyncEvent, - "jmpdefer": FuncID_jmpdefer, "main": FuncID_runtime_main, "mcall": FuncID_mcall, "morestack": FuncID_morestack, diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go index 05fd3023694..70e3e1284b9 100644 --- a/src/cmd/link/internal/ld/pcln.go +++ b/src/cmd/link/internal/ld/pcln.go @@ -129,11 +129,10 @@ func computeDeferReturn(ctxt *Link, deferReturnSym, s loader.Sym) uint32 { for ri := 0; ri < relocs.Count(); ri++ { r := relocs.At(ri) if target.IsWasm() && r.Type() == objabi.R_ADDR { - // Wasm does not have a live variable set at the deferreturn - // call itself. Instead it has one identified by the - // resumption point immediately preceding the deferreturn. - // The wasm code has a R_ADDR relocation which is used to - // set the resumption point to PC_B. + // wasm/ssa.go generates an ARESUMEPOINT just + // before the deferreturn call. The "PC" of + // the deferreturn call is stored in the + // R_ADDR relocation on the ARESUMEPOINT. lastWasmAddr = uint32(r.Add()) } if r.Type().IsDirectCall() && (r.Sym() == deferReturnSym || ldr.IsDeferReturnTramp(r.Sym())) { diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s index dd2ea458cc5..11c60309f4e 100644 --- a/src/runtime/asm_386.s +++ b/src/runtime/asm_386.s @@ -582,26 +582,6 @@ TEXT ·publicationBarrier(SB),NOSPLIT,$0-0 // compile barrier. RET -// void jmpdefer(fn, sp); -// called from deferreturn. -// 1. pop the caller -// 2. sub 5 bytes (the length of CALL & a 32 bit displacement) from the callers -// return (when building for shared libraries, subtract 16 bytes -- 5 bytes -// for CALL & displacement to call __x86.get_pc_thunk.cx, 6 bytes for the -// LEAL to load the offset into BX, and finally 5 for the call & displacement) -// 3. jmp to the argument -TEXT runtime·jmpdefer(SB), NOSPLIT, $0-8 - MOVL fv+0(FP), DX // fn - MOVL argp+4(FP), BX // caller sp - LEAL -4(BX), SP // caller sp after CALL -#ifdef GOBUILDMODE_shared - SUBL $16, (SP) // return to CALL again -#else - SUBL $5, (SP) // return to CALL again -#endif - MOVL 0(DX), BX - JMP BX // but first run the deferred function - // Save state of caller into g->sched, // but using fake PC from systemstack_switch. // Must only be called from functions with no locals ($0) diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index 0f719b2664a..2d8f4c24120 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -662,21 +662,6 @@ TEXT ·publicationBarrier(SB),NOSPLIT,$0-0 // compile barrier. RET -// func jmpdefer(fv func(), argp uintptr) -// argp is a caller SP. -// called from deferreturn. -// 1. pop the caller -// 2. sub 5 bytes from the callers return -// 3. jmp to the argument -TEXT runtime·jmpdefer(SB), NOSPLIT, $0-16 - MOVQ fv+0(FP), DX // fn - MOVQ argp+8(FP), BX // caller sp - LEAQ -8(BX), SP // caller sp after CALL - MOVQ -8(SP), BP // restore BP as if deferreturn returned (harmless if framepointers not in use) - SUBQ $5, (SP) // return to CALL again - MOVQ 0(DX), BX - JMP BX // but first run the deferred function - // Save state of caller into g->sched, // but using fake PC from systemstack_switch. // Must only be called from functions with no locals ($0) diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index 5c2bc00fe81..a1164781d2e 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -506,20 +506,6 @@ CALLFN(·call268435456, 268435456) CALLFN(·call536870912, 536870912) CALLFN(·call1073741824, 1073741824) -// void jmpdefer(fn, sp); -// called from deferreturn. -// 1. grab stored LR for caller -// 2. sub 4 bytes to get back to BL deferreturn -// 3. B to fn -TEXT runtime·jmpdefer(SB),NOSPLIT,$0-8 - MOVW 0(R13), LR - MOVW $-4(LR), LR // BL deferreturn - MOVW fv+0(FP), R7 - MOVW argp+4(FP), R13 - MOVW $-4(R13), R13 // SP is 4 below argp, due to saved LR - MOVW 0(R7), R1 - B (R1) - // Save state of caller into g->sched, // but using fake PC from systemstack_switch. // Must only be called from functions with no locals ($0) diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s index e7c5fa32252..e51ce2f8316 100644 --- a/src/runtime/asm_arm64.s +++ b/src/runtime/asm_arm64.s @@ -982,23 +982,6 @@ again: CBNZ R0, again RET -// void jmpdefer(fv, sp); -// called from deferreturn. -// 1. grab stored LR for caller -// 2. sub 4 bytes to get back to BL deferreturn -// 3. BR to fn -TEXT runtime·jmpdefer(SB), NOSPLIT|NOFRAME, $0-16 - MOVD 0(RSP), R0 - SUB $4, R0 - MOVD R0, LR - - MOVD fv+0(FP), R26 - MOVD argp+8(FP), R0 - MOVD R0, RSP - SUB $8, RSP - MOVD 0(R26), R3 - B (R3) - // Save state of caller into g->sched, // but using fake PC from systemstack_switch. // Must only be called from functions with no locals ($0) diff --git a/src/runtime/asm_mips64x.s b/src/runtime/asm_mips64x.s index f3ac453d998..b2e2384c368 100644 --- a/src/runtime/asm_mips64x.s +++ b/src/runtime/asm_mips64x.s @@ -384,22 +384,6 @@ CALLFN(·call1073741824, 1073741824) TEXT runtime·procyield(SB),NOSPLIT,$0-0 RET -// void jmpdefer(fv, sp); -// called from deferreturn. -// 1. grab stored LR for caller -// 2. sub 8 bytes to get back to JAL deferreturn -// 3. JMP to fn -TEXT runtime·jmpdefer(SB), NOSPLIT|NOFRAME, $0-16 - MOVV 0(R29), R31 - ADDV $-8, R31 - - MOVV fv+0(FP), REGCTXT - MOVV argp+8(FP), R29 - ADDV $-8, R29 - NOR R0, R0 // prevent scheduling - MOVV 0(REGCTXT), R4 - JMP (R4) - // Save state of caller into g->sched, // but using fake PC from systemstack_switch. // Must only be called from functions with no locals ($0) diff --git a/src/runtime/asm_mipsx.s b/src/runtime/asm_mipsx.s index 4dc165849e2..87a1344e8f6 100644 --- a/src/runtime/asm_mipsx.s +++ b/src/runtime/asm_mipsx.s @@ -382,22 +382,6 @@ CALLFN(·call1073741824, 1073741824) TEXT runtime·procyield(SB),NOSPLIT,$0-4 RET -// void jmpdefer(fv, sp); -// called from deferreturn. -// 1. grab stored LR for caller -// 2. sub 8 bytes to get back to JAL deferreturn -// 3. JMP to fn -TEXT runtime·jmpdefer(SB),NOSPLIT,$0-8 - MOVW 0(R29), R31 - ADDU $-8, R31 - - MOVW fv+0(FP), REGCTXT - MOVW argp+4(FP), R29 - ADDU $-4, R29 - NOR R0, R0 // prevent scheduling - MOVW 0(REGCTXT), R4 - JMP (R4) - // Save state of caller into g->sched, // but using fake PC from systemstack_switch. // Must only be called from functions with no locals ($0) diff --git a/src/runtime/asm_ppc64x.s b/src/runtime/asm_ppc64x.s index a789d041e43..5dc96c59473 100644 --- a/src/runtime/asm_ppc64x.s +++ b/src/runtime/asm_ppc64x.s @@ -503,34 +503,6 @@ again: OR R6, R6, R6 // Set PPR priority back to medium-low RET -// void jmpdefer(fv, sp); -// called from deferreturn. -// 1. grab stored LR for caller -// 2. sub 8 bytes to get back to either nop or toc reload before deferreturn -// 3. BR to fn -// When dynamically linking Go, it is not sufficient to rewind to the BL -// deferreturn -- we might be jumping between modules and so we need to reset -// the TOC pointer in r2. To do this, codegen inserts MOVD 24(R1), R2 *before* -// the BL deferreturn and jmpdefer rewinds to that. -TEXT runtime·jmpdefer(SB), NOSPLIT|NOFRAME, $0-16 - MOVD 0(R1), R31 - SUB $8, R31 - MOVD R31, LR - - MOVD fv+0(FP), R11 - MOVD argp+8(FP), R1 - SUB $FIXED_FRAME, R1 -#ifdef GOOS_aix - // AIX won't trigger a SIGSEGV if R11 = nil - // So it manually triggers it - CMP R0, R11 - BNE 2(PC) - MOVD R0, 0(R0) -#endif - MOVD 0(R11), R12 - MOVD R12, CTR - BR (CTR) - // Save state of caller into g->sched, // but using fake PC from systemstack_switch. // Must only be called from functions with no locals ($0) diff --git a/src/runtime/asm_riscv64.s b/src/runtime/asm_riscv64.s index 9957ae201bc..9927a817f72 100644 --- a/src/runtime/asm_riscv64.s +++ b/src/runtime/asm_riscv64.s @@ -248,21 +248,6 @@ TEXT gogo<>(SB), NOSPLIT|NOFRAME, $0 MOV gobuf_pc(T0), T0 JALR ZERO, T0 -// func jmpdefer(fv func(), argp uintptr) -// called from deferreturn -// 1. grab stored return address from the caller's frame -// 2. sub 8 bytes to get back to JAL deferreturn -// 3. JMP to fn -TEXT runtime·jmpdefer(SB), NOSPLIT|NOFRAME, $0-16 - MOV 0(X2), RA - ADD $-8, RA - - MOV fv+0(FP), CTXT - MOV argp+8(FP), X2 - ADD $-8, X2 - MOV 0(CTXT), T0 - JALR ZERO, T0 - // func procyield(cycles uint32) TEXT runtime·procyield(SB),NOSPLIT,$0-0 RET diff --git a/src/runtime/asm_s390x.s b/src/runtime/asm_s390x.s index 534cb6112c6..d4110d563f4 100644 --- a/src/runtime/asm_s390x.s +++ b/src/runtime/asm_s390x.s @@ -480,21 +480,6 @@ TEXT callfnMVC<>(SB),NOSPLIT|NOFRAME,$0-0 TEXT runtime·procyield(SB),NOSPLIT,$0-0 RET -// void jmpdefer(fv, sp); -// called from deferreturn. -// 1. grab stored LR for caller -// 2. sub 6 bytes to get back to BL deferreturn (size of BRASL instruction) -// 3. BR to fn -TEXT runtime·jmpdefer(SB),NOSPLIT|NOFRAME,$0-16 - MOVD 0(R15), R1 - SUB $6, R1, LR - - MOVD fv+0(FP), R12 - MOVD argp+8(FP), R15 - SUB $8, R15 - MOVD 0(R12), R3 - BR (R3) - // Save state of caller into g->sched, // but using fake PC from systemstack_switch. // Must only be called from functions with no locals ($0) diff --git a/src/runtime/asm_wasm.s b/src/runtime/asm_wasm.s index 53c271aa708..d885da6e70f 100644 --- a/src/runtime/asm_wasm.s +++ b/src/runtime/asm_wasm.s @@ -193,35 +193,6 @@ TEXT runtime·return0(SB), NOSPLIT, $0-0 MOVD $0, RET0 RET -TEXT runtime·jmpdefer(SB), NOSPLIT, $0-16 - MOVD fv+0(FP), CTXT - - Get CTXT - I64Eqz - If - CALLNORESUME runtime·sigpanic(SB) - End - - // caller sp after CALL - I64Load argp+8(FP) - I64Const $8 - I64Sub - I32WrapI64 - Set SP - - // decrease PC_B by 1 to CALL again - Get SP - I32Load16U (SP) - I32Const $1 - I32Sub - I32Store16 $0 - - // but first run the deferred function - Get CTXT - I32WrapI64 - I64Load $0 - JMP - TEXT runtime·asminit(SB), NOSPLIT, $0-0 // No per-thread init. RET diff --git a/src/runtime/panic.go b/src/runtime/panic.go index b77376b5986..b2158d376e4 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -404,47 +404,39 @@ func freedeferfn() { throw("freedefer with d.fn != nil") } -// Run a deferred function if there is one. +// deferreturn runs deferred functions for the caller's frame. // The compiler inserts a call to this at the end of any // function which calls defer. -// If there is a deferred function, this will call runtime·jmpdefer, -// which will jump to the deferred function such that it appears -// to have been called by the caller of deferreturn at the point -// just before deferreturn was called. The effect is that deferreturn -// is called again and again until there are no more deferred functions. func deferreturn() { gp := getg() - d := gp._defer - if d == nil { - return - } - sp := getcallersp() - if d.sp != sp { - return - } - if d.openDefer { - done := runOpenDeferFrame(gp, d) - if !done { - throw("unfinished open-coded defers in deferreturn") + for { + d := gp._defer + if d == nil { + return } + sp := getcallersp() + if d.sp != sp { + return + } + if d.openDefer { + done := runOpenDeferFrame(gp, d) + if !done { + throw("unfinished open-coded defers in deferreturn") + } + gp._defer = d.link + freedefer(d) + // If this frame uses open defers, then this + // must be the only defer record for the + // frame, so we can just return. + return + } + + fn := d.fn + d.fn = nil gp._defer = d.link freedefer(d) - return + fn() } - - fn := d.fn - d.fn = nil - gp._defer = d.link - freedefer(d) - // If the defer function pointer is nil, force the seg fault to happen - // here rather than in jmpdefer. gentraceback() throws an error if it is - // called with a callback on an LR architecture and jmpdefer is on the - // stack, because jmpdefer manipulates SP (see issue #8153). - _ = **(**funcval)(unsafe.Pointer(&fn)) - // We must not split the stack between computing argp and - // calling jmpdefer because argp is a uintptr stack pointer. - argp := getcallersp() + sys.MinFrameSize - jmpdefer(fn, argp) } // Goexit terminates the goroutine that calls it. No other goroutine is affected. diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index b94acdea1f6..fc29a1bac31 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -176,8 +176,6 @@ func cgocallback(fn, frame, ctxt uintptr) func gogo(buf *gobuf) -//go:noescape -func jmpdefer(fv func(), argp uintptr) func asminit() func setg(gg *g) func breakpoint() diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index 44ea0710c65..d08aa0b3204 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -331,7 +331,6 @@ const ( funcID_gogo funcID_gopanic funcID_handleAsyncEvent - funcID_jmpdefer funcID_mcall funcID_morestack funcID_mstart From 88bd92bb6dd7997b415723c9c4a8d26ebe17634b Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 3 Aug 2021 17:03:42 -0400 Subject: [PATCH 844/940] [dev.typeparams] runtime: simplify freedefer Currently, freedefer manually zeros all the fields in the _defer because simply assigning _defer{} used to cause a nosplit stack overflow. freedefer is no longer nosplit, so go back to the simpler, more robust code. Change-Id: I881f557bab3b1ee7ab29b68e7fb56d0fe6d35d8d Reviewed-on: https://go-review.googlesource.com/c/go/+/339669 Trust: Austin Clements Run-TryBot: Austin Clements TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/runtime/panic.go | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/runtime/panic.go b/src/runtime/panic.go index b2158d376e4..48b1b5dd9db 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -372,19 +372,7 @@ func freedefer(d *_defer) { unlock(&sched.deferlock) } - // These lines used to be simply `*d = _defer{}` but that - // started causing a nosplit stack overflow via typedmemmove. - d.started = false - d.openDefer = false - d.sp = 0 - d.pc = 0 - d.framepc = 0 - d.varp = 0 - d.fd = nil - // d._panic and d.fn must be nil already. - // If not, we would have called freedeferpanic or freedeferfn above, - // both of which throw. - d.link = nil + *d = _defer{} pp.deferpool = append(pp.deferpool, d) From 1ea3596b4103fcbe8741f8af48a119aa8220180b Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Tue, 3 Aug 2021 16:22:00 -0400 Subject: [PATCH 845/940] [dev.typeparams] go/types: adjust unsafe.Alignof/Offsetof/Sizeof This is a port of CL 335413 to go/types, adjusted for the parsing API of go/parser. Change-Id: Ie6836add7d027aaf5d6d3dae65222b1d15bd7558 Reviewed-on: https://go-review.googlesource.com/c/go/+/339649 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/builtins.go | 73 ++++++++---- src/go/types/builtins_test.go | 7 +- src/go/types/infer.go | 4 +- src/go/types/sizes.go | 10 +- src/go/types/testdata/check/builtins.go2 | 107 ++++++++++++++++++ .../types/testdata/fixedbugs/issue40301.go2 | 4 +- 6 files changed, 177 insertions(+), 28 deletions(-) diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index b6fb36b185a..ecb9920a811 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -633,19 +633,22 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b case _Alignof: // unsafe.Alignof(x T) uintptr - if asTypeParam(x.typ) != nil { - check.invalidOp(call, _Todo, "unsafe.Alignof undefined for %s", x) - return - } check.assignment(x, nil, "argument to unsafe.Alignof") if x.mode == invalid { return } - x.mode = constant_ - x.val = constant.MakeInt64(check.conf.alignof(x.typ)) + if hasVarSize(x.typ) { + x.mode = value + if check.Types != nil { + check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], x.typ)) + } + } else { + x.mode = constant_ + x.val = constant.MakeInt64(check.conf.alignof(x.typ)) + // result is constant - no need to record signature + } x.typ = Typ[Uintptr] - // result is constant - no need to record signature case _Offsetof: // unsafe.Offsetof(x T) uintptr, where x must be a selector @@ -683,30 +686,43 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b return } - // TODO(gri) Should we pass x.typ instead of base (and indirect report if derefStructPtr indirected)? + // TODO(gri) Should we pass x.typ instead of base (and have indirect report if derefStructPtr indirected)? check.recordSelection(selx, FieldVal, base, obj, index, false) - offs := check.conf.offsetof(base, index) - x.mode = constant_ - x.val = constant.MakeInt64(offs) + // The field offset is considered a variable even if the field is declared before + // the part of the struct which is variable-sized. This makes both the rules + // simpler and also permits (or at least doesn't prevent) a compiler from re- + // arranging struct fields if it wanted to. + if hasVarSize(base) { + x.mode = value + if check.Types != nil { + check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], obj.Type())) + } + } else { + x.mode = constant_ + x.val = constant.MakeInt64(check.conf.offsetof(base, index)) + // result is constant - no need to record signature + } x.typ = Typ[Uintptr] - // result is constant - no need to record signature case _Sizeof: // unsafe.Sizeof(x T) uintptr - if asTypeParam(x.typ) != nil { - check.invalidOp(call, _Todo, "unsafe.Sizeof undefined for %s", x) - return - } check.assignment(x, nil, "argument to unsafe.Sizeof") if x.mode == invalid { return } - x.mode = constant_ - x.val = constant.MakeInt64(check.conf.sizeof(x.typ)) + if hasVarSize(x.typ) { + x.mode = value + if check.Types != nil { + check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], x.typ)) + } + } else { + x.mode = constant_ + x.val = constant.MakeInt64(check.conf.sizeof(x.typ)) + // result is constant - no need to record signature + } x.typ = Typ[Uintptr] - // result is constant - no need to record signature case _Slice: // unsafe.Slice(ptr *T, len IntegerType) []T @@ -778,6 +794,25 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b return true } +// hasVarSize reports if the size of type t is variable due to type parameters. +func hasVarSize(t Type) bool { + switch t := under(t).(type) { + case *Array: + return hasVarSize(t.elem) + case *Struct: + for _, f := range t.fields { + if hasVarSize(f.typ) { + return true + } + } + case *TypeParam: + return true + case *Named, *Union, *top: + unreachable() + } + return false +} + // applyTypeFunc applies f to x. If x is a type parameter, // the result is a type parameter constrained by an new // interface bound. The type bounds for that interface diff --git a/src/go/types/builtins_test.go b/src/go/types/builtins_test.go index 11de9a1ac1a..cee3d315e59 100644 --- a/src/go/types/builtins_test.go +++ b/src/go/types/builtins_test.go @@ -113,12 +113,15 @@ var builtinCalls = []struct { {"Alignof", `_ = unsafe.Alignof(0)`, `invalid type`}, // constant {"Alignof", `var x struct{}; _ = unsafe.Alignof(x)`, `invalid type`}, // constant + {"Alignof", `var x P; _ = unsafe.Alignof(x)`, `func(p.P₁) uintptr`}, {"Offsetof", `var x struct{f bool}; _ = unsafe.Offsetof(x.f)`, `invalid type`}, // constant {"Offsetof", `var x struct{_ int; f bool}; _ = unsafe.Offsetof((&x).f)`, `invalid type`}, // constant + {"Offsetof", `var x struct{_ int; f P}; _ = unsafe.Offsetof((&x).f)`, `func(p.P₁) uintptr`}, {"Sizeof", `_ = unsafe.Sizeof(0)`, `invalid type`}, // constant {"Sizeof", `var x struct{}; _ = unsafe.Sizeof(x)`, `invalid type`}, // constant + {"Sizeof", `var x P; _ = unsafe.Sizeof(x)`, `func(p.P₁) uintptr`}, {"Slice", `var p *int; _ = unsafe.Slice(p, 1)`, `func(*int, int) []int`}, {"Slice", `var p *byte; var n uintptr; _ = unsafe.Slice(p, n)`, `func(*byte, uintptr) []byte`}, @@ -151,8 +154,10 @@ func TestBuiltinSignatures(t *testing.T) { } } +// parseGenericSrc in types2 is not necessary. We can just parse in testBuiltinSignature below. + func testBuiltinSignature(t *testing.T, name, src0, want string) { - src := fmt.Sprintf(`package p; import "unsafe"; type _ unsafe.Pointer /* use unsafe */; func _() { %s }`, src0) + src := fmt.Sprintf(`package p; import "unsafe"; type _ unsafe.Pointer /* use unsafe */; func _[P any]() { %s }`, src0) f, err := parser.ParseFile(fset, "", src, 0) if err != nil { t.Errorf("%s: %s", src0, err) diff --git a/src/go/types/infer.go b/src/go/types/infer.go index 774d2fd158f..f3f69e01b65 100644 --- a/src/go/types/infer.go +++ b/src/go/types/infer.go @@ -393,8 +393,8 @@ func (check *Checker) inferB(tparams []*TypeName, targs []Type, report bool) (ty // u.x.types() now contains the incoming type arguments plus any additional type // arguments for which there were structural constraints. The newly inferred non- - // nil entries may still contain references to other type parameters. For instance, - // for [A any, B interface{type []C}, C interface{type *A}], if A == int + // nil entries may still contain references to other type parameters. + // For instance, for [A any, B interface{ []C }, C interface{ *A }], if A == int // was given, unification produced the type list [int, []C, *A]. We eliminate the // remaining type parameters by substituting the type parameters in this type list // until nothing changes anymore. diff --git a/src/go/types/sizes.go b/src/go/types/sizes.go index 35219836ecf..4c85bfe057f 100644 --- a/src/go/types/sizes.go +++ b/src/go/types/sizes.go @@ -48,7 +48,7 @@ type StdSizes struct { func (s *StdSizes) Alignof(T Type) int64 { // For arrays and structs, alignment is defined in terms // of alignment of the elements and fields, respectively. - switch t := optype(T).(type) { + switch t := under(T).(type) { case *Array: // spec: "For a variable x of array type: unsafe.Alignof(x) // is the same as unsafe.Alignof(x[0]), but at least 1." @@ -73,6 +73,8 @@ func (s *StdSizes) Alignof(T Type) int64 { if t.Info()&IsString != 0 { return s.WordSize } + case *TypeParam, *Union: + unreachable() } a := s.Sizeof(T) // may be 0 // spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1." @@ -118,7 +120,7 @@ var basicSizes = [...]byte{ } func (s *StdSizes) Sizeof(T Type) int64 { - switch t := optype(T).(type) { + switch t := under(T).(type) { case *Basic: assert(isTyped(T)) k := t.kind @@ -148,10 +150,10 @@ func (s *StdSizes) Sizeof(T Type) int64 { } offsets := s.Offsetsof(t.fields) return offsets[n-1] + s.Sizeof(t.fields[n-1].typ) - case *Union: - panic("Sizeof unimplemented for union") case *Interface: return s.WordSize * 2 + case *TypeParam, *Union: + unreachable() } return s.WordSize // catch-all } diff --git a/src/go/types/testdata/check/builtins.go2 b/src/go/types/testdata/check/builtins.go2 index 8fe6d7b332e..3881090603e 100644 --- a/src/go/types/testdata/check/builtins.go2 +++ b/src/go/types/testdata/check/builtins.go2 @@ -6,6 +6,8 @@ package builtins +import "unsafe" + // close type C0 interface{ int } @@ -127,3 +129,108 @@ func _[T Bss]() { _ = make(T, 10) _ = make(T, 10, 20) } + +// unsafe.Alignof + +func _[T comparable]() { + var ( + b int64 + a [10]T + s struct{ f T } + p *T + l []T + f func(T) + i interface{ m() T } + c chan T + m map[T]T + t T + ) + + const bb = unsafe.Alignof(b) + assert(bb == 8) + const _ = unsafe /* ERROR not constant */ .Alignof(a) + const _ = unsafe /* ERROR not constant */ .Alignof(s) + const pp = unsafe.Alignof(p) + assert(pp == 8) + const ll = unsafe.Alignof(l) + assert(ll == 8) + const ff = unsafe.Alignof(f) + assert(ff == 8) + const ii = unsafe.Alignof(i) + assert(ii == 8) + const cc = unsafe.Alignof(c) + assert(cc == 8) + const mm = unsafe.Alignof(m) + assert(mm == 8) + const _ = unsafe /* ERROR not constant */ .Alignof(t) +} + +// unsafe.Offsetof + +func _[T comparable]() { + var ( + b struct{ _, f int64 } + a struct{ _, f [10]T } + s struct{ _, f struct{ f T } } + p struct{ _, f *T } + l struct{ _, f []T } + f struct{ _, f func(T) } + i struct{ _, f interface{ m() T } } + c struct{ _, f chan T } + m struct{ _, f map[T]T } + t struct{ _, f T } + ) + + const bb = unsafe.Offsetof(b.f) + assert(bb == 8) + const _ = unsafe /* ERROR not constant */ .Alignof(a) + const _ = unsafe /* ERROR not constant */ .Alignof(s) + const pp = unsafe.Offsetof(p.f) + assert(pp == 8) + const ll = unsafe.Offsetof(l.f) + assert(ll == 24) + const ff = unsafe.Offsetof(f.f) + assert(ff == 8) + const ii = unsafe.Offsetof(i.f) + assert(ii == 16) + const cc = unsafe.Offsetof(c.f) + assert(cc == 8) + const mm = unsafe.Offsetof(m.f) + assert(mm == 8) + const _ = unsafe /* ERROR not constant */ .Alignof(t) +} + +// unsafe.Sizeof + +func _[T comparable]() { + var ( + b int64 + a [10]T + s struct{ f T } + p *T + l []T + f func(T) + i interface{ m() T } + c chan T + m map[T]T + t T + ) + + const bb = unsafe.Sizeof(b) + assert(bb == 8) + const _ = unsafe /* ERROR not constant */ .Alignof(a) + const _ = unsafe /* ERROR not constant */ .Alignof(s) + const pp = unsafe.Sizeof(p) + assert(pp == 8) + const ll = unsafe.Sizeof(l) + assert(ll == 24) + const ff = unsafe.Sizeof(f) + assert(ff == 8) + const ii = unsafe.Sizeof(i) + assert(ii == 16) + const cc = unsafe.Sizeof(c) + assert(cc == 8) + const mm = unsafe.Sizeof(m) + assert(mm == 8) + const _ = unsafe /* ERROR not constant */ .Alignof(t) +} diff --git a/src/go/types/testdata/fixedbugs/issue40301.go2 b/src/go/types/testdata/fixedbugs/issue40301.go2 index 5d97855f8a1..c78f9a1fa04 100644 --- a/src/go/types/testdata/fixedbugs/issue40301.go2 +++ b/src/go/types/testdata/fixedbugs/issue40301.go2 @@ -7,6 +7,6 @@ package p import "unsafe" func _[T any](x T) { - _ = unsafe /* ERROR undefined */ .Alignof(x) - _ = unsafe /* ERROR undefined */ .Sizeof(x) + _ = unsafe.Alignof(x) + _ = unsafe.Sizeof(x) } From 89897473e289a58bf9608d525f1e9b4abd970c8d Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Tue, 3 Aug 2021 16:24:20 -0400 Subject: [PATCH 846/940] [dev.typeparams] go/types: implement TypeParam.Constraint This is a clean port of CL 336989 to go/types. Change-Id: Ib8dbe03f420d28ada6d5fc7003ab0c82c7e06c41 Reviewed-on: https://go-review.googlesource.com/c/go/+/339650 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/typeparam.go | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/src/go/types/typeparam.go b/src/go/types/typeparam.go index a3d60c16486..8cb44ea25ec 100644 --- a/src/go/types/typeparam.go +++ b/src/go/types/typeparam.go @@ -60,24 +60,32 @@ func (t *TypeParam) _SetId(id uint64) { t.id = id } -// TODO(rfindley): document the Bound and SetBound methods. - -func (t *TypeParam) Bound() *Interface { - // we may not have an interface (error reported elsewhere) - iface, _ := under(t.bound).(*Interface) - if iface == nil { - return &emptyInterface +// Constraint returns the type constraint specified for t. +func (t *TypeParam) Constraint() Type { + // compute the type set if possible (we may not have an interface) + if iface, _ := under(t.bound).(*Interface); iface != nil { + // use the type bound position if we have one + pos := token.NoPos + if n, _ := t.bound.(*Named); n != nil { + pos = n.obj.pos + } + computeTypeSet(t.check, pos, iface) } - // use the type bound position if we have one - pos := token.NoPos - if n, _ := t.bound.(*Named); n != nil { - pos = n.obj.pos - } - // TODO(rFindley) switch this to an unexported method on Checker. - computeTypeSet(t.check, pos, iface) - return iface + return t.bound } +// Bound returns the underlying type of the type parameter's +// constraint. +// Deprecated for external use. Use Constraint instead. +func (t *TypeParam) Bound() *Interface { + if iface, _ := under(t.Constraint()).(*Interface); iface != nil { + return iface + } + return &emptyInterface +} + +// TODO(rfindley): document the SetBound methods. + func (t *TypeParam) SetBound(bound Type) { if bound == nil { panic("internal error: bound must not be nil") From 18e0503724e64c3d55dbc705eb4f08be2fde1b32 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Tue, 3 Aug 2021 16:32:23 -0400 Subject: [PATCH 847/940] [dev.typeparams] go/types: embedded type cannot be a (pointer to) a type parameter This is a port of CL 337353 to go/types, adjusted for the error API and to comment out a test for MethodSet. Some nearby error messages that were using errorf rather than error were also adjusted. Fixes #43621 Change-Id: I28c9747e044ec7a2863f6890db69475fb8c29231 Reviewed-on: https://go-review.googlesource.com/c/go/+/339651 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/methodset_test.go | 12 +++++++----- src/go/types/struct.go | 10 ++++++---- src/go/types/testdata/check/typeparams.go2 | 4 ++-- src/go/types/testdata/fixedbugs/issue39938.go2 | 4 ++-- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/go/types/methodset_test.go b/src/go/types/methodset_test.go index 5b29b2f0fea..73a8442f214 100644 --- a/src/go/types/methodset_test.go +++ b/src/go/types/methodset_test.go @@ -46,12 +46,14 @@ func TestNewMethodSet(t *testing.T) { genericTests := map[string][]method{ // By convention, look up a in the scope of "g" - "type C interface{ f() }; func g[T C](a T){}": {{"f", []int{0}, true}}, - "type C interface{ f() }; func g[T C]() { var a T; _ = a }": {{"f", []int{0}, true}}, - "type C interface{ f() }; func g[T C]() { var a struct{T}; _ = a }": {{"f", []int{0, 0}, true}}, + "type C interface{ f() }; func g[T C](a T){}": {{"f", []int{0}, true}}, + "type C interface{ f() }; func g[T C]() { var a T; _ = a }": {{"f", []int{0}, true}}, - // Issue #45639: We don't allow this anymore. Keep this code in case we - // decide to revisit this decision. + // Issue #43621: We don't allow this anymore. Keep this code in case we + // decide to revisit this decision. + // "type C interface{ f() }; func g[T C]() { var a struct{T}; _ = a }": {{"f", []int{0, 0}, true}}, + + // Issue #45639: We also don't allow this anymore. // "type C interface{ f() }; func g[T C]() { type Y T; var a Y; _ = a }": {}, } diff --git a/src/go/types/struct.go b/src/go/types/struct.go index d1fb813c147..48b07346dc3 100644 --- a/src/go/types/struct.go +++ b/src/go/types/struct.go @@ -136,7 +136,7 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType) { check.later(func() { t, isPtr := deref(embeddedTyp) - switch t := optype(t).(type) { + switch t := under(t).(type) { case *Basic: if t == Typ[Invalid] { // error was reported before @@ -144,13 +144,15 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType) { } // unsafe.Pointer is treated like a regular pointer if t.kind == UnsafePointer { - check.errorf(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be unsafe.Pointer") + check.error(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be unsafe.Pointer") } case *Pointer: - check.errorf(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be a pointer") + check.error(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be a pointer") + case *TypeParam: + check.error(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be a (pointer to a) type parameter") case *Interface: if isPtr { - check.errorf(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be a pointer to an interface") + check.error(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be a pointer to an interface") } } }) diff --git a/src/go/types/testdata/check/typeparams.go2 b/src/go/types/testdata/check/typeparams.go2 index b03725ff2aa..77cd65d19a8 100644 --- a/src/go/types/testdata/check/typeparams.go2 +++ b/src/go/types/testdata/check/typeparams.go2 @@ -79,11 +79,11 @@ var _ *int = new[int]() func _[T any](map[T /* ERROR incomparable map key type T \(missing comparable constraint\) */]int) // w/o constraint we don't know if T is comparable -func f1[T1 any](struct{T1}) int +func f1[T1 any](struct{T1 /* ERROR cannot be a .* type parameter */ }) int var _ = f1[int](struct{T1}{}) type T1 = int -func f2[t1 any](struct{t1; x float32}) int +func f2[t1 any](struct{t1 /* ERROR cannot be a .* type parameter */ ; x float32}) int var _ = f2[t1](struct{t1; x float32}{}) type t1 = int diff --git a/src/go/types/testdata/fixedbugs/issue39938.go2 b/src/go/types/testdata/fixedbugs/issue39938.go2 index 76e7e369ca1..0da6e103fd1 100644 --- a/src/go/types/testdata/fixedbugs/issue39938.go2 +++ b/src/go/types/testdata/fixedbugs/issue39938.go2 @@ -8,8 +8,8 @@ package p type E0[P any] P type E1[P any] *P -type E2[P any] struct{ P } -type E3[P any] struct{ *P } +type E2[P any] struct{ _ P } +type E3[P any] struct{ _ *P } type T0 /* ERROR illegal cycle */ struct { _ E0[T0] From e0d09072123c40cfef3015be146b55e0d26a67dd Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Tue, 3 Aug 2021 16:47:15 -0400 Subject: [PATCH 848/940] [dev.typeparams] go/types: use comparable bit rather than ==() method This is a port of CL 337354 to go/types, adjusted for the error reporting API and to reposition a couple error messages in issue47411.go2 (the go/types position is probably better). A panic is also fixed in lookup.go when method lookup fails and static == false. I'll send a fix for types2 in a separate CL. For #47411 Change-Id: Icc48f03c3958695f581f10e8675c1f32434c424b Reviewed-on: https://go-review.googlesource.com/c/go/+/339652 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/instantiate.go | 16 +++++++++--- src/go/types/interface.go | 2 +- src/go/types/lookup.go | 7 +---- src/go/types/predicates.go | 17 +----------- src/go/types/sizeof_test.go | 2 +- src/go/types/testdata/check/issues.go2 | 6 ++--- .../types/testdata/fixedbugs/issue47411.go2 | 26 +++++++++++++++++++ src/go/types/typeset.go | 26 ++++++++++++++++--- src/go/types/universe.go | 12 +++------ 9 files changed, 71 insertions(+), 43 deletions(-) create mode 100644 src/go/types/testdata/fixedbugs/issue47411.go2 diff --git a/src/go/types/instantiate.go b/src/go/types/instantiate.go index 28d68cad0ef..2e6c20723b3 100644 --- a/src/go/types/instantiate.go +++ b/src/go/types/instantiate.go @@ -173,6 +173,17 @@ func (check *Checker) satisfies(pos token.Pos, targ Type, tpar *TypeParam, smap // the parameterized type. iface = check.subst(pos, iface, smap).(*Interface) + // if iface is comparable, targ must be comparable + // TODO(gri) the error messages needs to be better, here + if iface.IsComparable() && !Comparable(targ) { + if tpar := asTypeParam(targ); tpar != nil && tpar.Bound().typeSet().IsTop() { + check.softErrorf(atPos(pos), _Todo, "%s has no constraints", targ) + return false + } + check.softErrorf(atPos(pos), _Todo, "%s does not satisfy comparable", targ) + return false + } + // targ must implement iface (methods) // - check only if we have methods if iface.NumMethods() > 0 { @@ -188,10 +199,7 @@ func (check *Checker) satisfies(pos token.Pos, targ Type, tpar *TypeParam, smap // (print warning for now) // Old warning: // check.softErrorf(pos, "%s does not satisfy %s (warning: name not updated) = %s (missing method %s)", targ, tpar.bound, iface, m) - if m.name == "==" { - // We don't want to report "missing method ==". - check.softErrorf(atPos(pos), 0, "%s does not satisfy comparable", targ) - } else if wrong != nil { + if wrong != nil { // TODO(gri) This can still report uninstantiated types which makes the error message // more difficult to read then necessary. // TODO(rFindley) should this use parentheses rather than ':' for qualification? diff --git a/src/go/types/interface.go b/src/go/types/interface.go index 686dd7a786d..51eff8fbddc 100644 --- a/src/go/types/interface.go +++ b/src/go/types/interface.go @@ -111,7 +111,7 @@ func (t *Interface) Method(i int) *Func { return t.typeSet().Method(i) } // Empty reports whether t is the empty interface. func (t *Interface) Empty() bool { return t.typeSet().IsTop() } -// IsComparable reports whether interface t is or embeds the predeclared interface "comparable". +// IsComparable reports whether each type in interface t's type set is comparable. func (t *Interface) IsComparable() bool { return t.typeSet().IsComparable() } // IsConstraint reports whether interface t is not just a method set. diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go index 07baf2a48b6..6d38db45238 100644 --- a/src/go/types/lookup.go +++ b/src/go/types/lookup.go @@ -307,8 +307,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, _, f := ityp.typeSet().LookupMethod(m.pkg, m.name) if f == nil { - // if m is the magic method == we're ok (interfaces are comparable) - if m.name == "==" || !static { + if !static { continue } return m, f @@ -358,10 +357,6 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // we must have a method (not a field of matching function type) f, _ := obj.(*Func) if f == nil { - // if m is the magic method == and V is comparable, we're ok - if m.name == "==" && Comparable(V) { - continue - } return m, nil } diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index 41e0c25d6bc..caf72c2f2ed 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -96,19 +96,6 @@ func comparable(T Type, seen map[Type]bool) bool { } seen[T] = true - // If T is a type parameter not constrained by any type - // (i.e., it's operational type is the top type), - // T is comparable if it has the == method. Otherwise, - // the operational type "wins". For instance - // - // interface{ comparable; type []byte } - // - // is not comparable because []byte is not comparable. - // TODO(gri) this code is not 100% correct (see comment for TypeSet.IsComparable) - if t := asTypeParam(T); t != nil && optype(t) == theTop { - return t.Bound().IsComparable() - } - switch t := under(T).(type) { case *Basic: // assume invalid types to be comparable @@ -126,9 +113,7 @@ func comparable(T Type, seen map[Type]bool) bool { case *Array: return comparable(t.elem, seen) case *TypeParam: - return t.underIs(func(t Type) bool { - return comparable(t, seen) - }) + return t.Bound().IsComparable() } return false } diff --git a/src/go/types/sizeof_test.go b/src/go/types/sizeof_test.go index c8758663ec0..b892e7e521a 100644 --- a/src/go/types/sizeof_test.go +++ b/src/go/types/sizeof_test.go @@ -47,7 +47,7 @@ func TestSizeof(t *testing.T) { // Misc {Scope{}, 44, 88}, {Package{}, 40, 80}, - {TypeSet{}, 20, 40}, + {TypeSet{}, 24, 48}, } for _, test := range tests { got := reflect.TypeOf(test.val).Size() diff --git a/src/go/types/testdata/check/issues.go2 b/src/go/types/testdata/check/issues.go2 index c57f0023034..6a1a10ad49b 100644 --- a/src/go/types/testdata/check/issues.go2 +++ b/src/go/types/testdata/check/issues.go2 @@ -65,7 +65,7 @@ func _() { type T1[P interface{~uint}] struct{} func _[P any]() { - _ = T1[P /* ERROR P has no type constraints */ ]{} + _ = T1[P /* ERROR P has no constraints */ ]{} } // This is the original (simplified) program causing the same issue. @@ -81,8 +81,8 @@ func (u T2[U]) Add1() U { return u.s + 1 } -func NewT2[U any]() T2[U /* ERROR U has no type constraints */ ] { - return T2[U /* ERROR U has no type constraints */ ]{} +func NewT2[U any]() T2[U /* ERROR U has no constraints */ ] { + return T2[U /* ERROR U has no constraints */ ]{} } func _() { diff --git a/src/go/types/testdata/fixedbugs/issue47411.go2 b/src/go/types/testdata/fixedbugs/issue47411.go2 new file mode 100644 index 00000000000..7326205863f --- /dev/null +++ b/src/go/types/testdata/fixedbugs/issue47411.go2 @@ -0,0 +1,26 @@ +// Copyright 2021 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 + +func f[_ comparable]() +func g[_ interface{interface{comparable; ~int|~string}}]() + +func _[P comparable, + Q interface{ comparable; ~int|~string }, + R any, // not comparable + S interface{ comparable; ~func() }, // not comparable +]() { + _ = f[int] + _ = f[P] + _ = f[Q] + _ = f[func /* ERROR does not satisfy comparable */ ()] + _ = f[R /* ERROR R has no constraints */ ] + + _ = g[int] + _ = g[P /* ERROR P has no type constraints */ ] + _ = g[Q] + _ = g[func /* ERROR does not satisfy comparable */()] + _ = g[R /* ERROR R has no constraints */ ] +} diff --git a/src/go/types/typeset.go b/src/go/types/typeset.go index 3df2f1235f5..226e438cc9a 100644 --- a/src/go/types/typeset.go +++ b/src/go/types/typeset.go @@ -16,22 +16,31 @@ import ( // A TypeSet represents the type set of an interface. type TypeSet struct { + comparable bool // if set, the interface is or embeds comparable // TODO(gri) consider using a set for the methods for faster lookup methods []*Func // all methods of the interface; sorted by unique ID types Type // typically a *Union; nil means no type restrictions } // IsTop reports whether type set s is the top type set (corresponding to the empty interface). -func (s *TypeSet) IsTop() bool { return len(s.methods) == 0 && s.types == nil } +func (s *TypeSet) IsTop() bool { return !s.comparable && len(s.methods) == 0 && s.types == nil } // IsMethodSet reports whether the type set s is described by a single set of methods. -func (s *TypeSet) IsMethodSet() bool { return s.types == nil && !s.IsComparable() } +func (s *TypeSet) IsMethodSet() bool { return !s.comparable && s.types == nil } // IsComparable reports whether each type in the set is comparable. // TODO(gri) this is not correct - there may be s.types values containing non-comparable types func (s *TypeSet) IsComparable() bool { - _, m := s.LookupMethod(nil, "==") - return m != nil + if s.types == nil { + return s.comparable + } + tcomparable := s.underIs(func(u Type) bool { + return Comparable(u) + }) + if !s.comparable { + return tcomparable + } + return s.comparable && tcomparable } // NumMethods returns the number of methods available. @@ -54,6 +63,12 @@ func (s *TypeSet) String() string { var buf bytes.Buffer buf.WriteByte('{') + if s.comparable { + buf.WriteString(" comparable") + if len(s.methods) > 0 || s.types != nil { + buf.WriteByte(';') + } + } for i, m := range s.methods { if i > 0 { buf.WriteByte(';') @@ -205,6 +220,9 @@ func computeTypeSet(check *Checker, pos token.Pos, ityp *Interface) *TypeSet { switch t := under(typ).(type) { case *Interface: tset := computeTypeSet(check, pos, t) + if tset.comparable { + ityp.tset.comparable = true + } for _, m := range tset.methods { addMethod(pos, m, false) // use embedding position pos rather than m.pos diff --git a/src/go/types/universe.go b/src/go/types/universe.go index 489587f3938..e2b3bd7c187 100644 --- a/src/go/types/universe.go +++ b/src/go/types/universe.go @@ -89,23 +89,19 @@ func defPredeclaredTypes() { res := NewVar(token.NoPos, nil, "", Typ[String]) sig := NewSignature(nil, nil, NewTuple(res), false) err := NewFunc(token.NoPos, nil, "Error", sig) - ityp := NewInterfaceType([]*Func{err}, nil) + ityp := &Interface{obj, []*Func{err}, nil, nil, true, nil} computeTypeSet(nil, token.NoPos, ityp) // prevent races due to lazy computation of tset typ := NewNamed(obj, ityp, nil) sig.recv = NewVar(token.NoPos, nil, "", typ) def(obj) } - // type comparable interface{ ==() } + // type comparable interface{ /* type set marked comparable */ } { obj := NewTypeName(token.NoPos, nil, "comparable", nil) obj.setColor(black) - sig := NewSignature(nil, nil, nil, false) - eql := NewFunc(token.NoPos, nil, "==", sig) - ityp := NewInterfaceType([]*Func{eql}, nil) - computeTypeSet(nil, token.NoPos, ityp) // prevent races due to lazy computation of tset - typ := NewNamed(obj, ityp, nil) - sig.recv = NewVar(token.NoPos, nil, "", typ) + ityp := &Interface{obj, nil, nil, nil, true, &TypeSet{true, nil, nil}} + NewNamed(obj, ityp, nil) def(obj) } } From 5b51cf47dcf08d86eb1de22850ebd7d75e7a02af Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Tue, 3 Aug 2021 16:50:35 -0400 Subject: [PATCH 849/940] [dev.typeparams] go/types: implement type terms This is a port of CL 338049 to go/types. It identical to that CL, except for eliding unnecessary typenames from the testTerms declaration. Change-Id: Ieb04d7bbc20063044eb63ea985f75d529f030cd7 Reviewed-on: https://go-review.googlesource.com/c/go/+/339653 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/typeterm.go | 166 +++++++++++++++++++++++++++ src/go/types/typeterm_test.go | 205 ++++++++++++++++++++++++++++++++++ 2 files changed, 371 insertions(+) create mode 100644 src/go/types/typeterm.go create mode 100644 src/go/types/typeterm_test.go diff --git a/src/go/types/typeterm.go b/src/go/types/typeterm.go new file mode 100644 index 00000000000..dbd055a580c --- /dev/null +++ b/src/go/types/typeterm.go @@ -0,0 +1,166 @@ +// Copyright 2021 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 types + +// TODO(gri) use a different symbol instead of ⊤ for the set of all types +// (⊤ is hard to distinguish from T in some fonts) + +// A term describes elementary type sets: +// +// ∅: (*term)(nil) == ∅ // set of no types (empty set) +// ⊤: &term{} == ⊤ // set of all types +// T: &term{false, T} == {T} // set of type T +// ~t: &term{true, t} == {t' | under(t') == t} // set of types with underlying type t +// +type term struct { + tilde bool // valid if typ != nil + typ Type +} + +func (x *term) String() string { + switch { + case x == nil: + return "∅" + case x.typ == nil: + return "⊤" + case x.tilde: + return "~" + x.typ.String() + default: + return x.typ.String() + } +} + +// equal reports whether x and y represent the same type set. +func (x *term) equal(y *term) bool { + // easy cases + switch { + case x == nil || y == nil: + return x == y + case x.typ == nil || y.typ == nil: + return x.typ == y.typ + } + // ∅ ⊂ x, y ⊂ ⊤ + + return x.tilde == y.tilde && Identical(x.typ, y.typ) +} + +// union returns the union x ∪ y: zero, one, or two non-nil terms. +func (x *term) union(y *term) (_, _ *term) { + // easy cases + switch { + case x == nil && y == nil: + return nil, nil // ∅ ∪ ∅ == ∅ + case x == nil: + return y, nil // ∅ ∪ y == y + case y == nil: + return x, nil // x ∪ ∅ == x + case x.typ == nil: + return x, nil // ⊤ ∪ y == ⊤ + case y.typ == nil: + return y, nil // x ∪ ⊤ == ⊤ + } + // ∅ ⊂ x, y ⊂ ⊤ + + if x.disjoint(y) { + return x, y // x ∪ y == (x, y) if x ∩ y == ∅ + } + // x.typ == y.typ + + // ~t ∪ ~t == ~t + // ~t ∪ T == ~t + // T ∪ ~t == ~t + // T ∪ T == T + if x.tilde || !y.tilde { + return x, nil + } + return y, nil +} + +// intersect returns the intersection x ∩ y. +func (x *term) intersect(y *term) *term { + // easy cases + switch { + case x == nil || y == nil: + return nil // ∅ ∩ y == ∅ and ∩ ∅ == ∅ + case x.typ == nil: + return y // ⊤ ∩ y == y + case y.typ == nil: + return x // x ∩ ⊤ == x + } + // ∅ ⊂ x, y ⊂ ⊤ + + if x.disjoint(y) { + return nil // x ∩ y == ∅ if x ∩ y == ∅ + } + // x.typ == y.typ + + // ~t ∩ ~t == ~t + // ~t ∩ T == T + // T ∩ ~t == T + // T ∩ T == T + if !x.tilde || y.tilde { + return x + } + return y +} + +// includes reports whether t ∈ x. +func (x *term) includes(t Type) bool { + // easy cases + switch { + case x == nil: + return false // t ∈ ∅ == false + case x.typ == nil: + return true // t ∈ ⊤ == true + } + // ∅ ⊂ x ⊂ ⊤ + + u := t + if x.tilde { + u = under(u) + } + return Identical(x.typ, u) +} + +// subsetOf reports whether x ⊆ y. +func (x *term) subsetOf(y *term) bool { + // easy cases + switch { + case x == nil: + return true // ∅ ⊆ y == true + case y == nil: + return false // x ⊆ ∅ == false since x != ∅ + case y.typ == nil: + return true // x ⊆ ⊤ == true + case x.typ == nil: + return false // ⊤ ⊆ y == false since y != ⊤ + } + // ∅ ⊂ x, y ⊂ ⊤ + + if x.disjoint(y) { + return false // x ⊆ y == false if x ∩ y == ∅ + } + // x.typ == y.typ + + // ~t ⊆ ~t == true + // ~t ⊆ T == false + // T ⊆ ~t == true + // T ⊆ T == true + return !x.tilde || y.tilde +} + +// disjoint reports whether x ∩ y == ∅. +// x.typ and y.typ must not be nil. +func (x *term) disjoint(y *term) bool { + ux := x.typ + if y.tilde { + ux = under(ux) + } + uy := y.typ + if x.tilde { + uy = under(uy) + } + return !Identical(ux, uy) +} diff --git a/src/go/types/typeterm_test.go b/src/go/types/typeterm_test.go new file mode 100644 index 00000000000..391ff3e05f8 --- /dev/null +++ b/src/go/types/typeterm_test.go @@ -0,0 +1,205 @@ +// Copyright 2021 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 types + +import ( + "strings" + "testing" +) + +var testTerms = map[string]*term{ + "∅": nil, + "⊤": {}, + "int": {false, Typ[Int]}, + "~int": {true, Typ[Int]}, + "string": {false, Typ[String]}, + "~string": {true, Typ[String]}, + // TODO(gri) add a defined type +} + +func TestTermString(t *testing.T) { + for want, x := range testTerms { + if got := x.String(); got != want { + t.Errorf("%v.String() == %v; want %v", x, got, want) + } + } +} + +func split(s string, n int) []string { + r := strings.Split(s, " ") + if len(r) != n { + panic("invalid test case: " + s) + } + return r +} + +func testTerm(name string) *term { + r, ok := testTerms[name] + if !ok { + panic("invalid test argument: " + name) + } + return r +} + +func TestTermEqual(t *testing.T) { + for _, test := range []string{ + "∅ ∅ T", + "⊤ ⊤ T", + "int int T", + "~int ~int T", + "∅ ⊤ F", + "∅ int F", + "∅ ~int F", + "⊤ int F", + "⊤ ~int F", + "int ~int F", + } { + args := split(test, 3) + x := testTerm(args[0]) + y := testTerm(args[1]) + want := args[2] == "T" + if got := x.equal(y); got != want { + t.Errorf("%v.equal(%v) = %v; want %v", x, y, got, want) + } + // equal is symmetric + x, y = y, x + if got := x.equal(y); got != want { + t.Errorf("%v.equal(%v) = %v; want %v", x, y, got, want) + } + } +} + +func TestTermUnion(t *testing.T) { + for _, test := range []string{ + "∅ ∅ ∅ ∅", + "∅ ⊤ ⊤ ∅", + "∅ int int ∅", + "∅ ~int ~int ∅", + "⊤ ⊤ ⊤ ∅", + "⊤ int ⊤ ∅", + "⊤ ~int ⊤ ∅", + "int int int ∅", + "int ~int ~int ∅", + "int string int string", + "int ~string int ~string", + "~int ~string ~int ~string", + + // union is symmetric, but the result order isn't - repeat symmetric cases explictly + "⊤ ∅ ⊤ ∅", + "int ∅ int ∅", + "~int ∅ ~int ∅", + "int ⊤ ⊤ ∅", + "~int ⊤ ⊤ ∅", + "~int int ~int ∅", + "string int string int", + "~string int ~string int", + "~string ~int ~string ~int", + } { + args := split(test, 4) + x := testTerm(args[0]) + y := testTerm(args[1]) + want1 := testTerm(args[2]) + want2 := testTerm(args[3]) + if got1, got2 := x.union(y); !got1.equal(want1) || !got2.equal(want2) { + t.Errorf("%v.union(%v) = %v, %v; want %v, %v", x, y, got1, got2, want1, want2) + } + } +} + +func TestTermIntersection(t *testing.T) { + for _, test := range []string{ + "∅ ∅ ∅", + "∅ ⊤ ∅", + "∅ int ∅", + "∅ ~int ∅", + "⊤ ⊤ ⊤", + "⊤ int int", + "⊤ ~int ~int", + "int int int", + "int ~int int", + "int string ∅", + "int ~string ∅", + "~int ~string ∅", + } { + args := split(test, 3) + x := testTerm(args[0]) + y := testTerm(args[1]) + want := testTerm(args[2]) + if got := x.intersect(y); !got.equal(want) { + t.Errorf("%v.intersect(%v) = %v; want %v", x, y, got, want) + } + // intersect is symmetric + x, y = y, x + if got := x.intersect(y); !got.equal(want) { + t.Errorf("%v.intersect(%v) = %v; want %v", x, y, got, want) + } + } +} + +func TestTermIncludes(t *testing.T) { + for _, test := range []string{ + "∅ int F", + "⊤ int T", + "int int T", + "~int int T", + "string int F", + "~string int F", + } { + args := split(test, 3) + x := testTerm(args[0]) + y := testTerm(args[1]).typ + want := args[2] == "T" + if got := x.includes(y); got != want { + t.Errorf("%v.includes(%v) = %v; want %v", x, y, got, want) + } + } +} + +func TestTermSubsetOf(t *testing.T) { + for _, test := range []string{ + "∅ ∅ T", + "⊤ ⊤ T", + "int int T", + "~int ~int T", + "∅ ⊤ T", + "∅ int T", + "∅ ~int T", + "⊤ int F", + "⊤ ~int F", + "int ~int T", + } { + args := split(test, 3) + x := testTerm(args[0]) + y := testTerm(args[1]) + want := args[2] == "T" + if got := x.subsetOf(y); got != want { + t.Errorf("%v.subsetOf(%v) = %v; want %v", x, y, got, want) + } + } +} + +func TestTermDisjoint(t *testing.T) { + for _, test := range []string{ + "int int F", + "~int ~int F", + "int ~int F", + "int string T", + "int ~string T", + "~int ~string T", + } { + args := split(test, 3) + x := testTerm(args[0]) + y := testTerm(args[1]) + want := args[2] == "T" + if got := x.disjoint(y); got != want { + t.Errorf("%v.disjoint(%v) = %v; want %v", x, y, got, want) + } + // disjoint is symmetric + x, y = y, x + if got := x.disjoint(y); got != want { + t.Errorf("%v.disjoint(%v) = %v; want %v", x, y, got, want) + } + } +} From 880ab6209e618c7dd6e47fa07e66176cd801eba1 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Tue, 3 Aug 2021 20:36:02 -0400 Subject: [PATCH 850/940] [dev.typeparams] cmd/compile/internal/types2: fix a panic in missingMethod When static == false, missingMethod incorrectly continues with a nil Func. Also remove some unnecessary type names from typeterm_test.go, which was done in the go/types port. Change-Id: I21fa637ac82b115563d3601314a470a5a43f9ae0 Reviewed-on: https://go-review.googlesource.com/c/go/+/339672 Trust: Robert Findley Trust: Robert Griesemer Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types2/lookup.go | 5 ++++- src/cmd/compile/internal/types2/typeterm_test.go | 10 +++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/cmd/compile/internal/types2/lookup.go b/src/cmd/compile/internal/types2/lookup.go index 41e5bc7811a..f62c3771d28 100644 --- a/src/cmd/compile/internal/types2/lookup.go +++ b/src/cmd/compile/internal/types2/lookup.go @@ -308,7 +308,10 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, for _, m := range T.typeSet().methods { _, f := ityp.typeSet().LookupMethod(m.pkg, m.name) - if f == nil && static { + if f == nil { + if !static { + continue + } return m, f } diff --git a/src/cmd/compile/internal/types2/typeterm_test.go b/src/cmd/compile/internal/types2/typeterm_test.go index 4676fb04373..cc4e30d9893 100644 --- a/src/cmd/compile/internal/types2/typeterm_test.go +++ b/src/cmd/compile/internal/types2/typeterm_test.go @@ -11,11 +11,11 @@ import ( var testTerms = map[string]*term{ "∅": nil, - "⊤": &term{}, - "int": &term{false, Typ[Int]}, - "~int": &term{true, Typ[Int]}, - "string": &term{false, Typ[String]}, - "~string": &term{true, Typ[String]}, + "⊤": {}, + "int": {false, Typ[Int]}, + "~int": {true, Typ[Int]}, + "string": {false, Typ[String]}, + "~string": {true, Typ[String]}, // TODO(gri) add a defined type } From ed3667d0795c6567dc5635d6c5c38c2abff4c8e4 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Tue, 3 Aug 2021 21:10:42 -0400 Subject: [PATCH 851/940] [dev.typeparams] go/types: use type terms to represent unions This is a straightforward port of CL 338092 to go/types. Change-Id: I414ec0ad95648c201e85fd2b4f494b1206c658e7 Reviewed-on: https://go-review.googlesource.com/c/go/+/339674 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/infer.go | 18 ++- src/go/types/interface.go | 6 +- src/go/types/operand.go | 6 +- src/go/types/predicates.go | 16 +-- src/go/types/sizeof_test.go | 3 +- src/go/types/subst.go | 22 +++- .../types/testdata/examples/constraints.go2 | 6 +- src/go/types/type.go | 2 +- src/go/types/typeset.go | 7 ++ src/go/types/typestring.go | 6 +- src/go/types/union.go | 117 +++++++++++------- 11 files changed, 130 insertions(+), 79 deletions(-) diff --git a/src/go/types/infer.go b/src/go/types/infer.go index f3f69e01b65..6e70a103e72 100644 --- a/src/go/types/infer.go +++ b/src/go/types/infer.go @@ -303,7 +303,7 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { } case *Union: - return w.isParameterizedList(t.types) + return w.isParameterizedTermList(t.terms) case *Signature: // t.tparams may not be nil if we are looking at a signature @@ -331,7 +331,7 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { return w.isParameterized(t.elem) case *Named: - return w.isParameterizedList(t.targs) + return w.isParameterizedTypeList(t.targs) case *TypeParam: // t must be one of w.tparams @@ -344,7 +344,7 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { return false } -func (w *tpWalker) isParameterizedList(list []Type) bool { +func (w *tpWalker) isParameterizedTypeList(list []Type) bool { for _, t := range list { if w.isParameterized(t) { return true @@ -353,6 +353,15 @@ func (w *tpWalker) isParameterizedList(list []Type) bool { return false } +func (w *tpWalker) isParameterizedTermList(list []*term) bool { + for _, t := range list { + if w.isParameterized(t.typ) { + return true + } + } + return false +} + // inferB returns the list of actual type arguments inferred from the type parameters' // bounds and an initial set of type arguments. If type inference is impossible because // unification fails, an error is reported if report is set to true, the resulting types @@ -461,7 +470,8 @@ func (check *Checker) structuralType(constraint Type) Type { if u, _ := types.(*Union); u != nil { if u.NumTerms() == 1 { // TODO(gri) do we need to respect tilde? - return u.types[0] + t, _ := u.Term(0) + return t } return nil } diff --git a/src/go/types/interface.go b/src/go/types/interface.go index 51eff8fbddc..e98e40179ca 100644 --- a/src/go/types/interface.go +++ b/src/go/types/interface.go @@ -34,7 +34,7 @@ func (t *Interface) is(f func(Type, bool) bool) bool { // TODO(gri) should settle on top or nil to represent this case return false // we must have at least one type! (was bug) case *Union: - return t.is(func(typ Type, tilde bool) bool { return f(typ, tilde) }) + return t.is(func(t *term) bool { return f(t.typ, t.tilde) }) default: return f(t, false) } @@ -266,8 +266,8 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d // (don't sort embeddeds: they must correspond to *embedPos entries) // Compute type set with a non-nil *Checker as soon as possible - // to report any errors. Subsequent uses of type sets should be - // using this computed type set and won't need to pass in a *Checker. + // to report any errors. Subsequent uses of type sets will use + // this computed type set and won't need to pass in a *Checker. check.later(func() { computeTypeSet(check, iface.Pos(), ityp) }) } diff --git a/src/go/types/operand.go b/src/go/types/operand.go index 1d0f5b80b6c..c605cf781ce 100644 --- a/src/go/types/operand.go +++ b/src/go/types/operand.go @@ -255,13 +255,13 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er // x is an untyped value representable by a value of type T. if isUntyped(Vu) { if t, ok := Tu.(*Union); ok { - return t.is(func(t Type, tilde bool) bool { + return t.is(func(t *term) bool { // TODO(gri) this could probably be more efficient - if tilde { + if t.tilde { // TODO(gri) We need to check assignability // for the underlying type of x. } - ok, _ := x.assignableTo(check, t, reason) + ok, _ := x.assignableTo(check, t.typ, reason) return ok }), _IncompatibleAssign } diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index caf72c2f2ed..579d35da420 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -238,20 +238,8 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { // types - each type appears exactly once. Thus, two union types // must contain the same number of types to have chance of // being equal. - if y, ok := y.(*Union); ok && x.NumTerms() == y.NumTerms() { - // Every type in x.types must be in y.types. - // Quadratic algorithm, but probably good enough for now. - // TODO(gri) we need a fast quick type ID/hash for all types. - L: - for i, xt := range x.types { - for j, yt := range y.types { - if Identical(xt, yt) && x.tilde[i] == y.tilde[j] { - continue L // x is in y.types - } - } - return false // x is not in y.types - } - return true + if y, ok := y.(*Union); ok { + return identicalTerms(x.terms, y.terms) } case *Interface: diff --git a/src/go/types/sizeof_test.go b/src/go/types/sizeof_test.go index b892e7e521a..75122b02735 100644 --- a/src/go/types/sizeof_test.go +++ b/src/go/types/sizeof_test.go @@ -26,12 +26,13 @@ func TestSizeof(t *testing.T) { {Pointer{}, 8, 16}, {Tuple{}, 12, 24}, {Signature{}, 28, 56}, - {Union{}, 24, 48}, + {Union{}, 12, 24}, {Interface{}, 40, 80}, {Map{}, 16, 32}, {Chan{}, 12, 24}, {Named{}, 80, 152}, {TypeParam{}, 28, 48}, + {term{}, 12, 24}, {top{}, 0, 0}, // Objects diff --git a/src/go/types/subst.go b/src/go/types/subst.go index c05e51d4250..322e30d3577 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -148,12 +148,12 @@ func (subst *subster) typ(typ Type) Type { } case *Union: - types, copied := subst.typeList(t.types) + terms, copied := subst.termList(t.terms) if copied { // TODO(gri) Remove duplicates that may have crept in after substitution // (unlikely but possible). This matters for the Identical // predicate on unions. - return newUnion(types, t.tilde) + return &Union{terms} } case *Interface: @@ -393,3 +393,21 @@ func (subst *subster) typeList(in []Type) (out []Type, copied bool) { } return } + +func (subst *subster) termList(in []*term) (out []*term, copied bool) { + out = in + for i, t := range in { + if u := subst.typ(t.typ); u != t.typ { + if !copied { + // first function that got substituted => allocate new out slice + // and copy all functions + new := make([]*term, len(in)) + copy(new, out) + out = new + copied = true + } + out[i] = &term{t.tilde, u} + } + } + return +} diff --git a/src/go/types/testdata/examples/constraints.go2 b/src/go/types/testdata/examples/constraints.go2 index d9805fe6940..28aa19bb12c 100644 --- a/src/go/types/testdata/examples/constraints.go2 +++ b/src/go/types/testdata/examples/constraints.go2 @@ -31,9 +31,9 @@ type ( _ interface{int|~ /* ERROR duplicate term int */ int } _ interface{~int|~ /* ERROR duplicate term int */ int } - // For now we do not permit interfaces with ~ or in unions. - _ interface{~ /* ERROR cannot use interface */ interface{}} - _ interface{int|interface /* ERROR cannot use interface */ {}} + // For now we do not permit interfaces with methods in unions. + _ interface{~ /* ERROR invalid use of ~ */ interface{}} + _ interface{int|interface /* ERROR cannot use .* in union */ { m() }} ) type ( diff --git a/src/go/types/type.go b/src/go/types/type.go index b575b11e4e1..2ad89d97059 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -60,7 +60,7 @@ func optype(typ Type) Type { // If we have a union with a single entry, ignore // any tilde because under(~t) == under(t). if u, _ := a.(*Union); u != nil && u.NumTerms() == 1 { - a = u.types[0] + a, _ = u.Term(0) } if a != typ { // a != typ and a is a type parameter => under(a) != typ, so this is ok diff --git a/src/go/types/typeset.go b/src/go/types/typeset.go index 226e438cc9a..cbd867dd953 100644 --- a/src/go/types/typeset.go +++ b/src/go/types/typeset.go @@ -43,6 +43,13 @@ func (s *TypeSet) IsComparable() bool { return s.comparable && tcomparable } +// TODO(gri) IsTypeSet is not a great name. Find a better one. + +// IsTypeSet reports whether the type set s is represented by a finite set of underlying types. +func (s *TypeSet) IsTypeSet() bool { + return !s.comparable && len(s.methods) == 0 +} + // NumMethods returns the number of methods available. func (s *TypeSet) NumMethods() int { return len(s.methods) } diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go index 74b18a9ec83..c0c69624ec7 100644 --- a/src/go/types/typestring.go +++ b/src/go/types/typestring.go @@ -163,14 +163,14 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { buf.WriteString("⊥") break } - for i, e := range t.types { + for i, t := range t.terms { if i > 0 { buf.WriteByte('|') } - if t.tilde[i] { + if t.tilde { buf.WriteByte('~') } - writeType(buf, e, qf, visited) + writeType(buf, t.typ, qf, visited) } case *Interface: diff --git a/src/go/types/union.go b/src/go/types/union.go index 556be46bf6a..a56f9d29f34 100644 --- a/src/go/types/union.go +++ b/src/go/types/union.go @@ -13,10 +13,8 @@ import ( // API // A Union represents a union of terms. -// A term is a type with a ~ (tilde) flag. type Union struct { - types []Type // types are unique - tilde []bool // if tilde[i] is set, terms[i] is of the form ~T + terms []*term } // NewUnion returns a new Union type with the given terms (types[i], tilde[i]). @@ -24,9 +22,9 @@ type Union struct { // of no types. func NewUnion(types []Type, tilde []bool) *Union { return newUnion(types, tilde) } -func (u *Union) IsEmpty() bool { return len(u.types) == 0 } -func (u *Union) NumTerms() int { return len(u.types) } -func (u *Union) Term(i int) (Type, bool) { return u.types[i], u.tilde[i] } +func (u *Union) IsEmpty() bool { return len(u.terms) == 0 } +func (u *Union) NumTerms() int { return len(u.terms) } +func (u *Union) Term(i int) (Type, bool) { t := u.terms[i]; return t.typ, t.tilde } func (u *Union) Underlying() Type { return u } func (u *Union) String() string { return TypeString(u, nil) } @@ -42,18 +40,20 @@ func newUnion(types []Type, tilde []bool) *Union { return emptyUnion } t := new(Union) - t.types = types - t.tilde = tilde + t.terms = make([]*term, len(types)) + for i, typ := range types { + t.terms[i] = &term{tilde[i], typ} + } return t } -// is reports whether f returned true for all terms (type, tilde) of u. -func (u *Union) is(f func(Type, bool) bool) bool { +// is reports whether f returns true for all terms of u. +func (u *Union) is(f func(*term) bool) bool { if u.IsEmpty() { return false } - for i, t := range u.types { - if !f(t, u.tilde[i]) { + for _, t := range u.terms { + if !f(t) { return false } } @@ -65,8 +65,8 @@ func (u *Union) underIs(f func(Type) bool) bool { if u.IsEmpty() { return false } - for _, t := range u.types { - if !f(under(t)) { + for _, t := range u.terms { + if !f(under(t.typ)) { return false } } @@ -86,7 +86,7 @@ func parseUnion(check *Checker, tlist []ast.Expr) Type { } // Ensure that each type is only present once in the type list. - // It's ok to do this check at the end because it's not a requirement + // It's ok to do this check later because it's not a requirement // for correctness of the code. // Note: This is a quadratic algorithm, but unions tend to be short. check.later(func() { @@ -99,7 +99,7 @@ func parseUnion(check *Checker, tlist []ast.Expr) Type { x := tlist[i] pos := x.Pos() // We may not know the position of x if it was a typechecker- - // introduced ~T type of a type list entry T. Use the position + // introduced ~T term for a type list entry T. Use the position // of T instead. // TODO(rfindley) remove this test once we don't support type lists anymore if !pos.IsValid() { @@ -109,13 +109,24 @@ func parseUnion(check *Checker, tlist []ast.Expr) Type { } u := under(t) - if tilde[i] && !Identical(u, t) { - check.errorf(x, _Todo, "invalid use of ~ (underlying type of %s is %s)", t, u) - continue // don't report another error for t + f, _ := u.(*Interface) + if tilde[i] { + if f != nil { + check.errorf(x, _Todo, "invalid use of ~ (%s is an interface)", t) + continue // don't report another error for t + } + + if !Identical(u, t) { + check.errorf(x, _Todo, "invalid use of ~ (underlying type of %s is %s)", t, u) + continue // don't report another error for t + } } - if _, ok := u.(*Interface); ok { - // A single type with a ~ is a single-term union. - check.errorf(atPos(pos), _Todo, "cannot use interface %s with ~ or inside a union (implementation restriction)", t) + + // Stand-alone embedded interfaces are ok and are handled by the single-type case + // in the beginning. Embedded interfaces with tilde are excluded above. If we reach + // here, we must have at least two terms in the union. + if f != nil && !f.typeSet().IsTypeSet() { + check.errorf(atPos(pos), _Todo, "cannot use %s in union (interface contains methods)", t) continue // don't report another error for t } @@ -167,25 +178,7 @@ func intersect(x, y Type) (r Type) { yu, _ := y.(*Union) switch { case xu != nil && yu != nil: - // Quadratic algorithm, but good enough for now. - // TODO(gri) fix asymptotic performance - var types []Type - var tilde []bool - for j, y := range yu.types { - yt := yu.tilde[j] - if r, rt := xu.intersect(y, yt); r != nil { - // Terms x[i] and y[j] match: Select the one that - // is not a ~t because that is the intersection - // type. If both are ~t, they are identical: - // T ∩ T = T - // T ∩ ~t = T - // ~t ∩ T = T - // ~t ∩ ~t = ~t - types = append(types, r) - tilde = append(tilde, rt) - } - } - return newUnion(types, tilde) + return &Union{intersectTerms(xu.terms, yu.terms)} case xu != nil: if r, _ := xu.intersect(y, false); r != nil { @@ -219,14 +212,16 @@ func includes(list []Type, typ Type) bool { // intersect computes the intersection of the union u and term (y, yt) // and returns the intersection term, if any. Otherwise the result is // (nil, false). +// TODO(gri) this needs to cleaned up/removed once we switch to lazy +// union type set computation. func (u *Union) intersect(y Type, yt bool) (Type, bool) { under_y := under(y) - for i, x := range u.types { - xt := u.tilde[i] + for _, x := range u.terms { + xt := x.tilde // determine which types xx, yy to compare - xx := x + xx := x.typ if yt { - xx = under(x) + xx = under(xx) } yy := y if xt { @@ -242,3 +237,35 @@ func (u *Union) intersect(y Type, yt bool) (Type, bool) { } return nil, false } + +func identicalTerms(list1, list2 []*term) bool { + if len(list1) != len(list2) { + return false + } + // Every term in list1 must be in list2. + // Quadratic algorithm, but probably good enough for now. + // TODO(gri) we need a fast quick type ID/hash for all types. +L: + for _, x := range list1 { + for _, y := range list2 { + if x.equal(y) { + continue L // x is in list2 + } + } + return false + } + return true +} + +func intersectTerms(list1, list2 []*term) (list []*term) { + // Quadratic algorithm, but good enough for now. + // TODO(gri) fix asymptotic performance + for _, x := range list1 { + for _, y := range list2 { + if r := x.intersect(y); r != nil { + list = append(list, r) + } + } + } + return +} From 3efc8f9a8dc93ccacb8b139cafc44ee0709d8fdd Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Tue, 3 Aug 2021 21:14:31 -0400 Subject: [PATCH 852/940] [dev.typeparams] go/types: (TypeParam) SetBound -> SetConstraint This is a straightforward port of CL 338196 to go/types, minus the deprecated TypeParam.Bound() method (since it is not needed), plus an adjustment for methodset.go. Change-Id: Ie372bfeec245094102a2c3257a43499d75981447 Reviewed-on: https://go-review.googlesource.com/c/go/+/339675 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/builtins.go | 2 +- src/go/types/call.go | 2 +- src/go/types/instantiate.go | 6 +++--- src/go/types/lookup.go | 2 +- src/go/types/methodset.go | 2 +- src/go/types/predicates.go | 2 +- src/go/types/type.go | 2 +- src/go/types/typeparam.go | 25 +++++++++++-------------- 8 files changed, 20 insertions(+), 23 deletions(-) diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index ecb9920a811..aae05438cd3 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -826,7 +826,7 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { // type and collect possible result types at the same time. var rtypes []Type var tildes []bool - if !tp.Bound().is(func(typ Type, tilde bool) bool { + if !tp.iface().is(func(typ Type, tilde bool) bool { if r := f(typ); r != nil { rtypes = append(rtypes, r) tildes = append(tildes, tilde) diff --git a/src/go/types/call.go b/src/go/types/call.go index 16b8e4eb7c4..da2f319a4a7 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -482,7 +482,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) { var why string if tpar := asTypeParam(x.typ); tpar != nil { // Type parameter bounds don't specify fields, so don't mention "field". - if tname := tpar.Bound().obj; tname != nil { + if tname := tpar.iface().obj; tname != nil { why = check.sprintf("interface %s has no method %s", tname.name, sel) } else { why = check.sprintf("type bound for %s has no method %s", x.typ, sel) diff --git a/src/go/types/instantiate.go b/src/go/types/instantiate.go index 2e6c20723b3..6d56eb7ea21 100644 --- a/src/go/types/instantiate.go +++ b/src/go/types/instantiate.go @@ -162,7 +162,7 @@ func (check *Checker) verify(pos token.Pos, tparams []*TypeName, targs []Type, p // A suitable error is reported if the result is false. // TODO(gri) This should be a method of interfaces or type sets. func (check *Checker) satisfies(pos token.Pos, targ Type, tpar *TypeParam, smap *substMap) bool { - iface := tpar.Bound() + iface := tpar.iface() if iface.Empty() { return true // no type bound } @@ -176,7 +176,7 @@ func (check *Checker) satisfies(pos token.Pos, targ Type, tpar *TypeParam, smap // if iface is comparable, targ must be comparable // TODO(gri) the error messages needs to be better, here if iface.IsComparable() && !Comparable(targ) { - if tpar := asTypeParam(targ); tpar != nil && tpar.Bound().typeSet().IsTop() { + if tpar := asTypeParam(targ); tpar != nil && tpar.iface().typeSet().IsTop() { check.softErrorf(atPos(pos), _Todo, "%s has no constraints", targ) return false } @@ -222,7 +222,7 @@ func (check *Checker) satisfies(pos token.Pos, targ Type, tpar *TypeParam, smap // If targ is itself a type parameter, each of its possible types, but at least one, must be in the // list of iface types (i.e., the targ type list must be a non-empty subset of the iface types). if targ := asTypeParam(targ); targ != nil { - targBound := targ.Bound() + targBound := targ.iface() if targBound.typeSet().types == nil { check.softErrorf(atPos(pos), _Todo, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ) return false diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go index 6d38db45238..7cab336dbe2 100644 --- a/src/go/types/lookup.go +++ b/src/go/types/lookup.go @@ -190,7 +190,7 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o } case *TypeParam: - if i, m := t.Bound().typeSet().LookupMethod(pkg, name); m != nil { + if i, m := t.iface().typeSet().LookupMethod(pkg, name); m != nil { assert(m.typ != nil) index = concat(e.index, i) if obj != nil || e.multiples { diff --git a/src/go/types/methodset.go b/src/go/types/methodset.go index 491917d6bcd..1462601d586 100644 --- a/src/go/types/methodset.go +++ b/src/go/types/methodset.go @@ -160,7 +160,7 @@ func NewMethodSet(T Type) *MethodSet { mset = mset.add(t.typeSet().methods, e.index, true, e.multiples) case *TypeParam: - mset = mset.add(t.Bound().typeSet().methods, e.index, true, e.multiples) + mset = mset.add(t.iface().typeSet().methods, e.index, true, e.multiples) } } diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index 579d35da420..f9cac34a031 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -113,7 +113,7 @@ func comparable(T Type, seen map[Type]bool) bool { case *Array: return comparable(t.elem, seen) case *TypeParam: - return t.Bound().IsComparable() + return t.iface().IsComparable() } return false } diff --git a/src/go/types/type.go b/src/go/types/type.go index 2ad89d97059..5819dd290ca 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -56,7 +56,7 @@ func optype(typ Type) Type { // for a type parameter list of the form: // (type T interface { type T }). // See also issue #39680. - if a := t.Bound().typeSet().types; a != nil && a != typ { + if a := t.iface().typeSet().types; a != nil && a != typ { // If we have a union with a single entry, ignore // any tilde because under(~t) == under(t). if u, _ := a.(*Union); u != nil && u.NumTerms() == 1 { diff --git a/src/go/types/typeparam.go b/src/go/types/typeparam.go index 8cb44ea25ec..33a516c2097 100644 --- a/src/go/types/typeparam.go +++ b/src/go/types/typeparam.go @@ -74,25 +74,22 @@ func (t *TypeParam) Constraint() Type { return t.bound } -// Bound returns the underlying type of the type parameter's -// constraint. -// Deprecated for external use. Use Constraint instead. -func (t *TypeParam) Bound() *Interface { +// SetConstraint sets the type constraint for t. +func (t *TypeParam) SetConstraint(bound Type) { + if bound == nil { + panic("types2.TypeParam.SetConstraint: bound must not be nil") + } + t.bound = bound +} + +// iface returns the constraint interface of t. +func (t *TypeParam) iface() *Interface { if iface, _ := under(t.Constraint()).(*Interface); iface != nil { return iface } return &emptyInterface } -// TODO(rfindley): document the SetBound methods. - -func (t *TypeParam) SetBound(bound Type) { - if bound == nil { - panic("internal error: bound must not be nil") - } - t.bound = bound -} - func (t *TypeParam) Underlying() Type { return t } func (t *TypeParam) String() string { return TypeString(t, nil) } @@ -135,5 +132,5 @@ func bindTParams(list []*TypeName) *TypeParams { // Implementation func (t *TypeParam) underIs(f func(Type) bool) bool { - return t.Bound().typeSet().underIs(f) + return t.iface().typeSet().underIs(f) } From b01e775e9c05dd2e5fa19ea06ac09f9a12ae660e Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Tue, 3 Aug 2021 21:39:53 -0400 Subject: [PATCH 853/940] [dev.typeparams] go/types: print constraint info for type param operands This is a clean port of CL 338309 to go/types. Change-Id: Ie2c9e2ea51d6321af8bf149e43cd71b7ac282d13 Reviewed-on: https://go-review.googlesource.com/c/go/+/339676 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/operand.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/go/types/operand.go b/src/go/types/operand.go index c605cf781ce..aea8bf5e7ad 100644 --- a/src/go/types/operand.go +++ b/src/go/types/operand.go @@ -159,16 +159,20 @@ func operandString(x *operand, qf Qualifier) string { if hasType { if x.typ != Typ[Invalid] { var intro string - switch { - case isGeneric(x.typ): - intro = " of generic type " - case asTypeParam(x.typ) != nil: - intro = " of type parameter type " - default: + var tpar *TypeParam + if isGeneric(x.typ) { + intro = " of parameterized type " + } else if tpar = asTypeParam(x.typ); tpar != nil { + intro = " of type parameter " + } else { intro = " of type " } buf.WriteString(intro) WriteType(&buf, x.typ, qf) + if tpar != nil { + buf.WriteString(" constrained by ") + WriteType(&buf, tpar.bound, qf) // do not compute interface type sets here + } } else { buf.WriteString(" with invalid type") } From d27a889119ce05b1faae29aa549887e86ce453df Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Tue, 3 Aug 2021 21:43:39 -0400 Subject: [PATCH 854/940] [dev.typeparams] go/types: move instance.go contents into named.go (cleanup) This is a port of CL 338469 to go/types. Change-Id: I3ee655fa2dc7e789f210c8dec171b3358c4ff132 Reviewed-on: https://go-review.googlesource.com/c/go/+/339677 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/instance.go | 44 -------------------------------------- src/go/types/named.go | 40 +++++++++++++++++++++++++++++++++- src/go/types/predicates.go | 6 ------ src/go/types/unify.go | 3 --- 4 files changed, 39 insertions(+), 54 deletions(-) delete mode 100644 src/go/types/instance.go diff --git a/src/go/types/instance.go b/src/go/types/instance.go deleted file mode 100644 index 1223c9f6f18..00000000000 --- a/src/go/types/instance.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2011 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 types - -// TODO(rfindley): move this code to named.go. - -import "go/token" - -// instance holds position information for use in lazy instantiation. -// -// TODO(rfindley): come up with a better name for this type, now that its usage -// has changed. -type instance struct { - pos token.Pos // position of type instantiation; for error reporting only - posList []token.Pos // position of each targ; for error reporting only -} - -// expand ensures that the underlying type of n is instantiated. -// The underlying type will be Typ[Invalid] if there was an error. -// TODO(rfindley): expand would be a better name for this method, but conflicts -// with the existing concept of lazy expansion. Need to reconcile this. -func (n *Named) expand() { - if n.instance != nil { - // n must be loaded before instantiation, in order to have accurate - // tparams. This is done implicitly by the call to n.TParams, but making it - // explicit is harmless: load is idempotent. - n.load() - inst := n.check.instantiate(n.instance.pos, n.orig.underlying, n.TParams().list(), n.targs, n.instance.posList) - n.underlying = inst - n.fromRHS = inst - n.instance = nil - } -} - -// expand expands uninstantiated named types and leaves all other types alone. -// expand does not recurse. -func expand(typ Type) Type { - if t, _ := typ.(*Named); t != nil { - t.expand() - } - return typ -} diff --git a/src/go/types/named.go b/src/go/types/named.go index 87eaa3179e8..fc53783ab85 100644 --- a/src/go/types/named.go +++ b/src/go/types/named.go @@ -4,7 +4,10 @@ package types -import "sync" +import ( + "go/token" + "sync" +) // TODO(rfindley) Clean up Named struct below; specifically the fromRHS field (can we use underlying?). @@ -252,3 +255,38 @@ func (n *Named) setUnderlying(typ Type) { n.underlying = typ } } + +// instance holds position information for use in lazy instantiation. +// +// TODO(rfindley): come up with a better name for this type, now that its usage +// has changed. +type instance struct { + pos token.Pos // position of type instantiation; for error reporting only + posList []token.Pos // position of each targ; for error reporting only +} + +// expand ensures that the underlying type of n is instantiated. +// The underlying type will be Typ[Invalid] if there was an error. +// TODO(rfindley): expand would be a better name for this method, but conflicts +// with the existing concept of lazy expansion. Need to reconcile this. +func (n *Named) expand() { + if n.instance != nil { + // n must be loaded before instantiation, in order to have accurate + // tparams. This is done implicitly by the call to n.TParams, but making it + // explicit is harmless: load is idempotent. + n.load() + inst := n.check.instantiate(n.instance.pos, n.orig.underlying, n.TParams().list(), n.targs, n.instance.posList) + n.underlying = inst + n.fromRHS = inst + n.instance = nil + } +} + +// expand expands uninstantiated named types and leaves all other types alone. +// expand does not recurse. +func expand(typ Type) Type { + if t, _ := typ.(*Named); t != nil { + t.expand() + } + return typ +} diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index f9cac34a031..23924693fd2 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -57,9 +57,6 @@ func isNumericOrString(typ Type) bool { return is(typ, IsNumeric|IsString) } func isTyped(typ Type) bool { // isTyped is called with types that are not fully // set up. Must not call asBasic()! - // A *Named or *instance type is always typed, so - // we only need to check if we have a true *Basic - // type. t, _ := typ.(*Basic) return t == nil || t.info&IsUntyped == 0 } @@ -328,9 +325,6 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { case *TypeParam: // nothing to do (x and y being equal is caught in the very beginning of this function) - // case *instance: - // unreachable since types are expanded - case *top: // Either both types are theTop in which case the initial x == y check // will have caught them. Otherwise they are not identical. diff --git a/src/go/types/unify.go b/src/go/types/unify.go index da57e533cc8..90a5cf7c728 100644 --- a/src/go/types/unify.go +++ b/src/go/types/unify.go @@ -456,9 +456,6 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool { // are identical if they originate in the same declaration. return x == y - // case *instance: - // unreachable since types are expanded - case nil: // avoid a crash in case of nil type From 6e738868a7a943d7d4fd6bb1963e7f6d78111726 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Tue, 3 Aug 2021 19:38:37 -0700 Subject: [PATCH 855/940] net/http: speed up and deflake TestCancelRequestWhenSharingConnection This test made many requests over the same connection for 10 seconds, trusting that this will exercise the request cancelation race from #41600. Change the test to exhibit the specific race in a targeted fashion with only two requests. Updates #41600. Updates #47016. Change-Id: If99c9b9331ff645f6bb67fe9fb79b8aab8784710 Reviewed-on: https://go-review.googlesource.com/c/go/+/339594 Trust: Damien Neil Run-TryBot: Damien Neil TryBot-Result: Go Bot Reviewed-by: Heschi Kreinick --- src/net/http/transport_test.go | 81 ++++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 28 deletions(-) diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index 690e0c299d2..eeaa4926445 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -6441,10 +6441,11 @@ func TestErrorWriteLoopRace(t *testing.T) { // Test that a new request which uses the connection of an active request // cannot cause it to be canceled as well. func TestCancelRequestWhenSharingConnection(t *testing.T) { - if testing.Short() { - t.Skip("skipping in short mode") - } + reqc := make(chan chan struct{}, 2) ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, req *Request) { + ch := make(chan struct{}, 1) + reqc <- ch + <-ch w.Header().Add("Content-Length", "0") })) defer ts.Close() @@ -6456,34 +6457,58 @@ func TestCancelRequestWhenSharingConnection(t *testing.T) { var wg sync.WaitGroup - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - - for i := 0; i < 10; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for ctx.Err() == nil { - reqctx, reqcancel := context.WithCancel(ctx) - go reqcancel() - req, _ := NewRequestWithContext(reqctx, "GET", ts.URL, nil) - res, err := client.Do(req) - if err == nil { - res.Body.Close() - } - } - }() - } - - for ctx.Err() == nil { - req, _ := NewRequest("GET", ts.URL, nil) - if res, err := client.Do(req); err != nil { - t.Errorf("unexpected: %p %v", req, err) - break - } else { + wg.Add(1) + putidlec := make(chan chan struct{}) + go func() { + defer wg.Done() + ctx := httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{ + PutIdleConn: func(error) { + // Signal that the idle conn has been returned to the pool, + // and wait for the order to proceed. + ch := make(chan struct{}) + putidlec <- ch + <-ch + }, + }) + req, _ := NewRequestWithContext(ctx, "GET", ts.URL, nil) + res, err := client.Do(req) + if err == nil { res.Body.Close() } - } + if err != nil { + t.Errorf("request 1: got err %v, want nil", err) + } + }() + // Wait for the first request to receive a response and return the + // connection to the idle pool. + r1c := <-reqc + close(r1c) + idlec := <-putidlec + + wg.Add(1) + cancelctx, cancel := context.WithCancel(context.Background()) + go func() { + defer wg.Done() + req, _ := NewRequestWithContext(cancelctx, "GET", ts.URL, nil) + res, err := client.Do(req) + if err == nil { + res.Body.Close() + } + if !errors.Is(err, context.Canceled) { + t.Errorf("request 2: got err %v, want Canceled", err) + } + }() + + // Wait for the second request to arrive at the server, and then cancel + // the request context. + r2c := <-reqc cancel() + + // Give the cancelation a moment to take effect, and then unblock the first request. + time.Sleep(1 * time.Millisecond) + close(idlec) + + close(r2c) wg.Wait() } From e590cb64f940b2d4996a6e7773c1b855be952632 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Wed, 4 Aug 2021 08:54:09 -0400 Subject: [PATCH 856/940] [dev.typeparams] runtime: handle d.link carefully when freeing a defer CL 339396 allowed stack copying on entry to and during freedefer, but this introduced a subtle bug: if d is heap-allocated, and d.link points to a stack-allocated defer, stack copying during freedefer can briefly introduce a stale pointer, which the garbage collector can discover and panic about. This happens because d has already been unlinked from the defer chain when freedefer is called, so stack copying won't update stack pointers in it. Fix this by making freedefer nosplit again and immediately clearing d.link. This should fix the longtest builders, which currently fail on GOMAXPROCS=2 runtime -cpu=1,2,4 -quick in the TestDeferHeapAndStack test. This seems like the simplest fix, but it just deals with the subtlety rather than eliminating it. Really, every call site of freedefer (of which there are surprisingly many) has hidden subtlety between unlinking the defer and calling freedefer. We could consolidate the subtlety into each call site by requiring that they unlink the defer and set d.link to nil before calling freedefer. freedefer could check this condition like it checks that various other fields have already been zeroed. A more radical option is to replace freedefer with "popDefer", which would both pop the defer off the link and take care of freeing it. There would still be a brief moment of subtlety, but it would be in one place, in popDefer. Annoyingly, *almost* every call to freedefer just pops the defer from the head of the G's list, but there's one place when handling open-coded defers where we have to remove a defer from the middle of the list. I'm inclined to first fix that subtlety by only expanding open-coded defer records when they're at the head of the defer list, and then revisit the popDefer idea. Change-Id: I3130d2542c01a421a5d60e8c31f5379263219627 Reviewed-on: https://go-review.googlesource.com/c/go/+/339730 Trust: Austin Clements Run-TryBot: Austin Clements TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/runtime/panic.go | 10 ++++++++++ src/runtime/runtime2.go | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 48b1b5dd9db..e4bdceb32f1 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -338,7 +338,17 @@ func newdefer() *_defer { // Free the given defer. // The defer cannot be used after this call. +// +// This is nosplit because the incoming defer is in a perilous state. +// It's not on any defer list, so stack copying won't adjust stack +// pointers in it (namely, d.link). Hence, if we were to copy the +// stack, d could then contain a stale pointer. +// +//go:nosplit func freedefer(d *_defer) { + d.link = nil + // After this point we can copy the stack. + if d._panic != nil { freedeferpanic() } diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index b5e4b3dec8f..c5e2501991b 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -957,7 +957,7 @@ type _defer struct { pc uintptr // pc at time of defer fn func() // can be nil for open-coded defers _panic *_panic // panic that is running defer - link *_defer + link *_defer // next defer on G; can point to either heap or stack! // If openDefer is true, the fields below record values about the stack // frame and associated function that has the open-coded defer(s). sp From b730a26729ec8c00c3e31e564f9b5cf8b1deb580 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 3 Aug 2021 19:33:01 -0700 Subject: [PATCH 857/940] [dev.typeparams] cmd/compile: put shape types in their own package Put shape types in the top level package called ".shape". Name them using the serialization of the shape name, instead of the .shapeN names. This allows the linker to deduplicate instantiations across packages. Not sure that this is entirely correct, as shapes in this package may reference other packages (e.g. a field of a struct). But it seems to work for now. For the added test, when you look at the resulting binary (use the -k option with run.go) it has only one instantiation of F, and 4 call sites: $ objdump -d a.exe | grep _a\.F 1053cb0: e8 8b 00 00 00 callq 139 <_a.F[.shape.*uint8]> 1053ce9: e8 52 00 00 00 callq 82 <_a.F[.shape.*uint8]> _a.F[.shape.*uint8]: 1053d90: e8 ab ff ff ff callq -85 <_a.F[.shape.*uint8]> 1053dc9: e8 72 ff ff ff callq -142 <_a.F[.shape.*uint8]> Change-Id: I627f7e50210aabe4a10d0e2717d87b75ac82e99b Reviewed-on: https://go-review.googlesource.com/c/go/+/339595 Trust: Keith Randall Trust: Dan Scales Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/reflectdata/reflect.go | 7 ++++++- src/cmd/compile/internal/typecheck/subr.go | 7 +++---- test/typeparam/dedup.dir/a.go | 10 ++++++++++ test/typeparam/dedup.dir/b.go | 14 ++++++++++++++ test/typeparam/dedup.dir/c.go | 14 ++++++++++++++ test/typeparam/dedup.dir/main.go | 15 +++++++++++++++ test/typeparam/dedup.go | 12 ++++++++++++ test/typeparam/dedup.out | 4 ++++ 8 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 test/typeparam/dedup.dir/a.go create mode 100644 test/typeparam/dedup.dir/b.go create mode 100644 test/typeparam/dedup.dir/c.go create mode 100644 test/typeparam/dedup.dir/main.go create mode 100644 test/typeparam/dedup.go create mode 100644 test/typeparam/dedup.out diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index 19cf2a0a125..a8df7a1a243 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -947,7 +947,7 @@ func writeType(t *types.Type) *obj.LSym { } dupok := 0 - if tbase.Sym() == nil { // TODO(mdempsky): Probably need DUPOK for instantiated types too. + if tbase.Sym() == nil || tbase.HasShape() { // TODO(mdempsky): Probably need DUPOK for instantiated types too. dupok = obj.DUPOK } @@ -1738,6 +1738,11 @@ func NeedEmit(typ *types.Type) bool { // Need to emit to be safe (however, see TODO above). return true + case typ.HasShape(): + // Shape type; need to emit even though it lives in the .shape package. + // TODO: make sure the linker deduplicates them (see dupok in writeType above). + return true + default: // Should have been emitted by an imported package. return false diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index 25db24259c3..53c39333705 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -1362,8 +1362,7 @@ func Shapify(t *types.Type) *types.Type { return s } - sym := Lookup(fmt.Sprintf(".shape%d", snum)) - snum++ + sym := shapePkg.Lookup(u.LinkString()) name := ir.NewDeclNameAt(u.Pos(), ir.OTYPE, sym) s := types.NewNamed(name) s.SetUnderlying(u) @@ -1375,6 +1374,6 @@ func Shapify(t *types.Type) *types.Type { return s } -var snum int - var shaped = map[*types.Type]*types.Type{} + +var shapePkg = types.NewPkg(".shape", ".shape") diff --git a/test/typeparam/dedup.dir/a.go b/test/typeparam/dedup.dir/a.go new file mode 100644 index 00000000000..f5cb6dc7623 --- /dev/null +++ b/test/typeparam/dedup.dir/a.go @@ -0,0 +1,10 @@ +// Copyright 2021 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 a + +//go:noinline +func F[T comparable](a, b T) bool { + return a == b +} diff --git a/test/typeparam/dedup.dir/b.go b/test/typeparam/dedup.dir/b.go new file mode 100644 index 00000000000..ce037e2d8a3 --- /dev/null +++ b/test/typeparam/dedup.dir/b.go @@ -0,0 +1,14 @@ +// Copyright 2021 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 b + +import "a" + +func B() { + var x int64 + println(a.F(&x, &x)) + var y int32 + println(a.F(&y, &y)) +} diff --git a/test/typeparam/dedup.dir/c.go b/test/typeparam/dedup.dir/c.go new file mode 100644 index 00000000000..11a5d97642b --- /dev/null +++ b/test/typeparam/dedup.dir/c.go @@ -0,0 +1,14 @@ +// Copyright 2021 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 c + +import "a" + +func C() { + var x int64 + println(a.F(&x, &x)) + var y int32 + println(a.F(&y, &y)) +} diff --git a/test/typeparam/dedup.dir/main.go b/test/typeparam/dedup.dir/main.go new file mode 100644 index 00000000000..dc3ff6f75ff --- /dev/null +++ b/test/typeparam/dedup.dir/main.go @@ -0,0 +1,15 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "b" + "c" +) + +func main() { + b.B() + c.C() +} diff --git a/test/typeparam/dedup.go b/test/typeparam/dedup.go new file mode 100644 index 00000000000..dca4cf3a84f --- /dev/null +++ b/test/typeparam/dedup.go @@ -0,0 +1,12 @@ +// rundir -G=3 + +// Copyright 2021 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. + +// Note: this doesn't really test the deduplication of +// instantiations. It just provides an easy mechanism to build a +// binary that you can then check with objdump manually to make sure +// deduplication is happening. TODO: automate this somehow? + +package ignored diff --git a/test/typeparam/dedup.out b/test/typeparam/dedup.out new file mode 100644 index 00000000000..1140ff52e2b --- /dev/null +++ b/test/typeparam/dedup.out @@ -0,0 +1,4 @@ +true +true +true +true From e5fe769be15e60a1f4626cf30fb1f560cb9f317f Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 3 Aug 2021 20:43:39 -0700 Subject: [PATCH 858/940] [dev.typeparams] cmd/compile/internal/types2: implement term lists Prerequisite for clean implementation of type sets on top of term lists. Change-Id: Ice87f2f47327aa6b1f3eaad7f9af20ad7c548155 Reviewed-on: https://go-review.googlesource.com/c/go/+/339596 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/termlist.go | 167 +++++++++++ .../compile/internal/types2/termlist_test.go | 278 ++++++++++++++++++ 2 files changed, 445 insertions(+) create mode 100644 src/cmd/compile/internal/types2/termlist.go create mode 100644 src/cmd/compile/internal/types2/termlist_test.go diff --git a/src/cmd/compile/internal/types2/termlist.go b/src/cmd/compile/internal/types2/termlist.go new file mode 100644 index 00000000000..b2c26f41be1 --- /dev/null +++ b/src/cmd/compile/internal/types2/termlist.go @@ -0,0 +1,167 @@ +// Copyright 2021 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 types2 + +import "bytes" + +// A termlist represents the type set represented by the union +// t1 ∪ y2 ∪ ... tn of the type sets of the terms t1 to tn. +// A termlist is in normal form if all terms are disjoint. +// termlist operations don't require the operands to be in +// normal form. +type termlist []*term + +// topTermList represents the set of all types. +// It is in normal form. +var topTermlist = termlist{new(term)} + +// String prints the termlist exactly (without normalization). +func (xl termlist) String() string { + if len(xl) == 0 { + return "∅" + } + var buf bytes.Buffer + for i, x := range xl { + if i > 0 { + buf.WriteString(" ∪ ") + } + buf.WriteString(x.String()) + } + return buf.String() +} + +// isEmpty reports whether the termlist xl represents the empty set of types. +func (xl termlist) isEmpty() bool { + // If there's a non-nil term, the entire list is not empty. + // If the termlist is in normal form, this requires at most + // one iteration. + for _, x := range xl { + if x != nil { + return false + } + } + return true +} + +// isTop reports whether the termlist xl represents the set of all types. +func (xl termlist) isTop() bool { + // If there's a ⊤ (top) term, the entire list is ⊤ (top). + // If the termlist is in normal form, this requires at most + // one iteration. + for _, x := range xl { + if x != nil && x.typ == nil { + return true + } + } + return false +} + +// norm returns the normal form of xl. +func (xl termlist) norm() termlist { + // Quadratic algorithm, but good enough for now. + // TODO(gri) fix asymptotic performance + used := make([]bool, len(xl)) + var rl termlist + for i, xi := range xl { + if xi == nil || used[i] { + continue + } + for j := i + 1; j < len(xl); j++ { + xj := xl[j] + if xj == nil || used[j] { + continue + } + if u1, u2 := xi.union(xj); u2 == nil { + // If we encounter a ⊤ (top) term, the entire + // list is ⊤ (top). Exit early. + // (Note that this is not just an optimization; + // if we continue, we may end up with a ⊤ term + // and other terms and the result would not be + // in normal form.) + if u1.typ == nil { + return topTermlist + } + xi = u1 + used[j] = true // xj is now unioned into xi - ignore it in future iterations + } + } + rl = append(rl, xi) + } + return rl +} + +// If the type set represented by xl is specified by a single (non-⊤) term, +// structuralType returns that type. Otherwise it returns nil. +func (xl termlist) structuralType() Type { + if nl := xl.norm(); len(nl) == 1 { + return nl[0].typ // if nl.isTop() then typ is nil, which is ok + } + return nil +} + +// union returns the union xl ∪ yl. +func (xl termlist) union(yl termlist) termlist { + return append(xl, yl...).norm() +} + +// intersect returns the intersection xl ∩ yl. +func (xl termlist) intersect(yl termlist) termlist { + if xl.isEmpty() || yl.isEmpty() { + return nil + } + + // Quadratic algorithm, but good enough for now. + // TODO(gri) fix asymptotic performance + var rl termlist + for _, x := range xl { + for _, y := range yl { + if r := x.intersect(y); r != nil { + rl = append(rl, r) + } + } + } + return rl.norm() +} + +// equal reports whether xl and yl represent the same type set. +func (xl termlist) equal(yl termlist) bool { + // TODO(gri) this should be more efficient + return xl.subsetOf(yl) && yl.subsetOf(xl) +} + +// includes reports whether t ∈ xl. +func (xl termlist) includes(t Type) bool { + for _, x := range xl { + if x.includes(t) { + return true + } + } + return false +} + +// supersetOf reports whether y ⊆ xl. +func (xl termlist) supersetOf(y *term) bool { + for _, x := range xl { + if y.subsetOf(x) { + return true + } + } + return false +} + +// subsetOf reports whether xl ⊆ yl. +func (xl termlist) subsetOf(yl termlist) bool { + if yl.isEmpty() { + return xl.isEmpty() + } + + // each term x of xl must be a subset of yl + for _, x := range xl { + if !yl.supersetOf(x) { + return false // x is not a subset yl + } + } + return true +} diff --git a/src/cmd/compile/internal/types2/termlist_test.go b/src/cmd/compile/internal/types2/termlist_test.go new file mode 100644 index 00000000000..c36baeb86f0 --- /dev/null +++ b/src/cmd/compile/internal/types2/termlist_test.go @@ -0,0 +1,278 @@ +// Copyright 2021 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 types2 + +import ( + "strings" + "testing" +) + +// maketl makes a term list from a string of the term list. +func maketl(s string) termlist { + s = strings.Replace(s, " ", "", -1) + names := strings.Split(s, "∪") + r := make(termlist, len(names)) + for i, n := range names { + r[i] = testTerm(n) + } + return r +} + +func TestTermlistTop(t *testing.T) { + if !topTermlist.isTop() { + t.Errorf("topTermlist is not top") + } +} + +func TestTermlistString(t *testing.T) { + for _, want := range []string{ + "∅", + "⊤", + "int", + "~int", + "∅ ∪ ∅", + "⊤ ∪ ⊤", + "∅ ∪ ⊤ ∪ int", + } { + if got := maketl(want).String(); got != want { + t.Errorf("(%v).String() == %v", want, got) + } + } +} + +func TestTermlistIsEmpty(t *testing.T) { + for test, want := range map[string]bool{ + "∅": true, + "∅ ∪ ∅": true, + "∅ ∪ ∅ ∪ ⊤": false, + "⊤": false, + "⊤ ∪ int": false, + } { + xl := maketl(test) + got := xl.isEmpty() + if got != want { + t.Errorf("(%v).isEmpty() == %v; want %v", test, got, want) + } + } +} + +func TestTermlistIsTop(t *testing.T) { + for test, want := range map[string]bool{ + "∅": false, + "∅ ∪ ∅": false, + "int ∪ ~string": false, + "∅ ∪ ∅ ∪ ⊤": true, + "⊤": true, + "⊤ ∪ int": true, + } { + xl := maketl(test) + got := xl.isTop() + if got != want { + t.Errorf("(%v).isTop() == %v; want %v", test, got, want) + } + } +} + +func TestTermlistNorm(t *testing.T) { + for _, test := range []struct { + xl, want string + }{ + {"∅", "∅"}, + {"∅ ∪ ∅", "∅"}, + {"∅ ∪ int", "int"}, + {"⊤ ∪ int", "⊤"}, + {"~int ∪ int", "~int"}, + {"int ∪ ~string ∪ int", "int ∪ ~string"}, + {"~int ∪ string ∪ ⊤ ∪ ~string ∪ int", "⊤"}, + } { + xl := maketl(test.xl) + got := maketl(test.xl).norm() + if got.String() != test.want { + t.Errorf("(%v).norm() = %v; want %v", xl, got, test.want) + } + } +} + +func TestTermlistStructuralType(t *testing.T) { + // helper to deal with nil types + tstring := func(typ Type) string { + if typ == nil { + return "nil" + } + return typ.String() + } + + for test, want := range map[string]string{ + "∅": "nil", + "⊤": "nil", + "int": "int", + "~int": "int", + "~int ∪ string": "nil", + "∅ ∪ int": "int", + "∅ ∪ ~int": "int", + "∅ ∪ ~int ∪ string": "nil", + } { + xl := maketl(test) + got := tstring(xl.structuralType()) + if got != want { + t.Errorf("(%v).structuralType() == %v; want %v", test, got, want) + } + } +} + +func TestTermlistUnion(t *testing.T) { + for _, test := range []struct { + xl, yl, want string + }{ + + {"∅", "∅", "∅"}, + {"∅", "⊤", "⊤"}, + {"∅", "int", "int"}, + {"⊤", "~int", "⊤"}, + {"int", "~int", "~int"}, + {"int", "string", "int ∪ string"}, + {"int ∪ string", "~string", "int ∪ ~string"}, + {"~int ∪ string", "~string ∪ int", "~int ∪ ~string"}, + {"~int ∪ string ∪ ∅", "~string ∪ int", "~int ∪ ~string"}, + {"~int ∪ string ∪ ⊤", "~string ∪ int", "⊤"}, + } { + xl := maketl(test.xl) + yl := maketl(test.yl) + got := xl.union(yl).String() + if got != test.want { + t.Errorf("(%v).union(%v) = %v; want %v", test.xl, test.yl, got, test.want) + } + } +} + +func TestTermlistIntersect(t *testing.T) { + for _, test := range []struct { + xl, yl, want string + }{ + + {"∅", "∅", "∅"}, + {"∅", "⊤", "∅"}, + {"∅", "int", "∅"}, + {"⊤", "~int", "~int"}, + {"int", "~int", "int"}, + {"int", "string", "∅"}, + {"int ∪ string", "~string", "string"}, + {"~int ∪ string", "~string ∪ int", "int ∪ string"}, + {"~int ∪ string ∪ ∅", "~string ∪ int", "int ∪ string"}, + {"~int ∪ string ∪ ⊤", "~string ∪ int", "int ∪ ~string"}, + } { + xl := maketl(test.xl) + yl := maketl(test.yl) + got := xl.intersect(yl).String() + if got != test.want { + t.Errorf("(%v).intersect(%v) = %v; want %v", test.xl, test.yl, got, test.want) + } + } +} + +func TestTermlistEqual(t *testing.T) { + for _, test := range []struct { + xl, yl string + want bool + }{ + {"∅", "∅", true}, + {"∅", "⊤", false}, + {"⊤", "⊤", true}, + {"⊤ ∪ int", "⊤", true}, + {"⊤ ∪ int", "string ∪ ⊤", true}, + {"int ∪ ~string", "string ∪ int", false}, + {"int ∪ ~string ∪ ∅", "string ∪ int ∪ ~string", true}, + } { + xl := maketl(test.xl) + yl := maketl(test.yl) + got := xl.equal(yl) + if got != test.want { + t.Errorf("(%v).equal(%v) = %v; want %v", test.xl, test.yl, got, test.want) + } + } +} + +func TestTermlistIncludes(t *testing.T) { + for _, test := range []struct { + xl, typ string + want bool + }{ + {"∅", "int", false}, + {"⊤", "int", true}, + {"~int", "int", true}, + {"int", "string", false}, + {"~int", "string", false}, + {"int ∪ string", "string", true}, + {"~int ∪ string", "int", true}, + {"~int ∪ string ∪ ∅", "string", true}, + {"~string ∪ ∅ ∪ ⊤", "int", true}, + } { + xl := maketl(test.xl) + yl := testTerm(test.typ).typ + got := xl.includes(yl) + if got != test.want { + t.Errorf("(%v).includes(%v) = %v; want %v", test.xl, yl, got, test.want) + } + } +} + +func TestTermlistSupersetOf(t *testing.T) { + for _, test := range []struct { + xl, typ string + want bool + }{ + {"∅", "∅", true}, + {"∅", "⊤", false}, + {"∅", "int", false}, + {"⊤", "∅", true}, + {"⊤", "⊤", true}, + {"⊤", "int", true}, + {"⊤", "~int", true}, + {"~int", "int", true}, + {"~int", "~int", true}, + {"int", "~int", false}, + {"int", "string", false}, + {"~int", "string", false}, + {"int ∪ string", "string", true}, + {"int ∪ string", "~string", false}, + {"~int ∪ string", "int", true}, + {"~int ∪ string ∪ ∅", "string", true}, + {"~string ∪ ∅ ∪ ⊤", "int", true}, + } { + xl := maketl(test.xl) + y := testTerm(test.typ) + got := xl.supersetOf(y) + if got != test.want { + t.Errorf("(%v).supersetOf(%v) = %v; want %v", test.xl, y, got, test.want) + } + } +} + +func TestTermlistSubsetOf(t *testing.T) { + for _, test := range []struct { + xl, yl string + want bool + }{ + {"∅", "∅", true}, + {"∅", "⊤", true}, + {"⊤", "∅", false}, + {"⊤", "⊤", true}, + {"int", "int ∪ string", true}, + {"~int", "int ∪ string", false}, + {"~int", "string ∪ string ∪ int ∪ ~int", true}, + {"int ∪ string", "string", false}, + {"int ∪ string", "string ∪ int", true}, + {"int ∪ ~string", "string ∪ int", false}, + {"int ∪ ~string", "string ∪ int ∪ ⊤", true}, + {"int ∪ ~string", "string ∪ int ∪ ∅ ∪ string", false}, + } { + xl := maketl(test.xl) + yl := maketl(test.yl) + got := xl.subsetOf(yl) + if got != test.want { + t.Errorf("(%v).subsetOf(%v) = %v; want %v", test.xl, test.yl, got, test.want) + } + } +} From 0ec2a8b42d1aa94629ffebdb8f501435cfd14980 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Wed, 4 Aug 2021 10:43:08 -0400 Subject: [PATCH 859/940] [dev.typeparams] go/types: switch the TArgs API to NumTArgs/TArg As with other go/types APIs, we should not expose the underlying Named.targs slice. Change-Id: Iba869298fbd3856022ffe8ec2c3273341598c324 Reviewed-on: https://go-review.googlesource.com/c/go/+/340009 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/named.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/go/types/named.go b/src/go/types/named.go index fc53783ab85..f26b50aa811 100644 --- a/src/go/types/named.go +++ b/src/go/types/named.go @@ -125,8 +125,12 @@ func (t *Named) TParams() *TypeParams { return t.load().tparams } // SetTParams sets the type parameters of the named type t. func (t *Named) SetTParams(tparams []*TypeName) { t.load().tparams = bindTParams(tparams) } -// TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated. -func (t *Named) TArgs() []Type { return t.targs } +// NumTArgs returns the number of type arguments used to instantiate the named +// type t, or 0 if t is not an instantiated type. +func (t *Named) NumTArgs() int { return len(t.targs) } + +// TArgs returns the i'th type argument of the named type t for 0 <= i < t.NumTArgs(). +func (t *Named) TArg(i int) Type { return t.targs[i] } // SetTArgs sets the type arguments of the named type t. func (t *Named) SetTArgs(args []Type) { t.targs = args } From 1b708c0260b6627fc23dda30c3f1e691373c032d Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Wed, 4 Aug 2021 16:21:15 -0400 Subject: [PATCH 860/940] [dev.typeparams] go/types: remove a stale comment (cleanup) Remove a stale comment from when the new types.Info API was guarded behind the typeparams build constraint. Change-Id: I319ad0a9e4e4958efdb96c967bf13a0119b5647b Reviewed-on: https://go-review.googlesource.com/c/go/+/340010 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/api.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/go/types/api.go b/src/go/types/api.go index 6c0ceb7b7c5..315f77f362a 100644 --- a/src/go/types/api.go +++ b/src/go/types/api.go @@ -258,8 +258,6 @@ type Info struct { InitOrder []*Initializer } -// The Info struct is found in api_notypeparams.go and api_typeparams.go. - // TypeOf returns the type of expression e, or nil if not found. // Precondition: the Types, Uses and Defs maps are populated. // From 3cdf8b429e7550c04ab986327bf9aed8de08d6fa Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Wed, 4 Aug 2021 14:25:01 -0700 Subject: [PATCH 861/940] [dev.typeparams] cmd/compile: fixing case where type arg is an interface In this case, we can't use an itab for doing a bound call, since we're converting from an interface to an interface. We do a static or dynamic type assert in new function assertToBound(). The dynamic type assert in assertToBound() is only needed if a bound is parameterized. In that case, we must do a dynamic type assert, and therefore need a dictionary entry for the type bound (see change in getGfInfo). I'm not sure if we can somehow limit this case, since using an interface as a type arg AND having the type bound of the type arg be parameterized is a very unlikely case. Had to add the TUNION case to parameterizedBy1() (which is only used for extra checking). Added a bunch of these test cases to 13.go, which now passes. Change-Id: Ic22eed637fa879b5bbb46d36b40aaad6f90b9d01 Reviewed-on: https://go-review.googlesource.com/c/go/+/339898 Trust: Dan Scales Reviewed-by: Keith Randall --- src/cmd/compile/internal/noder/stencil.go | 91 +++++++++++++++++++---- test/run.go | 1 - test/typeparam/mdempsky/13.go | 82 +++++++++++++++----- 3 files changed, 141 insertions(+), 33 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index c006c4af446..b2677d5a775 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -1181,7 +1181,7 @@ func (subst *subster) node(n ir.Node) ir.Node { // The only dot on a shape type value are methods. if mse.X.Op() == ir.OTYPE { // Method expression T.M - m = subst.g.buildClosure2(subst.newf, subst.info, m, x) + m = subst.g.buildClosure2(subst, m, x) // No need for transformDot - buildClosure2 has already // transformed to OCALLINTER/ODOTINTER. } else { @@ -1189,11 +1189,18 @@ func (subst *subster) node(n ir.Node) ir.Node { // 1) convert x to the bound interface // 2) call M on that interface gsrc := x.(*ir.SelectorExpr).X.Type() - dst := gsrc.Bound() + bound := gsrc.Bound() + dst := bound if dst.HasTParam() { dst = subst.ts.Typ(dst) } - mse.X = convertUsingDictionary(subst.info, subst.info.dictParam, m.Pos(), mse.X, x, dst, gsrc) + if src.IsInterface() { + // If type arg is an interface (unusual case), + // we do a type assert to the type bound. + mse.X = assertToBound(subst.info, subst.info.dictParam, m.Pos(), mse.X, bound, dst) + } else { + mse.X = convertUsingDictionary(subst.info, subst.info.dictParam, m.Pos(), mse.X, x, dst, gsrc) + } transformDot(mse, false) } } else { @@ -1554,10 +1561,10 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) tparam := tmpse.X.Type() assert(tparam.IsTypeParam()) recvType := targs[tparam.Index()] - if len(recvType.RParams()) == 0 { + if recvType.IsInterface() || len(recvType.RParams()) == 0 { // No sub-dictionary entry is // actually needed, since the - // typeparam is not an + // type arg is not an // instantiated type that // will have generic methods. break @@ -1686,8 +1693,14 @@ func (g *irgen) finalizeSyms() { default: base.Fatalf("itab entry with unknown op %s", n.Op()) } - itabLsym := reflectdata.ITabLsym(srctype, dsttype) - d.off = objw.SymPtr(lsym, d.off, itabLsym, 0) + if srctype.IsInterface() { + // No itab is wanted if src type is an interface. We + // will use a type assert instead. + d.off = objw.Uintptr(lsym, d.off, 0) + } else { + itabLsym := reflectdata.ITabLsym(srctype, dsttype) + d.off = objw.SymPtr(lsym, d.off, itabLsym, 0) + } } objw.Global(lsym, int32(d.off), obj.DUPOK|obj.RODATA) @@ -1760,6 +1773,17 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo { info.tparams[i] = f.Type } } + + for _, t := range info.tparams { + b := t.Bound() + if b.HasTParam() { + // If a type bound is parameterized (unusual case), then we + // may need its derived type to do a type assert when doing a + // bound call for a type arg that is an interface. + addType(&info, nil, b) + } + } + for _, n := range gf.Dcl { addType(&info, n, n.Type()) } @@ -1950,6 +1974,15 @@ func parameterizedBy1(t *types.Type, params []*types.Type, visited map[*types.Ty types.TUINTPTR, types.TBOOL, types.TSTRING, types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128: return true + case types.TUNION: + for i := 0; i < t.NumTerms(); i++ { + tt, _ := t.Term(i) + if !parameterizedBy1(tt, params, visited) { + return false + } + } + return true + default: base.Fatalf("bad type kind %+v", t) return true @@ -2000,15 +2033,32 @@ func startClosure(pos src.XPos, outer *ir.Func, typ *types.Type) (*ir.Func, []*t } +// assertToBound returns a new node that converts a node rcvr with interface type to +// the 'dst' interface type. bound is the unsubstituted form of dst. +func assertToBound(info *instInfo, dictVar *ir.Name, pos src.XPos, rcvr ir.Node, bound, dst *types.Type) ir.Node { + if bound.HasTParam() { + ix := findDictType(info, bound) + assert(ix >= 0) + rt := getDictionaryType(info, dictVar, pos, ix) + rcvr = ir.NewDynamicTypeAssertExpr(pos, ir.ODYNAMICDOTTYPE, rcvr, rt) + typed(dst, rcvr) + } else { + rcvr = ir.NewTypeAssertExpr(pos, rcvr, nil) + typed(bound, rcvr) + } + return rcvr +} + // buildClosure2 makes a closure to implement a method expression m (generic form x) // which has a shape type as receiver. If the receiver is exactly a shape (i.e. from -// a typeparam), then the body of the closure converts the first argument (the -// receiver) to the interface bound type, and makes an interface call with the -// remaining arguments. +// a typeparam), then the body of the closure converts m.X (the receiver) to the +// interface bound type, and makes an interface call with the remaining arguments. // -// The returned closure is fully substituted and has already has any needed +// The returned closure is fully substituted and has already had any needed // transformations done. -func (g *irgen) buildClosure2(outer *ir.Func, info *instInfo, m, x ir.Node) ir.Node { +func (g *irgen) buildClosure2(subst *subster, m, x ir.Node) ir.Node { + outer := subst.newf + info := subst.info pos := m.Pos() typ := m.Type() // type of the closure @@ -2031,11 +2081,24 @@ func (g *irgen) buildClosure2(outer *ir.Func, info *instInfo, m, x ir.Node) ir.N rcvr := args[0] args = args[1:] assert(m.(*ir.SelectorExpr).X.Type().IsShape()) - rcvr = convertUsingDictionary(info, dictVar, pos, rcvr, x, x.(*ir.SelectorExpr).X.Type().Bound(), x.(*ir.SelectorExpr).X.Type()) + gsrc := x.(*ir.SelectorExpr).X.Type() + bound := gsrc.Bound() + dst := bound + if dst.HasTParam() { + dst = subst.ts.Typ(bound) + } + if m.(*ir.SelectorExpr).X.Type().IsInterface() { + // If type arg is an interface (unusual case), we do a type assert to + // the type bound. + rcvr = assertToBound(info, dictVar, pos, rcvr, bound, dst) + } else { + rcvr = convertUsingDictionary(info, dictVar, pos, rcvr, x, dst, gsrc) + } dot := ir.NewSelectorExpr(pos, ir.ODOTINTER, rcvr, x.(*ir.SelectorExpr).Sel) dot.Selection = typecheck.Lookdot1(dot, dot.Sel, dot.X.Type(), dot.X.Type().AllMethods(), 1) - typed(x.(*ir.SelectorExpr).Selection.Type, dot) + // Do a type substitution on the generic bound, in case it is parameterized. + typed(subst.ts.Typ(x.(*ir.SelectorExpr).Selection.Type), dot) innerCall = ir.NewCallExpr(pos, ir.OCALLINTER, dot, args) t := m.Type() if t.NumResults() == 0 { diff --git a/test/run.go b/test/run.go index 4971043ab64..6296234d565 100644 --- a/test/run.go +++ b/test/run.go @@ -2184,7 +2184,6 @@ var g3Failures = setOf( "typeparam/nested.go", // -G=3 doesn't support function-local types with generics "typeparam/mdempsky/4.go", // -G=3 can't export functions with labeled breaks in loops - "typeparam/mdempsky/13.go", // problem with interface as as a type arg. "typeparam/mdempsky/15.go", // ICE in (*irgen).buildClosure ) diff --git a/test/typeparam/mdempsky/13.go b/test/typeparam/mdempsky/13.go index dc1d29bce1c..b492774d3d8 100644 --- a/test/typeparam/mdempsky/13.go +++ b/test/typeparam/mdempsky/13.go @@ -6,33 +6,79 @@ package main -type Mer interface{ M() } +// Interface which will be used as a regular interface type and as a type bound. +type Mer interface{ + M() +} -func F[T Mer](expectPanic bool) { - defer func() { - err := recover() - if (err != nil) != expectPanic { - print("FAIL: (", err, " != nil) != ", expectPanic, "\n") - } - }() +// Interface that is a superset of Mer. +type Mer2 interface { + M() + String() string +} - var t T +func F[T Mer](t T) { T.M(t) + t.M() } type MyMer int func (MyMer) M() {} +func (MyMer) String() string { + return "aa" +} + +// Parameterized interface +type Abs[T any] interface { + Abs() T +} + +func G[T Abs[U], U any](t T) { + T.Abs(t) + t.Abs() +} + +type MyInt int +func (m MyInt) Abs() MyInt { + if m < 0 { + return -m + } + return m +} + +type Abs2 interface { + Abs() MyInt +} + func main() { - F[Mer](true) - F[struct{ Mer }](true) - F[*struct{ Mer }](true) + mm := MyMer(3) + ms := struct{ Mer }{Mer: mm } - F[MyMer](false) - F[*MyMer](true) - F[struct{ MyMer }](false) - F[struct{ *MyMer }](true) - F[*struct{ MyMer }](true) - F[*struct{ *MyMer }](true) + // Testing F with an interface type arg: Mer and Mer2 + F[Mer](mm) + F[Mer2](mm) + F[struct{ Mer }](ms) + F[*struct{ Mer }](&ms) + + ms2 := struct { MyMer }{MyMer: mm} + ms3 := struct { *MyMer }{MyMer: &mm} + + // Testing F with a concrete type arg + F[MyMer](mm) + F[*MyMer](&mm) + F[struct{ MyMer }](ms2) + F[struct{ *MyMer }](ms3) + F[*struct{ MyMer }](&ms2) + F[*struct{ *MyMer }](&ms3) + + // Testing G with a concrete type args + mi := MyInt(-3) + G[MyInt,MyInt](mi) + + // Interface Abs[MyInt] holding an mi. + intMi := Abs[MyInt](mi) + // First type arg here is Abs[MyInt], an interface type. + G[Abs[MyInt],MyInt](intMi) } From 5dcb5e2cea883b1bd69b543841b137a287aa7037 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Wed, 4 Aug 2021 17:58:54 -0700 Subject: [PATCH 862/940] [dev.typeparams] cmd/compile: dictionary/shape cleanup - Removed gcshapeType - we're going with more granular shapes for now, and gradually coarsening later if needed. - Put in early return in getDictionarySym(), so the entire rest of the function can be un-indented by one level. - Removed some duplicated infoprint calls, and fixed one infoprint message in getGfInfo. Change-Id: I13acce8fdabdb21e903275b53ff78a1e6a378de2 Reviewed-on: https://go-review.googlesource.com/c/go/+/339901 Trust: Dan Scales Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/noder/stencil.go | 443 ++++++---------------- 1 file changed, 113 insertions(+), 330 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index b2677d5a775..7cc37f1154e 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -8,7 +8,6 @@ package noder import ( - "bytes" "cmd/compile/internal/base" "cmd/compile/internal/ir" "cmd/compile/internal/objw" @@ -19,7 +18,6 @@ import ( "cmd/internal/src" "fmt" "go/constant" - "strconv" ) // Enable extra consistency checks. @@ -536,220 +534,6 @@ func (g *irgen) getDictOrSubdict(declInfo *instInfo, n ir.Node, nameNode *ir.Nam return dict, usingSubdict } -func addGcType(fl []*types.Field, t *types.Type) []*types.Field { - return append(fl, types.NewField(base.Pos, typecheck.Lookup("F"+strconv.Itoa(len(fl))), t)) -} - -const INTTYPE = types.TINT64 // XX fix for 32-bit arch -const UINTTYPE = types.TUINT64 // XX fix for 32-bit arch -const INTSTRING = "i8" // XX fix for 32-bit arch -const UINTSTRING = "u8" // XX fix for 32-bit arch - -// accumGcshape adds fields to fl resulting from the GCshape transformation of -// type t. The string associated with the GCshape transformation of t is added to -// buf. fieldSym is the sym of the field associated with type t, if it is in a -// struct. fieldSym could be used to have special naming for blank fields, etc. -func accumGcshape(fl []*types.Field, buf *bytes.Buffer, t *types.Type, fieldSym *types.Sym) []*types.Field { - // t.Kind() is already the kind of the underlying type, so no need to - // reference t.Underlying() to reference the underlying type. - assert(t.Kind() == t.Underlying().Kind()) - - switch t.Kind() { - case types.TINT8: - fl = addGcType(fl, types.Types[types.TINT8]) - buf.WriteString("i1") - - case types.TUINT8: - fl = addGcType(fl, types.Types[types.TUINT8]) - buf.WriteString("u1") - - case types.TINT16: - fl = addGcType(fl, types.Types[types.TINT16]) - buf.WriteString("i2") - - case types.TUINT16: - fl = addGcType(fl, types.Types[types.TUINT16]) - buf.WriteString("u2") - - case types.TINT32: - fl = addGcType(fl, types.Types[types.TINT32]) - buf.WriteString("i4") - - case types.TUINT32: - fl = addGcType(fl, types.Types[types.TUINT32]) - buf.WriteString("u4") - - case types.TINT64: - fl = addGcType(fl, types.Types[types.TINT64]) - buf.WriteString("i8") - - case types.TUINT64: - fl = addGcType(fl, types.Types[types.TUINT64]) - buf.WriteString("u8") - - case types.TINT: - fl = addGcType(fl, types.Types[INTTYPE]) - buf.WriteString(INTSTRING) - - case types.TUINT, types.TUINTPTR: - fl = addGcType(fl, types.Types[UINTTYPE]) - buf.WriteString(UINTSTRING) - - case types.TCOMPLEX64: - fl = addGcType(fl, types.Types[types.TFLOAT32]) - fl = addGcType(fl, types.Types[types.TFLOAT32]) - buf.WriteString("f4") - buf.WriteString("f4") - - case types.TCOMPLEX128: - fl = addGcType(fl, types.Types[types.TFLOAT64]) - fl = addGcType(fl, types.Types[types.TFLOAT64]) - buf.WriteString("f8") - buf.WriteString("f8") - - case types.TFLOAT32: - fl = addGcType(fl, types.Types[types.TFLOAT32]) - buf.WriteString("f4") - - case types.TFLOAT64: - fl = addGcType(fl, types.Types[types.TFLOAT64]) - buf.WriteString("f8") - - case types.TBOOL: - fl = addGcType(fl, types.Types[types.TINT8]) - buf.WriteString("i1") - - case types.TPTR: - fl = addGcType(fl, types.Types[types.TUNSAFEPTR]) - buf.WriteString("p") - - case types.TFUNC: - fl = addGcType(fl, types.Types[types.TUNSAFEPTR]) - buf.WriteString("p") - - case types.TSLICE: - fl = addGcType(fl, types.Types[types.TUNSAFEPTR]) - fl = addGcType(fl, types.Types[INTTYPE]) - fl = addGcType(fl, types.Types[INTTYPE]) - buf.WriteString("p") - buf.WriteString(INTSTRING) - buf.WriteString(INTSTRING) - - case types.TARRAY: - n := t.NumElem() - if n == 1 { - fl = accumGcshape(fl, buf, t.Elem(), nil) - } else if n > 0 { - // Represent an array with more than one element as its - // unique type, since it must be treated differently for - // regabi. - fl = addGcType(fl, t) - buf.WriteByte('[') - buf.WriteString(strconv.Itoa(int(n))) - buf.WriteString("](") - var ignore []*types.Field - // But to determine its gcshape name, we must call - // accumGcShape() on t.Elem(). - accumGcshape(ignore, buf, t.Elem(), nil) - buf.WriteByte(')') - } - - case types.TSTRUCT: - nfields := t.NumFields() - for i, f := range t.Fields().Slice() { - fl = accumGcshape(fl, buf, f.Type, f.Sym) - - // Check if we need to add an alignment field. - var pad int64 - if i < nfields-1 { - pad = t.Field(i+1).Offset - f.Offset - f.Type.Width - } else { - pad = t.Width - f.Offset - f.Type.Width - } - if pad > 0 { - // There is padding between fields or at end of - // struct. Add an alignment field. - fl = addGcType(fl, types.NewArray(types.Types[types.TUINT8], pad)) - buf.WriteString("a") - buf.WriteString(strconv.Itoa(int(pad))) - } - } - - case types.TCHAN: - fl = addGcType(fl, types.Types[types.TUNSAFEPTR]) - buf.WriteString("p") - - case types.TMAP: - fl = addGcType(fl, types.Types[types.TUNSAFEPTR]) - buf.WriteString("p") - - case types.TINTER: - fl = addGcType(fl, types.Types[types.TUNSAFEPTR]) - fl = addGcType(fl, types.Types[types.TUNSAFEPTR]) - buf.WriteString("pp") - - case types.TFORW, types.TANY: - assert(false) - - case types.TSTRING: - fl = addGcType(fl, types.Types[types.TUNSAFEPTR]) - fl = addGcType(fl, types.Types[INTTYPE]) - buf.WriteString("p") - buf.WriteString(INTSTRING) - - case types.TUNSAFEPTR: - fl = addGcType(fl, types.Types[types.TUNSAFEPTR]) - buf.WriteString("p") - - default: // Everything TTYPEPARAM and below in list of Kinds - assert(false) - } - - return fl -} - -// gcshapeType returns the GCshape type and name corresponding to type t. -func gcshapeType(t *types.Type) (*types.Type, string) { - var fl []*types.Field - buf := bytes.NewBufferString("") - - // Call CallSize so type sizes and field offsets are available. - types.CalcSize(t) - - instType := t.Sym() != nil && t.IsFullyInstantiated() - if instType { - // We distinguish the gcshape of all top-level instantiated type from - // normal concrete types, even if they have the exact same underlying - // "shape", because in a function instantiation, any method call on - // this type arg will be a generic method call (requiring a - // dictionary), rather than a direct method call on the underlying - // type (no dictionary). So, we add the instshape prefix to the - // normal gcshape name, and will make it a defined type with that - // name below. - buf.WriteString("instshape-") - } - fl = accumGcshape(fl, buf, t, nil) - - // TODO: Should gcshapes be in a global package, so we don't have to - // duplicate in each package? Or at least in the specified source package - // of a function/method instantiation? - gcshape := types.NewStruct(types.LocalPkg, fl) - gcname := buf.String() - if instType { - // Lookup or create type with name 'gcname' (with instshape prefix). - newsym := t.Sym().Pkg.Lookup(gcname) - if newsym.Def != nil { - gcshape = newsym.Def.Type() - } else { - newt := typecheck.NewIncompleteNamedType(t.Pos(), newsym) - newt.SetUnderlying(gcshape.Underlying()) - gcshape = newt - } - } - assert(gcshape.Size() == t.Size()) - return gcshape, buf.String() -} - // checkFetchBody checks if a generic body can be fetched, but hasn't been loaded // yet. If so, it imports the body. func checkFetchBody(nameNode *ir.Name) { @@ -1521,131 +1305,135 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) sym := typecheck.MakeDictName(gf.Sym(), targs, isMeth) // Initialize the dictionary, if we haven't yet already. - if lsym := sym.Linksym(); len(lsym.P) == 0 { - info := g.getGfInfo(gf) + lsym := sym.Linksym() + if len(lsym.P) > 0 { + // We already started creating this dictionary and its lsym. + return sym + } - infoPrint("=== Creating dictionary %v\n", sym.Name) - off := 0 - // Emit an entry for each targ (concrete type or gcshape). - for _, t := range targs { - infoPrint(" * %v\n", t) - s := reflectdata.TypeLinksym(t) - off = objw.SymPtr(lsym, off, s, 0) - markTypeUsed(t, lsym) - } - subst := typecheck.Tsubster{ - Tparams: info.tparams, - Targs: targs, - } - // Emit an entry for each derived type (after substituting targs) - for _, t := range info.derivedTypes { - ts := subst.Typ(t) - infoPrint(" - %v\n", ts) - s := reflectdata.TypeLinksym(ts) - off = objw.SymPtr(lsym, off, s, 0) - markTypeUsed(ts, lsym) - } - // Emit an entry for each subdictionary (after substituting targs) - for _, n := range info.subDictCalls { - var sym *types.Sym - switch n.Op() { - case ir.OCALL: - call := n.(*ir.CallExpr) - if call.X.Op() == ir.OXDOT { - var nameNode *ir.Name - se := call.X.(*ir.SelectorExpr) - if types.IsInterfaceMethod(se.Selection.Type) { - // This is a method call enabled by a type bound. - tmpse := ir.NewSelectorExpr(base.Pos, ir.OXDOT, se.X, se.Sel) - tmpse = typecheck.AddImplicitDots(tmpse) - tparam := tmpse.X.Type() - assert(tparam.IsTypeParam()) - recvType := targs[tparam.Index()] - if recvType.IsInterface() || len(recvType.RParams()) == 0 { - // No sub-dictionary entry is - // actually needed, since the - // type arg is not an - // instantiated type that - // will have generic methods. - break - } - // This is a method call for an - // instantiated type, so we need a - // sub-dictionary. - targs := recvType.RParams() - genRecvType := recvType.OrigSym.Def.Type() - nameNode = typecheck.Lookdot1(call.X, se.Sel, genRecvType, genRecvType.Methods(), 1).Nname.(*ir.Name) - sym = g.getDictionarySym(nameNode, targs, true) - } else { - // This is the case of a normal - // method call on a generic type. - nameNode = call.X.(*ir.SelectorExpr).Selection.Nname.(*ir.Name) - subtargs := deref(call.X.(*ir.SelectorExpr).X.Type()).RParams() - s2targs := make([]*types.Type, len(subtargs)) - for i, t := range subtargs { - s2targs[i] = subst.Typ(t) - } - sym = g.getDictionarySym(nameNode, s2targs, true) + info := g.getGfInfo(gf) + + infoPrint("=== Creating dictionary %v\n", sym.Name) + off := 0 + // Emit an entry for each targ (concrete type or gcshape). + for _, t := range targs { + infoPrint(" * %v\n", t) + s := reflectdata.TypeLinksym(t) + off = objw.SymPtr(lsym, off, s, 0) + markTypeUsed(t, lsym) + } + subst := typecheck.Tsubster{ + Tparams: info.tparams, + Targs: targs, + } + // Emit an entry for each derived type (after substituting targs) + for _, t := range info.derivedTypes { + ts := subst.Typ(t) + infoPrint(" - %v\n", ts) + s := reflectdata.TypeLinksym(ts) + off = objw.SymPtr(lsym, off, s, 0) + markTypeUsed(ts, lsym) + } + // Emit an entry for each subdictionary (after substituting targs) + for _, n := range info.subDictCalls { + var sym *types.Sym + switch n.Op() { + case ir.OCALL: + call := n.(*ir.CallExpr) + if call.X.Op() == ir.OXDOT { + var nameNode *ir.Name + se := call.X.(*ir.SelectorExpr) + if types.IsInterfaceMethod(se.Selection.Type) { + // This is a method call enabled by a type bound. + tmpse := ir.NewSelectorExpr(base.Pos, ir.OXDOT, se.X, se.Sel) + tmpse = typecheck.AddImplicitDots(tmpse) + tparam := tmpse.X.Type() + assert(tparam.IsTypeParam()) + recvType := targs[tparam.Index()] + if recvType.IsInterface() || len(recvType.RParams()) == 0 { + // No sub-dictionary entry is + // actually needed, since the + // type arg is not an + // instantiated type that + // will have generic methods. + break } + // This is a method call for an + // instantiated type, so we need a + // sub-dictionary. + targs := recvType.RParams() + genRecvType := recvType.OrigSym.Def.Type() + nameNode = typecheck.Lookdot1(call.X, se.Sel, genRecvType, genRecvType.Methods(), 1).Nname.(*ir.Name) + sym = g.getDictionarySym(nameNode, targs, true) } else { - inst := call.X.(*ir.InstExpr) - var nameNode *ir.Name - var meth *ir.SelectorExpr - var isMeth bool - if meth, isMeth = inst.X.(*ir.SelectorExpr); isMeth { - nameNode = meth.Selection.Nname.(*ir.Name) - } else { - nameNode = inst.X.(*ir.Name) - } - subtargs := typecheck.TypesOf(inst.Targs) + // This is the case of a normal + // method call on a generic type. + nameNode = call.X.(*ir.SelectorExpr).Selection.Nname.(*ir.Name) + subtargs := deref(call.X.(*ir.SelectorExpr).X.Type()).RParams() + s2targs := make([]*types.Type, len(subtargs)) for i, t := range subtargs { - subtargs[i] = subst.Typ(t) + s2targs[i] = subst.Typ(t) } - sym = g.getDictionarySym(nameNode, subtargs, isMeth) + sym = g.getDictionarySym(nameNode, s2targs, true) + } + } else { + inst := call.X.(*ir.InstExpr) + var nameNode *ir.Name + var meth *ir.SelectorExpr + var isMeth bool + if meth, isMeth = inst.X.(*ir.SelectorExpr); isMeth { + nameNode = meth.Selection.Nname.(*ir.Name) + } else { + nameNode = inst.X.(*ir.Name) } - - case ir.OFUNCINST: - inst := n.(*ir.InstExpr) - nameNode := inst.X.(*ir.Name) subtargs := typecheck.TypesOf(inst.Targs) for i, t := range subtargs { subtargs[i] = subst.Typ(t) } - sym = g.getDictionarySym(nameNode, subtargs, false) - - case ir.OXDOT: - selExpr := n.(*ir.SelectorExpr) - subtargs := deref(selExpr.X.Type()).RParams() - s2targs := make([]*types.Type, len(subtargs)) - for i, t := range subtargs { - s2targs[i] = subst.Typ(t) - } - nameNode := selExpr.Selection.Nname.(*ir.Name) - sym = g.getDictionarySym(nameNode, s2targs, true) - - default: - assert(false) + sym = g.getDictionarySym(nameNode, subtargs, isMeth) } - if sym == nil { - // Unused sub-dictionary entry, just emit 0. - off = objw.Uintptr(lsym, off, 0) - infoPrint(" - Unused subdict entry\n") - } else { - off = objw.SymPtr(lsym, off, sym.Linksym(), 0) - infoPrint(" - Subdict %v\n", sym.Name) + case ir.OFUNCINST: + inst := n.(*ir.InstExpr) + nameNode := inst.X.(*ir.Name) + subtargs := typecheck.TypesOf(inst.Targs) + for i, t := range subtargs { + subtargs[i] = subst.Typ(t) } + sym = g.getDictionarySym(nameNode, subtargs, false) + + case ir.OXDOT: + selExpr := n.(*ir.SelectorExpr) + subtargs := deref(selExpr.X.Type()).RParams() + s2targs := make([]*types.Type, len(subtargs)) + for i, t := range subtargs { + s2targs[i] = subst.Typ(t) + } + nameNode := selExpr.Selection.Nname.(*ir.Name) + sym = g.getDictionarySym(nameNode, s2targs, true) + + default: + assert(false) } - delay := &delayInfo{ - gf: gf, - targs: targs, - sym: sym, - off: off, + if sym == nil { + // Unused sub-dictionary entry, just emit 0. + off = objw.Uintptr(lsym, off, 0) + infoPrint(" - Unused subdict entry\n") + } else { + off = objw.SymPtr(lsym, off, sym.Linksym(), 0) + infoPrint(" - Subdict %v\n", sym.Name) } - g.dictSymsToFinalize = append(g.dictSymsToFinalize, delay) - g.instTypeList = append(g.instTypeList, subst.InstTypeList...) } + + delay := &delayInfo{ + gf: gf, + targs: targs, + sym: sym, + off: off, + } + g.dictSymsToFinalize = append(g.dictSymsToFinalize, delay) + g.instTypeList = append(g.instTypeList, subst.InstTypeList...) return sym } @@ -1805,11 +1593,6 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo { } else if n.Op() == ir.OXDOT && !n.(*ir.SelectorExpr).Implicit() && n.(*ir.SelectorExpr).Selection != nil && len(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) > 0 { - if n.(*ir.SelectorExpr).X.Op() == ir.OTYPE { - infoPrint(" Closure&subdictionary required at generic meth expr %v\n", n) - } else { - infoPrint(" Closure&subdictionary required at generic meth value %v\n", n) - } if hasTParamTypes(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) { if n.(*ir.SelectorExpr).X.Op() == ir.OTYPE { infoPrint(" Closure&subdictionary required at generic meth expr %v\n", n) @@ -1849,7 +1632,7 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo { info.itabConvs = append(info.itabConvs, n) } if n.Op() == ir.OXDOT && n.(*ir.SelectorExpr).X.Type().IsTypeParam() { - infoPrint(" Itab for interface conv: %v\n", n) + infoPrint(" Itab for bound call: %v\n", n) info.itabConvs = append(info.itabConvs, n) } if (n.Op() == ir.ODOTTYPE || n.Op() == ir.ODOTTYPE2) && !n.(*ir.TypeAssertExpr).Type().IsInterface() && !n.(*ir.TypeAssertExpr).X.Type().IsEmptyInterface() { From 6dadee759c812961300c8d1a44959d14299fd9f8 Mon Sep 17 00:00:00 2001 From: Leonard Wang Date: Thu, 5 Aug 2021 23:04:16 +0800 Subject: [PATCH 863/940] [dev.typeparams] cmd/compile: unified importReader receiver name to r Change-Id: Iaf8ec7665282f4f8c0cb09a652e78aa97959274b Reviewed-on: https://go-review.googlesource.com/c/go/+/340150 Reviewed-by: Robert Griesemer Trust: Robert Griesemer Trust: Robert Findley Run-TryBot: Robert Griesemer TryBot-Result: Go Bot --- src/cmd/compile/internal/typecheck/iimport.go | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index b389c7fcb07..8d960e58082 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -412,14 +412,14 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name { } } -func (p *importReader) value(typ *types.Type) constant.Value { +func (r *importReader) value(typ *types.Type) constant.Value { var kind constant.Kind var valType *types.Type if typ.IsTypeParam() { // If a constant had a typeparam type, then we wrote out its // actual constant kind as well. - kind = constant.Kind(p.int64()) + kind = constant.Kind(r.int64()) switch kind { case constant.Int: valType = types.Types[types.TINT64] @@ -435,24 +435,24 @@ func (p *importReader) value(typ *types.Type) constant.Value { switch kind { case constant.Bool: - return constant.MakeBool(p.bool()) + return constant.MakeBool(r.bool()) case constant.String: - return constant.MakeString(p.string()) + return constant.MakeString(r.string()) case constant.Int: var i big.Int - p.mpint(&i, valType) + r.mpint(&i, valType) return constant.Make(&i) case constant.Float: - return p.float(valType) + return r.float(valType) case constant.Complex: - return makeComplex(p.float(valType), p.float(valType)) + return makeComplex(r.float(valType), r.float(valType)) } base.Fatalf("unexpected value type: %v", typ) panic("unreachable") } -func (p *importReader) mpint(x *big.Int, typ *types.Type) { +func (r *importReader) mpint(x *big.Int, typ *types.Type) { signed, maxBytes := intSize(typ) maxSmall := 256 - maxBytes @@ -463,7 +463,7 @@ func (p *importReader) mpint(x *big.Int, typ *types.Type) { maxSmall = 256 } - n, _ := p.ReadByte() + n, _ := r.ReadByte() if uint(n) < maxSmall { v := int64(n) if signed { @@ -484,30 +484,30 @@ func (p *importReader) mpint(x *big.Int, typ *types.Type) { base.Fatalf("weird decoding: %v, %v => %v", n, signed, v) } b := make([]byte, v) - p.Read(b) + r.Read(b) x.SetBytes(b) if signed && n&1 != 0 { x.Neg(x) } } -func (p *importReader) float(typ *types.Type) constant.Value { +func (r *importReader) float(typ *types.Type) constant.Value { var mant big.Int - p.mpint(&mant, typ) + r.mpint(&mant, typ) var f big.Float f.SetInt(&mant) if f.Sign() != 0 { - f.SetMantExp(&f, int(p.int64())) + f.SetMantExp(&f, int(r.int64())) } return constant.Make(&f) } -func (p *importReader) mprat(orig constant.Value) constant.Value { - if !p.bool() { +func (r *importReader) mprat(orig constant.Value) constant.Value { + if !r.bool() { return orig } var rat big.Rat - rat.SetString(p.string()) + rat.SetString(r.string()) return constant.Make(&rat) } From bb5608dd5d056519bd90666b815e0b2bf65e5ee8 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 29 Jul 2021 11:10:04 -0700 Subject: [PATCH 864/940] [dev.typeparams] cmd/compile/internal/types2: implement type sets with term lists This CL resolves several known issues and TODOs. - Represent type sets with term lists and using term list abstractions. - Represent Unions internally as a list of (syntactical) terms. Use term operations to print terms and detect overlapping union entries. - Compute type sets corresponding to unions lazily, on demand. - Adjust code throughout. - Adjusted error check in test/typeparam/mincheck.dir/main.go to make test pass. Change-Id: Ib36fb7e1d343c2b6aec51d304f0f7d1ad415f999 Reviewed-on: https://go-review.googlesource.com/c/go/+/338310 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/builtins.go | 16 +- src/cmd/compile/internal/types2/infer.go | 37 +--- .../compile/internal/types2/instantiate.go | 24 +- src/cmd/compile/internal/types2/interface.go | 33 +-- src/cmd/compile/internal/types2/operand.go | 2 +- src/cmd/compile/internal/types2/predicates.go | 12 +- .../compile/internal/types2/sizeof_test.go | 4 +- src/cmd/compile/internal/types2/stmt.go | 2 +- src/cmd/compile/internal/types2/subst.go | 12 +- src/cmd/compile/internal/types2/termlist.go | 2 +- .../types2/testdata/check/typeinst2.go2 | 8 +- .../types2/testdata/check/typeparams.go2 | 65 +++--- .../types2/testdata/examples/constraints.go2 | 41 +++- .../types2/testdata/fixedbugs/issue41124.go2 | 10 +- src/cmd/compile/internal/types2/type.go | 21 +- src/cmd/compile/internal/types2/typeparam.go | 27 ++- src/cmd/compile/internal/types2/typeset.go | 171 ++++++++++----- src/cmd/compile/internal/types2/typestring.go | 25 ++- src/cmd/compile/internal/types2/typexpr.go | 16 +- src/cmd/compile/internal/types2/unify.go | 5 +- src/cmd/compile/internal/types2/union.go | 206 ++++-------------- src/cmd/compile/internal/types2/universe.go | 4 +- test/typeparam/mincheck.dir/main.go | 4 +- 23 files changed, 332 insertions(+), 415 deletions(-) diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index 7b2c92bfa86..c022e79c972 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -144,7 +144,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( mode := invalid var typ Type var val constant.Value - switch typ = implicitArrayDeref(optype(x.typ)); t := typ.(type) { + switch typ = implicitArrayDeref(under(x.typ)); t := typ.(type) { case *Basic: if isString(t) && id == _Len { if x.mode == constant_ { @@ -178,9 +178,9 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( mode = value } - case *Union: + case *TypeParam: if t.underIs(func(t Type) bool { - switch t := t.(type) { + switch t := implicitArrayDeref(t).(type) { case *Basic: if isString(t) && id == _Len { return true @@ -817,10 +817,10 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { // type and collect possible result types at the same time. var rtypes []Type var tildes []bool - if !tp.iface().is(func(typ Type, tilde bool) bool { - if r := f(typ); r != nil { + if !tp.iface().typeSet().is(func(t *term) bool { + if r := f(t.typ); r != nil { rtypes = append(rtypes, r) - tildes = append(tildes, tilde) + tildes = append(tildes, t.tilde) return true } return false @@ -837,10 +837,8 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { // type param is placed in the current package so export/import // works as expected. tpar := NewTypeName(nopos, check.pkg, "", nil) - ptyp := check.NewTypeParam(tpar, &emptyInterface) // assigns type to tpar as a side-effect + ptyp := check.NewTypeParam(tpar, NewInterfaceType(nil, []Type{newUnion(rtypes, tildes)})) // assigns type to tpar as a side-effect ptyp.index = tp.index - tsum := newUnion(rtypes, tildes) - ptyp.bound = &Interface{complete: true, tset: &TypeSet{types: tsum}} return ptyp } diff --git a/src/cmd/compile/internal/types2/infer.go b/src/cmd/compile/internal/types2/infer.go index 00548b402e8..a3772aa7131 100644 --- a/src/cmd/compile/internal/types2/infer.go +++ b/src/cmd/compile/internal/types2/infer.go @@ -280,7 +280,7 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { }() switch t := typ.(type) { - case nil, *Basic: // TODO(gri) should nil be handled here? + case nil, *top, *Basic: // TODO(gri) should nil be handled here? break case *Array: @@ -307,9 +307,6 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { } } - case *Union: - return w.isParameterizedTermList(t.terms) - case *Signature: // t.tparams may not be nil if we are looking at a signature // of a generic function type (or an interface method) that is @@ -327,7 +324,9 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { return true } } - return w.isParameterized(tset.types) + return tset.is(func(t *term) bool { + return w.isParameterized(t.typ) + }) case *Map: return w.isParameterized(t.key) || w.isParameterized(t.elem) @@ -358,15 +357,6 @@ func (w *tpWalker) isParameterizedTypeList(list []Type) bool { return false } -func (w *tpWalker) isParameterizedTermList(list []*term) bool { - for _, t := range list { - if w.isParameterized(t.typ) { - return true - } - } - return false -} - // inferB returns the list of actual type arguments inferred from the type parameters' // bounds and an initial set of type arguments. If type inference is impossible because // unification fails, an error is reported if report is set to true, the resulting types @@ -394,7 +384,7 @@ func (check *Checker) inferB(tparams []*TypeName, targs []Type, report bool) (ty // Unify type parameters with their structural constraints, if any. for _, tpar := range tparams { typ := tpar.typ.(*TypeParam) - sbound := check.structuralType(typ.bound) + sbound := typ.structuralType() if sbound != nil { if !u.unify(typ, sbound) { if report { @@ -467,20 +457,3 @@ func (check *Checker) inferB(tparams []*TypeName, targs []Type, report bool) (ty return } - -// structuralType returns the structural type of a constraint, if any. -func (check *Checker) structuralType(constraint Type) Type { - if iface, _ := under(constraint).(*Interface); iface != nil { - types := iface.typeSet().types - if u, _ := types.(*Union); u != nil { - if u.NumTerms() == 1 { - // TODO(gri) do we need to respect tilde? - t, _ := u.Term(0) - return t - } - return nil - } - return types - } - return nil -} diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go index 357f041c466..b7ea193a06e 100644 --- a/src/cmd/compile/internal/types2/instantiate.go +++ b/src/cmd/compile/internal/types2/instantiate.go @@ -212,7 +212,7 @@ func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap } // targ's underlying type must also be one of the interface types listed, if any - if iface.typeSet().types == nil { + if !iface.typeSet().hasTerms() { return true // nothing to do } @@ -220,24 +220,22 @@ func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap // list of iface types (i.e., the targ type list must be a non-empty subset of the iface types). if targ := asTypeParam(targ); targ != nil { targBound := targ.iface() - if targBound.typeSet().types == nil { + if !targBound.typeSet().hasTerms() { check.softErrorf(pos, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ) return false } - return iface.is(func(typ Type, tilde bool) bool { - // TODO(gri) incorporate tilde information! - if !iface.isSatisfiedBy(typ) { - // TODO(gri) match this error message with the one below (or vice versa) - check.softErrorf(pos, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, typ, iface.typeSet().types) - return false - } - return true - }) + if !targBound.typeSet().subsetOf(iface.typeSet()) { + // TODO(gri) need better error message + check.softErrorf(pos, "%s does not satisfy %s", targ, tpar.bound) + return false + } + return true } // Otherwise, targ's type or underlying type must also be one of the interface types listed, if any. - if !iface.isSatisfiedBy(targ) { - check.softErrorf(pos, "%s does not satisfy %s (%s not found in %s)", targ, tpar.bound, targ, iface.typeSet().types) + if !iface.typeSet().includes(targ) { + // TODO(gri) better error message + check.softErrorf(pos, "%s does not satisfy %s", targ, tpar.bound) return false } diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go index fc1f5ffe00d..aa7d0b05a0b 100644 --- a/src/cmd/compile/internal/types2/interface.go +++ b/src/cmd/compile/internal/types2/interface.go @@ -21,20 +21,7 @@ type Interface struct { } // typeSet returns the type set for interface t. -func (t *Interface) typeSet() *TypeSet { return computeTypeSet(nil, nopos, t) } - -// is reports whether interface t represents types that all satisfy f. -func (t *Interface) is(f func(Type, bool) bool) bool { - switch t := t.typeSet().types.(type) { - case nil, *top: - // TODO(gri) should settle on top or nil to represent this case - return false // we must have at least one type! (was bug) - case *Union: - return t.is(func(t *term) bool { return f(t.typ, t.tilde) }) - default: - return f(t, false) - } -} +func (t *Interface) typeSet() *TypeSet { return computeInterfaceTypeSet(nil, nopos, t) } // emptyInterface represents the empty interface var emptyInterface = Interface{complete: true, tset: &topTypeSet} @@ -113,22 +100,6 @@ func (t *Interface) IsComparable() bool { return t.typeSet().IsComparable() } // IsConstraint reports whether interface t is not just a method set. func (t *Interface) IsConstraint() bool { return !t.typeSet().IsMethodSet() } -// isSatisfiedBy reports whether interface t's type list is satisfied by the type typ. -// If the type list is empty (absent), typ trivially satisfies the interface. -// TODO(gri) This is not a great name. Eventually, we should have a more comprehensive -// "implements" predicate. -func (t *Interface) isSatisfiedBy(typ Type) bool { - switch t := t.typeSet().types.(type) { - case nil: - return true // no type restrictions - case *Union: - r, _ := t.intersect(typ, false) - return r != nil - default: - return Identical(t, typ) - } -} - // Complete computes the interface's type set. It must be called by users of // NewInterfaceType and NewInterface after the interface's embedded types are // fully defined and before using the interface type in any way other than to @@ -262,7 +233,7 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType // Compute type set with a non-nil *Checker as soon as possible // to report any errors. Subsequent uses of type sets will use // this computed type set and won't need to pass in a *Checker. - check.later(func() { computeTypeSet(check, iface.Pos(), ityp) }) + check.later(func() { computeInterfaceTypeSet(check, iface.Pos(), ityp) }) } func flattenUnion(list []syntax.Expr, x syntax.Expr) []syntax.Expr { diff --git a/src/cmd/compile/internal/types2/operand.go b/src/cmd/compile/internal/types2/operand.go index 34d35b25947..8336451e9ce 100644 --- a/src/cmd/compile/internal/types2/operand.go +++ b/src/cmd/compile/internal/types2/operand.go @@ -273,7 +273,7 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er // x is an untyped value representable by a value of type T. if isUntyped(Vu) { - if t, ok := Tu.(*Union); ok { + if t, ok := Tu.(*TypeParam); ok { return t.is(func(t *term) bool { // TODO(gri) this could probably be more efficient if t.tilde { diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go index bb7fedda3b2..afef488b964 100644 --- a/src/cmd/compile/internal/types2/predicates.go +++ b/src/cmd/compile/internal/types2/predicates.go @@ -229,16 +229,6 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { identical(x.results, y.results, cmpTags, p) } - case *Union: - // Two union types are identical if they contain the same terms. - // The set (list) of types in a union type consists of unique - // types - each type appears exactly once. Thus, two union types - // must contain the same number of types to have chance of - // being equal. - if y, ok := y.(*Union); ok { - return identicalTerms(x.terms, y.terms) - } - case *Interface: // Two interface types are identical if they describe the same type sets. // With the existing implementation restriction, this simplifies to: @@ -250,7 +240,7 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { if y, ok := y.(*Interface); ok { xset := x.typeSet() yset := y.typeSet() - if !Identical(xset.types, yset.types) { + if !xset.terms.equal(yset.terms) { return false } a := xset.methods diff --git a/src/cmd/compile/internal/types2/sizeof_test.go b/src/cmd/compile/internal/types2/sizeof_test.go index 8255e6ded4f..d2f53258f03 100644 --- a/src/cmd/compile/internal/types2/sizeof_test.go +++ b/src/cmd/compile/internal/types2/sizeof_test.go @@ -27,7 +27,7 @@ func TestSizeof(t *testing.T) { {Pointer{}, 8, 16}, {Tuple{}, 12, 24}, {Signature{}, 28, 56}, - {Union{}, 12, 24}, + {Union{}, 16, 32}, {Interface{}, 40, 80}, {Map{}, 16, 32}, {Chan{}, 12, 24}, @@ -49,7 +49,7 @@ func TestSizeof(t *testing.T) { // Misc {Scope{}, 60, 104}, {Package{}, 40, 80}, - {TypeSet{}, 24, 48}, + {TypeSet{}, 28, 56}, } for _, test := range tests { diff --git a/src/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go index 9b8295c4f4d..1efce511f1c 100644 --- a/src/cmd/compile/internal/types2/stmt.go +++ b/src/cmd/compile/internal/types2/stmt.go @@ -921,7 +921,7 @@ func rangeKeyVal(typ Type, wantKey, wantVal bool) (Type, Type, string) { msg = "receive from send-only channel" } return typ.elem, Typ[Invalid], msg - case *Union: + case *TypeParam: first := true var key, val Type var msg string diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index e497e174636..6c5f7564912 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -145,12 +145,12 @@ func (subst *subster) typ(typ Type) Type { } case *Union: - terms, copied := subst.termList(t.terms) + terms, copied := subst.termlist(t.terms) if copied { - // TODO(gri) Remove duplicates that may have crept in after substitution - // (unlikely but possible). This matters for the Identical - // predicate on unions. - return &Union{terms} + // term list substitution may introduce duplicate terms (unlikely but possible). + // This is ok; lazy type set computation will determine the actual type set + // in normal form. + return &Union{terms, nil} } case *Interface: @@ -387,7 +387,7 @@ func (subst *subster) typeList(in []Type) (out []Type, copied bool) { return } -func (subst *subster) termList(in []*term) (out []*term, copied bool) { +func (subst *subster) termlist(in []*term) (out []*term, copied bool) { out = in for i, t := range in { if u := subst.typ(t.typ); u != t.typ { diff --git a/src/cmd/compile/internal/types2/termlist.go b/src/cmd/compile/internal/types2/termlist.go index b2c26f41be1..07056edd974 100644 --- a/src/cmd/compile/internal/types2/termlist.go +++ b/src/cmd/compile/internal/types2/termlist.go @@ -13,7 +13,7 @@ import "bytes" // normal form. type termlist []*term -// topTermList represents the set of all types. +// topTermlist represents the set of all types. // It is in normal form. var topTermlist = termlist{new(term)} diff --git a/src/cmd/compile/internal/types2/testdata/check/typeinst2.go2 b/src/cmd/compile/internal/types2/testdata/check/typeinst2.go2 index 14d8f0ea8ca..e90e4dde448 100644 --- a/src/cmd/compile/internal/types2/testdata/check/typeinst2.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/typeinst2.go2 @@ -164,13 +164,13 @@ type _ interface { // for them to be all in a single list, and we report the error // as well.) type _ interface { - ~int|~int /* ERROR duplicate term int */ - ~int|int /* ERROR duplicate term int */ - int|int /* ERROR duplicate term int */ + ~int|~int /* ERROR overlapping terms ~int */ + ~int|int /* ERROR overlapping terms int */ + int|int /* ERROR overlapping terms int */ } type _ interface { - ~struct{f int} | ~struct{g int} | ~struct /* ERROR duplicate term */ {f int} + ~struct{f int} | ~struct{g int} | ~struct /* ERROR overlapping terms */ {f int} } // Interface type lists can contain any type, incl. *Named types. diff --git a/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 b/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 index 54efd1485b1..7392b88555d 100644 --- a/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 @@ -149,37 +149,40 @@ func _[T interface{}](x T) { for range x /* ERROR cannot range */ {} } -func _[T interface{ ~string | ~[]string }](x T) { - for range x {} - for i := range x { _ = i } - for i, _ := range x { _ = i } - for i, e := range x /* ERROR must have the same element type */ { _ = i } - for _, e := range x /* ERROR must have the same element type */ {} - var e rune - _ = e - for _, (e) = range x /* ERROR must have the same element type */ {} -} - - -func _[T interface{ ~string | ~[]rune | ~map[int]rune }](x T) { - for _, e := range x { _ = e } - for i, e := range x { _ = i; _ = e } -} - -func _[T interface{ ~string | ~[]rune | ~map[string]rune }](x T) { - for _, e := range x { _ = e } - for i, e := range x /* ERROR must have the same key type */ { _ = e } -} - -func _[T interface{ ~string | ~chan int }](x T) { - for range x {} - for i := range x { _ = i } - for i, _ := range x { _ = i } // TODO(gri) should get an error here: channels only return one value -} - -func _[T interface{ ~string | ~chan<-int }](x T) { - for i := range x /* ERROR send-only channel */ { _ = i } -} +// Disabled for now until we have clarified semantics of range. +// TODO(gri) fix this +// +// func _[T interface{ ~string | ~[]string }](x T) { +// for range x {} +// for i := range x { _ = i } +// for i, _ := range x { _ = i } +// for i, e := range x /* ERROR must have the same element type */ { _ = i } +// for _, e := range x /* ERROR must have the same element type */ {} +// var e rune +// _ = e +// for _, (e) = range x /* ERROR must have the same element type */ {} +// } +// +// +// func _[T interface{ ~string | ~[]rune | ~map[int]rune }](x T) { +// for _, e := range x { _ = e } +// for i, e := range x { _ = i; _ = e } +// } +// +// func _[T interface{ ~string | ~[]rune | ~map[string]rune }](x T) { +// for _, e := range x { _ = e } +// for i, e := range x /* ERROR must have the same key type */ { _ = e } +// } +// +// func _[T interface{ ~string | ~chan int }](x T) { +// for range x {} +// for i := range x { _ = i } +// for i, _ := range x { _ = i } // TODO(gri) should get an error here: channels only return one value +// } +// +// func _[T interface{ ~string | ~chan<-int }](x T) { +// for i := range x /* ERROR send-only channel */ { _ = i } +// } // type inference checks diff --git a/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 b/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 index 28aa19bb12c..f40d18c63e8 100644 --- a/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 +++ b/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 @@ -18,18 +18,25 @@ type ( } ) +type MyInt int + type ( // Arbitrary types may be embedded like interfaces. _ interface{int} _ interface{~int} // Types may be combined into a union. - _ interface{int|~string} + union interface{int|~string} - // Union terms must be unique independent of whether they are ~ or not. - _ interface{int|int /* ERROR duplicate term int */ } - _ interface{int|~ /* ERROR duplicate term int */ int } - _ interface{~int|~ /* ERROR duplicate term int */ int } + // Union terms must describe disjoint (non-overlapping) type sets. + _ interface{int|int /* ERROR overlapping terms int */ } + _ interface{int|~ /* ERROR overlapping terms ~int */ int } + _ interface{~int|~ /* ERROR overlapping terms ~int */ int } + _ interface{~int|MyInt /* ERROR overlapping terms p.MyInt and ~int */ } + _ interface{int|interface{}} + _ interface{int|~string|union} + _ interface{int|~string|interface{int}} + _ interface{union|union /* ERROR overlapping terms p.union and p.union */ } // For now we do not permit interfaces with methods in unions. _ interface{~ /* ERROR invalid use of ~ */ interface{}} @@ -45,6 +52,15 @@ type ( _ interface{~ /* ERROR invalid use of ~ */ bar } ) +// Stand-alone type parameters are not permitted as elements or terms in unions. +type ( + _[T interface{ *T } ] struct{} // ok + _[T interface{ int | *T } ] struct{} // ok + _[T interface{ T /* ERROR cannot embed a type parameter */ } ] struct{} + _[T interface{ ~T /* ERROR cannot embed a type parameter */ } ] struct{} + _[T interface{ int|T /* ERROR cannot embed a type parameter */ }] struct{} +) + // Multiple embedded union elements are intersected. The order in which they // appear in the interface doesn't matter since intersection is a symmetric // operation. @@ -58,3 +74,18 @@ func _[T interface{ ~int; myInt1|myInt2 }]() T { return T(0) } // Here the intersections are empty - there's no type that's in the type set of T. func _[T interface{ myInt1|myInt2; int }]() T { return T(0 /* ERROR cannot convert */ ) } func _[T interface{ int; myInt1|myInt2 }]() T { return T(0 /* ERROR cannot convert */ ) } + +// Union elements may be interfaces as long as they don't define +// any methods or embed comparable. + +type ( + Integer interface{ ~int|~int8|~int16|~int32|~int64 } + Unsigned interface{ ~uint|~uint8|~uint16|~uint32|~uint64 } + Floats interface{ ~float32|~float64 } + Complex interface{ ~complex64|~complex128 } + Number interface{ Integer|Unsigned|Floats|Complex } + Ordered interface{ Integer|Unsigned|Floats|~string } + + _ interface{ Number | error /* ERROR cannot use error in union */ } + _ interface{ Ordered | comparable /* ERROR cannot use comparable in union */ } +) diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue41124.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue41124.go2 index ab535049dd7..60650432a47 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue41124.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue41124.go2 @@ -47,7 +47,7 @@ type _ struct{ } type _ struct{ - I3 // ERROR interface contains type constraints + I3 // ERROR interface is .* comparable } // General composite types. @@ -59,19 +59,19 @@ type ( _ []I1 // ERROR interface is .* comparable _ []I2 // ERROR interface contains type constraints - _ *I3 // ERROR interface contains type constraints + _ *I3 // ERROR interface is .* comparable _ map[I1 /* ERROR interface is .* comparable */ ]I2 // ERROR interface contains type constraints - _ chan I3 // ERROR interface contains type constraints + _ chan I3 // ERROR interface is .* comparable _ func(I1 /* ERROR interface is .* comparable */ ) _ func() I2 // ERROR interface contains type constraints ) // Other cases. -var _ = [...]I3 /* ERROR interface contains type constraints */ {} +var _ = [...]I3 /* ERROR interface is .* comparable */ {} func _(x interface{}) { - _ = x.(I3 /* ERROR interface contains type constraints */ ) + _ = x.(I3 /* ERROR interface is .* comparable */ ) } type T1[_ any] struct{} diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index a9439261899..7ae2db3412d 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -44,28 +44,21 @@ func under(t Type) Type { // optype returns a type's operational type. Except for // type parameters, the operational type is the same // as the underlying type (as returned by under). For -// Type parameters, the operational type is determined -// by the corresponding type bound's type list. The -// result may be the bottom or top type, but it is never -// the incoming type parameter. +// Type parameters, the operational type is the structural +// type, if any; otherwise it's the top type. +// The result is never the incoming type parameter. func optype(typ Type) Type { if t := asTypeParam(typ); t != nil { + // TODO(gri) review accuracy of this comment // If the optype is typ, return the top type as we have // no information. It also prevents infinite recursion // via the asTypeParam converter function. This can happen // for a type parameter list of the form: // (type T interface { type T }). // See also issue #39680. - if a := t.iface().typeSet().types; a != nil { - // If we have a union with a single entry, ignore - // any tilde because under(~t) == under(t). - if u, _ := a.(*Union); u != nil && u.NumTerms() == 1 { - a, _ = u.Term(0) - } - if a != typ { - // a != typ and a is a type parameter => under(a) != typ, so this is ok - return under(a) - } + if u := t.structuralType(); u != nil { + assert(u != typ) // "naked" type parameters cannot be embedded + return u } return theTop } diff --git a/src/cmd/compile/internal/types2/typeparam.go b/src/cmd/compile/internal/types2/typeparam.go index 2614f467b15..27e6e355883 100644 --- a/src/cmd/compile/internal/types2/typeparam.go +++ b/src/cmd/compile/internal/types2/typeparam.go @@ -67,7 +67,7 @@ func (t *TypeParam) Constraint() Type { if n, _ := t.bound.(*Named); n != nil { pos = n.obj.pos } - computeTypeSet(t.check, pos, iface) + computeInterfaceTypeSet(t.check, pos, iface) } return t.bound } @@ -80,14 +80,6 @@ func (t *TypeParam) SetConstraint(bound Type) { t.bound = bound } -// iface returns the constraint interface of t. -func (t *TypeParam) iface() *Interface { - if iface, _ := under(t.Constraint()).(*Interface); iface != nil { - return iface - } - return &emptyInterface -} - // Bound returns the constraint interface of t. // Deprecated. Only here for the compiler. // TODO(gri) remove in favor of uses of Constraint. @@ -136,6 +128,23 @@ func bindTParams(list []*TypeName) *TypeParams { // ---------------------------------------------------------------------------- // Implementation +// iface returns the constraint interface of t. +func (t *TypeParam) iface() *Interface { + if iface, _ := under(t.Constraint()).(*Interface); iface != nil { + return iface + } + return &emptyInterface +} + +// structuralType returns the structural type of the type parameter's constraint; or nil. +func (t *TypeParam) structuralType() Type { + return t.iface().typeSet().structuralType() +} + +func (t *TypeParam) is(f func(*term) bool) bool { + return t.iface().typeSet().is(f) +} + func (t *TypeParam) underIs(f func(Type) bool) bool { return t.iface().typeSet().underIs(f) } diff --git a/src/cmd/compile/internal/types2/typeset.go b/src/cmd/compile/internal/types2/typeset.go index 5a334b2f533..6e19115ff59 100644 --- a/src/cmd/compile/internal/types2/typeset.go +++ b/src/cmd/compile/internal/types2/typeset.go @@ -18,31 +18,32 @@ import ( type TypeSet struct { comparable bool // if set, the interface is or embeds comparable // TODO(gri) consider using a set for the methods for faster lookup - methods []*Func // all methods of the interface; sorted by unique ID - types Type // typically a *Union; nil means no type restrictions + methods []*Func // all methods of the interface; sorted by unique ID + terms termlist // type terms of the type set } -// IsTop reports whether type set s is the top type set (corresponding to the empty interface). -func (s *TypeSet) IsTop() bool { return !s.comparable && len(s.methods) == 0 && s.types == nil } +// IsEmpty reports whether type set s is the empty set. +func (s *TypeSet) IsEmpty() bool { return s.terms.isEmpty() } + +// IsTop reports whether type set s is the set of all types (corresponding to the empty interface). +func (s *TypeSet) IsTop() bool { return !s.comparable && len(s.methods) == 0 && s.terms.isTop() } + +// TODO(gri) IsMethodSet is not a great name for this predicate. Find a better one. // IsMethodSet reports whether the type set s is described by a single set of methods. -func (s *TypeSet) IsMethodSet() bool { return !s.comparable && s.types == nil } +func (s *TypeSet) IsMethodSet() bool { return !s.comparable && s.terms.isTop() } // IsComparable reports whether each type in the set is comparable. func (s *TypeSet) IsComparable() bool { - if s.types == nil { + if s.terms.isTop() { return s.comparable } - tcomparable := s.underIs(func(u Type) bool { - return Comparable(u) + return s.is(func(t *term) bool { + return Comparable(t.typ) }) - if !s.comparable { - return tcomparable - } - return s.comparable && tcomparable } -// TODO(gri) IsTypeSet is not a great name. Find a better one. +// TODO(gri) IsTypeSet is not a great name for this predicate. Find a better one. // IsTypeSet reports whether the type set s is represented by a finite set of underlying types. func (s *TypeSet) IsTypeSet() bool { @@ -63,15 +64,21 @@ func (s *TypeSet) LookupMethod(pkg *Package, name string) (int, *Func) { } func (s *TypeSet) String() string { - if s.IsTop() { + switch { + case s.IsEmpty(): + return "∅" + case s.IsTop(): return "⊤" } + hasMethods := len(s.methods) > 0 + hasTerms := s.hasTerms() + var buf bytes.Buffer buf.WriteByte('{') if s.comparable { buf.WriteString(" comparable") - if len(s.methods) > 0 || s.types != nil { + if hasMethods || hasTerms { buf.WriteByte(';') } } @@ -82,41 +89,77 @@ func (s *TypeSet) String() string { buf.WriteByte(' ') buf.WriteString(m.String()) } - if len(s.methods) > 0 && s.types != nil { + if hasMethods && hasTerms { buf.WriteByte(';') } - if s.types != nil { - buf.WriteByte(' ') - writeType(&buf, s.types, nil, nil) + if hasTerms { + buf.WriteString(s.terms.String()) } + buf.WriteString(" }") // there was at least one method or term - buf.WriteString(" }") // there was a least one method or type return buf.String() } // ---------------------------------------------------------------------------- // Implementation -// underIs reports whether f returned true for the underlying types of the -// enumerable types in the type set s. If the type set comprises all types -// f is called once with the top type; if the type set is empty, the result -// is false. -func (s *TypeSet) underIs(f func(Type) bool) bool { - switch t := s.types.(type) { - case nil: - return f(theTop) - default: - return f(t) - case *Union: - return t.underIs(f) +func (s *TypeSet) hasTerms() bool { return !s.terms.isTop() } +func (s *TypeSet) structuralType() Type { return s.terms.structuralType() } +func (s *TypeSet) includes(t Type) bool { return s.terms.includes(t) } +func (s1 *TypeSet) subsetOf(s2 *TypeSet) bool { return s1.terms.subsetOf(s2.terms) } + +// TODO(gri) TypeSet.is and TypeSet.underIs should probably also go into termlist.go + +var topTerm = term{false, theTop} + +func (s *TypeSet) is(f func(*term) bool) bool { + if len(s.terms) == 0 { + return false } + for _, t := range s.terms { + // Terms represent the top term with a nil type. + // The rest of the type checker uses the top type + // instead. Convert. + // TODO(gri) investigate if we can do without this + if t.typ == nil { + t = &topTerm + } + if !f(t) { + return false + } + } + return true +} + +func (s *TypeSet) underIs(f func(Type) bool) bool { + if len(s.terms) == 0 { + return false + } + for _, t := range s.terms { + // see corresponding comment in TypeSet.is + u := t.typ + if u == nil { + u = theTop + } + // t == under(t) for ~t terms + if !t.tilde { + u = under(u) + } + if debug { + assert(Identical(u, under(u))) + } + if !f(u) { + return false + } + } + return true } // topTypeSet may be used as type set for the empty interface. -var topTypeSet TypeSet +var topTypeSet = TypeSet{terms: topTermlist} -// computeTypeSet may be called with check == nil. -func computeTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet { +// computeInterfaceTypeSet may be called with check == nil. +func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet { if ityp.tset != nil { return ityp.tset } @@ -152,7 +195,7 @@ func computeTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet { // have valid interfaces. Mark the interface as complete to avoid // infinite recursion if the validType check occurs later for some // reason. - ityp.tset = new(TypeSet) // TODO(gri) is this sufficient? + ityp.tset = &TypeSet{terms: topTermlist} // TODO(gri) is this sufficient? // Methods of embedded interfaces are collected unchanged; i.e., the identity // of a method I.m's Func Object of an interface I is the same as that of @@ -213,7 +256,7 @@ func computeTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet { } // collect embedded elements - var allTypes Type + var allTerms = topTermlist for i, typ := range ityp.embeddeds { // The embedding position is nil for imported interfaces // and also for interface copies after substitution (but @@ -222,25 +265,22 @@ func computeTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet { if ityp.embedPos != nil { pos = (*ityp.embedPos)[i] } - var types Type + var terms termlist switch t := under(typ).(type) { case *Interface: - tset := computeTypeSet(check, pos, t) + tset := computeInterfaceTypeSet(check, pos, t) if tset.comparable { ityp.tset.comparable = true } for _, m := range tset.methods { addMethod(pos, m, false) // use embedding position pos rather than m.pos } - types = tset.types + terms = tset.terms case *Union: - // TODO(gri) combine with default case once we have - // converted all tests to new notation and we - // can report an error when we don't have an - // interface before go1.18. - types = typ + tset := computeUnionTypeSet(check, pos, t) + terms = tset.terms case *TypeParam: - // Embedding stand-alone type parameters is not permitted for now. + // Embedding stand-alone type parameters is not permitted. // This case is handled during union parsing. unreachable() default: @@ -251,9 +291,11 @@ func computeTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet { check.errorf(pos, "%s is not an interface", typ) continue } - types = typ + terms = termlist{{false, typ}} } - allTypes = intersect(allTypes, types) + // The type set of an interface is the intersection + // of the type sets of all its elements. + allTerms = allTerms.intersect(terms) } ityp.embedPos = nil // not needed anymore (errors have been reported) @@ -270,7 +312,7 @@ func computeTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet { sortMethods(methods) ityp.tset.methods = methods } - ityp.tset.types = allTypes + ityp.tset.terms = allTerms return ityp.tset } @@ -294,3 +336,34 @@ type byUniqueMethodName []*Func func (a byUniqueMethodName) Len() int { return len(a) } func (a byUniqueMethodName) Less(i, j int) bool { return a[i].less(&a[j].object) } func (a byUniqueMethodName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } + +// computeUnionTypeSet may be called with check == nil. +func computeUnionTypeSet(check *Checker, pos syntax.Pos, utyp *Union) *TypeSet { + if utyp.tset != nil { + return utyp.tset + } + + // avoid infinite recursion (see also computeInterfaceTypeSet) + utyp.tset = new(TypeSet) + + var allTerms termlist + for _, t := range utyp.terms { + var terms termlist + switch u := under(t.typ).(type) { + case *Interface: + terms = computeInterfaceTypeSet(check, pos, u).terms + case *TypeParam: + // A stand-alone type parameters is not permitted as union term. + // This case is handled during union parsing. + unreachable() + default: + terms = termlist{t} + } + // The type set of a union expression is the union + // of the type sets of each term. + allTerms = allTerms.union(terms) + } + utyp.tset.terms = allTerms + + return utyp.tset +} diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go index b7e32c9860b..558da50528d 100644 --- a/src/cmd/compile/internal/types2/typestring.go +++ b/src/cmd/compile/internal/types2/typestring.go @@ -158,9 +158,10 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { writeSignature(buf, t, qf, visited) case *Union: - if t.IsEmpty() { - buf.WriteString("⊥") - break + // Unions only appear as (syntactic) embedded elements + // in interfaces and syntactically cannot be empty. + if t.NumTerms() == 0 { + panic("internal error: empty union") } for i, t := range t.terms { if i > 0 { @@ -198,13 +199,21 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { writeSignature(buf, m.typ.(*Signature), qf, visited) empty = false } - if !empty && tset.types != nil { + if !empty && tset.hasTerms() { buf.WriteString("; ") } - if tset.types != nil { - buf.WriteString("type ") - writeType(buf, tset.types, qf, visited) - } + first := true + tset.is(func(t *term) bool { + if !first { + buf.WriteByte('|') + } + first = false + if t.tilde { + buf.WriteByte('~') + } + writeType(buf, t.typ, qf, visited) + return true + }) } else { // print explicit interface methods and embedded types for i, m := range t.methods { diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index c55d5c093ab..fa4a1638b6c 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -147,18 +147,18 @@ func (check *Checker) varType(e syntax.Expr) Type { // ordinaryType reports an error if typ is an interface type containing // type lists or is (or embeds) the predeclared type comparable. func (check *Checker) ordinaryType(pos syntax.Pos, typ Type) { - // We don't want to call under() (via Interface) or complete interfaces while we + // We don't want to call under() (via asInterface) or complete interfaces while we // are in the middle of type-checking parameter declarations that might belong to // interface methods. Delay this check to the end of type-checking. check.later(func() { if t := asInterface(typ); t != nil { - tset := computeTypeSet(check, pos, t) // TODO(gri) is this the correct position? - if tset.types != nil { - check.softErrorf(pos, "interface contains type constraints (%s)", tset.types) - return - } - if tset.IsComparable() { - check.softErrorf(pos, "interface is (or embeds) comparable") + tset := computeInterfaceTypeSet(check, pos, t) // TODO(gri) is this the correct position? + if !tset.IsMethodSet() { + if tset.comparable { + check.softErrorf(pos, "interface is (or embeds) comparable") + } else { + check.softErrorf(pos, "interface contains type constraints") + } } } }) diff --git a/src/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go index aa9a23d243b..75b9a121979 100644 --- a/src/cmd/compile/internal/types2/unify.go +++ b/src/cmd/compile/internal/types2/unify.go @@ -361,9 +361,6 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool { u.nify(x.results, y.results, p) } - case *Union: - panic("unimplemented: unification with type sets described by types") - case *Interface: // Two interface types are identical if they have the same set of methods with // the same names and identical function types. Lower-case method names from @@ -371,7 +368,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool { if y, ok := y.(*Interface); ok { xset := x.typeSet() yset := y.typeSet() - if !Identical(xset.types, yset.types) { + if !xset.terms.equal(yset.terms) { return false } a := xset.methods diff --git a/src/cmd/compile/internal/types2/union.go b/src/cmd/compile/internal/types2/union.go index 1215ef90577..fcd83ce688a 100644 --- a/src/cmd/compile/internal/types2/union.go +++ b/src/cmd/compile/internal/types2/union.go @@ -9,17 +9,17 @@ import "cmd/compile/internal/syntax" // ---------------------------------------------------------------------------- // API -// A Union represents a union of terms. +// A Union represents a union of terms embedded in an interface. type Union struct { - terms []*term + terms []*term // list of syntactical terms (not a canonicalized termlist) + tset *TypeSet // type set described by this union, computed lazily } // NewUnion returns a new Union type with the given terms (types[i], tilde[i]). -// The lengths of both arguments must match. An empty union represents the set -// of no types. +// The lengths of both arguments must match. It is an error to create an empty +// union; they are syntactically not possible. func NewUnion(types []Type, tilde []bool) *Union { return newUnion(types, tilde) } -func (u *Union) IsEmpty() bool { return len(u.terms) == 0 } func (u *Union) NumTerms() int { return len(u.terms) } func (u *Union) Term(i int) (Type, bool) { t := u.terms[i]; return t.typ, t.tilde } @@ -29,12 +29,10 @@ func (u *Union) String() string { return TypeString(u, nil) } // ---------------------------------------------------------------------------- // Implementation -var emptyUnion = new(Union) - func newUnion(types []Type, tilde []bool) *Union { assert(len(types) == len(tilde)) if len(types) == 0 { - return emptyUnion + panic("empty union") } t := new(Union) t.terms = make([]*term, len(types)) @@ -44,52 +42,23 @@ func newUnion(types []Type, tilde []bool) *Union { return t } -// is reports whether f returns true for all terms of u. -func (u *Union) is(f func(*term) bool) bool { - if u.IsEmpty() { - return false - } - for _, t := range u.terms { - if !f(t) { - return false - } - } - return true -} - -// underIs reports whether f returned true for the underlying types of all terms of u. -func (u *Union) underIs(f func(Type) bool) bool { - if u.IsEmpty() { - return false - } - for _, t := range u.terms { - if !f(under(t.typ)) { - return false - } - } - return true -} - func parseUnion(check *Checker, tlist []syntax.Expr) Type { - var types []Type - var tilde []bool + var terms []*term for _, x := range tlist { - t, d := parseTilde(check, x) - if len(tlist) == 1 && !d { - return t // single type + tilde, typ := parseTilde(check, x) + if len(tlist) == 1 && !tilde { + return typ // single type } - types = append(types, t) - tilde = append(tilde, d) + terms = append(terms, &term{tilde, typ}) } - // Ensure that each type is only present once in the type list. - // It's ok to do this check later because it's not a requirement - // for correctness of the code. + // Check validity of terms. + // Do this check later because it requires types to be set up. // Note: This is a quadratic algorithm, but unions tend to be short. check.later(func() { - for i, t := range types { - t := expand(t) - if t == Typ[Invalid] { + for i, t := range terms { + typ := expand(t.typ) + if typ == Typ[Invalid] { continue } @@ -105,16 +74,16 @@ func parseUnion(check *Checker, tlist []syntax.Expr) Type { } } - u := under(t) + u := under(typ) f, _ := u.(*Interface) - if tilde[i] { + if t.tilde { if f != nil { - check.errorf(x, "invalid use of ~ (%s is an interface)", t) + check.errorf(x, "invalid use of ~ (%s is an interface)", typ) continue // don't report another error for t } - if !Identical(u, t) { - check.errorf(x, "invalid use of ~ (underlying type of %s is %s)", t, u) + if !Identical(u, typ) { + check.errorf(x, "invalid use of ~ (underlying type of %s is %s)", typ, u) continue // don't report another error for t } } @@ -127,19 +96,18 @@ func parseUnion(check *Checker, tlist []syntax.Expr) Type { continue // don't report another error for t } - // Complain about duplicate entries a|a, but also a|~a, and ~a|~a. - // TODO(gri) We should also exclude myint|~int since myint is included in ~int. - if includes(types[:i], t) { - // TODO(gri) this currently doesn't print the ~ if present - check.softErrorf(pos, "duplicate term %s in union element", t) + // Report overlapping (non-disjoint) terms such as + // a|a, a|~a, ~a|~a, and ~a|A (where under(A) == a). + if j := overlappingTerm(terms[:i], t); j >= 0 { + check.softErrorf(pos, "overlapping terms %s and %s", t, terms[j]) } } }) - return newUnion(types, tilde) + return &Union{terms, nil} } -func parseTilde(check *Checker, x syntax.Expr) (typ Type, tilde bool) { +func parseTilde(check *Checker, x syntax.Expr) (tilde bool, typ Type) { if op, _ := x.(*syntax.Operation); op != nil && op.Op == syntax.Tilde { x = op.X tilde = true @@ -153,116 +121,20 @@ func parseTilde(check *Checker, x syntax.Expr) (typ Type, tilde bool) { return } -// intersect computes the intersection of the types x and y, -// A nil type stands for the set of all types; an empty union -// stands for the set of no types. -func intersect(x, y Type) (r Type) { - // If one of the types is nil (no restrictions) - // the result is the other type. - switch { - case x == nil: - return y - case y == nil: - return x - } - - // Compute the terms which are in both x and y. - // TODO(gri) This is not correct as it may not always compute - // the "largest" intersection. For instance, for - // x = myInt|~int, y = ~int - // we get the result myInt but we should get ~int. - xu, _ := x.(*Union) - yu, _ := y.(*Union) - switch { - case xu != nil && yu != nil: - return &Union{intersectTerms(xu.terms, yu.terms)} - - case xu != nil: - if r, _ := xu.intersect(y, false); r != nil { - return y - } - - case yu != nil: - if r, _ := yu.intersect(x, false); r != nil { - return x - } - - default: // xu == nil && yu == nil - if Identical(x, y) { - return x - } - } - - return emptyUnion -} - -// includes reports whether typ is in list. -func includes(list []Type, typ Type) bool { - for _, e := range list { - if Identical(typ, e) { - return true - } - } - return false -} - -// intersect computes the intersection of the union u and term (y, yt) -// and returns the intersection term, if any. Otherwise the result is -// (nil, false). -// TODO(gri) this needs to cleaned up/removed once we switch to lazy -// union type set computation. -func (u *Union) intersect(y Type, yt bool) (Type, bool) { - under_y := under(y) - for _, x := range u.terms { - xt := x.tilde - // determine which types xx, yy to compare - xx := x.typ - if yt { - xx = under(xx) - } - yy := y - if xt { - yy = under_y - } - if Identical(xx, yy) { - // T ∩ T = T - // T ∩ ~t = T - // ~t ∩ T = T - // ~t ∩ ~t = ~t - return xx, xt && yt - } - } - return nil, false -} - -func identicalTerms(list1, list2 []*term) bool { - if len(list1) != len(list2) { - return false - } - // Every term in list1 must be in list2. - // Quadratic algorithm, but probably good enough for now. - // TODO(gri) we need a fast quick type ID/hash for all types. -L: - for _, x := range list1 { - for _, y := range list2 { - if x.equal(y) { - continue L // x is in list2 +// overlappingTerm reports the index of the term x in terms which is +// overlapping (not disjoint) from y. The result is < 0 if there is no +// such term. +func overlappingTerm(terms []*term, y *term) int { + for i, x := range terms { + // disjoint requires non-nil, non-top arguments + if debug { + if x == nil || x.typ == nil || y == nil || y.typ == nil { + panic("internal error: empty or top union term") } } - return false - } - return true -} - -func intersectTerms(list1, list2 []*term) (list []*term) { - // Quadratic algorithm, but good enough for now. - // TODO(gri) fix asymptotic performance - for _, x := range list1 { - for _, y := range list2 { - if r := x.intersect(y); r != nil { - list = append(list, r) - } + if !x.disjoint(y) { + return i } } - return + return -1 } diff --git a/src/cmd/compile/internal/types2/universe.go b/src/cmd/compile/internal/types2/universe.go index a3dd4bd0d66..7b6c297d054 100644 --- a/src/cmd/compile/internal/types2/universe.go +++ b/src/cmd/compile/internal/types2/universe.go @@ -89,7 +89,7 @@ func defPredeclaredTypes() { sig := NewSignature(nil, nil, NewTuple(res), false) err := NewFunc(nopos, nil, "Error", sig) ityp := &Interface{obj, []*Func{err}, nil, nil, true, nil} - computeTypeSet(nil, nopos, ityp) // prevent races due to lazy computation of tset + computeInterfaceTypeSet(nil, nopos, ityp) // prevent races due to lazy computation of tset typ := NewNamed(obj, ityp, nil) sig.recv = NewVar(nopos, nil, "", typ) def(obj) @@ -99,7 +99,7 @@ func defPredeclaredTypes() { { obj := NewTypeName(nopos, nil, "comparable", nil) obj.setColor(black) - ityp := &Interface{obj, nil, nil, nil, true, &TypeSet{true, nil, nil}} + ityp := &Interface{obj, nil, nil, nil, true, &TypeSet{true, nil, topTermlist}} NewNamed(obj, ityp, nil) def(obj) } diff --git a/test/typeparam/mincheck.dir/main.go b/test/typeparam/mincheck.dir/main.go index 72d8effcc50..9cf2c6bafd6 100644 --- a/test/typeparam/mincheck.dir/main.go +++ b/test/typeparam/mincheck.dir/main.go @@ -28,11 +28,11 @@ func main() { } const want2 = "ay" - if got := a.Min[string]("bb", "ay"); got != want2 { // ERROR "string does not satisfy interface{int|int64|float64}" + if got := a.Min[string]("bb", "ay"); got != want2 { // ERROR "string does not satisfy" panic(fmt.Sprintf("got %d, want %d", got, want2)) } - if got := a.Min("bb", "ay"); got != want2 { // ERROR "string does not satisfy interface{int|int64|float64}" + if got := a.Min("bb", "ay"); got != want2 { // ERROR "string does not satisfy" panic(fmt.Sprintf("got %d, want %d", got, want2)) } } From f14908d01b8c4832f9ad3939165d5eec969635e1 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 4 Aug 2021 12:12:27 -0700 Subject: [PATCH 865/940] [dev.typeparams] cmd/compile/internal/types2: remove unused gcCompatibilityMode flag (cleanup) This flag is not needed by types2 (and possibly can also be removed from go/types). Removed some unnecessary comments along the way. Updates #46174. Change-Id: I1a7a99f724205a084d1c9850bce6f6f5d33f83ca Reviewed-on: https://go-review.googlesource.com/c/go/+/339831 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/typestring.go | 98 +++---------------- 1 file changed, 13 insertions(+), 85 deletions(-) diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go index 558da50528d..1416008b163 100644 --- a/src/cmd/compile/internal/types2/typestring.go +++ b/src/cmd/compile/internal/types2/typestring.go @@ -39,27 +39,6 @@ func RelativeTo(pkg *Package) Qualifier { } } -// If gcCompatibilityMode is set, printing of types is modified -// to match the representation of some types in the gc compiler: -// -// - byte and rune lose their alias name and simply stand for -// uint8 and int32 respectively -// - embedded interfaces get flattened (the embedding info is lost, -// and certain recursive interface types cannot be printed anymore) -// -// This makes it easier to compare packages computed with the type- -// checker vs packages imported from gc export data. -// -// Caution: This flag affects all uses of WriteType, globally. -// It is only provided for testing in conjunction with -// gc-generated data. -// -// This flag is exported in the x/tools/go/types package. We don't -// need it at the moment in the std repo and so we don't export it -// anymore. We should eventually try to remove it altogether. -// TODO(gri) remove this -var gcCompatibilityMode bool - // TypeString returns the string representation of typ. // The Qualifier controls the printing of // package-level objects, and may be nil. @@ -106,16 +85,6 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { break } } - - if gcCompatibilityMode { - // forget the alias names - switch t.kind { - case Byte: - t = Typ[Uint8] - case Rune: - t = Typ[Int32] - } - } buf.WriteString(t.name) case *Array: @@ -174,66 +143,25 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { } case *Interface: - // We write the source-level methods and embedded types rather - // than the actual method set since resolved method signatures - // may have non-printable cycles if parameters have embedded - // interface types that (directly or indirectly) embed the - // current interface. For instance, consider the result type - // of m: - // - // type T interface{ - // m() interface{ T } - // } - // buf.WriteString("interface{") empty := true - if gcCompatibilityMode { - // print flattened interface - // (useful to compare against gc-generated interfaces) - tset := t.typeSet() - for i, m := range tset.methods { - if i > 0 { - buf.WriteString("; ") - } - buf.WriteString(m.name) - writeSignature(buf, m.typ.(*Signature), qf, visited) - empty = false - } - if !empty && tset.hasTerms() { + for i, m := range t.methods { + if i > 0 { buf.WriteString("; ") } - first := true - tset.is(func(t *term) bool { - if !first { - buf.WriteByte('|') - } - first = false - if t.tilde { - buf.WriteByte('~') - } - writeType(buf, t.typ, qf, visited) - return true - }) - } else { - // print explicit interface methods and embedded types - for i, m := range t.methods { - if i > 0 { - buf.WriteString("; ") - } - buf.WriteString(m.name) - writeSignature(buf, m.typ.(*Signature), qf, visited) - empty = false - } - if !empty && len(t.embeddeds) > 0 { + buf.WriteString(m.name) + writeSignature(buf, m.typ.(*Signature), qf, visited) + empty = false + } + if !empty && len(t.embeddeds) > 0 { + buf.WriteString("; ") + } + for i, typ := range t.embeddeds { + if i > 0 { buf.WriteString("; ") } - for i, typ := range t.embeddeds { - if i > 0 { - buf.WriteString("; ") - } - writeType(buf, typ, qf, visited) - empty = false - } + writeType(buf, typ, qf, visited) + empty = false } // print /* incomplete */ if needed to satisfy existing tests // TODO(gri) get rid of this eventually From c5b6c36ddd0ecdee401c4e78da1addf64bdc6376 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 4 Aug 2021 12:27:26 -0700 Subject: [PATCH 866/940] [dev.typeparams] cmd/compile/internal/types2: remove TestIncompleteInterfaces (cleanup) TestIncompleteInterfaces is not useful anymore because interface printing always shows the syntactic type structure of an interface. Also remove the respective support code in interface printing and simplify that code. Move the newDefined and nopos support declarations unchanged into api_test.go where they are used. Updates #46167. Change-Id: I23e303bc4ae4271912ba75f201bd2b7cd4a17b3e Reviewed-on: https://go-review.googlesource.com/c/go/+/339832 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/api_test.go | 8 +++ src/cmd/compile/internal/types2/typestring.go | 25 +++----- .../internal/types2/typestring_test.go | 58 ------------------- 3 files changed, 15 insertions(+), 76 deletions(-) diff --git a/src/cmd/compile/internal/types2/api_test.go b/src/cmd/compile/internal/types2/api_test.go index 1d3347a6dea..c625bd49594 100644 --- a/src/cmd/compile/internal/types2/api_test.go +++ b/src/cmd/compile/internal/types2/api_test.go @@ -1567,6 +1567,14 @@ func F(){ } } +var nopos syntax.Pos + +// newDefined creates a new defined type named T with the given underlying type. +func newDefined(underlying Type) *Named { + tname := NewTypeName(nopos, nil, "T", nil) + return NewNamed(tname, underlying, nil) +} + func TestConvertibleTo(t *testing.T) { for _, test := range []struct { v, t Type diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go index 1416008b163..628eeaf3dda 100644 --- a/src/cmd/compile/internal/types2/typestring.go +++ b/src/cmd/compile/internal/types2/typestring.go @@ -144,32 +144,21 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { case *Interface: buf.WriteString("interface{") - empty := true - for i, m := range t.methods { - if i > 0 { + first := true + for _, m := range t.methods { + if !first { buf.WriteString("; ") } + first = false buf.WriteString(m.name) writeSignature(buf, m.typ.(*Signature), qf, visited) - empty = false } - if !empty && len(t.embeddeds) > 0 { - buf.WriteString("; ") - } - for i, typ := range t.embeddeds { - if i > 0 { + for _, typ := range t.embeddeds { + if !first { buf.WriteString("; ") } + first = false writeType(buf, typ, qf, visited) - empty = false - } - // print /* incomplete */ if needed to satisfy existing tests - // TODO(gri) get rid of this eventually - if debug && t.tset == nil { - if !empty { - buf.WriteByte(' ') - } - buf.WriteString("/* incomplete */") } buf.WriteByte('}') diff --git a/src/cmd/compile/internal/types2/typestring_test.go b/src/cmd/compile/internal/types2/typestring_test.go index 88103b81b12..0ed29349610 100644 --- a/src/cmd/compile/internal/types2/typestring_test.go +++ b/src/cmd/compile/internal/types2/typestring_test.go @@ -136,64 +136,6 @@ func TestTypeString(t *testing.T) { } } -var nopos syntax.Pos - -func TestIncompleteInterfaces(t *testing.T) { - if !Debug { - t.Skip("requires type checker to be compiled with debug = true") - } - - sig := NewSignature(nil, nil, nil, false) - m := NewFunc(nopos, nil, "m", sig) - for _, test := range []struct { - typ *Interface - want string - }{ - {new(Interface), "interface{/* incomplete */}"}, - {new(Interface).Complete(), "interface{}"}, - - {NewInterface(nil, nil), "interface{}"}, - {NewInterface(nil, nil).Complete(), "interface{}"}, - {NewInterface([]*Func{}, nil), "interface{}"}, - {NewInterface([]*Func{}, nil).Complete(), "interface{}"}, - {NewInterface(nil, []*Named{}), "interface{}"}, - {NewInterface(nil, []*Named{}).Complete(), "interface{}"}, - {NewInterface([]*Func{m}, nil), "interface{m() /* incomplete */}"}, - {NewInterface([]*Func{m}, nil).Complete(), "interface{m()}"}, - {NewInterface(nil, []*Named{newDefined(new(Interface).Complete())}), "interface{T /* incomplete */}"}, - {NewInterface(nil, []*Named{newDefined(new(Interface).Complete())}).Complete(), "interface{T}"}, - {NewInterface(nil, []*Named{newDefined(NewInterface([]*Func{m}, nil))}), "interface{T /* incomplete */}"}, - {NewInterface(nil, []*Named{newDefined(NewInterface([]*Func{m}, nil).Complete())}), "interface{T /* incomplete */}"}, - {NewInterface(nil, []*Named{newDefined(NewInterface([]*Func{m}, nil).Complete())}).Complete(), "interface{T}"}, - - {NewInterfaceType(nil, nil), "interface{}"}, - {NewInterfaceType(nil, nil).Complete(), "interface{}"}, - {NewInterfaceType([]*Func{}, nil), "interface{}"}, - {NewInterfaceType([]*Func{}, nil).Complete(), "interface{}"}, - {NewInterfaceType(nil, []Type{}), "interface{}"}, - {NewInterfaceType(nil, []Type{}).Complete(), "interface{}"}, - {NewInterfaceType([]*Func{m}, nil), "interface{m() /* incomplete */}"}, - {NewInterfaceType([]*Func{m}, nil).Complete(), "interface{m()}"}, - {NewInterfaceType(nil, []Type{new(Interface).Complete()}), "interface{interface{} /* incomplete */}"}, - {NewInterfaceType(nil, []Type{new(Interface).Complete()}).Complete(), "interface{interface{}}"}, - {NewInterfaceType(nil, []Type{NewInterfaceType([]*Func{m}, nil)}), "interface{interface{m() /* incomplete */} /* incomplete */}"}, - {NewInterfaceType(nil, []Type{NewInterfaceType([]*Func{m}, nil).Complete()}), "interface{interface{m()} /* incomplete */}"}, - {NewInterfaceType(nil, []Type{NewInterfaceType([]*Func{m}, nil).Complete()}).Complete(), "interface{interface{m()}}"}, - } { - got := test.typ.String() - if got != test.want { - t.Errorf("got: %s, want: %s", got, test.want) - } - } -} - -// newDefined creates a new defined type named T with the given underlying type. -// Helper function for use with TestIncompleteInterfaces only. -func newDefined(underlying Type) *Named { - tname := NewTypeName(nopos, nil, "T", nil) - return NewNamed(tname, underlying, nil) -} - func TestQualifiedTypeString(t *testing.T) { p, _ := pkgFor("p.go", "package p; type T int", nil) q, _ := pkgFor("q.go", "package q", nil) From f78d538858a2d9aae975b2e2c144d23bcc22c22e Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 4 Aug 2021 12:57:23 -0700 Subject: [PATCH 867/940] [dev.typeparams] cmd/compile/internal/types2: cleanup panic calls End-users are not expected to deal with the details of panics, so providing extra information such as an "internal error" prefix or the name of the function invoking the panic are not helpful. Remove unnecessary panic verbiage if it is readily available from a stack trace (such as the function where it happens, and the fact that is is an "internal error"). Change-Id: I5f86bae6d2cca7c04ce692d17257da7ddee206d7 Reviewed-on: https://go-review.googlesource.com/c/go/+/339969 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/decl.go | 4 ++-- src/cmd/compile/internal/types2/errors.go | 4 ++-- src/cmd/compile/internal/types2/lookup.go | 4 ++-- src/cmd/compile/internal/types2/named.go | 12 ++++++------ src/cmd/compile/internal/types2/signature.go | 4 ++-- src/cmd/compile/internal/types2/stmt.go | 2 +- src/cmd/compile/internal/types2/typeparam.go | 4 ++-- src/cmd/compile/internal/types2/typeset.go | 4 ++-- src/cmd/compile/internal/types2/typestring.go | 6 +++--- src/cmd/compile/internal/types2/union.go | 2 +- src/cmd/compile/internal/types2/universe.go | 2 +- 11 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go index cf4d4c95a7e..bb33c287f32 100644 --- a/src/cmd/compile/internal/types2/decl.go +++ b/src/cmd/compile/internal/types2/decl.go @@ -340,7 +340,7 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo { // cycle detected for i, tn := range path { if t.obj.pkg != check.pkg { - panic("internal error: type cycle via package-external type") + panic("type cycle via package-external type") } if tn == t.obj { check.cycleError(path[i:]) @@ -348,7 +348,7 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo { return t.info } } - panic("internal error: cycle start not found") + panic("cycle start not found") } return t.info } diff --git a/src/cmd/compile/internal/types2/errors.go b/src/cmd/compile/internal/types2/errors.go index 8c5e185f6cb..a68273271b7 100644 --- a/src/cmd/compile/internal/types2/errors.go +++ b/src/cmd/compile/internal/types2/errors.go @@ -88,7 +88,7 @@ func sprintf(qf Qualifier, format string, args ...interface{}) string { case nil: arg = "" case operand: - panic("internal error: should always pass *operand") + panic("got operand instead of *operand") case *operand: arg = operandString(a, qf) case syntax.Pos: @@ -148,7 +148,7 @@ func (check *Checker) sprintf(format string, args ...interface{}) string { func (check *Checker) report(err *error_) { if err.empty() { - panic("internal error: reporting no error") + panic("no error to report") } check.err(err.pos(), err.msg(check.qualifier), err.soft) } diff --git a/src/cmd/compile/internal/types2/lookup.go b/src/cmd/compile/internal/types2/lookup.go index f62c3771d28..0363008ad9a 100644 --- a/src/cmd/compile/internal/types2/lookup.go +++ b/src/cmd/compile/internal/types2/lookup.go @@ -322,7 +322,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, return m, f } if !acceptMethodTypeParams && ftyp.TParams().Len() > 0 { - panic("internal error: method with type parameters") + panic("method with type parameters") } // If the methods have type parameters we don't care whether they @@ -374,7 +374,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, return m, f } if !acceptMethodTypeParams && ftyp.TParams().Len() > 0 { - panic("internal error: method with type parameters") + panic("method with type parameters") } // If V is a (instantiated) generic type, its methods are still diff --git a/src/cmd/compile/internal/types2/named.go b/src/cmd/compile/internal/types2/named.go index 8ded197df5b..14e073bfaeb 100644 --- a/src/cmd/compile/internal/types2/named.go +++ b/src/cmd/compile/internal/types2/named.go @@ -33,7 +33,7 @@ type Named struct { // The underlying type must not be a *Named. func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named { if _, ok := underlying.(*Named); ok { - panic("types2.NewNamed: underlying type must not be *Named") + panic("underlying type must not be *Named") } return (*Checker)(nil).newNamed(obj, nil, underlying, nil, methods) } @@ -100,7 +100,7 @@ func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tpar check.later(func() { switch typ.under().(type) { case *Named: - panic("internal error: unexpanded underlying type") + panic("unexpanded underlying type") } typ.check = nil }) @@ -140,10 +140,10 @@ func (t *Named) Method(i int) *Func { return t.load().methods[i] } // SetUnderlying sets the underlying type and marks t as complete. func (t *Named) SetUnderlying(underlying Type) { if underlying == nil { - panic("types2.Named.SetUnderlying: underlying type must not be nil") + panic("underlying type must not be nil") } if _, ok := underlying.(*Named); ok { - panic("types2.Named.SetUnderlying: underlying type must not be *Named") + panic("underlying type must not be *Named") } t.load().underlying = underlying } @@ -191,7 +191,7 @@ func (n0 *Named) under() Type { } if n0.check == nil { - panic("internal error: Named.check == nil but type is incomplete") + panic("Named.check == nil but type is incomplete") } // Invariant: after this point n0 as well as any named types in its @@ -242,7 +242,7 @@ func (n0 *Named) under() Type { // Also, doing so would lead to a race condition (was issue #31749). // Do this check always, not just in debug mode (it's cheap). if n.obj.pkg != check.pkg { - panic("internal error: imported type with unresolved underlying type") + panic("imported type with unresolved underlying type") } n.underlying = u } diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go index 832f37a6af4..14112462e18 100644 --- a/src/cmd/compile/internal/types2/signature.go +++ b/src/cmd/compile/internal/types2/signature.go @@ -36,10 +36,10 @@ func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature { if variadic { n := params.Len() if n == 0 { - panic("types2.NewSignature: variadic function must have at least one parameter") + panic("variadic function must have at least one parameter") } if _, ok := params.At(n - 1).typ.(*Slice); !ok { - panic("types2.NewSignature: variadic parameter must be of unnamed slice type") + panic("variadic parameter must be of unnamed slice type") } } return &Signature{recv: recv, params: params, results: results, variadic: variadic} diff --git a/src/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go index 1efce511f1c..ad8efa91f86 100644 --- a/src/cmd/compile/internal/types2/stmt.go +++ b/src/cmd/compile/internal/types2/stmt.go @@ -14,7 +14,7 @@ import ( func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body *syntax.BlockStmt, iota constant.Value) { if check.conf.IgnoreFuncBodies { - panic("internal error: function body not ignored") + panic("function body not ignored") } if check.conf.Trace { diff --git a/src/cmd/compile/internal/types2/typeparam.go b/src/cmd/compile/internal/types2/typeparam.go index 27e6e355883..12513ed6dda 100644 --- a/src/cmd/compile/internal/types2/typeparam.go +++ b/src/cmd/compile/internal/types2/typeparam.go @@ -75,7 +75,7 @@ func (t *TypeParam) Constraint() Type { // SetConstraint sets the type constraint for t. func (t *TypeParam) SetConstraint(bound Type) { if bound == nil { - panic("types2.TypeParam.SetConstraint: bound must not be nil") + panic("nil constraint") } t.bound = bound } @@ -118,7 +118,7 @@ func bindTParams(list []*TypeName) *TypeParams { for i, tp := range list { typ := tp.Type().(*TypeParam) if typ.index >= 0 { - panic("internal error: type parameter bound more than once") + panic("type parameter bound more than once") } typ.index = i } diff --git a/src/cmd/compile/internal/types2/typeset.go b/src/cmd/compile/internal/types2/typeset.go index 6e19115ff59..c5fcb97ff9d 100644 --- a/src/cmd/compile/internal/types2/typeset.go +++ b/src/cmd/compile/internal/types2/typeset.go @@ -323,10 +323,10 @@ func sortMethods(list []*Func) { func assertSortedMethods(list []*Func) { if !debug { - panic("internal error: assertSortedMethods called outside debug mode") + panic("assertSortedMethods called outside debug mode") } if !sort.IsSorted(byUniqueMethodName(list)) { - panic("internal error: methods not sorted") + panic("methods not sorted") } } diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go index 628eeaf3dda..b3675424a5b 100644 --- a/src/cmd/compile/internal/types2/typestring.go +++ b/src/cmd/compile/internal/types2/typestring.go @@ -130,7 +130,7 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { // Unions only appear as (syntactic) embedded elements // in interfaces and syntactically cannot be empty. if t.NumTerms() == 0 { - panic("internal error: empty union") + panic("empty union") } for i, t := range t.terms { if i > 0 { @@ -183,7 +183,7 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { case RecvOnly: s = "<-chan " default: - panic("unreachable") + unreachable() } buf.WriteString(s) if parens { @@ -329,7 +329,7 @@ func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visi // special case: // append(s, "foo"...) leads to signature func([]byte, string...) if t := asBasic(typ); t == nil || t.kind != String { - panic("internal error: string type expected") + panic("expected string type") } writeType(buf, typ, qf, visited) buf.WriteString("...") diff --git a/src/cmd/compile/internal/types2/union.go b/src/cmd/compile/internal/types2/union.go index fcd83ce688a..0325c72dbb5 100644 --- a/src/cmd/compile/internal/types2/union.go +++ b/src/cmd/compile/internal/types2/union.go @@ -129,7 +129,7 @@ func overlappingTerm(terms []*term, y *term) int { // disjoint requires non-nil, non-top arguments if debug { if x == nil || x.typ == nil || y == nil || y.typ == nil { - panic("internal error: empty or top union term") + panic("empty or top union term") } } if !x.disjoint(y) { diff --git a/src/cmd/compile/internal/types2/universe.go b/src/cmd/compile/internal/types2/universe.go index 7b6c297d054..55bf0982b30 100644 --- a/src/cmd/compile/internal/types2/universe.go +++ b/src/cmd/compile/internal/types2/universe.go @@ -258,6 +258,6 @@ func def(obj Object) { } } if scope.Insert(obj) != nil { - panic("internal error: double declaration") + panic("double declaration of predeclared identifier") } } From fd45e267c2f6ce7c6a88842e3ad94d3469223e42 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 5 Aug 2021 13:05:23 -0700 Subject: [PATCH 868/940] runtime: warn that KeepAlive is not an unsafe.Pointer workaround Even experienced users occasionally mistake that runtime.KeepAlive can be used as a workaround for following the unsafe.Pointer safety rules, but it cannot. Add an explicit warning to this effect to dissuade users from trying to use it as such. Fixes #47562. Change-Id: I842e33a3e1c080933c6b1bd1b6318448adbf495c Reviewed-on: https://go-review.googlesource.com/c/go/+/340269 Trust: Matthew Dempsky Reviewed-by: Ian Lance Taylor --- src/runtime/mfinal.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/runtime/mfinal.go b/src/runtime/mfinal.go index fd318d49a8d..c134a0f22d8 100644 --- a/src/runtime/mfinal.go +++ b/src/runtime/mfinal.go @@ -466,6 +466,10 @@ okarg: // Without the KeepAlive call, the finalizer could run at the start of // syscall.Read, closing the file descriptor before syscall.Read makes // the actual system call. +// +// Note: KeepAlive should only be used to prevent finalizers from +// running prematurely. In particular, when used with unsafe.Pointer, +// the rules for valid uses of unsafe.Pointer still apply. func KeepAlive(x interface{}) { // Introduce a use of x that the compiler can't eliminate. // This makes sure x is alive on entry. We need x to be alive From 70546f6404c5927a9868a80ccbf4c6c2beaea671 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Thu, 5 Aug 2021 13:37:29 +0200 Subject: [PATCH 869/940] runtime: allow arm64 SEH to be called if illegal instruction DLLs built with recent Microsoft toolchains for ARM64 test for ARMv8.1 atomics by potentially calling an illegal instruction, and then trapping the exception to disable use of them by way of a structured exception handler. However, vectored exception handlers are always called before structured exception handlers. When LoadLibrary-ing DLLs that do this probing during initialization, our lastcontinuehandler winds up being called, and then crashing, but actually it should give execution back to the library to handle the exception and fix up the state. So special case this for arm64 with illegal instructions, and hope that we're not masking other things in external DLLs that might more fatally trigger an illegal instruction exception. Updates #47576. Change-Id: I341ab99cd8d513ae999b75596749d49779072022 Reviewed-on: https://go-review.googlesource.com/c/go/+/340070 Trust: Jason A. Donenfeld Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Brad Fitzpatrick Reviewed-by: Russ Cox --- src/runtime/signal_windows.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/runtime/signal_windows.go b/src/runtime/signal_windows.go index f2ce24d735c..b720ddcf164 100644 --- a/src/runtime/signal_windows.go +++ b/src/runtime/signal_windows.go @@ -183,6 +183,17 @@ func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 { return _EXCEPTION_CONTINUE_SEARCH } + // VEH is called before SEH, but arm64 MSVC DLLs use SEH to trap + // illegal instructions during runtime initialization to determine + // CPU features, so if we make it to the last handler and we're + // arm64 and it's an illegal instruction and this is coming from + // non-Go code, then assume it's this runtime probing happen, and + // pass that onward to SEH. + if GOARCH == "arm64" && info.exceptioncode == _EXCEPTION_ILLEGAL_INSTRUCTION && + (r.ip() < firstmoduledata.text || firstmoduledata.etext < r.ip()) { + return _EXCEPTION_CONTINUE_SEARCH + } + winthrow(info, r, gp) return 0 // not reached } From ac78501b9c4f7458c6b4352b1590db058d9ac27c Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Thu, 5 Aug 2021 23:26:21 -0700 Subject: [PATCH 870/940] [dev.typeparams] cmd/compile: make sure closures inside generic funcs are not compiled Closures inside generic functions were being added to the g.target.Decls list during noding, just like other closures. We remove generic functions/methods from g.target.Decls, so they don't get compiled (they're only available for export and stenciling). Most closures inside generic functions/methods were similarly being removed from g.target.Decls, because they have a generic parameter. But we need to ensure no closures in generic function/methods are left remaining in g.target.Decls, since we don't want them transformed and compiled. So, we set a flag in (*irgen) that records when we are noding a top-level generic function/method, and don't add any closures to g.target.Decls when the flag is true. Updates #47514 Change-Id: Id66b4c41d307ffa8f54cab6ce3646ade81606862 Reviewed-on: https://go-review.googlesource.com/c/go/+/340258 Trust: Dan Scales Reviewed-by: Keith Randall --- src/cmd/compile/internal/noder/decl.go | 4 ++++ src/cmd/compile/internal/noder/expr.go | 9 ++++++++- src/cmd/compile/internal/noder/irgen.go | 5 +++++ test/typeparam/issue47514.go | 20 ++++++++++++++++++++ 4 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 test/typeparam/issue47514.go diff --git a/src/cmd/compile/internal/noder/decl.go b/src/cmd/compile/internal/noder/decl.go index 2416d1a49e2..429c8a14c8a 100644 --- a/src/cmd/compile/internal/noder/decl.go +++ b/src/cmd/compile/internal/noder/decl.go @@ -102,7 +102,11 @@ func (g *irgen) funcDecl(out *ir.Nodes, decl *syntax.FuncDecl) { g.target.Inits = append(g.target.Inits, fn) } + if fn.Type().HasTParam() { + g.topFuncIsGeneric = true + } g.funcBody(fn, decl.Recv, decl.Type, decl.Body) + g.topFuncIsGeneric = false if fn.Type().HasTParam() && fn.Body != nil { // Set pointers to the dcls/body of a generic function/method in // the Inl struct, so it is marked for export, is available for diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go index a0d3cad6994..6e2b1a839be 100644 --- a/src/cmd/compile/internal/noder/expr.go +++ b/src/cmd/compile/internal/noder/expr.go @@ -465,7 +465,14 @@ func (g *irgen) funcLit(typ2 types2.Type, expr *syntax.FuncLit) ir.Node { cv.SetWalkdef(1) } - return ir.UseClosure(fn.OClosure, g.target) + if g.topFuncIsGeneric { + // Don't add any closure inside a generic function/method to the + // g.target.Decls list, even though it may not be generic itself. + // See issue #47514. + return ir.UseClosure(fn.OClosure, nil) + } else { + return ir.UseClosure(fn.OClosure, g.target) + } } func (g *irgen) typeExpr(typ syntax.Expr) *types.Type { diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go index 6a8763c9088..571e294416a 100644 --- a/src/cmd/compile/internal/noder/irgen.go +++ b/src/cmd/compile/internal/noder/irgen.go @@ -154,6 +154,11 @@ type irgen struct { // dictionary syms which we need to finish, by writing out any itabconv // entries. dictSymsToFinalize []*delayInfo + + // True when we are compiling a top-level generic function or method. Use to + // avoid adding closures of generic functions/methods to the target.Decls + // list. + topFuncIsGeneric bool } type delayInfo struct { diff --git a/test/typeparam/issue47514.go b/test/typeparam/issue47514.go new file mode 100644 index 00000000000..947f254003d --- /dev/null +++ b/test/typeparam/issue47514.go @@ -0,0 +1,20 @@ +// run -gcflags=-G=3 + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test that closures inside a generic function are not exported, +// even though not themselves generic. + +package main + +func Do[T any]() { + _ = func() string { + return "" + } +} + +func main() { + Do[int]() +} From 5e33d11e1051734b2495021aa64ed9f47fbae87e Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Thu, 5 Aug 2021 15:59:39 -0700 Subject: [PATCH 871/940] [dev.typeparams] cmd/compile: do transformCall with non-shape type of call Do the transformCall using the original types2-derived type of the call (in particular, the types of the params as non-shapes). Currently, since we were using the param types of the instantiation, we might add in interface conversions to an interface with shapes in the one case of a full-instantiated generic call. So, we do the transformCall() before installing the shaped-based instantiation. transformCall() works correctly even in the case of OCALL/FUNCINST. Fixed two related bugs: - Fixed case where we still were not correctly substituting the types for a function instantiation. - The type substituter needs to copy field flags while substituting in tstruct. Change-Id: I14e960737d6840a75846ede480e6650534ba3af3 Reviewed-on: https://go-review.googlesource.com/c/go/+/340259 Trust: Dan Scales Run-TryBot: Dan Scales Reviewed-by: Keith Randall --- src/cmd/compile/internal/noder/expr.go | 8 ++++++-- src/cmd/compile/internal/noder/stencil.go | 11 ++++++++--- src/cmd/compile/internal/noder/transform.go | 3 ++- src/cmd/compile/internal/typecheck/subr.go | 6 ++++++ 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go index 6e2b1a839be..3e3c352a32f 100644 --- a/src/cmd/compile/internal/noder/expr.go +++ b/src/cmd/compile/internal/noder/expr.go @@ -125,13 +125,17 @@ func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node { } if fun.Op() == ir.OFUNCINST { // Replace explicit type args with the full list that - // includes the additional inferred type args + // includes the additional inferred type args. + // Substitute the type args for the type params in + // the generic function's type. fun.(*ir.InstExpr).Targs = targs + newt := g.substType(fun.Type(), fun.Type().TParams(), targs) + typed(newt, fun) } else { // Create a function instantiation here, given there // are only inferred type args (e.g. min(5,6), where // min is a generic function). Substitute the type - // args for the type params in the uninstantiated function's + // args for the type params in the generic function's // type. inst := ir.NewInstExpr(pos, ir.OFUNCINST, fun, targs) newt := g.substType(fun.Type(), fun.Type().TParams(), targs) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 7cc37f1154e..b37f76dcee4 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -119,6 +119,14 @@ func (g *irgen) stencil() { fmt.Printf("%s in %v at generic function call: %v - %v\n", dictkind, decl, inst.X, call) } } + + // Transform the Call now, which changes OCALL to + // OCALLFUNC and does typecheckaste/assignconvfn. Do + // it before installing the instantiation, so we are + // checking against non-shape param types in + // typecheckaste. + transformCall(call) + // Replace the OFUNCINST with a direct reference to the // new stenciled function call.X = st.Nname @@ -132,9 +140,6 @@ func (g *irgen) stencil() { // Add dictionary to argument list. call.Args.Prepend(dictValue) - // Transform the Call now, which changes OCALL - // to OCALLFUNC and does typecheckaste/assignconvfn. - transformCall(call) modified = true } if n.Op() == ir.OCALLMETH && n.(*ir.CallExpr).X.Op() == ir.ODOTMETH && len(deref(n.(*ir.CallExpr).X.Type().Recv().Type).RParams()) > 0 { diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go index 9c791d8a7bb..61af92b62a7 100644 --- a/src/cmd/compile/internal/noder/transform.go +++ b/src/cmd/compile/internal/noder/transform.go @@ -130,7 +130,8 @@ func transformConvCall(n *ir.CallExpr) ir.Node { } // transformCall transforms a normal function/method call. Corresponds to last half -// (non-conversion, non-builtin part) of typecheck.tcCall. +// (non-conversion, non-builtin part) of typecheck.tcCall. This code should work even +// in the case of OCALL/OFUNCINST. func transformCall(n *ir.CallExpr) { // n.Type() can be nil for calls with no return value assert(n.Typecheck() == 1) diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index 53c39333705..e840df56dc2 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -1278,6 +1278,12 @@ func (ts *Tsubster) tstruct(t *types.Type, force bool) *types.Type { // the type param, not the instantiated type). newfields[i] = types.NewField(f.Pos, f.Sym, t2) newfields[i].Embedded = f.Embedded + if f.IsDDD() { + newfields[i].SetIsDDD(true) + } + if f.Nointerface() { + newfields[i].SetNointerface(true) + } if f.Nname != nil && ts.Vars != nil { v := ts.Vars[f.Nname.(*ir.Name)] if v != nil { From 110343e4a2a953a581e34e91e51cef08856b0b0a Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Thu, 5 Aug 2021 10:17:40 -0700 Subject: [PATCH 872/940] [dev.typeparams] cmd/compile: cleanup wrapper code for generics Simple change - added some comments, but also removed some TODO comments which are now done or no longer a question. Cleaned up the initial check for generic methods. The one remaining TODO that really needs to be done is generating dictionary wrappers for any methods involving embedded fields. Given we are not doing this, I think this would only affect if a struct with an embedded field with methods was converted to an interface containing the embedded method, and then the method was called via that interface. Change-Id: I6a8a2885de33ad60b313c1899b659daef7550dfb Reviewed-on: https://go-review.googlesource.com/c/go/+/340260 Trust: Dan Scales Run-TryBot: Dan Scales Reviewed-by: Keith Randall --- .../compile/internal/reflectdata/reflect.go | 50 ++++++++++--------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index a8df7a1a243..b04e4d684fa 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -303,6 +303,7 @@ func MapIterType(t *types.Type) *types.Type { // Generates stub functions as needed. func methods(t *types.Type) []*typeSig { if t.HasShape() { + // Shape types have no methods. return nil } // method type @@ -1228,9 +1229,8 @@ func InterfaceMethodOffset(ityp *types.Type, i int64) int64 { // NeedRuntimeType ensures that a runtime type descriptor is emitted for t. func NeedRuntimeType(t *types.Type) { if t.HasTParam() { - // Generic types don't have a runtime type descriptor (but will - // have a dictionary) - // TODO: also shape type here? + // Generic types don't really exist at run-time and have no runtime + // type descriptor. But we do write out shape types. return } if _, ok := signatset[t]; !ok { @@ -1786,26 +1786,28 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy if forItab && !types.IsDirectIface(rcvr) { rcvr = rcvr.PtrTo() } - generic := false - if !types.IsInterfaceMethod(method.Type) && - (len(rcvr.RParams()) > 0 || - rcvr.IsPtr() && len(rcvr.Elem().RParams()) > 0) { // TODO: right detection? - // Don't need dictionary if we are reaching a method (possibly via - // an embedded field) which is an interface method. - // TODO: check that we do the right thing when method is an interface method. - generic = true - targs := rcvr.RParams() - if rcvr.IsPtr() { - targs = rcvr.Elem().RParams() + generic := false + // We don't need a dictionary if we are reaching a method (possibly via an + // embedded field) which is an interface method. + if !types.IsInterfaceMethod(method.Type) { + rcvr1 := rcvr + if rcvr1.IsPtr() { + rcvr1 = rcvr.Elem() } - // TODO: why do shape-instantiated types exist? - for _, t := range targs { - if t.HasShape() { - base.Fatalf("method on type instantiated with shapes targ:%+v rcvr:%+v", t, rcvr) + if len(rcvr1.RParams()) > 0 { + // If rcvr has rparams, remember method as generic, which + // means we need to add a dictionary to the wrapper. + generic = true + targs := rcvr1.RParams() + for _, t := range targs { + if t.HasShape() { + base.Fatalf("method on type instantiated with shapes targ:%+v rcvr:%+v", t, rcvr) + } } } } + newnam := ir.MethodSym(rcvr, method.Sym) lsym := newnam.Linksym() if newnam.Siggen() { @@ -1818,6 +1820,8 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy return lsym } + // For generic methods, we need to generate the wrapper even if the receiver + // types are identical, because we want to add the dictionary. if !generic && types.Identical(rcvr, method.Type.Recv().Type) { return lsym } @@ -1890,7 +1894,7 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy if generic { var args []ir.Node var targs []*types.Type - if rcvr.IsPtr() { // TODO: correct condition? + if rcvr.IsPtr() { targs = rcvr.Elem().RParams() } else { targs = rcvr.RParams() @@ -1899,10 +1903,9 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy fmt.Printf("%s\n", ir.MethodSym(orig, method.Sym).Name) panic("multiple .inst.") } - // Temporary fix: the wrapper for an auto-generated - // pointer/non-pointer receiver method should share the - // same dictionary as the corresponding original - // (user-written) method. + // The wrapper for an auto-generated pointer/non-pointer + // receiver method should share the same dictionary as the + // corresponding original (user-written) method. baseOrig := orig if baseOrig.IsPtr() && !method.Type.Recv().Type.IsPtr() { baseOrig = baseOrig.Elem() @@ -2058,7 +2061,6 @@ func getDictionary(gf *types.Sym, targs []*types.Type) ir.Node { // Note: treat dictionary pointers as uintptrs, so they aren't pointers // with respect to GC. That saves on stack scanning work, write barriers, etc. // We can get away with it because dictionaries are global variables. - // TODO: use a cast, or is typing directly ok? np.SetType(types.Types[types.TUINTPTR]) np.SetTypecheck(1) return np From 5aac85ad5ebfa9c2ecb01a3292bcf3513d876d7a Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 4 Aug 2021 15:18:37 -0700 Subject: [PATCH 873/940] [dev.typeparams] cmd/compile/internal/types2: better names for things (cleanup) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - use the symbol 𝓤 (as in 𝓤niverse) instead of ⊤ to denote the set of all types (for better readabilty, ⊤ is hard to distinguish from T in some fonts) - use isAll instead of isTop to test for the set of all types - use allTermlist instead of topTermlist to denote the termlist representing all types Change-Id: Idcb0b3398782b38653338e65173c0dbb935e430a Reviewed-on: https://go-review.googlesource.com/c/go/+/339891 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- .../compile/internal/types2/instantiate.go | 2 +- src/cmd/compile/internal/types2/interface.go | 2 +- src/cmd/compile/internal/types2/termlist.go | 22 +++--- .../compile/internal/types2/termlist_test.go | 78 +++++++++---------- src/cmd/compile/internal/types2/typeset.go | 22 +++--- src/cmd/compile/internal/types2/typeterm.go | 31 ++++---- .../compile/internal/types2/typeterm_test.go | 42 +++++----- src/cmd/compile/internal/types2/universe.go | 2 +- 8 files changed, 100 insertions(+), 101 deletions(-) diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go index b7ea193a06e..0bb4ac956b2 100644 --- a/src/cmd/compile/internal/types2/instantiate.go +++ b/src/cmd/compile/internal/types2/instantiate.go @@ -174,7 +174,7 @@ func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap // if iface is comparable, targ must be comparable // TODO(gri) the error messages needs to be better, here if iface.IsComparable() && !Comparable(targ) { - if tpar := asTypeParam(targ); tpar != nil && tpar.iface().typeSet().IsTop() { + if tpar := asTypeParam(targ); tpar != nil && tpar.iface().typeSet().IsAll() { check.softErrorf(pos, "%s has no constraints", targ) return false } diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go index aa7d0b05a0b..f763f8ff443 100644 --- a/src/cmd/compile/internal/types2/interface.go +++ b/src/cmd/compile/internal/types2/interface.go @@ -92,7 +92,7 @@ func (t *Interface) NumMethods() int { return t.typeSet().NumMethods() } func (t *Interface) Method(i int) *Func { return t.typeSet().Method(i) } // Empty reports whether t is the empty interface. -func (t *Interface) Empty() bool { return t.typeSet().IsTop() } +func (t *Interface) Empty() bool { return t.typeSet().IsAll() } // IsComparable reports whether each type in interface t's type set is comparable. func (t *Interface) IsComparable() bool { return t.typeSet().IsComparable() } diff --git a/src/cmd/compile/internal/types2/termlist.go b/src/cmd/compile/internal/types2/termlist.go index 07056edd974..378ba6b8f4c 100644 --- a/src/cmd/compile/internal/types2/termlist.go +++ b/src/cmd/compile/internal/types2/termlist.go @@ -13,9 +13,9 @@ import "bytes" // normal form. type termlist []*term -// topTermlist represents the set of all types. +// allTermlist represents the set of all types. // It is in normal form. -var topTermlist = termlist{new(term)} +var allTermlist = termlist{new(term)} // String prints the termlist exactly (without normalization). func (xl termlist) String() string { @@ -45,9 +45,9 @@ func (xl termlist) isEmpty() bool { return true } -// isTop reports whether the termlist xl represents the set of all types. -func (xl termlist) isTop() bool { - // If there's a ⊤ (top) term, the entire list is ⊤ (top). +// isAll reports whether the termlist xl represents the set of all types. +func (xl termlist) isAll() bool { + // If there's a 𝓤 term, the entire list is 𝓤. // If the termlist is in normal form, this requires at most // one iteration. for _, x := range xl { @@ -74,14 +74,14 @@ func (xl termlist) norm() termlist { continue } if u1, u2 := xi.union(xj); u2 == nil { - // If we encounter a ⊤ (top) term, the entire - // list is ⊤ (top). Exit early. + // If we encounter a 𝓤 term, the entire list is 𝓤. + // Exit early. // (Note that this is not just an optimization; - // if we continue, we may end up with a ⊤ term + // if we continue, we may end up with a 𝓤 term // and other terms and the result would not be // in normal form.) if u1.typ == nil { - return topTermlist + return allTermlist } xi = u1 used[j] = true // xj is now unioned into xi - ignore it in future iterations @@ -92,11 +92,11 @@ func (xl termlist) norm() termlist { return rl } -// If the type set represented by xl is specified by a single (non-⊤) term, +// If the type set represented by xl is specified by a single (non-𝓤) term, // structuralType returns that type. Otherwise it returns nil. func (xl termlist) structuralType() Type { if nl := xl.norm(); len(nl) == 1 { - return nl[0].typ // if nl.isTop() then typ is nil, which is ok + return nl[0].typ // if nl.isAll() then typ is nil, which is ok } return nil } diff --git a/src/cmd/compile/internal/types2/termlist_test.go b/src/cmd/compile/internal/types2/termlist_test.go index c36baeb86f0..706b4c97565 100644 --- a/src/cmd/compile/internal/types2/termlist_test.go +++ b/src/cmd/compile/internal/types2/termlist_test.go @@ -21,20 +21,20 @@ func maketl(s string) termlist { } func TestTermlistTop(t *testing.T) { - if !topTermlist.isTop() { - t.Errorf("topTermlist is not top") + if !allTermlist.isAll() { + t.Errorf("allTermlist is not the set of all types") } } func TestTermlistString(t *testing.T) { for _, want := range []string{ "∅", - "⊤", + "𝓤", "int", "~int", "∅ ∪ ∅", - "⊤ ∪ ⊤", - "∅ ∪ ⊤ ∪ int", + "𝓤 ∪ 𝓤", + "∅ ∪ 𝓤 ∪ int", } { if got := maketl(want).String(); got != want { t.Errorf("(%v).String() == %v", want, got) @@ -46,9 +46,9 @@ func TestTermlistIsEmpty(t *testing.T) { for test, want := range map[string]bool{ "∅": true, "∅ ∪ ∅": true, - "∅ ∪ ∅ ∪ ⊤": false, - "⊤": false, - "⊤ ∪ int": false, + "∅ ∪ ∅ ∪ 𝓤": false, + "𝓤": false, + "𝓤 ∪ int": false, } { xl := maketl(test) got := xl.isEmpty() @@ -58,19 +58,19 @@ func TestTermlistIsEmpty(t *testing.T) { } } -func TestTermlistIsTop(t *testing.T) { +func TestTermlistIsAll(t *testing.T) { for test, want := range map[string]bool{ "∅": false, "∅ ∪ ∅": false, "int ∪ ~string": false, - "∅ ∪ ∅ ∪ ⊤": true, - "⊤": true, - "⊤ ∪ int": true, + "∅ ∪ ∅ ∪ 𝓤": true, + "𝓤": true, + "𝓤 ∪ int": true, } { xl := maketl(test) - got := xl.isTop() + got := xl.isAll() if got != want { - t.Errorf("(%v).isTop() == %v; want %v", test, got, want) + t.Errorf("(%v).isAll() == %v; want %v", test, got, want) } } } @@ -82,10 +82,10 @@ func TestTermlistNorm(t *testing.T) { {"∅", "∅"}, {"∅ ∪ ∅", "∅"}, {"∅ ∪ int", "int"}, - {"⊤ ∪ int", "⊤"}, + {"𝓤 ∪ int", "𝓤"}, {"~int ∪ int", "~int"}, {"int ∪ ~string ∪ int", "int ∪ ~string"}, - {"~int ∪ string ∪ ⊤ ∪ ~string ∪ int", "⊤"}, + {"~int ∪ string ∪ 𝓤 ∪ ~string ∪ int", "𝓤"}, } { xl := maketl(test.xl) got := maketl(test.xl).norm() @@ -106,7 +106,7 @@ func TestTermlistStructuralType(t *testing.T) { for test, want := range map[string]string{ "∅": "nil", - "⊤": "nil", + "𝓤": "nil", "int": "int", "~int": "int", "~int ∪ string": "nil", @@ -128,15 +128,15 @@ func TestTermlistUnion(t *testing.T) { }{ {"∅", "∅", "∅"}, - {"∅", "⊤", "⊤"}, + {"∅", "𝓤", "𝓤"}, {"∅", "int", "int"}, - {"⊤", "~int", "⊤"}, + {"𝓤", "~int", "𝓤"}, {"int", "~int", "~int"}, {"int", "string", "int ∪ string"}, {"int ∪ string", "~string", "int ∪ ~string"}, {"~int ∪ string", "~string ∪ int", "~int ∪ ~string"}, {"~int ∪ string ∪ ∅", "~string ∪ int", "~int ∪ ~string"}, - {"~int ∪ string ∪ ⊤", "~string ∪ int", "⊤"}, + {"~int ∪ string ∪ 𝓤", "~string ∪ int", "𝓤"}, } { xl := maketl(test.xl) yl := maketl(test.yl) @@ -153,15 +153,15 @@ func TestTermlistIntersect(t *testing.T) { }{ {"∅", "∅", "∅"}, - {"∅", "⊤", "∅"}, + {"∅", "𝓤", "∅"}, {"∅", "int", "∅"}, - {"⊤", "~int", "~int"}, + {"𝓤", "~int", "~int"}, {"int", "~int", "int"}, {"int", "string", "∅"}, {"int ∪ string", "~string", "string"}, {"~int ∪ string", "~string ∪ int", "int ∪ string"}, {"~int ∪ string ∪ ∅", "~string ∪ int", "int ∪ string"}, - {"~int ∪ string ∪ ⊤", "~string ∪ int", "int ∪ ~string"}, + {"~int ∪ string ∪ 𝓤", "~string ∪ int", "int ∪ ~string"}, } { xl := maketl(test.xl) yl := maketl(test.yl) @@ -178,10 +178,10 @@ func TestTermlistEqual(t *testing.T) { want bool }{ {"∅", "∅", true}, - {"∅", "⊤", false}, - {"⊤", "⊤", true}, - {"⊤ ∪ int", "⊤", true}, - {"⊤ ∪ int", "string ∪ ⊤", true}, + {"∅", "𝓤", false}, + {"𝓤", "𝓤", true}, + {"𝓤 ∪ int", "𝓤", true}, + {"𝓤 ∪ int", "string ∪ 𝓤", true}, {"int ∪ ~string", "string ∪ int", false}, {"int ∪ ~string ∪ ∅", "string ∪ int ∪ ~string", true}, } { @@ -200,14 +200,14 @@ func TestTermlistIncludes(t *testing.T) { want bool }{ {"∅", "int", false}, - {"⊤", "int", true}, + {"𝓤", "int", true}, {"~int", "int", true}, {"int", "string", false}, {"~int", "string", false}, {"int ∪ string", "string", true}, {"~int ∪ string", "int", true}, {"~int ∪ string ∪ ∅", "string", true}, - {"~string ∪ ∅ ∪ ⊤", "int", true}, + {"~string ∪ ∅ ∪ 𝓤", "int", true}, } { xl := maketl(test.xl) yl := testTerm(test.typ).typ @@ -224,12 +224,12 @@ func TestTermlistSupersetOf(t *testing.T) { want bool }{ {"∅", "∅", true}, - {"∅", "⊤", false}, + {"∅", "𝓤", false}, {"∅", "int", false}, - {"⊤", "∅", true}, - {"⊤", "⊤", true}, - {"⊤", "int", true}, - {"⊤", "~int", true}, + {"𝓤", "∅", true}, + {"𝓤", "𝓤", true}, + {"𝓤", "int", true}, + {"𝓤", "~int", true}, {"~int", "int", true}, {"~int", "~int", true}, {"int", "~int", false}, @@ -239,7 +239,7 @@ func TestTermlistSupersetOf(t *testing.T) { {"int ∪ string", "~string", false}, {"~int ∪ string", "int", true}, {"~int ∪ string ∪ ∅", "string", true}, - {"~string ∪ ∅ ∪ ⊤", "int", true}, + {"~string ∪ ∅ ∪ 𝓤", "int", true}, } { xl := maketl(test.xl) y := testTerm(test.typ) @@ -256,16 +256,16 @@ func TestTermlistSubsetOf(t *testing.T) { want bool }{ {"∅", "∅", true}, - {"∅", "⊤", true}, - {"⊤", "∅", false}, - {"⊤", "⊤", true}, + {"∅", "𝓤", true}, + {"𝓤", "∅", false}, + {"𝓤", "𝓤", true}, {"int", "int ∪ string", true}, {"~int", "int ∪ string", false}, {"~int", "string ∪ string ∪ int ∪ ~int", true}, {"int ∪ string", "string", false}, {"int ∪ string", "string ∪ int", true}, {"int ∪ ~string", "string ∪ int", false}, - {"int ∪ ~string", "string ∪ int ∪ ⊤", true}, + {"int ∪ ~string", "string ∪ int ∪ 𝓤", true}, {"int ∪ ~string", "string ∪ int ∪ ∅ ∪ string", false}, } { xl := maketl(test.xl) diff --git a/src/cmd/compile/internal/types2/typeset.go b/src/cmd/compile/internal/types2/typeset.go index c5fcb97ff9d..83df51389b7 100644 --- a/src/cmd/compile/internal/types2/typeset.go +++ b/src/cmd/compile/internal/types2/typeset.go @@ -25,17 +25,19 @@ type TypeSet struct { // IsEmpty reports whether type set s is the empty set. func (s *TypeSet) IsEmpty() bool { return s.terms.isEmpty() } -// IsTop reports whether type set s is the set of all types (corresponding to the empty interface). -func (s *TypeSet) IsTop() bool { return !s.comparable && len(s.methods) == 0 && s.terms.isTop() } +// IsAll reports whether type set s is the set of all types (corresponding to the empty interface). +func (s *TypeSet) IsAll() bool { + return !s.comparable && len(s.methods) == 0 && s.terms.isAll() +} // TODO(gri) IsMethodSet is not a great name for this predicate. Find a better one. // IsMethodSet reports whether the type set s is described by a single set of methods. -func (s *TypeSet) IsMethodSet() bool { return !s.comparable && s.terms.isTop() } +func (s *TypeSet) IsMethodSet() bool { return !s.comparable && s.terms.isAll() } // IsComparable reports whether each type in the set is comparable. func (s *TypeSet) IsComparable() bool { - if s.terms.isTop() { + if s.terms.isAll() { return s.comparable } return s.is(func(t *term) bool { @@ -67,8 +69,8 @@ func (s *TypeSet) String() string { switch { case s.IsEmpty(): return "∅" - case s.IsTop(): - return "⊤" + case s.IsAll(): + return "𝓤" } hasMethods := len(s.methods) > 0 @@ -103,7 +105,7 @@ func (s *TypeSet) String() string { // ---------------------------------------------------------------------------- // Implementation -func (s *TypeSet) hasTerms() bool { return !s.terms.isTop() } +func (s *TypeSet) hasTerms() bool { return !s.terms.isAll() } func (s *TypeSet) structuralType() Type { return s.terms.structuralType() } func (s *TypeSet) includes(t Type) bool { return s.terms.includes(t) } func (s1 *TypeSet) subsetOf(s2 *TypeSet) bool { return s1.terms.subsetOf(s2.terms) } @@ -156,7 +158,7 @@ func (s *TypeSet) underIs(f func(Type) bool) bool { } // topTypeSet may be used as type set for the empty interface. -var topTypeSet = TypeSet{terms: topTermlist} +var topTypeSet = TypeSet{terms: allTermlist} // computeInterfaceTypeSet may be called with check == nil. func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet { @@ -195,7 +197,7 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *T // have valid interfaces. Mark the interface as complete to avoid // infinite recursion if the validType check occurs later for some // reason. - ityp.tset = &TypeSet{terms: topTermlist} // TODO(gri) is this sufficient? + ityp.tset = &TypeSet{terms: allTermlist} // TODO(gri) is this sufficient? // Methods of embedded interfaces are collected unchanged; i.e., the identity // of a method I.m's Func Object of an interface I is the same as that of @@ -256,7 +258,7 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *T } // collect embedded elements - var allTerms = topTermlist + var allTerms = allTermlist for i, typ := range ityp.embeddeds { // The embedding position is nil for imported interfaces // and also for interface copies after substitution (but diff --git a/src/cmd/compile/internal/types2/typeterm.go b/src/cmd/compile/internal/types2/typeterm.go index 59a89cb004c..8edbefa579e 100644 --- a/src/cmd/compile/internal/types2/typeterm.go +++ b/src/cmd/compile/internal/types2/typeterm.go @@ -4,13 +4,10 @@ package types2 -// TODO(gri) use a different symbol instead of ⊤ for the set of all types -// (⊤ is hard to distinguish from T in some fonts) - // A term describes elementary type sets: // // ∅: (*term)(nil) == ∅ // set of no types (empty set) -// ⊤: &term{} == ⊤ // set of all types +// 𝓤: &term{} == 𝓤 // set of all types (𝓤niverse) // T: &term{false, T} == {T} // set of type T // ~t: &term{true, t} == {t' | under(t') == t} // set of types with underlying type t // @@ -24,7 +21,7 @@ func (x *term) String() string { case x == nil: return "∅" case x.typ == nil: - return "⊤" + return "𝓤" case x.tilde: return "~" + x.typ.String() default: @@ -41,7 +38,7 @@ func (x *term) equal(y *term) bool { case x.typ == nil || y.typ == nil: return x.typ == y.typ } - // ∅ ⊂ x, y ⊂ ⊤ + // ∅ ⊂ x, y ⊂ 𝓤 return x.tilde == y.tilde && Identical(x.typ, y.typ) } @@ -57,11 +54,11 @@ func (x *term) union(y *term) (_, _ *term) { case y == nil: return x, nil // x ∪ ∅ == x case x.typ == nil: - return x, nil // ⊤ ∪ y == ⊤ + return x, nil // 𝓤 ∪ y == 𝓤 case y.typ == nil: - return y, nil // x ∪ ⊤ == ⊤ + return y, nil // x ∪ 𝓤 == 𝓤 } - // ∅ ⊂ x, y ⊂ ⊤ + // ∅ ⊂ x, y ⊂ 𝓤 if x.disjoint(y) { return x, y // x ∪ y == (x, y) if x ∩ y == ∅ @@ -85,11 +82,11 @@ func (x *term) intersect(y *term) *term { case x == nil || y == nil: return nil // ∅ ∩ y == ∅ and ∩ ∅ == ∅ case x.typ == nil: - return y // ⊤ ∩ y == y + return y // 𝓤 ∩ y == y case y.typ == nil: - return x // x ∩ ⊤ == x + return x // x ∩ 𝓤 == x } - // ∅ ⊂ x, y ⊂ ⊤ + // ∅ ⊂ x, y ⊂ 𝓤 if x.disjoint(y) { return nil // x ∩ y == ∅ if x ∩ y == ∅ @@ -113,9 +110,9 @@ func (x *term) includes(t Type) bool { case x == nil: return false // t ∈ ∅ == false case x.typ == nil: - return true // t ∈ ⊤ == true + return true // t ∈ 𝓤 == true } - // ∅ ⊂ x ⊂ ⊤ + // ∅ ⊂ x ⊂ 𝓤 u := t if x.tilde { @@ -133,11 +130,11 @@ func (x *term) subsetOf(y *term) bool { case y == nil: return false // x ⊆ ∅ == false since x != ∅ case y.typ == nil: - return true // x ⊆ ⊤ == true + return true // x ⊆ 𝓤 == true case x.typ == nil: - return false // ⊤ ⊆ y == false since y != ⊤ + return false // 𝓤 ⊆ y == false since y != 𝓤 } - // ∅ ⊂ x, y ⊂ ⊤ + // ∅ ⊂ x, y ⊂ 𝓤 if x.disjoint(y) { return false // x ⊆ y == false if x ∩ y == ∅ diff --git a/src/cmd/compile/internal/types2/typeterm_test.go b/src/cmd/compile/internal/types2/typeterm_test.go index cc4e30d9893..a8cc362f569 100644 --- a/src/cmd/compile/internal/types2/typeterm_test.go +++ b/src/cmd/compile/internal/types2/typeterm_test.go @@ -11,7 +11,7 @@ import ( var testTerms = map[string]*term{ "∅": nil, - "⊤": {}, + "𝓤": {}, "int": {false, Typ[Int]}, "~int": {true, Typ[Int]}, "string": {false, Typ[String]}, @@ -46,14 +46,14 @@ func testTerm(name string) *term { func TestTermEqual(t *testing.T) { for _, test := range []string{ "∅ ∅ T", - "⊤ ⊤ T", + "𝓤 𝓤 T", "int int T", "~int ~int T", - "∅ ⊤ F", + "∅ 𝓤 F", "∅ int F", "∅ ~int F", - "⊤ int F", - "⊤ ~int F", + "𝓤 int F", + "𝓤 ~int F", "int ~int F", } { args := split(test, 3) @@ -74,12 +74,12 @@ func TestTermEqual(t *testing.T) { func TestTermUnion(t *testing.T) { for _, test := range []string{ "∅ ∅ ∅ ∅", - "∅ ⊤ ⊤ ∅", + "∅ 𝓤 𝓤 ∅", "∅ int int ∅", "∅ ~int ~int ∅", - "⊤ ⊤ ⊤ ∅", - "⊤ int ⊤ ∅", - "⊤ ~int ⊤ ∅", + "𝓤 𝓤 𝓤 ∅", + "𝓤 int 𝓤 ∅", + "𝓤 ~int 𝓤 ∅", "int int int ∅", "int ~int ~int ∅", "int string int string", @@ -87,11 +87,11 @@ func TestTermUnion(t *testing.T) { "~int ~string ~int ~string", // union is symmetric, but the result order isn't - repeat symmetric cases explictly - "⊤ ∅ ⊤ ∅", + "𝓤 ∅ 𝓤 ∅", "int ∅ int ∅", "~int ∅ ~int ∅", - "int ⊤ ⊤ ∅", - "~int ⊤ ⊤ ∅", + "int 𝓤 𝓤 ∅", + "~int 𝓤 𝓤 ∅", "~int int ~int ∅", "string int string int", "~string int ~string int", @@ -111,12 +111,12 @@ func TestTermUnion(t *testing.T) { func TestTermIntersection(t *testing.T) { for _, test := range []string{ "∅ ∅ ∅", - "∅ ⊤ ∅", + "∅ 𝓤 ∅", "∅ int ∅", "∅ ~int ∅", - "⊤ ⊤ ⊤", - "⊤ int int", - "⊤ ~int ~int", + "𝓤 𝓤 𝓤", + "𝓤 int int", + "𝓤 ~int ~int", "int int int", "int ~int int", "int string ∅", @@ -141,7 +141,7 @@ func TestTermIntersection(t *testing.T) { func TestTermIncludes(t *testing.T) { for _, test := range []string{ "∅ int F", - "⊤ int T", + "𝓤 int T", "int int T", "~int int T", "string int F", @@ -160,14 +160,14 @@ func TestTermIncludes(t *testing.T) { func TestTermSubsetOf(t *testing.T) { for _, test := range []string{ "∅ ∅ T", - "⊤ ⊤ T", + "𝓤 𝓤 T", "int int T", "~int ~int T", - "∅ ⊤ T", + "∅ 𝓤 T", "∅ int T", "∅ ~int T", - "⊤ int F", - "⊤ ~int F", + "𝓤 int F", + "𝓤 ~int F", "int ~int T", } { args := split(test, 3) diff --git a/src/cmd/compile/internal/types2/universe.go b/src/cmd/compile/internal/types2/universe.go index 55bf0982b30..f14c0792229 100644 --- a/src/cmd/compile/internal/types2/universe.go +++ b/src/cmd/compile/internal/types2/universe.go @@ -99,7 +99,7 @@ func defPredeclaredTypes() { { obj := NewTypeName(nopos, nil, "comparable", nil) obj.setColor(black) - ityp := &Interface{obj, nil, nil, nil, true, &TypeSet{true, nil, topTermlist}} + ityp := &Interface{obj, nil, nil, nil, true, &TypeSet{true, nil, allTermlist}} NewNamed(obj, ityp, nil) def(obj) } From 93285c89d1146e2698d2b8e5bf45279961f5026e Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 4 Aug 2021 16:52:25 -0700 Subject: [PATCH 874/940] [dev.typeparams] cmd/compile/internal/types2: fix range over exprs of type parameter type For range expressions of type parameter type, the structural type of the type parameter's constraint determines the range operation. While at it, rename implicitArrayDeref to arrayPtrDeref. Change-Id: Ib631a8a14e717498e5264944f659309df1f68cc2 Reviewed-on: https://go-review.googlesource.com/c/go/+/339897 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/builtins.go | 9 +- src/cmd/compile/internal/types2/stmt.go | 37 +---- .../types2/testdata/check/typeparams.go2 | 137 +++++++++++++----- 3 files changed, 112 insertions(+), 71 deletions(-) diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index c022e79c972..e9df605fd12 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -144,7 +144,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( mode := invalid var typ Type var val constant.Value - switch typ = implicitArrayDeref(under(x.typ)); t := typ.(type) { + switch typ = arrayPtrDeref(under(x.typ)); t := typ.(type) { case *Basic: if isString(t) && id == _Len { if x.mode == constant_ { @@ -180,7 +180,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( case *TypeParam: if t.underIs(func(t Type) bool { - switch t := implicitArrayDeref(t).(type) { + switch t := arrayPtrDeref(t).(type) { case *Basic: if isString(t) && id == _Len { return true @@ -862,10 +862,9 @@ func makeSig(res Type, args ...Type) *Signature { return &Signature{params: params, results: result} } -// implicitArrayDeref returns A if typ is of the form *A and A is an array; +// arrayPtrDeref returns A if typ is of the form *A and A is an array; // otherwise it returns typ. -// -func implicitArrayDeref(typ Type) Type { +func arrayPtrDeref(typ Type) Type { if p, ok := typ.(*Pointer); ok { if a := asArray(p.base); a != nil { return a diff --git a/src/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go index ad8efa91f86..7865c2d4f45 100644 --- a/src/cmd/compile/internal/types2/stmt.go +++ b/src/cmd/compile/internal/types2/stmt.go @@ -789,9 +789,9 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s // determine key/value types var key, val Type if x.mode != invalid { + // Ranging over a type parameter is permitted if it has a structural type. typ := optype(x.typ) if _, ok := typ.(*Chan); ok && sValue != nil { - // TODO(gri) this also needs to happen for channels in generic variables check.softErrorf(sValue, "range over %s permits only one iteration variable", &x) // ok to continue } @@ -900,7 +900,7 @@ func isVarName(x syntax.Expr) bool { // variables are used or present; this matters if we range over a generic // type where not all keys or values are of the same type. func rangeKeyVal(typ Type, wantKey, wantVal bool) (Type, Type, string) { - switch typ := typ.(type) { + switch typ := arrayPtrDeref(typ).(type) { case *Basic: if isString(typ) { return Typ[Int], universeRune, "" // use 'rune' name @@ -909,10 +909,6 @@ func rangeKeyVal(typ Type, wantKey, wantVal bool) (Type, Type, string) { return Typ[Int], typ.elem, "" case *Slice: return Typ[Int], typ.elem, "" - case *Pointer: - if typ := asArray(typ.base); typ != nil { - return Typ[Int], typ.elem, "" - } case *Map: return typ.key, typ.elem, "" case *Chan: @@ -921,32 +917,9 @@ func rangeKeyVal(typ Type, wantKey, wantVal bool) (Type, Type, string) { msg = "receive from send-only channel" } return typ.elem, Typ[Invalid], msg - case *TypeParam: - first := true - var key, val Type - var msg string - typ.underIs(func(t Type) bool { - k, v, m := rangeKeyVal(t, wantKey, wantVal) - if k == nil || m != "" { - key, val, msg = k, v, m - return false - } - if first { - key, val, msg = k, v, m - first = false - return true - } - if wantKey && !Identical(key, k) { - key, val, msg = nil, nil, "all possible values must have the same key type" - return false - } - if wantVal && !Identical(val, v) { - key, val, msg = nil, nil, "all possible values must have the same element type" - return false - } - return true - }) - return key, val, msg + case *top: + // we have a type parameter with no structural type + return nil, nil, "no structural type" } return nil, nil, "" } diff --git a/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 b/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 index 7392b88555d..ba8e8373464 100644 --- a/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 @@ -149,40 +149,109 @@ func _[T interface{}](x T) { for range x /* ERROR cannot range */ {} } -// Disabled for now until we have clarified semantics of range. -// TODO(gri) fix this -// -// func _[T interface{ ~string | ~[]string }](x T) { -// for range x {} -// for i := range x { _ = i } -// for i, _ := range x { _ = i } -// for i, e := range x /* ERROR must have the same element type */ { _ = i } -// for _, e := range x /* ERROR must have the same element type */ {} -// var e rune -// _ = e -// for _, (e) = range x /* ERROR must have the same element type */ {} -// } -// -// -// func _[T interface{ ~string | ~[]rune | ~map[int]rune }](x T) { -// for _, e := range x { _ = e } -// for i, e := range x { _ = i; _ = e } -// } -// -// func _[T interface{ ~string | ~[]rune | ~map[string]rune }](x T) { -// for _, e := range x { _ = e } -// for i, e := range x /* ERROR must have the same key type */ { _ = e } -// } -// -// func _[T interface{ ~string | ~chan int }](x T) { -// for range x {} -// for i := range x { _ = i } -// for i, _ := range x { _ = i } // TODO(gri) should get an error here: channels only return one value -// } -// -// func _[T interface{ ~string | ~chan<-int }](x T) { -// for i := range x /* ERROR send-only channel */ { _ = i } -// } +type myString string + +func _[ + B1 interface{ string }, + B2 interface{ string | myString }, + + C1 interface{ chan int }, + C2 interface{ chan int | <-chan int }, + C3 interface{ chan<- int }, + + S1 interface{ []int }, + S2 interface{ []int | [10]int }, + + A1 interface{ [10]int }, + A2 interface{ [10]int | []int }, + + P1 interface{ *[10]int }, + P2 interface{ *[10]int | *[]int }, + + M1 interface{ map[string]int }, + M2 interface{ map[string]int | map[string]string }, +]() { + var b0 string + for range b0 {} + for _ = range b0 {} + for _, _ = range b0 {} + + var b1 B1 + for range b1 {} + for _ = range b1 {} + for _, _ = range b1 {} + + var b2 B2 + for range b2 /* ERROR cannot range over b2 .* no structural type */ {} + + var c0 chan int + for range c0 {} + for _ = range c0 {} + for _, _ /* ERROR permits only one iteration variable */ = range c0 {} + + var c1 C1 + for range c1 {} + for _ = range c1 {} + for _, _ /* ERROR permits only one iteration variable */ = range c1 {} + + var c2 C2 + for range c2 /* ERROR cannot range over c2 .* no structural type */ {} + + var c3 C3 + for range c3 /* ERROR receive from send-only channel */ {} + + var s0 []int + for range s0 {} + for _ = range s0 {} + for _, _ = range s0 {} + + var s1 S1 + for range s1 {} + for _ = range s1 {} + for _, _ = range s1 {} + + var s2 S2 + for range s2 /* ERROR cannot range over s2 .* no structural type */ {} + + var a0 []int + for range a0 {} + for _ = range a0 {} + for _, _ = range a0 {} + + var a1 A1 + for range a1 {} + for _ = range a1 {} + for _, _ = range a1 {} + + var a2 A2 + for range a2 /* ERROR cannot range over a2 .* no structural type */ {} + + var p0 *[10]int + for range p0 {} + for _ = range p0 {} + for _, _ = range p0 {} + + var p1 P1 + for range p1 {} + for _ = range p1 {} + for _, _ = range p1 {} + + var p2 P2 + for range p2 /* ERROR cannot range over p2 .* no structural type */ {} + + var m0 map[string]int + for range m0 {} + for _ = range m0 {} + for _, _ = range m0 {} + + var m1 M1 + for range m1 {} + for _ = range m1 {} + for _, _ = range m1 {} + + var m2 M2 + for range m2 /* ERROR cannot range over m2 .* no structural type */ {} +} // type inference checks From 0811108670a178eb3d1403da81bfed20a7ffe1d7 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 4 Aug 2021 18:01:41 -0700 Subject: [PATCH 875/940] [dev.typeparams] cmd/compile/internal/types2: fix make with type parameter argument For make with a type parameter argument, the structural type of the type parameter's constraint determines what make is making. Change-Id: I3b48f8ce3236b7624e0638b5f5be208c5915c987 Reviewed-on: https://go-review.googlesource.com/c/go/+/339899 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/builtins.go | 42 ++++------- .../types2/testdata/check/builtins.go2 | 71 ++++++++----------- test/typeparam/builtins.go | 71 +++++++++---------- 3 files changed, 76 insertions(+), 108 deletions(-) diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index e9df605fd12..184cd027cb4 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -472,39 +472,21 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( return } - min, max := -1, 10 - var valid func(t Type) bool - valid = func(t Type) bool { - var m int - switch t := under(t).(type) { - case *Slice: - m = 2 - case *Map, *Chan: - m = 1 - case *TypeParam: - return t.underIs(valid) - default: - return false - } - if m > min { - min = m - } - if m+1 < max { - max = m + 1 - } - return true - } - - if !valid(T) { + var min int // minimum number of arguments + switch optype(T).(type) { + case *Slice: + min = 2 + case *Map, *Chan: + min = 1 + case *top: + check.errorf(arg0, invalidArg+"cannot make %s; type parameter has no structural type", arg0) + return + default: check.errorf(arg0, invalidArg+"cannot make %s; type must be slice, map, or channel", arg0) return } - if nargs < min || max < nargs { - if min == max { - check.errorf(call, "%v expects %d arguments; found %d", call, min, nargs) - } else { - check.errorf(call, "%v expects %d or %d arguments; found %d", call, min, max, nargs) - } + if nargs < min || min+1 < nargs { + check.errorf(call, invalidOp+"%v expects %d or %d arguments; found %d", call, min, min+1, nargs) return } diff --git a/src/cmd/compile/internal/types2/testdata/check/builtins.go2 b/src/cmd/compile/internal/types2/testdata/check/builtins.go2 index 3881090603e..0cfea93bf6d 100644 --- a/src/cmd/compile/internal/types2/testdata/check/builtins.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/builtins.go2 @@ -84,50 +84,41 @@ func _[T M4[K, V], K comparable, V any](m T) { // make -type Bmc interface { - ~map[rune]string | ~chan int -} +func _[ + S1 interface{ []int }, + S2 interface{ []int | chan int }, -type Bms interface { - ~map[string]int | ~[]int -} + M1 interface{ map[string]int }, + M2 interface{ map[string]int | chan int }, -type Bcs interface { - ~chan bool | ~[]float64 -} + C1 interface{ chan int }, + C2 interface{ chan int | chan string }, +]() { + type S0 []int + _ = make([]int, 10) + _ = make(S0, 10) + _ = make(S1, 10) + _ = make /* ERROR not enough arguments */ () + _ = make /* ERROR expects 2 or 3 arguments */ (S1) + _ = make(S1, 10, 20) + _ = make /* ERROR expects 2 or 3 arguments */ (S1, 10, 20, 30) + _ = make(S2 /* ERROR cannot make .* no structural type */ , 10) -type Bss interface { - ~[]int | ~[]string -} + type M0 map[string]int + _ = make(map[string]int) + _ = make(M0) + _ = make(M1) + _ = make(M1, 10) + _ = make/* ERROR expects 1 or 2 arguments */(M1, 10, 20) + _ = make(M2 /* ERROR cannot make .* no structural type */ ) -func _[T any]() { - _ = make(T /* ERROR invalid argument */) - _ = make(T /* ERROR invalid argument */, 10) - _ = make(T /* ERROR invalid argument */, 10, 20) -} - -func _[T Bmc]() { - _ = make(T) - _ = make(T, 10) - _ = make /* ERROR expects 1 or 2 arguments */ (T, 10, 20) -} - -func _[T Bms]() { - _ = make /* ERROR expects 2 arguments */ (T) - _ = make(T, 10) - _ = make /* ERROR expects 2 arguments */ (T, 10, 20) -} - -func _[T Bcs]() { - _ = make /* ERROR expects 2 arguments */ (T) - _ = make(T, 10) - _ = make /* ERROR expects 2 arguments */ (T, 10, 20) -} - -func _[T Bss]() { - _ = make /* ERROR expects 2 or 3 arguments */ (T) - _ = make(T, 10) - _ = make(T, 10, 20) + type C0 chan int + _ = make(chan int) + _ = make(C0) + _ = make(C1) + _ = make(C1, 10) + _ = make/* ERROR expects 1 or 2 arguments */(C1, 10, 20) + _ = make(C2 /* ERROR cannot make .* no structural type */ ) } // unsafe.Alignof diff --git a/test/typeparam/builtins.go b/test/typeparam/builtins.go index 819588b07d0..844cdae8ab3 100644 --- a/test/typeparam/builtins.go +++ b/test/typeparam/builtins.go @@ -19,19 +19,19 @@ type C3 interface{ chan int | chan float32 } type C4 interface{ chan int | chan<- int } type C5[T any] interface{ ~chan T | chan<- T } -func _[T C1](ch T) { +func f1[T C1](ch T) { close(ch) } -func _[T C3](ch T) { +func f2[T C3](ch T) { close(ch) } -func _[T C4](ch T) { +func f3[T C4](ch T) { close(ch) } -func _[T C5[X], X any](ch T) { +func f4[T C5[X], X any](ch T) { close(ch) } @@ -45,61 +45,56 @@ type M2 interface { type M3 interface{ map[string]int | map[rune]int } type M4[K comparable, V any] interface{ map[K]V | map[rune]V } -func _[T M1](m T) { +func g1[T M1](m T) { delete(m, "foo") } -func _[T M2](m T) { +func g2[T M2](m T) { delete(m, "foo") } -func _[T M4[rune, V], V any](m T) { +func g3[T M4[rune, V], V any](m T) { delete(m, 'k') } // make -type Bmc interface { - ~map[rune]string | ~chan int -} +func m1[ + S1 interface{ []int }, + S2 interface{ []int | chan int }, -type Bms interface { - ~map[string]int | ~[]int -} + M1 interface{ map[string]int }, + M2 interface{ map[string]int | chan int }, -type Bcs interface { - ~chan bool | ~[]float64 -} + C1 interface{ chan int }, + C2 interface{ chan int | chan string }, +]() { + type S0 []int + _ = make([]int, 10) + _ = make(S0, 10) + _ = make(S1, 10) + _ = make(S1, 10, 20) -type Bss interface { - ~[]int | ~[]string -} + type M0 map[string]int + _ = make(map[string]int) + _ = make(M0) + _ = make(M1) + _ = make(M1, 10) -func _[T Bmc]() { - _ = make(T) - _ = make(T, 10) -} - -func _[T Bms]() { - _ = make(T, 10) -} - -func _[T Bcs]() { - _ = make(T, 10) -} - -func _[T Bss]() { - _ = make(T, 10) - _ = make(T, 10, 20) + type C0 chan int + _ = make(chan int) + _ = make(C0) + _ = make(C1) + _ = make(C1, 10) } // len/cap type Slice[T any] interface { - type []T + []T } -func _[T any, S Slice[T]]() { +func c1[T any, S Slice[T]]() { x := make(S, 5, 10) _ = len(x) _ = cap(x) @@ -107,7 +102,7 @@ func _[T any, S Slice[T]]() { // append -func _[T any, S Slice[T]]() { +func a1[T any, S Slice[T]]() { x := make(S, 5) y := make(S, 2) var z T From c3b57af8bc0fb4fe9b30e42891e9aff54c0c7a82 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 4 Aug 2021 21:10:31 -0700 Subject: [PATCH 876/940] [dev.typeparams] cmd/compile/internal/types2: minor cleanup of writeTParamList Change-Id: Iaa58b17ad65e93548bb3da8231e0cb6da0c48105 Reviewed-on: https://go-review.googlesource.com/c/go/+/339903 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/infer.go | 2 +- src/cmd/compile/internal/types2/typestring.go | 22 +++++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/cmd/compile/internal/types2/infer.go b/src/cmd/compile/internal/types2/infer.go index a3772aa7131..ff4bb3ea175 100644 --- a/src/cmd/compile/internal/types2/infer.go +++ b/src/cmd/compile/internal/types2/infer.go @@ -83,7 +83,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeName, targs []Type, p // Substitute type arguments for their respective type parameters in params, // if any. Note that nil targs entries are ignored by check.subst. - // TODO(gri) Can we avoid this (we're setting known type argumemts below, + // TODO(gri) Can we avoid this (we're setting known type arguments below, // but that doesn't impact the isParameterized check for now). if params.Len() > 0 { smap := makeSubstMap(tparams, targs) diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go index b3675424a5b..ead17ba2f3c 100644 --- a/src/cmd/compile/internal/types2/typestring.go +++ b/src/cmd/compile/internal/types2/typestring.go @@ -246,23 +246,27 @@ func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited buf.WriteString("[") var prev Type for i, p := range list { - // TODO(gri) support 'any' sugar here. - var b Type = &emptyInterface - if t, _ := p.typ.(*TypeParam); t != nil && t.bound != nil { - b = t.bound + // Determine the type parameter and its constraint. + // list is expected to hold type parameter names, + // but don't crash if that's not the case. + tpar, _ := p.typ.(*TypeParam) + var bound Type + if tpar != nil { + bound = tpar.bound // should not be nil but we want to see it if it is } + if i > 0 { - if b != prev { - // type bound changed - write previous one before advancing + if bound != prev { + // bound changed - write previous one before advancing buf.WriteByte(' ') writeType(buf, prev, qf, visited) } buf.WriteString(", ") } - prev = b + prev = bound - if t, _ := p.typ.(*TypeParam); t != nil { - writeType(buf, t, qf, visited) + if tpar != nil { + writeType(buf, tpar, qf, visited) } else { buf.WriteString(p.name) } From 3a9fd99849bbd9eab7e4e14a4dda95239c41ab83 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 4 Aug 2021 21:17:54 -0700 Subject: [PATCH 877/940] [dev.typeparams] cmd/compile/internal/syntax: cleanup panic calls End-users are not expected to deal with the details of panics, so providing extra information such as an "internal error" prefix is not helpful. Matches the types2 changes made in https://golang.org/cl/339969 . Change-Id: Icb34a9daab981a84f41f8ae7ae5dc1b85b2d2c81 Reviewed-on: https://go-review.googlesource.com/c/go/+/339904 Trust: Robert Griesemer Run-TryBot: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/syntax/parser.go | 2 +- src/cmd/compile/internal/syntax/positions.go | 4 ++-- src/cmd/compile/internal/syntax/walk.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go index 503dea7fae6..acffd848855 100644 --- a/src/cmd/compile/internal/syntax/parser.go +++ b/src/cmd/compile/internal/syntax/parser.go @@ -604,7 +604,7 @@ func (p *parser) typeDecl(group *Group) Decl { } else { // x is the array length expression if debug && x == nil { - panic("internal error: nil expression") + panic("length expression is nil") } d.Type = p.arrayType(pos, x) } diff --git a/src/cmd/compile/internal/syntax/positions.go b/src/cmd/compile/internal/syntax/positions.go index b00f86c67cd..93596559a02 100644 --- a/src/cmd/compile/internal/syntax/positions.go +++ b/src/cmd/compile/internal/syntax/positions.go @@ -12,7 +12,7 @@ func StartPos(n Node) Pos { for m := n; ; { switch n := m.(type) { case nil: - panic("internal error: nil") + panic("nil node") // packages case *File: @@ -124,7 +124,7 @@ func EndPos(n Node) Pos { for m := n; ; { switch n := m.(type) { case nil: - panic("internal error: nil") + panic("nil node") // packages case *File: diff --git a/src/cmd/compile/internal/syntax/walk.go b/src/cmd/compile/internal/syntax/walk.go index ef213daf7d1..b0258442048 100644 --- a/src/cmd/compile/internal/syntax/walk.go +++ b/src/cmd/compile/internal/syntax/walk.go @@ -70,7 +70,7 @@ type walker struct { func (w walker) node(n Node) { if n == nil { - panic("invalid syntax tree: nil node") + panic("nil node") } w.v = w.v.Visit(n) From 09d82689ed899d601a9f4b5615d67025dcdb958b Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 4 Aug 2021 22:22:54 -0700 Subject: [PATCH 878/940] [dev.typeparams] cmd/compile/internal/types2: add defined type to term/termlist tests Follow-up on https://golang.org/cl/339596 . Change-Id: Ifa249379df083f80176b9f99900be0bf12483f41 Reviewed-on: https://go-review.googlesource.com/c/go/+/339905 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- .../compile/internal/types2/termlist_test.go | 53 +++++++++++++++---- src/cmd/compile/internal/types2/typeterm.go | 3 ++ .../compile/internal/types2/typeterm_test.go | 36 ++++++++++++- 3 files changed, 82 insertions(+), 10 deletions(-) diff --git a/src/cmd/compile/internal/types2/termlist_test.go b/src/cmd/compile/internal/types2/termlist_test.go index 706b4c97565..2f3772ddeb8 100644 --- a/src/cmd/compile/internal/types2/termlist_test.go +++ b/src/cmd/compile/internal/types2/termlist_test.go @@ -32,9 +32,11 @@ func TestTermlistString(t *testing.T) { "𝓤", "int", "~int", + "myInt", "∅ ∪ ∅", "𝓤 ∪ 𝓤", "∅ ∪ 𝓤 ∪ int", + "∅ ∪ 𝓤 ∪ int ∪ myInt", } { if got := maketl(want).String(); got != want { t.Errorf("(%v).String() == %v", want, got) @@ -44,11 +46,13 @@ func TestTermlistString(t *testing.T) { func TestTermlistIsEmpty(t *testing.T) { for test, want := range map[string]bool{ - "∅": true, - "∅ ∪ ∅": true, - "∅ ∪ ∅ ∪ 𝓤": false, - "𝓤": false, - "𝓤 ∪ int": false, + "∅": true, + "∅ ∪ ∅": true, + "∅ ∪ ∅ ∪ 𝓤": false, + "∅ ∪ ∅ ∪ myInt": false, + "𝓤": false, + "𝓤 ∪ int": false, + "𝓤 ∪ myInt ∪ ∅": false, } { xl := maketl(test) got := xl.isEmpty() @@ -63,9 +67,11 @@ func TestTermlistIsAll(t *testing.T) { "∅": false, "∅ ∪ ∅": false, "int ∪ ~string": false, + "~int ∪ myInt": false, "∅ ∪ ∅ ∪ 𝓤": true, "𝓤": true, "𝓤 ∪ int": true, + "myInt ∪ 𝓤": true, } { xl := maketl(test) got := xl.isAll() @@ -82,10 +88,15 @@ func TestTermlistNorm(t *testing.T) { {"∅", "∅"}, {"∅ ∪ ∅", "∅"}, {"∅ ∪ int", "int"}, + {"∅ ∪ myInt", "myInt"}, {"𝓤 ∪ int", "𝓤"}, + {"𝓤 ∪ myInt", "𝓤"}, + {"int ∪ myInt", "int ∪ myInt"}, {"~int ∪ int", "~int"}, + {"~int ∪ myInt", "~int"}, {"int ∪ ~string ∪ int", "int ∪ ~string"}, {"~int ∪ string ∪ 𝓤 ∪ ~string ∪ int", "𝓤"}, + {"~int ∪ string ∪ myInt ∪ ~string ∪ int", "~int ∪ ~string"}, } { xl := maketl(test.xl) got := maketl(test.xl).norm() @@ -108,8 +119,10 @@ func TestTermlistStructuralType(t *testing.T) { "∅": "nil", "𝓤": "nil", "int": "int", + "myInt": "myInt", "~int": "int", "~int ∪ string": "nil", + "~int ∪ myInt": "int", "∅ ∪ int": "int", "∅ ∪ ~int": "int", "∅ ∪ ~int ∪ string": "nil", @@ -133,10 +146,14 @@ func TestTermlistUnion(t *testing.T) { {"𝓤", "~int", "𝓤"}, {"int", "~int", "~int"}, {"int", "string", "int ∪ string"}, + {"int", "myInt", "int ∪ myInt"}, + {"~int", "myInt", "~int"}, {"int ∪ string", "~string", "int ∪ ~string"}, {"~int ∪ string", "~string ∪ int", "~int ∪ ~string"}, {"~int ∪ string ∪ ∅", "~string ∪ int", "~int ∪ ~string"}, + {"~int ∪ myInt ∪ ∅", "~string ∪ int", "~int ∪ ~string"}, {"~int ∪ string ∪ 𝓤", "~string ∪ int", "𝓤"}, + {"~int ∪ string ∪ myInt", "~string ∪ int", "~int ∪ ~string"}, } { xl := maketl(test.xl) yl := maketl(test.yl) @@ -155,13 +172,19 @@ func TestTermlistIntersect(t *testing.T) { {"∅", "∅", "∅"}, {"∅", "𝓤", "∅"}, {"∅", "int", "∅"}, + {"∅", "myInt", "∅"}, {"𝓤", "~int", "~int"}, + {"𝓤", "myInt", "myInt"}, {"int", "~int", "int"}, {"int", "string", "∅"}, + {"int", "myInt", "∅"}, + {"~int", "myInt", "myInt"}, {"int ∪ string", "~string", "string"}, {"~int ∪ string", "~string ∪ int", "int ∪ string"}, {"~int ∪ string ∪ ∅", "~string ∪ int", "int ∪ string"}, + {"~int ∪ myInt ∪ ∅", "~string ∪ int", "int"}, {"~int ∪ string ∪ 𝓤", "~string ∪ int", "int ∪ ~string"}, + {"~int ∪ string ∪ myInt", "~string ∪ int", "int ∪ string"}, } { xl := maketl(test.xl) yl := maketl(test.yl) @@ -182,7 +205,9 @@ func TestTermlistEqual(t *testing.T) { {"𝓤", "𝓤", true}, {"𝓤 ∪ int", "𝓤", true}, {"𝓤 ∪ int", "string ∪ 𝓤", true}, + {"𝓤 ∪ myInt", "string ∪ 𝓤", true}, {"int ∪ ~string", "string ∪ int", false}, + {"~int ∪ string", "string ∪ myInt", false}, {"int ∪ ~string ∪ ∅", "string ∪ int ∪ ~string", true}, } { xl := maketl(test.xl) @@ -204,10 +229,12 @@ func TestTermlistIncludes(t *testing.T) { {"~int", "int", true}, {"int", "string", false}, {"~int", "string", false}, + {"~int", "myInt", true}, {"int ∪ string", "string", true}, {"~int ∪ string", "int", true}, - {"~int ∪ string ∪ ∅", "string", true}, - {"~string ∪ ∅ ∪ 𝓤", "int", true}, + {"~int ∪ string", "myInt", true}, + {"~int ∪ myInt ∪ ∅", "myInt", true}, + {"myInt ∪ ∅ ∪ 𝓤", "int", true}, } { xl := maketl(test.xl) yl := testTerm(test.typ).typ @@ -230,16 +257,20 @@ func TestTermlistSupersetOf(t *testing.T) { {"𝓤", "𝓤", true}, {"𝓤", "int", true}, {"𝓤", "~int", true}, + {"𝓤", "myInt", true}, {"~int", "int", true}, {"~int", "~int", true}, + {"~int", "myInt", true}, {"int", "~int", false}, + {"myInt", "~int", false}, {"int", "string", false}, {"~int", "string", false}, {"int ∪ string", "string", true}, {"int ∪ string", "~string", false}, {"~int ∪ string", "int", true}, + {"~int ∪ string", "myInt", true}, {"~int ∪ string ∪ ∅", "string", true}, - {"~string ∪ ∅ ∪ 𝓤", "int", true}, + {"~string ∪ ∅ ∪ 𝓤", "myInt", true}, } { xl := maketl(test.xl) y := testTerm(test.typ) @@ -261,12 +292,16 @@ func TestTermlistSubsetOf(t *testing.T) { {"𝓤", "𝓤", true}, {"int", "int ∪ string", true}, {"~int", "int ∪ string", false}, + {"~int", "myInt ∪ string", false}, + {"myInt", "~int ∪ string", true}, {"~int", "string ∪ string ∪ int ∪ ~int", true}, + {"myInt", "string ∪ string ∪ ~int", true}, {"int ∪ string", "string", false}, {"int ∪ string", "string ∪ int", true}, {"int ∪ ~string", "string ∪ int", false}, - {"int ∪ ~string", "string ∪ int ∪ 𝓤", true}, + {"myInt ∪ ~string", "string ∪ int ∪ 𝓤", true}, {"int ∪ ~string", "string ∪ int ∪ ∅ ∪ string", false}, + {"int ∪ myInt", "string ∪ ~int ∪ ∅ ∪ string", true}, } { xl := maketl(test.xl) yl := maketl(test.yl) diff --git a/src/cmd/compile/internal/types2/typeterm.go b/src/cmd/compile/internal/types2/typeterm.go index 8edbefa579e..1d7223f13c4 100644 --- a/src/cmd/compile/internal/types2/typeterm.go +++ b/src/cmd/compile/internal/types2/typeterm.go @@ -151,6 +151,9 @@ func (x *term) subsetOf(y *term) bool { // disjoint reports whether x ∩ y == ∅. // x.typ and y.typ must not be nil. func (x *term) disjoint(y *term) bool { + if debug && (x.typ == nil || y.typ == nil) { + panic("invalid argument(s)") + } ux := x.typ if y.tilde { ux = under(ux) diff --git a/src/cmd/compile/internal/types2/typeterm_test.go b/src/cmd/compile/internal/types2/typeterm_test.go index a8cc362f569..5a5c1fa4477 100644 --- a/src/cmd/compile/internal/types2/typeterm_test.go +++ b/src/cmd/compile/internal/types2/typeterm_test.go @@ -9,6 +9,11 @@ import ( "testing" ) +var myInt = func() Type { + tname := NewTypeName(nopos, nil, "myInt", nil) + return NewNamed(tname, Typ[Int], nil) +}() + var testTerms = map[string]*term{ "∅": nil, "𝓤": {}, @@ -16,7 +21,7 @@ var testTerms = map[string]*term{ "~int": {true, Typ[Int]}, "string": {false, Typ[String]}, "~string": {true, Typ[String]}, - // TODO(gri) add a defined type + "myInt": {false, myInt}, } func TestTermString(t *testing.T) { @@ -49,12 +54,16 @@ func TestTermEqual(t *testing.T) { "𝓤 𝓤 T", "int int T", "~int ~int T", + "myInt myInt T", "∅ 𝓤 F", "∅ int F", "∅ ~int F", "𝓤 int F", "𝓤 ~int F", + "𝓤 myInt F", "int ~int F", + "int myInt F", + "~int myInt F", } { args := split(test, 3) x := testTerm(args[0]) @@ -77,25 +86,33 @@ func TestTermUnion(t *testing.T) { "∅ 𝓤 𝓤 ∅", "∅ int int ∅", "∅ ~int ~int ∅", + "∅ myInt myInt ∅", "𝓤 𝓤 𝓤 ∅", "𝓤 int 𝓤 ∅", "𝓤 ~int 𝓤 ∅", + "𝓤 myInt 𝓤 ∅", "int int int ∅", "int ~int ~int ∅", "int string int string", "int ~string int ~string", + "int myInt int myInt", "~int ~string ~int ~string", + "~int myInt ~int ∅", // union is symmetric, but the result order isn't - repeat symmetric cases explictly "𝓤 ∅ 𝓤 ∅", "int ∅ int ∅", "~int ∅ ~int ∅", + "myInt ∅ myInt ∅", "int 𝓤 𝓤 ∅", "~int 𝓤 𝓤 ∅", + "myInt 𝓤 𝓤 ∅", "~int int ~int ∅", "string int string int", "~string int ~string int", + "myInt int myInt int", "~string ~int ~string ~int", + "myInt ~int ~int ∅", } { args := split(test, 4) x := testTerm(args[0]) @@ -114,14 +131,18 @@ func TestTermIntersection(t *testing.T) { "∅ 𝓤 ∅", "∅ int ∅", "∅ ~int ∅", + "∅ myInt ∅", "𝓤 𝓤 𝓤", "𝓤 int int", "𝓤 ~int ~int", + "𝓤 myInt myInt", "int int int", "int ~int int", "int string ∅", "int ~string ∅", + "int string ∅", "~int ~string ∅", + "~int myInt myInt", } { args := split(test, 3) x := testTerm(args[0]) @@ -144,8 +165,10 @@ func TestTermIncludes(t *testing.T) { "𝓤 int T", "int int T", "~int int T", + "~int myInt T", "string int F", "~string int F", + "myInt int F", } { args := split(test, 3) x := testTerm(args[0]) @@ -163,12 +186,19 @@ func TestTermSubsetOf(t *testing.T) { "𝓤 𝓤 T", "int int T", "~int ~int T", + "myInt myInt T", "∅ 𝓤 T", "∅ int T", "∅ ~int T", + "∅ myInt T", "𝓤 int F", "𝓤 ~int F", + "𝓤 myInt F", "int ~int T", + "int myInt F", + "~int myInt F", + "myInt int F", + "myInt ~int T", } { args := split(test, 3) x := testTerm(args[0]) @@ -187,7 +217,11 @@ func TestTermDisjoint(t *testing.T) { "int ~int F", "int string T", "int ~string T", + "int myInt T", "~int ~string T", + "~int myInt F", + "string myInt T", + "~string myInt T", } { args := split(test, 3) x := testTerm(args[0]) From 0d7dc417eaebd35249994bfd5cf211df9bf457c6 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 5 Aug 2021 13:24:15 -0700 Subject: [PATCH 879/940] [dev.typeparams] cmd/compile: change types2.Union API to accept a list of Terms Instead of providing a list of tildes and types, use a list of Terms to create a Union, with suitable accessors. Define the (exported) notion of a Term representing a union term. This simplified various uses and also will be easier to extend should we want to add more information to a Term in the future. Change-Id: I52fd73938bfa11bac60adbf10580b6d0680df4f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/340250 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/importer/iimport.go | 10 ++-- src/cmd/compile/internal/noder/reader2.go | 10 ++-- src/cmd/compile/internal/noder/types.go | 8 +-- src/cmd/compile/internal/noder/writer.go | 10 ++-- src/cmd/compile/internal/types2/builtins.go | 8 ++- src/cmd/compile/internal/types2/subst.go | 6 +-- src/cmd/compile/internal/types2/typeset.go | 2 +- src/cmd/compile/internal/types2/typestring.go | 2 +- src/cmd/compile/internal/types2/union.go | 49 ++++++++++--------- 9 files changed, 52 insertions(+), 53 deletions(-) diff --git a/src/cmd/compile/internal/importer/iimport.go b/src/cmd/compile/internal/importer/iimport.go index 3dd28033a1a..3aab32fc6bd 100644 --- a/src/cmd/compile/internal/importer/iimport.go +++ b/src/cmd/compile/internal/importer/iimport.go @@ -677,13 +677,13 @@ func (r *importReader) doType(base *types2.Named) types2.Type { errorf("unexpected instantiation type") } nt := int(r.uint64()) - terms := make([]types2.Type, nt) - tildes := make([]bool, nt) + terms := make([]*types2.Term, nt) for i := range terms { - terms[i] = r.typ() - tildes[i] = r.bool() + typ := r.typ() + tilde := r.bool() + terms[i] = types2.NewTerm(tilde, typ) } - return types2.NewUnion(terms, tildes) + return types2.NewUnion(terms) } } diff --git a/src/cmd/compile/internal/noder/reader2.go b/src/cmd/compile/internal/noder/reader2.go index d1839349002..0bea6675ea4 100644 --- a/src/cmd/compile/internal/noder/reader2.go +++ b/src/cmd/compile/internal/noder/reader2.go @@ -281,13 +281,13 @@ func (r *reader2) structType() *types2.Struct { } func (r *reader2) unionType() *types2.Union { - terms := make([]types2.Type, r.len()) - tildes := make([]bool, len(terms)) + terms := make([]*types2.Term, r.len()) for i := range terms { - terms[i] = r.typ() - tildes[i] = r.bool() + typ := r.typ() + tilde := r.bool() + terms[i] = types2.NewTerm(tilde, typ) } - return types2.NewUnion(terms, tildes) + return types2.NewUnion(terms) } func (r *reader2) interfaceType() *types2.Interface { diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go index 3f7280a823e..4e80b1a0ffe 100644 --- a/src/cmd/compile/internal/noder/types.go +++ b/src/cmd/compile/internal/noder/types.go @@ -232,13 +232,13 @@ func (g *irgen) typ0(typ types2.Type) *types.Type { return tp case *types2.Union: - nt := typ.NumTerms() + nt := typ.Len() tlist := make([]*types.Type, nt) tildes := make([]bool, nt) for i := range tlist { - term, tilde := typ.Term(i) - tlist[i] = g.typ1(term) - tildes[i] = tilde + t := typ.Term(i) + tlist[i] = g.typ1(t.Type()) + tildes[i] = t.Tilde() } return types.NewUnion(tlist, tildes) diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go index eb1db623b4a..8b65559d1ad 100644 --- a/src/cmd/compile/internal/noder/writer.go +++ b/src/cmd/compile/internal/noder/writer.go @@ -394,11 +394,11 @@ func (w *writer) structType(typ *types2.Struct) { } func (w *writer) unionType(typ *types2.Union) { - w.len(typ.NumTerms()) - for i := 0; i < typ.NumTerms(); i++ { - term, tilde := typ.Term(i) - w.typ(term) - w.bool(tilde) + w.len(typ.Len()) + for i := 0; i < typ.Len(); i++ { + t := typ.Term(i) + w.typ(t.Type()) + w.bool(t.Tilde()) } } diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index 184cd027cb4..eafe6e9eb82 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -797,12 +797,10 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { if tp := asTypeParam(x); tp != nil { // Test if t satisfies the requirements for the argument // type and collect possible result types at the same time. - var rtypes []Type - var tildes []bool + var terms []*Term if !tp.iface().typeSet().is(func(t *term) bool { if r := f(t.typ); r != nil { - rtypes = append(rtypes, r) - tildes = append(tildes, t.tilde) + terms = append(terms, NewTerm(t.tilde, r)) return true } return false @@ -819,7 +817,7 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { // type param is placed in the current package so export/import // works as expected. tpar := NewTypeName(nopos, check.pkg, "", nil) - ptyp := check.NewTypeParam(tpar, NewInterfaceType(nil, []Type{newUnion(rtypes, tildes)})) // assigns type to tpar as a side-effect + ptyp := check.NewTypeParam(tpar, NewInterfaceType(nil, []Type{NewUnion(terms)})) // assigns type to tpar as a side-effect ptyp.index = tp.index return ptyp diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index 6c5f7564912..26796fc604d 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -387,19 +387,19 @@ func (subst *subster) typeList(in []Type) (out []Type, copied bool) { return } -func (subst *subster) termlist(in []*term) (out []*term, copied bool) { +func (subst *subster) termlist(in []*Term) (out []*Term, copied bool) { out = in for i, t := range in { if u := subst.typ(t.typ); u != t.typ { if !copied { // first function that got substituted => allocate new out slice // and copy all functions - new := make([]*term, len(in)) + new := make([]*Term, len(in)) copy(new, out) out = new copied = true } - out[i] = &term{t.tilde, u} + out[i] = NewTerm(t.tilde, u) } } return diff --git a/src/cmd/compile/internal/types2/typeset.go b/src/cmd/compile/internal/types2/typeset.go index 83df51389b7..da364699ce5 100644 --- a/src/cmd/compile/internal/types2/typeset.go +++ b/src/cmd/compile/internal/types2/typeset.go @@ -359,7 +359,7 @@ func computeUnionTypeSet(check *Checker, pos syntax.Pos, utyp *Union) *TypeSet { // This case is handled during union parsing. unreachable() default: - terms = termlist{t} + terms = termlist{(*term)(t)} } // The type set of a union expression is the union // of the type sets of each term. diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go index ead17ba2f3c..cb7cf73a629 100644 --- a/src/cmd/compile/internal/types2/typestring.go +++ b/src/cmd/compile/internal/types2/typestring.go @@ -129,7 +129,7 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { case *Union: // Unions only appear as (syntactic) embedded elements // in interfaces and syntactically cannot be empty. - if t.NumTerms() == 0 { + if t.Len() == 0 { panic("empty union") } for i, t := range t.terms { diff --git a/src/cmd/compile/internal/types2/union.go b/src/cmd/compile/internal/types2/union.go index 0325c72dbb5..102826947c6 100644 --- a/src/cmd/compile/internal/types2/union.go +++ b/src/cmd/compile/internal/types2/union.go @@ -11,45 +11,46 @@ import "cmd/compile/internal/syntax" // A Union represents a union of terms embedded in an interface. type Union struct { - terms []*term // list of syntactical terms (not a canonicalized termlist) + terms []*Term // list of syntactical terms (not a canonicalized termlist) tset *TypeSet // type set described by this union, computed lazily } -// NewUnion returns a new Union type with the given terms (types[i], tilde[i]). -// The lengths of both arguments must match. It is an error to create an empty -// union; they are syntactically not possible. -func NewUnion(types []Type, tilde []bool) *Union { return newUnion(types, tilde) } +// NewUnion returns a new Union type with the given terms. +// It is an error to create an empty union; they are syntactically not possible. +func NewUnion(terms []*Term) *Union { + if len(terms) == 0 { + panic("empty union") + } + return &Union{terms, nil} +} -func (u *Union) NumTerms() int { return len(u.terms) } -func (u *Union) Term(i int) (Type, bool) { t := u.terms[i]; return t.typ, t.tilde } +func (u *Union) Len() int { return len(u.terms) } +func (u *Union) Term(i int) *Term { return u.terms[i] } func (u *Union) Underlying() Type { return u } func (u *Union) String() string { return TypeString(u, nil) } +// A Term represents a term in a Union. +type Term term + +// NewTerm returns a new union term. +func NewTerm(tilde bool, typ Type) *Term { return &Term{tilde, typ} } + +func (t *Term) Tilde() bool { return t.tilde } +func (t *Term) Type() Type { return t.typ } +func (t *Term) String() string { return (*term)(t).String() } + // ---------------------------------------------------------------------------- // Implementation -func newUnion(types []Type, tilde []bool) *Union { - assert(len(types) == len(tilde)) - if len(types) == 0 { - panic("empty union") - } - t := new(Union) - t.terms = make([]*term, len(types)) - for i, typ := range types { - t.terms[i] = &term{tilde[i], typ} - } - return t -} - func parseUnion(check *Checker, tlist []syntax.Expr) Type { - var terms []*term + var terms []*Term for _, x := range tlist { tilde, typ := parseTilde(check, x) if len(tlist) == 1 && !tilde { return typ // single type } - terms = append(terms, &term{tilde, typ}) + terms = append(terms, NewTerm(tilde, typ)) } // Check validity of terms. @@ -124,7 +125,7 @@ func parseTilde(check *Checker, x syntax.Expr) (tilde bool, typ Type) { // overlappingTerm reports the index of the term x in terms which is // overlapping (not disjoint) from y. The result is < 0 if there is no // such term. -func overlappingTerm(terms []*term, y *term) int { +func overlappingTerm(terms []*Term, y *Term) int { for i, x := range terms { // disjoint requires non-nil, non-top arguments if debug { @@ -132,7 +133,7 @@ func overlappingTerm(terms []*term, y *term) int { panic("empty or top union term") } } - if !x.disjoint(y) { + if !(*term)(x).disjoint((*term)(y)) { return i } } From 313924f2726947eb0df5f8fd0462c3a7343f5bc9 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 5 Aug 2021 13:58:24 -0700 Subject: [PATCH 880/940] [dev.typeparams] cmd/compile: swap export order of union term components (cleanup) Export a term as a pair (tilde, type) rather than (type, tilde) to match the new Union/Term API. Change-Id: I221c09c2c746ae19fbae0c970ffb26fa7a8ac736 Reviewed-on: https://go-review.googlesource.com/c/go/+/340251 Trust: Robert Griesemer Trust: Dan Scales Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Dan Scales Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/importer/iimport.go | 7 ++----- src/cmd/compile/internal/noder/reader2.go | 4 +--- src/cmd/compile/internal/noder/writer.go | 2 +- src/cmd/compile/internal/typecheck/iexport.go | 6 +++--- src/cmd/compile/internal/typecheck/iimport.go | 2 +- 5 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/cmd/compile/internal/importer/iimport.go b/src/cmd/compile/internal/importer/iimport.go index 3aab32fc6bd..6dd8d595ae6 100644 --- a/src/cmd/compile/internal/importer/iimport.go +++ b/src/cmd/compile/internal/importer/iimport.go @@ -676,12 +676,9 @@ func (r *importReader) doType(base *types2.Named) types2.Type { if r.p.exportVersion < iexportVersionGenerics { errorf("unexpected instantiation type") } - nt := int(r.uint64()) - terms := make([]*types2.Term, nt) + terms := make([]*types2.Term, r.uint64()) for i := range terms { - typ := r.typ() - tilde := r.bool() - terms[i] = types2.NewTerm(tilde, typ) + terms[i] = types2.NewTerm(r.bool(), r.typ()) } return types2.NewUnion(terms) } diff --git a/src/cmd/compile/internal/noder/reader2.go b/src/cmd/compile/internal/noder/reader2.go index 0bea6675ea4..fe1f329c822 100644 --- a/src/cmd/compile/internal/noder/reader2.go +++ b/src/cmd/compile/internal/noder/reader2.go @@ -283,9 +283,7 @@ func (r *reader2) structType() *types2.Struct { func (r *reader2) unionType() *types2.Union { terms := make([]*types2.Term, r.len()) for i := range terms { - typ := r.typ() - tilde := r.bool() - terms[i] = types2.NewTerm(tilde, typ) + terms[i] = types2.NewTerm(r.bool(), r.typ()) } return types2.NewUnion(terms) } diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go index 8b65559d1ad..b5028e7f695 100644 --- a/src/cmd/compile/internal/noder/writer.go +++ b/src/cmd/compile/internal/noder/writer.go @@ -397,8 +397,8 @@ func (w *writer) unionType(typ *types2.Union) { w.len(typ.Len()) for i := 0; i < typ.Len(); i++ { t := typ.Term(i) - w.typ(t.Type()) w.bool(t.Tilde()) + w.typ(t.Type()) } } diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index 25a0bfbb3a4..d877b03e489 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -1002,9 +1002,9 @@ func (w *exportWriter) doTyp(t *types.Type) { nt := t.NumTerms() w.uint64(uint64(nt)) for i := 0; i < nt; i++ { - t, b := t.Term(i) - w.typ(t) - w.bool(b) + typ, tilde := t.Term(i) + w.bool(tilde) + w.typ(typ) } default: diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 8d960e58082..2957212fb2e 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -847,8 +847,8 @@ func (r *importReader) typ1() *types.Type { terms := make([]*types.Type, nt) tildes := make([]bool, nt) for i := range terms { - terms[i] = r.typ() tildes[i] = r.bool() + terms[i] = r.typ() } return types.NewUnion(terms, tildes) } From 9bd1817e417e9f07c6b3aba0189576bbf06f1592 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 5 Aug 2021 18:14:28 -0700 Subject: [PATCH 881/940] [dev.typeparams] cmd/compile/internal/types2: limit termlist lengths At the moment, operations on termlists are O(n^2). This is fine for normal-sized unions, but overlong termlist lenghts will lead to excessive type checking times. Limit the length of termlists to avoid "compilations that don't finish". Change-Id: I39a7fc61b01c9db06faeb49a0e014b1ede532710 Reviewed-on: https://go-review.googlesource.com/c/go/+/340254 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/interface.go | 2 +- .../internal/types2/testdata/check/unions.go2 | 66 +++++++++++++++++++ src/cmd/compile/internal/types2/typeset.go | 27 +++++++- .../compile/internal/types2/typeset_test.go | 15 +++++ src/cmd/compile/internal/types2/union.go | 12 +++- 5 files changed, 117 insertions(+), 5 deletions(-) create mode 100644 src/cmd/compile/internal/types2/testdata/check/unions.go2 create mode 100644 src/cmd/compile/internal/types2/typeset_test.go diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go index f763f8ff443..89cf8465987 100644 --- a/src/cmd/compile/internal/types2/interface.go +++ b/src/cmd/compile/internal/types2/interface.go @@ -140,7 +140,7 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType for _, f := range iface.MethodList { if f.Name == nil { // We have an embedded type; possibly a union of types. - addEmbedded(f.Type.Pos(), parseUnion(check, flattenUnion(nil, f.Type))) + addEmbedded(posFor(f.Type), parseUnion(check, flattenUnion(nil, f.Type))) continue } // f.Name != nil diff --git a/src/cmd/compile/internal/types2/testdata/check/unions.go2 b/src/cmd/compile/internal/types2/testdata/check/unions.go2 new file mode 100644 index 00000000000..bcd7de66448 --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/check/unions.go2 @@ -0,0 +1,66 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Check that overlong unions don't bog down type checking. +// Disallow them for now. + +package p + +type t int + +type ( + t00 t; t01 t; t02 t; t03 t; t04 t; t05 t; t06 t; t07 t; t08 t; t09 t + t10 t; t11 t; t12 t; t13 t; t14 t; t15 t; t16 t; t17 t; t18 t; t19 t + t20 t; t21 t; t22 t; t23 t; t24 t; t25 t; t26 t; t27 t; t28 t; t29 t + t30 t; t31 t; t32 t; t33 t; t34 t; t35 t; t36 t; t37 t; t38 t; t39 t + t40 t; t41 t; t42 t; t43 t; t44 t; t45 t; t46 t; t47 t; t48 t; t49 t + t50 t; t51 t; t52 t; t53 t; t54 t; t55 t; t56 t; t57 t; t58 t; t59 t + t60 t; t61 t; t62 t; t63 t; t64 t; t65 t; t66 t; t67 t; t68 t; t69 t + t70 t; t71 t; t72 t; t73 t; t74 t; t75 t; t76 t; t77 t; t78 t; t79 t + t80 t; t81 t; t82 t; t83 t; t84 t; t85 t; t86 t; t87 t; t88 t; t89 t + t90 t; t91 t; t92 t; t93 t; t94 t; t95 t; t96 t; t97 t; t98 t; t99 t +) + +type u99 interface { + t00|t01|t02|t03|t04|t05|t06|t07|t08|t09| + t10|t11|t12|t13|t14|t15|t16|t17|t18|t19| + t20|t21|t22|t23|t24|t25|t26|t27|t28|t29| + t30|t31|t32|t33|t34|t35|t36|t37|t38|t39| + t40|t41|t42|t43|t44|t45|t46|t47|t48|t49| + t50|t51|t52|t53|t54|t55|t56|t57|t58|t59| + t60|t61|t62|t63|t64|t65|t66|t67|t68|t69| + t70|t71|t72|t73|t74|t75|t76|t77|t78|t79| + t80|t81|t82|t83|t84|t85|t86|t87|t88|t89| + t90|t91|t92|t93|t94|t95|t96|t97|t98 +} + +type u100a interface { + u99|float32 +} + +type u100b interface { + u99|float64 +} + +type u101 interface { + t00|t01|t02|t03|t04|t05|t06|t07|t08|t09| + t10|t11|t12|t13|t14|t15|t16|t17|t18|t19| + t20|t21|t22|t23|t24|t25|t26|t27|t28|t29| + t30|t31|t32|t33|t34|t35|t36|t37|t38|t39| + t40|t41|t42|t43|t44|t45|t46|t47|t48|t49| + t50|t51|t52|t53|t54|t55|t56|t57|t58|t59| + t60|t61|t62|t63|t64|t65|t66|t67|t68|t69| + t70|t71|t72|t73|t74|t75|t76|t77|t78|t79| + t80|t81|t82|t83|t84|t85|t86|t87|t88|t89| + t90|t91|t92|t93|t94|t95|t96|t97|t98|t99| + int // ERROR cannot handle more than 100 union terms +} + +type u102 interface { + int /* ERROR cannot handle more than 100 union terms */ |string|u100a +} + +type u200 interface { + u100a /* ERROR cannot handle more than 100 union terms */ |u100b +} diff --git a/src/cmd/compile/internal/types2/typeset.go b/src/cmd/compile/internal/types2/typeset.go index da364699ce5..5955bbe8054 100644 --- a/src/cmd/compile/internal/types2/typeset.go +++ b/src/cmd/compile/internal/types2/typeset.go @@ -268,9 +268,9 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *T pos = (*ityp.embedPos)[i] } var terms termlist - switch t := under(typ).(type) { + switch u := under(typ).(type) { case *Interface: - tset := computeInterfaceTypeSet(check, pos, t) + tset := computeInterfaceTypeSet(check, pos, u) if tset.comparable { ityp.tset.comparable = true } @@ -279,7 +279,10 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *T } terms = tset.terms case *Union: - tset := computeUnionTypeSet(check, pos, t) + tset := computeUnionTypeSet(check, pos, u) + if tset == &invalidTypeSet { + continue // ignore invalid unions + } terms = tset.terms case *TypeParam: // Embedding stand-alone type parameters is not permitted. @@ -297,6 +300,8 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *T } // The type set of an interface is the intersection // of the type sets of all its elements. + // Intersection cannot produce longer termlists and + // thus cannot overflow. allTerms = allTerms.intersect(terms) } ityp.embedPos = nil // not needed anymore (errors have been reported) @@ -339,7 +344,13 @@ func (a byUniqueMethodName) Len() int { return len(a) } func (a byUniqueMethodName) Less(i, j int) bool { return a[i].less(&a[j].object) } func (a byUniqueMethodName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +// invalidTypeSet is a singleton type set to signal an invalid type set +// due to an error. It's also a valid empty type set, so consumers of +// type sets may choose to ignore it. +var invalidTypeSet TypeSet + // computeUnionTypeSet may be called with check == nil. +// The result is &invalidTypeSet if the union overflows. func computeUnionTypeSet(check *Checker, pos syntax.Pos, utyp *Union) *TypeSet { if utyp.tset != nil { return utyp.tset @@ -359,11 +370,21 @@ func computeUnionTypeSet(check *Checker, pos syntax.Pos, utyp *Union) *TypeSet { // This case is handled during union parsing. unreachable() default: + if t.typ == Typ[Invalid] { + continue + } terms = termlist{(*term)(t)} } // The type set of a union expression is the union // of the type sets of each term. allTerms = allTerms.union(terms) + if len(allTerms) > maxTermCount { + if check != nil { + check.errorf(pos, "cannot handle more than %d union terms (implementation limitation)", maxTermCount) + } + utyp.tset = &invalidTypeSet + return utyp.tset + } } utyp.tset.terms = allTerms diff --git a/src/cmd/compile/internal/types2/typeset_test.go b/src/cmd/compile/internal/types2/typeset_test.go new file mode 100644 index 00000000000..0e14d523c8b --- /dev/null +++ b/src/cmd/compile/internal/types2/typeset_test.go @@ -0,0 +1,15 @@ +// Copyright 2021 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 types2 + +import "testing" + +func TestInvalidTypeSet(t *testing.T) { + if !invalidTypeSet.IsEmpty() { + t.Error("invalidTypeSet is not empty") + } +} + +// TODO(gri) add more tests diff --git a/src/cmd/compile/internal/types2/union.go b/src/cmd/compile/internal/types2/union.go index 102826947c6..85aa3d91040 100644 --- a/src/cmd/compile/internal/types2/union.go +++ b/src/cmd/compile/internal/types2/union.go @@ -43,12 +43,22 @@ func (t *Term) String() string { return (*term)(t).String() } // ---------------------------------------------------------------------------- // Implementation +// Avoid excessive type-checking times due to quadratic termlist operations. +const maxTermCount = 100 + +// parseUnion parses the given list of type expressions tlist as a union of +// those expressions. The result is a Union type, or Typ[Invalid] for some +// errors. func parseUnion(check *Checker, tlist []syntax.Expr) Type { var terms []*Term for _, x := range tlist { tilde, typ := parseTilde(check, x) if len(tlist) == 1 && !tilde { - return typ // single type + return typ // single type (optimization) + } + if len(terms) >= maxTermCount { + check.errorf(x, "cannot handle more than %d union terms (implementation limitation)", maxTermCount) + return Typ[Invalid] } terms = append(terms, NewTerm(tilde, typ)) } From 9e0ac72d680e71d22c7d31950a16d4f92f08305a Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 5 Aug 2021 18:33:22 -0700 Subject: [PATCH 882/940] [dev.typeparams] cmd/compile/internal/types2: remove Interface.Complete (cleanup) Interface.Complete is not needed anymore. We can remove it in types2 (and eventually make it an empty function in go/types, where we must maintain the existing API). Change-Id: I689f0d6f3a83997d8ca5bae773b9af0083d0bf4f Reviewed-on: https://go-review.googlesource.com/c/go/+/340255 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/importer/iimport.go | 4 ---- src/cmd/compile/internal/noder/reader2.go | 4 +--- src/cmd/compile/internal/types2/interface.go | 19 ------------------- .../compile/internal/types2/issues_test.go | 3 ++- 4 files changed, 3 insertions(+), 27 deletions(-) diff --git a/src/cmd/compile/internal/importer/iimport.go b/src/cmd/compile/internal/importer/iimport.go index 6dd8d595ae6..523b00313da 100644 --- a/src/cmd/compile/internal/importer/iimport.go +++ b/src/cmd/compile/internal/importer/iimport.go @@ -183,10 +183,6 @@ func ImportData(imports map[string]*types2.Package, data, path string) (pkg *typ p.doDecl(localpkg, name) } - for _, typ := range p.interfaceList { - typ.Complete() - } - // record all referenced packages as imports list := append(([]*types2.Package)(nil), pkgList[1:]...) sort.Sort(byPath(list)) diff --git a/src/cmd/compile/internal/noder/reader2.go b/src/cmd/compile/internal/noder/reader2.go index fe1f329c822..5637196dc0e 100644 --- a/src/cmd/compile/internal/noder/reader2.go +++ b/src/cmd/compile/internal/noder/reader2.go @@ -303,9 +303,7 @@ func (r *reader2) interfaceType() *types2.Interface { embeddeds[i] = r.typ() } - typ := types2.NewInterfaceType(methods, embeddeds) - typ.Complete() - return typ + return types2.NewInterfaceType(methods, embeddeds) } func (r *reader2) signature(recv *types2.Var) *types2.Signature { diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go index 89cf8465987..2617f748de6 100644 --- a/src/cmd/compile/internal/types2/interface.go +++ b/src/cmd/compile/internal/types2/interface.go @@ -100,25 +100,6 @@ func (t *Interface) IsComparable() bool { return t.typeSet().IsComparable() } // IsConstraint reports whether interface t is not just a method set. func (t *Interface) IsConstraint() bool { return !t.typeSet().IsMethodSet() } -// Complete computes the interface's type set. It must be called by users of -// NewInterfaceType and NewInterface after the interface's embedded types are -// fully defined and before using the interface type in any way other than to -// form other types. The interface must not contain duplicate methods or a -// panic occurs. Complete returns the receiver. -// -// Deprecated: Type sets are now computed lazily, on demand; this function -// is only here for backward-compatibility. It does not have to -// be called explicitly anymore. -func (t *Interface) Complete() *Interface { - // Some tests are still depending on the state change - // (string representation of an Interface not containing an - // /* incomplete */ marker) caused by the explicit Complete - // call, so we compute the type set eagerly here. - t.complete = true - t.typeSet() - return t -} - func (t *Interface) Underlying() Type { return t } func (t *Interface) String() string { return TypeString(t, nil) } diff --git a/src/cmd/compile/internal/types2/issues_test.go b/src/cmd/compile/internal/types2/issues_test.go index aafe8de3676..9890b79323a 100644 --- a/src/cmd/compile/internal/types2/issues_test.go +++ b/src/cmd/compile/internal/types2/issues_test.go @@ -402,8 +402,9 @@ func TestIssue28282(t *testing.T) { // create type interface { error } et := Universe.Lookup("error").Type() it := NewInterfaceType(nil, []Type{et}) - it.Complete() // verify that after completing the interface, the embedded method remains unchanged + // (interfaces are "completed" lazily now, so the completion happens implicitly when + // accessing Method(0)) want := et.Underlying().(*Interface).Method(0) got := it.Method(0) if got != want { From 63b968f4f86f4c23ce92b7ac2feda4fc7ca17c8e Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Fri, 16 Jul 2021 16:51:11 -0400 Subject: [PATCH 883/940] doc/go1.17: clarify Modules changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Writing CL 333629 clarified my thinking about the behavioral changes associated with lazy loading. There are really two interrelated changes — graph pruning, and lazy loading proper — that are both made possible by the added redundancy in the go.mod file. (I had initially approached the whole cluster of features as “lazy loading” because that was the starting point for the design. Graph pruning came into the picture when we looked at how to bound the worst-case behavior of lazy loading, but it is really the more important of the two aspects of the design.) Note that this change adds links to doc anchors added in CL 333629. Fixes #36460 Fixes #47397 Change-Id: I0ef4af57f647bf5ee210ea7099191fb4befa2cc1 Reviewed-on: https://go-review.googlesource.com/c/go/+/335135 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Jay Conrod --- doc/go1.17.html | 70 +++++++++++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 48811e6b679..a8307bacac2 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -134,35 +134,54 @@ Do not send CLs removing the interior tags from such phrases.

Go command

-

Lazy module loading

+ +

Pruned module graphs in go 1.17 modules

+ If a module specifies go 1.17 or higher, the module + graph includes only the immediate dependencies of + other go 1.17 modules, not their full transitive + dependencies. (See Module graph pruning + for more detail.) +

+ +

+ +

+ Since the expanded go.mod file needed for module graph pruning + includes all of the dependencies needed to load the imports of any package in + the main module, if the main module specifies + go 1.17 or higher the go tool no longer + reads (or even downloads) go.mod files for dependencies if they + are not needed in order to complete the requested command. + (See Lazy loading.)

- Because the number of additional explicit requirements in the go.mod file may - be substantial, in a Go 1.17 module the newly-added requirements - on indirect dependencies are maintained in a - separate require block from the block containing direct - dependencies. + Because the number of explicit requirements may be substantially larger in an + expanded Go 1.17 go.mod file, the newly-added requirements + on indirect dependencies in a go 1.17 + module are maintained in a separate require block from the block + containing direct dependencies.

- To facilitate the upgrade to lazy loading, the - go mod tidy subcommand now supports - a -go flag to set or change the go version in - the go.mod file. To enable lazy loading for an existing module - without changing the selected versions of its dependencies, run: + To facilitate the upgrade to Go 1.17 pruned module graphs, the + go mod tidy + subcommand now supports a -go flag to set or change + the go version in the go.mod file. To convert + the go.mod file for an existing module to Go 1.17 without + changing the selected versions of its dependencies, run:

+ For the go command to correctly resolve transitive imports using + the pruned module graph, the go.mod file for each module needs to + include more detail about the transitive dependencies relevant to that module. If a module specifies go 1.17 or higher in its - go.mod file, its transitive requirements are now loaded lazily, - avoiding the need to download or read go.mod files for - otherwise-irrelevant dependencies. To support lazy loading, in Go 1.17 modules - the go command maintains explicit requirements in - the go.mod file for every dependency that provides any package - transitively imported by any package or test within the module. - See the design - document for more detail. - + go.mod file, its go.mod file now contains an + explicit require + directive for every module that provides a transitively-imported package. + (In previous versions, the go.mod file typically only included + explicit requirements for directly-imported packages.) +

@@ -199,10 +218,10 @@ Do not send CLs removing the interior tags from such phrases.
 

- The go mod graph subcommand also - supports the -go flag, which causes it to report the graph as - seen by the indicated Go version, showing dependencies that may otherwise be - pruned out by lazy loading. + The go mod graph + subcommand also supports the -go flag, which causes it to report + the graph as seen by the indicated Go version, showing dependencies that may + otherwise be pruned out.

Module deprecation comments

@@ -270,7 +289,8 @@ Do not send CLs removing the interior tags from such phrases.

If the main module specifies go 1.17 or higher, - go mod vendor now annotates + go mod vendor + now annotates vendor/modules.txt with the go version indicated by each vendored module in its own go.mod file. The annotated version is used when building the module's packages from vendored source code. From 8eaf4d16bc69724cd450345cbaf55f2e2aef9b9c Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Fri, 6 Aug 2021 15:37:10 -0400 Subject: [PATCH 884/940] make.bash: do not overwrite GO_LDSO if already set Change-Id: I704bdb411bda3d8a40906c12f182e268dca4718f Reviewed-on: https://go-review.googlesource.com/c/go/+/340450 Trust: Cherry Mui Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot --- src/make.bash | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/make.bash b/src/make.bash index 4fb13f62758..f5e1b60bd5f 100755 --- a/src/make.bash +++ b/src/make.bash @@ -130,8 +130,8 @@ if [ "$(uname -s)" = "GNU/kFreeBSD" ]; then export CGO_ENABLED=0 fi -# Test which linker/loader our system is using -if type readelf >/dev/null 2>&1; then +# Test which linker/loader our system is using, if GO_LDSO is not set. +if [ -z "$GO_LDSO" ] && type readelf >/dev/null 2>&1; then if echo "int main() { return 0; }" | ${CC:-cc} -o ./test-musl-ldso -x c - >/dev/null 2>&1; then LDSO=$(readelf -l ./test-musl-ldso | grep 'interpreter:' | sed -e 's/^.*interpreter: \(.*\)[]]/\1/') >/dev/null 2>&1 [ -z "$LDSO" ] || export GO_LDSO="$LDSO" From 891547e2d4bc2a23973e2c9f972ce69b2b48478e Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Fri, 6 Aug 2021 21:10:31 -0400 Subject: [PATCH 885/940] doc/go1.17: fix a typo introduced in CL 335135 Change-Id: I62388bcb6d6f910ffa95d3db856ea29838573256 Reviewed-on: https://go-review.googlesource.com/c/go/+/340590 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills Reviewed-by: Rob Pike --- doc/go1.17.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index a8307bacac2..d469f400ad9 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -150,7 +150,7 @@ Do not send CLs removing the interior tags from such phrases. the pruned module graph, the go.mod file for each module needs to include more detail about the transitive dependencies relevant to that module. If a module specifies go 1.17 or higher in its - go.mod file, its go.mod file now contains an + go.mod file, its go.mod file now contains an explicit require directive for every module that provides a transitively-imported package. (In previous versions, the go.mod file typically only included From d10a90471275bf2d91c4c853d7d1f75f23a70a32 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Fri, 6 Aug 2021 16:29:09 -0700 Subject: [PATCH 886/940] [dev.typeparams] cmd/compile: don't export/import type parameter indices anymore types2 now determines type parameter indices lazily, so we don't need them just as we are importing. We set them in types1 as we are importing the type param list itself. type param indices are not strongly needed in types1 - we only use them in one place which could be rewritten. But I kept them in analogy to types2 (TypeParam.Index). Fixes #47451 Change-Id: I30631f95c45a259354eaf7ec5194f71e799eb358 Reviewed-on: https://go-review.googlesource.com/c/go/+/340532 Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Robert Griesemer Trust: Dan Scales --- src/cmd/compile/internal/importer/iimport.go | 4 ---- src/cmd/compile/internal/typecheck/iexport.go | 1 - src/cmd/compile/internal/typecheck/iimport.go | 9 +++++++-- src/cmd/compile/internal/types/type.go | 6 ++++++ 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/cmd/compile/internal/importer/iimport.go b/src/cmd/compile/internal/importer/iimport.go index 523b00313da..99eb9644159 100644 --- a/src/cmd/compile/internal/importer/iimport.go +++ b/src/cmd/compile/internal/importer/iimport.go @@ -364,10 +364,6 @@ func (r *importReader) obj(name string) { if r.p.exportVersion < iexportVersionGenerics { errorf("unexpected type param type") } - // Type parameter indices are lazily "allocated". - // There's no need to export them anymore. - // TODO change the export format accordingly - _ = int(r.int64()) name0, sub := parseSubscript(name) tn := types2.NewTypeName(pos, r.currPkg, name0, nil) t := (*types2.Checker)(nil).NewTypeParam(tn, nil) diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index d877b03e489..2944908bcbc 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -531,7 +531,6 @@ func (p *iexporter) doDecl(n *ir.Name) { // A typeparam has a name, and has a type bound rather // than an underlying type. w.pos(n.Pos()) - w.int64(int64(n.Type().Index())) w.typ(n.Type().Bound()) break } diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 2957212fb2e..2e8b18c0b7c 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -388,8 +388,9 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name { // this types2-to-types1 translation. return sym.Def.(*ir.Name) } - index := int(r.int64()) - t := types.NewTypeParam(sym, index) + // The typeparam index is set at the point where the containing type + // param list is imported. + t := types.NewTypeParam(sym, 0) // Nname needed to save the pos. nname := ir.NewDeclNameAt(pos, ir.OTYPE, sym) sym.Def = nname @@ -875,6 +876,9 @@ func (r *importReader) typeList() []*types.Type { ts := make([]*types.Type, n) for i := range ts { ts[i] = r.typ() + if ts[i].IsTypeParam() { + ts[i].SetIndex(i) + } } return ts } @@ -887,6 +891,7 @@ func (r *importReader) tparamList() []*types.Field { fs := make([]*types.Field, n) for i := range fs { typ := r.typ() + typ.SetIndex(i) fs[i] = types.NewField(typ.Pos(), typ.Sym(), typ) } return fs diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index 1f01498ca19..099080f48f3 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -1885,6 +1885,12 @@ func (t *Type) Index() int { return t.Extra.(*Typeparam).index } +// SetIndex sets the index of the type param within its param list. +func (t *Type) SetIndex(i int) { + t.wantEtype(TTYPEPARAM) + t.Extra.(*Typeparam).index = i +} + // SetBound sets the bound of a typeparam. func (t *Type) SetBound(bound *Type) { t.wantEtype(TTYPEPARAM) From 507cc341ec2cb96b0199800245f222146f799266 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Mon, 9 Aug 2021 00:52:21 +0700 Subject: [PATCH 887/940] doc: add example for conversion from slice expressions to array ptr Fixes #47599 Change-Id: I8f4ccd3b0c2bcdb057ee853163b4421229141333 Reviewed-on: https://go-review.googlesource.com/c/go/+/340351 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Keith Randall --- doc/go_spec.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/go_spec.html b/doc/go_spec.html index 0e14a1f3b63..fd5fee46eb2 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -4329,6 +4329,7 @@ a run-time panic occurs.

 s := make([]byte, 2, 4)
 s0 := (*[0]byte)(s)      // s0 != nil
+s1 := (*[1]byte)(s[1:])  // &s1[0] == &s[1]
 s2 := (*[2]byte)(s)      // &s2[0] == &s[0]
 s4 := (*[4]byte)(s)      // panics: len([4]byte) > len(s)
 

From 7aeaad5c86174f61b084d72d89fb02d7fc64391c Mon Sep 17 00:00:00 2001
From: Ian Lance Taylor 
Date: Wed, 4 Aug 2021 20:55:28 -0700
Subject: [PATCH 888/940] runtime/cgo: when using msan explicitly unpoison
 cgoCallers

This avoids an incorrect msan uninitialized memory report when using
runtime.SetCgoTraceback when a signal occurs while the fifth argument
register is undefined. See the issue for more details.

Fixes #47543

Change-Id: I3d1b673e2c93471ccdae0171a99b88b5a6062840
Reviewed-on: https://go-review.googlesource.com/c/go/+/339902
Trust: Ian Lance Taylor 
Run-TryBot: Ian Lance Taylor 
TryBot-Result: Go Bot 
Reviewed-by: Austin Clements 
---
 misc/cgo/testsanitizers/msan_test.go      |   1 +
 misc/cgo/testsanitizers/testdata/msan8.go | 109 ++++++++++++++++++++++
 src/runtime/cgo/gcc_traceback.c           |  20 ++++
 3 files changed, 130 insertions(+)
 create mode 100644 misc/cgo/testsanitizers/testdata/msan8.go

diff --git a/misc/cgo/testsanitizers/msan_test.go b/misc/cgo/testsanitizers/msan_test.go
index 2a3494fbfc1..5ee9947a585 100644
--- a/misc/cgo/testsanitizers/msan_test.go
+++ b/misc/cgo/testsanitizers/msan_test.go
@@ -42,6 +42,7 @@ func TestMSAN(t *testing.T) {
 		{src: "msan5.go"},
 		{src: "msan6.go"},
 		{src: "msan7.go"},
+		{src: "msan8.go"},
 		{src: "msan_fail.go", wantErr: true},
 	}
 	for _, tc := range cases {
diff --git a/misc/cgo/testsanitizers/testdata/msan8.go b/misc/cgo/testsanitizers/testdata/msan8.go
new file mode 100644
index 00000000000..1cb5c5677fa
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/msan8.go
@@ -0,0 +1,109 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+/*
+#include 
+#include 
+#include 
+
+#include 
+
+// cgoTracebackArg is the type of the argument passed to msanGoTraceback.
+struct cgoTracebackArg {
+	uintptr_t context;
+	uintptr_t sigContext;
+	uintptr_t* buf;
+	uintptr_t max;
+};
+
+// msanGoTraceback is registered as the cgo traceback function.
+// This will be called when a signal occurs.
+void msanGoTraceback(void* parg) {
+	struct cgoTracebackArg* arg = (struct cgoTracebackArg*)(parg);
+        arg->buf[0] = 0;
+}
+
+// msanGoWait will be called with all registers undefined as far as
+// msan is concerned. It just waits for a signal.
+// Because the registers are msan-undefined, the signal handler will
+// be invoked with all registers msan-undefined.
+__attribute__((noinline))
+void msanGoWait(unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5, unsigned long a6) {
+	sigset_t mask;
+
+	sigemptyset(&mask);
+        sigsuspend(&mask);
+}
+
+// msanGoSignalThread is the thread ID of the msanGoLoop thread.
+static pthread_t msanGoSignalThread;
+
+// msanGoSignalThreadSet is used to record that msanGoSignalThread
+// has been initialized. This is accessed atomically.
+static int32_t msanGoSignalThreadSet;
+
+// uninit is explicitly poisoned, so that we can make all registers
+// undefined by calling msanGoWait.
+static unsigned long uninit;
+
+// msanGoLoop loops calling msanGoWait, with the arguments passed
+// such that msan thinks that they are undefined. msan permits
+// undefined values to be used as long as they are not used to
+// for conditionals or for memory access.
+void msanGoLoop() {
+	int i;
+
+	msanGoSignalThread = pthread_self();
+        __atomic_store_n(&msanGoSignalThreadSet, 1, __ATOMIC_SEQ_CST);
+
+	// Force uninit to be undefined for msan.
+	__msan_poison(&uninit, sizeof uninit);
+	for (i = 0; i < 100; i++) {
+		msanGoWait(uninit, uninit, uninit, uninit, uninit, uninit);
+        }
+}
+
+// msanGoReady returns whether msanGoSignalThread is set.
+int msanGoReady() {
+	return __atomic_load_n(&msanGoSignalThreadSet, __ATOMIC_SEQ_CST) != 0;
+}
+
+// msanGoSendSignal sends a signal to the msanGoLoop thread.
+void msanGoSendSignal() {
+	pthread_kill(msanGoSignalThread, SIGWINCH);
+}
+*/
+import "C"
+
+import (
+	"runtime"
+	"time"
+)
+
+func main() {
+	runtime.SetCgoTraceback(0, C.msanGoTraceback, nil, nil)
+
+	c := make(chan bool)
+	go func() {
+		defer func() { c <- true }()
+		C.msanGoLoop()
+	}()
+
+	for C.msanGoReady() == 0 {
+		time.Sleep(time.Microsecond)
+	}
+
+loop:
+	for {
+		select {
+		case <-c:
+			break loop
+		default:
+			C.msanGoSendSignal()
+			time.Sleep(time.Microsecond)
+		}
+	}
+}
diff --git a/src/runtime/cgo/gcc_traceback.c b/src/runtime/cgo/gcc_traceback.c
index d86331c583a..6e9470c43c2 100644
--- a/src/runtime/cgo/gcc_traceback.c
+++ b/src/runtime/cgo/gcc_traceback.c
@@ -7,6 +7,14 @@
 #include 
 #include "libcgo.h"
 
+#ifndef __has_feature
+#define __has_feature(x) 0
+#endif
+
+#if __has_feature(memory_sanitizer)
+#include 
+#endif
+
 // Call the user's traceback function and then call sigtramp.
 // The runtime signal handler will jump to this code.
 // We do it this way so that the user's traceback function will be called
@@ -19,6 +27,18 @@ x_cgo_callers(uintptr_t sig, void *info, void *context, void (*cgoTraceback)(str
 	arg.SigContext = (uintptr_t)(context);
 	arg.Buf = cgoCallers;
 	arg.Max = 32; // must match len(runtime.cgoCallers)
+
+#if __has_feature(memory_sanitizer)
+        // This function is called directly from the signal handler.
+        // The arguments are passed in registers, so whether msan
+        // considers cgoCallers to be initialized depends on whether
+        // it considers the appropriate register to be initialized.
+        // That can cause false reports in rare cases.
+        // Explicitly unpoison the memory to avoid that.
+        // See issue #47543 for more details.
+        __msan_unpoison(&arg, sizeof arg);
+#endif
+
 	(*cgoTraceback)(&arg);
 	sigtramp(sig, info, context);
 }

From 57668b84ff43b15746a25e9653c278d174ea483f Mon Sep 17 00:00:00 2001
From: Keith Randall 
Date: Wed, 4 Aug 2021 22:18:23 -0700
Subject: [PATCH 889/940] [dev.typeparams] cmd/compile: simplify interface
 conversions

Simplify the implementation of interface conversions in the compiler.
Don't pass fields that aren't needed (the data word, usually) to the runtime.

For generics, we need to put a dynamic type in an interface. The new
dataWord function is exactly what we need (the type word will come
from a dictionary).

Change-Id: Iade5de5c174854b65ad248f35c7893c603f7be3d
Reviewed-on: https://go-review.googlesource.com/c/go/+/340029
Trust: Keith Randall 
Trust: Dan Scales 
Run-TryBot: Keith Randall 
TryBot-Result: Go Bot 
Reviewed-by: Dan Scales 
---
 src/cmd/compile/internal/typecheck/builtin.go | 423 +++++++++---------
 .../internal/typecheck/builtin/runtime.go     |  19 +-
 src/cmd/compile/internal/walk/convert.go      | 298 ++++++------
 src/cmd/compile/internal/walk/expr.go         |   5 +-
 src/cmd/compile/internal/walk/order.go        |   6 +-
 src/runtime/iface.go                          |  91 ++--
 test/devirt.go                                |   3 +-
 test/fixedbugs/issue20250.go                  |   2 +-
 test/live.go                                  |   6 +-
 test/live_regabi.go                           |   6 +-
 10 files changed, 396 insertions(+), 463 deletions(-)

diff --git a/src/cmd/compile/internal/typecheck/builtin.go b/src/cmd/compile/internal/typecheck/builtin.go
index 833b17b4148..3f177d91732 100644
--- a/src/cmd/compile/internal/typecheck/builtin.go
+++ b/src/cmd/compile/internal/typecheck/builtin.go
@@ -71,137 +71,135 @@ var runtimeDecls = [...]struct {
 	{"slicecopy", funcTag, 54},
 	{"decoderune", funcTag, 55},
 	{"countrunes", funcTag, 56},
-	{"convI2I", funcTag, 57},
-	{"convT16", funcTag, 59},
-	{"convT32", funcTag, 61},
-	{"convT64", funcTag, 62},
-	{"convTstring", funcTag, 63},
-	{"convTslice", funcTag, 66},
-	{"convT2E", funcTag, 67},
-	{"convT2Enoptr", funcTag, 67},
-	{"convT2I", funcTag, 67},
-	{"convT2Inoptr", funcTag, 67},
-	{"assertE2I", funcTag, 68},
-	{"assertE2I2", funcTag, 57},
-	{"assertI2I", funcTag, 68},
-	{"assertI2I2", funcTag, 57},
-	{"panicdottypeE", funcTag, 69},
-	{"panicdottypeI", funcTag, 69},
-	{"panicnildottype", funcTag, 70},
-	{"ifaceeq", funcTag, 72},
-	{"efaceeq", funcTag, 72},
-	{"fastrand", funcTag, 73},
-	{"makemap64", funcTag, 75},
-	{"makemap", funcTag, 76},
-	{"makemap_small", funcTag, 77},
-	{"mapaccess1", funcTag, 78},
-	{"mapaccess1_fast32", funcTag, 79},
-	{"mapaccess1_fast64", funcTag, 80},
-	{"mapaccess1_faststr", funcTag, 81},
-	{"mapaccess1_fat", funcTag, 82},
-	{"mapaccess2", funcTag, 83},
-	{"mapaccess2_fast32", funcTag, 84},
-	{"mapaccess2_fast64", funcTag, 85},
-	{"mapaccess2_faststr", funcTag, 86},
-	{"mapaccess2_fat", funcTag, 87},
-	{"mapassign", funcTag, 78},
-	{"mapassign_fast32", funcTag, 79},
-	{"mapassign_fast32ptr", funcTag, 88},
-	{"mapassign_fast64", funcTag, 80},
-	{"mapassign_fast64ptr", funcTag, 88},
-	{"mapassign_faststr", funcTag, 81},
-	{"mapiterinit", funcTag, 89},
-	{"mapdelete", funcTag, 89},
-	{"mapdelete_fast32", funcTag, 90},
-	{"mapdelete_fast64", funcTag, 91},
-	{"mapdelete_faststr", funcTag, 92},
-	{"mapiternext", funcTag, 93},
-	{"mapclear", funcTag, 94},
-	{"makechan64", funcTag, 96},
-	{"makechan", funcTag, 97},
-	{"chanrecv1", funcTag, 99},
-	{"chanrecv2", funcTag, 100},
-	{"chansend1", funcTag, 102},
+	{"convI2I", funcTag, 58},
+	{"convT", funcTag, 59},
+	{"convTnoptr", funcTag, 59},
+	{"convT16", funcTag, 61},
+	{"convT32", funcTag, 63},
+	{"convT64", funcTag, 64},
+	{"convTstring", funcTag, 65},
+	{"convTslice", funcTag, 68},
+	{"assertE2I", funcTag, 69},
+	{"assertE2I2", funcTag, 70},
+	{"assertI2I", funcTag, 69},
+	{"assertI2I2", funcTag, 70},
+	{"panicdottypeE", funcTag, 71},
+	{"panicdottypeI", funcTag, 71},
+	{"panicnildottype", funcTag, 72},
+	{"ifaceeq", funcTag, 73},
+	{"efaceeq", funcTag, 73},
+	{"fastrand", funcTag, 74},
+	{"makemap64", funcTag, 76},
+	{"makemap", funcTag, 77},
+	{"makemap_small", funcTag, 78},
+	{"mapaccess1", funcTag, 79},
+	{"mapaccess1_fast32", funcTag, 80},
+	{"mapaccess1_fast64", funcTag, 81},
+	{"mapaccess1_faststr", funcTag, 82},
+	{"mapaccess1_fat", funcTag, 83},
+	{"mapaccess2", funcTag, 84},
+	{"mapaccess2_fast32", funcTag, 85},
+	{"mapaccess2_fast64", funcTag, 86},
+	{"mapaccess2_faststr", funcTag, 87},
+	{"mapaccess2_fat", funcTag, 88},
+	{"mapassign", funcTag, 79},
+	{"mapassign_fast32", funcTag, 80},
+	{"mapassign_fast32ptr", funcTag, 89},
+	{"mapassign_fast64", funcTag, 81},
+	{"mapassign_fast64ptr", funcTag, 89},
+	{"mapassign_faststr", funcTag, 82},
+	{"mapiterinit", funcTag, 90},
+	{"mapdelete", funcTag, 90},
+	{"mapdelete_fast32", funcTag, 91},
+	{"mapdelete_fast64", funcTag, 92},
+	{"mapdelete_faststr", funcTag, 93},
+	{"mapiternext", funcTag, 94},
+	{"mapclear", funcTag, 95},
+	{"makechan64", funcTag, 97},
+	{"makechan", funcTag, 98},
+	{"chanrecv1", funcTag, 100},
+	{"chanrecv2", funcTag, 101},
+	{"chansend1", funcTag, 103},
 	{"closechan", funcTag, 30},
-	{"writeBarrier", varTag, 104},
-	{"typedmemmove", funcTag, 105},
-	{"typedmemclr", funcTag, 106},
-	{"typedslicecopy", funcTag, 107},
-	{"selectnbsend", funcTag, 108},
-	{"selectnbrecv", funcTag, 109},
-	{"selectsetpc", funcTag, 110},
-	{"selectgo", funcTag, 111},
+	{"writeBarrier", varTag, 105},
+	{"typedmemmove", funcTag, 106},
+	{"typedmemclr", funcTag, 107},
+	{"typedslicecopy", funcTag, 108},
+	{"selectnbsend", funcTag, 109},
+	{"selectnbrecv", funcTag, 110},
+	{"selectsetpc", funcTag, 111},
+	{"selectgo", funcTag, 112},
 	{"block", funcTag, 9},
-	{"makeslice", funcTag, 112},
-	{"makeslice64", funcTag, 113},
-	{"makeslicecopy", funcTag, 114},
-	{"growslice", funcTag, 116},
-	{"unsafeslice", funcTag, 117},
-	{"unsafeslice64", funcTag, 118},
-	{"unsafeslicecheckptr", funcTag, 118},
-	{"memmove", funcTag, 119},
-	{"memclrNoHeapPointers", funcTag, 120},
-	{"memclrHasPointers", funcTag, 120},
-	{"memequal", funcTag, 121},
-	{"memequal0", funcTag, 122},
-	{"memequal8", funcTag, 122},
-	{"memequal16", funcTag, 122},
-	{"memequal32", funcTag, 122},
-	{"memequal64", funcTag, 122},
-	{"memequal128", funcTag, 122},
-	{"f32equal", funcTag, 123},
-	{"f64equal", funcTag, 123},
-	{"c64equal", funcTag, 123},
-	{"c128equal", funcTag, 123},
-	{"strequal", funcTag, 123},
-	{"interequal", funcTag, 123},
-	{"nilinterequal", funcTag, 123},
-	{"memhash", funcTag, 124},
-	{"memhash0", funcTag, 125},
-	{"memhash8", funcTag, 125},
-	{"memhash16", funcTag, 125},
-	{"memhash32", funcTag, 125},
-	{"memhash64", funcTag, 125},
-	{"memhash128", funcTag, 125},
-	{"f32hash", funcTag, 125},
-	{"f64hash", funcTag, 125},
-	{"c64hash", funcTag, 125},
-	{"c128hash", funcTag, 125},
-	{"strhash", funcTag, 125},
-	{"interhash", funcTag, 125},
-	{"nilinterhash", funcTag, 125},
-	{"int64div", funcTag, 126},
-	{"uint64div", funcTag, 127},
-	{"int64mod", funcTag, 126},
-	{"uint64mod", funcTag, 127},
-	{"float64toint64", funcTag, 128},
-	{"float64touint64", funcTag, 129},
-	{"float64touint32", funcTag, 130},
-	{"int64tofloat64", funcTag, 131},
-	{"uint64tofloat64", funcTag, 132},
-	{"uint32tofloat64", funcTag, 133},
-	{"complex128div", funcTag, 134},
-	{"getcallerpc", funcTag, 135},
-	{"getcallersp", funcTag, 135},
+	{"makeslice", funcTag, 113},
+	{"makeslice64", funcTag, 114},
+	{"makeslicecopy", funcTag, 115},
+	{"growslice", funcTag, 117},
+	{"unsafeslice", funcTag, 118},
+	{"unsafeslice64", funcTag, 119},
+	{"unsafeslicecheckptr", funcTag, 119},
+	{"memmove", funcTag, 120},
+	{"memclrNoHeapPointers", funcTag, 121},
+	{"memclrHasPointers", funcTag, 121},
+	{"memequal", funcTag, 122},
+	{"memequal0", funcTag, 123},
+	{"memequal8", funcTag, 123},
+	{"memequal16", funcTag, 123},
+	{"memequal32", funcTag, 123},
+	{"memequal64", funcTag, 123},
+	{"memequal128", funcTag, 123},
+	{"f32equal", funcTag, 124},
+	{"f64equal", funcTag, 124},
+	{"c64equal", funcTag, 124},
+	{"c128equal", funcTag, 124},
+	{"strequal", funcTag, 124},
+	{"interequal", funcTag, 124},
+	{"nilinterequal", funcTag, 124},
+	{"memhash", funcTag, 125},
+	{"memhash0", funcTag, 126},
+	{"memhash8", funcTag, 126},
+	{"memhash16", funcTag, 126},
+	{"memhash32", funcTag, 126},
+	{"memhash64", funcTag, 126},
+	{"memhash128", funcTag, 126},
+	{"f32hash", funcTag, 126},
+	{"f64hash", funcTag, 126},
+	{"c64hash", funcTag, 126},
+	{"c128hash", funcTag, 126},
+	{"strhash", funcTag, 126},
+	{"interhash", funcTag, 126},
+	{"nilinterhash", funcTag, 126},
+	{"int64div", funcTag, 127},
+	{"uint64div", funcTag, 128},
+	{"int64mod", funcTag, 127},
+	{"uint64mod", funcTag, 128},
+	{"float64toint64", funcTag, 129},
+	{"float64touint64", funcTag, 130},
+	{"float64touint32", funcTag, 131},
+	{"int64tofloat64", funcTag, 132},
+	{"uint64tofloat64", funcTag, 133},
+	{"uint32tofloat64", funcTag, 134},
+	{"complex128div", funcTag, 135},
+	{"getcallerpc", funcTag, 136},
+	{"getcallersp", funcTag, 136},
 	{"racefuncenter", funcTag, 31},
 	{"racefuncexit", funcTag, 9},
 	{"raceread", funcTag, 31},
 	{"racewrite", funcTag, 31},
-	{"racereadrange", funcTag, 136},
-	{"racewriterange", funcTag, 136},
-	{"msanread", funcTag, 136},
-	{"msanwrite", funcTag, 136},
-	{"msanmove", funcTag, 137},
-	{"checkptrAlignment", funcTag, 138},
-	{"checkptrArithmetic", funcTag, 140},
-	{"libfuzzerTraceCmp1", funcTag, 141},
-	{"libfuzzerTraceCmp2", funcTag, 142},
-	{"libfuzzerTraceCmp4", funcTag, 143},
-	{"libfuzzerTraceCmp8", funcTag, 144},
-	{"libfuzzerTraceConstCmp1", funcTag, 141},
-	{"libfuzzerTraceConstCmp2", funcTag, 142},
-	{"libfuzzerTraceConstCmp4", funcTag, 143},
-	{"libfuzzerTraceConstCmp8", funcTag, 144},
+	{"racereadrange", funcTag, 137},
+	{"racewriterange", funcTag, 137},
+	{"msanread", funcTag, 137},
+	{"msanwrite", funcTag, 137},
+	{"msanmove", funcTag, 138},
+	{"checkptrAlignment", funcTag, 139},
+	{"checkptrArithmetic", funcTag, 141},
+	{"libfuzzerTraceCmp1", funcTag, 142},
+	{"libfuzzerTraceCmp2", funcTag, 143},
+	{"libfuzzerTraceCmp4", funcTag, 144},
+	{"libfuzzerTraceCmp8", funcTag, 145},
+	{"libfuzzerTraceConstCmp1", funcTag, 142},
+	{"libfuzzerTraceConstCmp2", funcTag, 143},
+	{"libfuzzerTraceConstCmp4", funcTag, 144},
+	{"libfuzzerTraceConstCmp8", funcTag, 145},
 	{"x86HasPOPCNT", varTag, 6},
 	{"x86HasSSE41", varTag, 6},
 	{"x86HasFMA", varTag, 6},
@@ -224,7 +222,7 @@ func params(tlist ...*types.Type) []*types.Field {
 }
 
 func runtimeTypes() []*types.Type {
-	var typs [145]*types.Type
+	var typs [146]*types.Type
 	typs[0] = types.ByteType
 	typs[1] = types.NewPtr(typs[0])
 	typs[2] = types.Types[types.TANY]
@@ -282,93 +280,94 @@ func runtimeTypes() []*types.Type {
 	typs[54] = newSig(params(typs[3], typs[15], typs[3], typs[15], typs[5]), params(typs[15]))
 	typs[55] = newSig(params(typs[28], typs[15]), params(typs[46], typs[15]))
 	typs[56] = newSig(params(typs[28]), params(typs[15]))
-	typs[57] = newSig(params(typs[1], typs[2]), params(typs[2]))
-	typs[58] = types.Types[types.TUINT16]
-	typs[59] = newSig(params(typs[58]), params(typs[7]))
-	typs[60] = types.Types[types.TUINT32]
+	typs[57] = types.NewPtr(typs[5])
+	typs[58] = newSig(params(typs[1], typs[57]), params(typs[57]))
+	typs[59] = newSig(params(typs[1], typs[3]), params(typs[7]))
+	typs[60] = types.Types[types.TUINT16]
 	typs[61] = newSig(params(typs[60]), params(typs[7]))
-	typs[62] = newSig(params(typs[24]), params(typs[7]))
-	typs[63] = newSig(params(typs[28]), params(typs[7]))
-	typs[64] = types.Types[types.TUINT8]
-	typs[65] = types.NewSlice(typs[64])
-	typs[66] = newSig(params(typs[65]), params(typs[7]))
-	typs[67] = newSig(params(typs[1], typs[3]), params(typs[2]))
-	typs[68] = newSig(params(typs[1], typs[1]), params(typs[1]))
-	typs[69] = newSig(params(typs[1], typs[1], typs[1]), nil)
-	typs[70] = newSig(params(typs[1]), nil)
-	typs[71] = types.NewPtr(typs[5])
-	typs[72] = newSig(params(typs[71], typs[7], typs[7]), params(typs[6]))
-	typs[73] = newSig(nil, params(typs[60]))
-	typs[74] = types.NewMap(typs[2], typs[2])
-	typs[75] = newSig(params(typs[1], typs[22], typs[3]), params(typs[74]))
-	typs[76] = newSig(params(typs[1], typs[15], typs[3]), params(typs[74]))
-	typs[77] = newSig(nil, params(typs[74]))
-	typs[78] = newSig(params(typs[1], typs[74], typs[3]), params(typs[3]))
-	typs[79] = newSig(params(typs[1], typs[74], typs[60]), params(typs[3]))
-	typs[80] = newSig(params(typs[1], typs[74], typs[24]), params(typs[3]))
-	typs[81] = newSig(params(typs[1], typs[74], typs[28]), params(typs[3]))
-	typs[82] = newSig(params(typs[1], typs[74], typs[3], typs[1]), params(typs[3]))
-	typs[83] = newSig(params(typs[1], typs[74], typs[3]), params(typs[3], typs[6]))
-	typs[84] = newSig(params(typs[1], typs[74], typs[60]), params(typs[3], typs[6]))
-	typs[85] = newSig(params(typs[1], typs[74], typs[24]), params(typs[3], typs[6]))
-	typs[86] = newSig(params(typs[1], typs[74], typs[28]), params(typs[3], typs[6]))
-	typs[87] = newSig(params(typs[1], typs[74], typs[3], typs[1]), params(typs[3], typs[6]))
-	typs[88] = newSig(params(typs[1], typs[74], typs[7]), params(typs[3]))
-	typs[89] = newSig(params(typs[1], typs[74], typs[3]), nil)
-	typs[90] = newSig(params(typs[1], typs[74], typs[60]), nil)
-	typs[91] = newSig(params(typs[1], typs[74], typs[24]), nil)
-	typs[92] = newSig(params(typs[1], typs[74], typs[28]), nil)
-	typs[93] = newSig(params(typs[3]), nil)
-	typs[94] = newSig(params(typs[1], typs[74]), nil)
-	typs[95] = types.NewChan(typs[2], types.Cboth)
-	typs[96] = newSig(params(typs[1], typs[22]), params(typs[95]))
-	typs[97] = newSig(params(typs[1], typs[15]), params(typs[95]))
-	typs[98] = types.NewChan(typs[2], types.Crecv)
-	typs[99] = newSig(params(typs[98], typs[3]), nil)
-	typs[100] = newSig(params(typs[98], typs[3]), params(typs[6]))
-	typs[101] = types.NewChan(typs[2], types.Csend)
-	typs[102] = newSig(params(typs[101], typs[3]), nil)
-	typs[103] = types.NewArray(typs[0], 3)
-	typs[104] = types.NewStruct(types.NoPkg, []*types.Field{types.NewField(src.NoXPos, Lookup("enabled"), typs[6]), types.NewField(src.NoXPos, Lookup("pad"), typs[103]), types.NewField(src.NoXPos, Lookup("needed"), typs[6]), types.NewField(src.NoXPos, Lookup("cgo"), typs[6]), types.NewField(src.NoXPos, Lookup("alignme"), typs[24])})
-	typs[105] = newSig(params(typs[1], typs[3], typs[3]), nil)
-	typs[106] = newSig(params(typs[1], typs[3]), nil)
-	typs[107] = newSig(params(typs[1], typs[3], typs[15], typs[3], typs[15]), params(typs[15]))
-	typs[108] = newSig(params(typs[101], typs[3]), params(typs[6]))
-	typs[109] = newSig(params(typs[3], typs[98]), params(typs[6], typs[6]))
-	typs[110] = newSig(params(typs[71]), nil)
-	typs[111] = newSig(params(typs[1], typs[1], typs[71], typs[15], typs[15], typs[6]), params(typs[15], typs[6]))
-	typs[112] = newSig(params(typs[1], typs[15], typs[15]), params(typs[7]))
-	typs[113] = newSig(params(typs[1], typs[22], typs[22]), params(typs[7]))
-	typs[114] = newSig(params(typs[1], typs[15], typs[15], typs[7]), params(typs[7]))
-	typs[115] = types.NewSlice(typs[2])
-	typs[116] = newSig(params(typs[1], typs[115], typs[15]), params(typs[115]))
-	typs[117] = newSig(params(typs[1], typs[7], typs[15]), nil)
-	typs[118] = newSig(params(typs[1], typs[7], typs[22]), nil)
-	typs[119] = newSig(params(typs[3], typs[3], typs[5]), nil)
-	typs[120] = newSig(params(typs[7], typs[5]), nil)
-	typs[121] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6]))
-	typs[122] = newSig(params(typs[3], typs[3]), params(typs[6]))
-	typs[123] = newSig(params(typs[7], typs[7]), params(typs[6]))
-	typs[124] = newSig(params(typs[7], typs[5], typs[5]), params(typs[5]))
-	typs[125] = newSig(params(typs[7], typs[5]), params(typs[5]))
-	typs[126] = newSig(params(typs[22], typs[22]), params(typs[22]))
-	typs[127] = newSig(params(typs[24], typs[24]), params(typs[24]))
-	typs[128] = newSig(params(typs[20]), params(typs[22]))
-	typs[129] = newSig(params(typs[20]), params(typs[24]))
-	typs[130] = newSig(params(typs[20]), params(typs[60]))
-	typs[131] = newSig(params(typs[22]), params(typs[20]))
-	typs[132] = newSig(params(typs[24]), params(typs[20]))
-	typs[133] = newSig(params(typs[60]), params(typs[20]))
-	typs[134] = newSig(params(typs[26], typs[26]), params(typs[26]))
-	typs[135] = newSig(nil, params(typs[5]))
-	typs[136] = newSig(params(typs[5], typs[5]), nil)
-	typs[137] = newSig(params(typs[5], typs[5], typs[5]), nil)
-	typs[138] = newSig(params(typs[7], typs[1], typs[5]), nil)
-	typs[139] = types.NewSlice(typs[7])
-	typs[140] = newSig(params(typs[7], typs[139]), nil)
-	typs[141] = newSig(params(typs[64], typs[64]), nil)
-	typs[142] = newSig(params(typs[58], typs[58]), nil)
+	typs[62] = types.Types[types.TUINT32]
+	typs[63] = newSig(params(typs[62]), params(typs[7]))
+	typs[64] = newSig(params(typs[24]), params(typs[7]))
+	typs[65] = newSig(params(typs[28]), params(typs[7]))
+	typs[66] = types.Types[types.TUINT8]
+	typs[67] = types.NewSlice(typs[66])
+	typs[68] = newSig(params(typs[67]), params(typs[7]))
+	typs[69] = newSig(params(typs[1], typs[1]), params(typs[1]))
+	typs[70] = newSig(params(typs[1], typs[2]), params(typs[2]))
+	typs[71] = newSig(params(typs[1], typs[1], typs[1]), nil)
+	typs[72] = newSig(params(typs[1]), nil)
+	typs[73] = newSig(params(typs[57], typs[7], typs[7]), params(typs[6]))
+	typs[74] = newSig(nil, params(typs[62]))
+	typs[75] = types.NewMap(typs[2], typs[2])
+	typs[76] = newSig(params(typs[1], typs[22], typs[3]), params(typs[75]))
+	typs[77] = newSig(params(typs[1], typs[15], typs[3]), params(typs[75]))
+	typs[78] = newSig(nil, params(typs[75]))
+	typs[79] = newSig(params(typs[1], typs[75], typs[3]), params(typs[3]))
+	typs[80] = newSig(params(typs[1], typs[75], typs[62]), params(typs[3]))
+	typs[81] = newSig(params(typs[1], typs[75], typs[24]), params(typs[3]))
+	typs[82] = newSig(params(typs[1], typs[75], typs[28]), params(typs[3]))
+	typs[83] = newSig(params(typs[1], typs[75], typs[3], typs[1]), params(typs[3]))
+	typs[84] = newSig(params(typs[1], typs[75], typs[3]), params(typs[3], typs[6]))
+	typs[85] = newSig(params(typs[1], typs[75], typs[62]), params(typs[3], typs[6]))
+	typs[86] = newSig(params(typs[1], typs[75], typs[24]), params(typs[3], typs[6]))
+	typs[87] = newSig(params(typs[1], typs[75], typs[28]), params(typs[3], typs[6]))
+	typs[88] = newSig(params(typs[1], typs[75], typs[3], typs[1]), params(typs[3], typs[6]))
+	typs[89] = newSig(params(typs[1], typs[75], typs[7]), params(typs[3]))
+	typs[90] = newSig(params(typs[1], typs[75], typs[3]), nil)
+	typs[91] = newSig(params(typs[1], typs[75], typs[62]), nil)
+	typs[92] = newSig(params(typs[1], typs[75], typs[24]), nil)
+	typs[93] = newSig(params(typs[1], typs[75], typs[28]), nil)
+	typs[94] = newSig(params(typs[3]), nil)
+	typs[95] = newSig(params(typs[1], typs[75]), nil)
+	typs[96] = types.NewChan(typs[2], types.Cboth)
+	typs[97] = newSig(params(typs[1], typs[22]), params(typs[96]))
+	typs[98] = newSig(params(typs[1], typs[15]), params(typs[96]))
+	typs[99] = types.NewChan(typs[2], types.Crecv)
+	typs[100] = newSig(params(typs[99], typs[3]), nil)
+	typs[101] = newSig(params(typs[99], typs[3]), params(typs[6]))
+	typs[102] = types.NewChan(typs[2], types.Csend)
+	typs[103] = newSig(params(typs[102], typs[3]), nil)
+	typs[104] = types.NewArray(typs[0], 3)
+	typs[105] = types.NewStruct(types.NoPkg, []*types.Field{types.NewField(src.NoXPos, Lookup("enabled"), typs[6]), types.NewField(src.NoXPos, Lookup("pad"), typs[104]), types.NewField(src.NoXPos, Lookup("needed"), typs[6]), types.NewField(src.NoXPos, Lookup("cgo"), typs[6]), types.NewField(src.NoXPos, Lookup("alignme"), typs[24])})
+	typs[106] = newSig(params(typs[1], typs[3], typs[3]), nil)
+	typs[107] = newSig(params(typs[1], typs[3]), nil)
+	typs[108] = newSig(params(typs[1], typs[3], typs[15], typs[3], typs[15]), params(typs[15]))
+	typs[109] = newSig(params(typs[102], typs[3]), params(typs[6]))
+	typs[110] = newSig(params(typs[3], typs[99]), params(typs[6], typs[6]))
+	typs[111] = newSig(params(typs[57]), nil)
+	typs[112] = newSig(params(typs[1], typs[1], typs[57], typs[15], typs[15], typs[6]), params(typs[15], typs[6]))
+	typs[113] = newSig(params(typs[1], typs[15], typs[15]), params(typs[7]))
+	typs[114] = newSig(params(typs[1], typs[22], typs[22]), params(typs[7]))
+	typs[115] = newSig(params(typs[1], typs[15], typs[15], typs[7]), params(typs[7]))
+	typs[116] = types.NewSlice(typs[2])
+	typs[117] = newSig(params(typs[1], typs[116], typs[15]), params(typs[116]))
+	typs[118] = newSig(params(typs[1], typs[7], typs[15]), nil)
+	typs[119] = newSig(params(typs[1], typs[7], typs[22]), nil)
+	typs[120] = newSig(params(typs[3], typs[3], typs[5]), nil)
+	typs[121] = newSig(params(typs[7], typs[5]), nil)
+	typs[122] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6]))
+	typs[123] = newSig(params(typs[3], typs[3]), params(typs[6]))
+	typs[124] = newSig(params(typs[7], typs[7]), params(typs[6]))
+	typs[125] = newSig(params(typs[7], typs[5], typs[5]), params(typs[5]))
+	typs[126] = newSig(params(typs[7], typs[5]), params(typs[5]))
+	typs[127] = newSig(params(typs[22], typs[22]), params(typs[22]))
+	typs[128] = newSig(params(typs[24], typs[24]), params(typs[24]))
+	typs[129] = newSig(params(typs[20]), params(typs[22]))
+	typs[130] = newSig(params(typs[20]), params(typs[24]))
+	typs[131] = newSig(params(typs[20]), params(typs[62]))
+	typs[132] = newSig(params(typs[22]), params(typs[20]))
+	typs[133] = newSig(params(typs[24]), params(typs[20]))
+	typs[134] = newSig(params(typs[62]), params(typs[20]))
+	typs[135] = newSig(params(typs[26], typs[26]), params(typs[26]))
+	typs[136] = newSig(nil, params(typs[5]))
+	typs[137] = newSig(params(typs[5], typs[5]), nil)
+	typs[138] = newSig(params(typs[5], typs[5], typs[5]), nil)
+	typs[139] = newSig(params(typs[7], typs[1], typs[5]), nil)
+	typs[140] = types.NewSlice(typs[7])
+	typs[141] = newSig(params(typs[7], typs[140]), nil)
+	typs[142] = newSig(params(typs[66], typs[66]), nil)
 	typs[143] = newSig(params(typs[60], typs[60]), nil)
-	typs[144] = newSig(params(typs[24], typs[24]), nil)
+	typs[144] = newSig(params(typs[62], typs[62]), nil)
+	typs[145] = newSig(params(typs[24], typs[24]), nil)
 	return typs[:]
 }
diff --git a/src/cmd/compile/internal/typecheck/builtin/runtime.go b/src/cmd/compile/internal/typecheck/builtin/runtime.go
index 2b29ea3c08c..605b9042880 100644
--- a/src/cmd/compile/internal/typecheck/builtin/runtime.go
+++ b/src/cmd/compile/internal/typecheck/builtin/runtime.go
@@ -84,10 +84,15 @@ func decoderune(string, int) (retv rune, retk int)
 func countrunes(string) int
 
 // Non-empty-interface to non-empty-interface conversion.
-func convI2I(typ *byte, elem any) (ret any)
+func convI2I(typ *byte, itab *uintptr) (ret *uintptr)
 
-// Specialized type-to-interface conversion.
-// These return only a data pointer.
+// Convert non-interface type to the data word of a (empty or nonempty) interface.
+func convT(typ *byte, elem *any) unsafe.Pointer
+
+// Same as convT, for types with no pointers in them.
+func convTnoptr(typ *byte, elem *any) unsafe.Pointer
+
+// Specialized versions of convT for specific types.
 // These functions take concrete types in the runtime. But they may
 // be used for a wider range of types, which have the same memory
 // layout as the parameter type. The compiler converts the
@@ -99,14 +104,6 @@ func convT64(val uint64) unsafe.Pointer
 func convTstring(val string) unsafe.Pointer
 func convTslice(val []uint8) unsafe.Pointer
 
-// Type to empty-interface conversion.
-func convT2E(typ *byte, elem *any) (ret any)
-func convT2Enoptr(typ *byte, elem *any) (ret any)
-
-// Type to non-empty-interface conversion.
-func convT2I(tab *byte, elem *any) (ret any)
-func convT2Inoptr(tab *byte, elem *any) (ret any)
-
 // interface type assertions x.(T)
 func assertE2I(inter *byte, typ *byte) *byte
 func assertE2I2(inter *byte, eface any) (ret any)
diff --git a/src/cmd/compile/internal/walk/convert.go b/src/cmd/compile/internal/walk/convert.go
index d15575f643c..27a07ce4b60 100644
--- a/src/cmd/compile/internal/walk/convert.go
+++ b/src/cmd/compile/internal/walk/convert.go
@@ -39,56 +39,100 @@ func walkConv(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
 	return typecheck.Conv(mkcall(fn, types.Types[result], init, typecheck.Conv(n.X, types.Types[param])), n.Type())
 }
 
-// walkConvInterface walks an OCONVIFACE or OCONVIDATA node.
+// walkConvInterface walks an OCONVIFACE node.
 func walkConvInterface(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
 
 	n.X = walkExpr(n.X, init)
 
 	fromType := n.X.Type()
 	toType := n.Type()
-	if n.Op() == ir.OCONVIDATA {
-		// Just convert to empty interface, to make it easy.
-		// The caller throws away the type word.
-		toType = types.NewInterface(types.LocalPkg, nil)
-		// Note: don't pass fromType to MarkTypeUsedInInterface because it is likely
-		// a shape type. The appropriate call to MarkTypeUsedInInterface will come
-		// when building the dictionary (from which the matching type word will come).
-	} else if !fromType.IsInterface() && !ir.IsBlank(ir.CurFunc.Nname) {
+	if !fromType.IsInterface() && !ir.IsBlank(ir.CurFunc.Nname) {
 		// skip unnamed functions (func _())
 		reflectdata.MarkTypeUsedInInterface(fromType, ir.CurFunc.LSym)
 	}
 
-	// typeword generates the type word of the interface value.
-	typeword := func() ir.Node {
+	if !fromType.IsInterface() {
+		var typeWord ir.Node
 		if toType.IsEmptyInterface() {
-			return reflectdata.TypePtr(fromType)
+			typeWord = reflectdata.TypePtr(fromType)
+		} else {
+			typeWord = reflectdata.ITabAddr(fromType, toType)
 		}
-		return reflectdata.ITabAddr(fromType, toType)
-	}
-
-	// Optimize convT2E or convT2I as a two-word copy when T is pointer-shaped.
-	if types.IsDirectIface(fromType) {
-		l := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeword(), n.X)
+		l := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeWord, dataWord(n.X, init, n.Esc() != ir.EscNone))
 		l.SetType(toType)
 		l.SetTypecheck(n.Typecheck())
 		return l
 	}
+	if fromType.IsEmptyInterface() {
+		base.Fatalf("OCONVIFACE can't operate on an empty interface")
+	}
 
-	// Optimize convT2{E,I} for many cases in which T is not pointer-shaped,
-	// by using an existing addressable value identical to n.Left
-	// or creating one on the stack.
+	// Evaluate the input interface.
+	c := typecheck.Temp(fromType)
+	init.Append(ir.NewAssignStmt(base.Pos, c, n.X))
+
+	// Grab its parts.
+	itab := ir.NewUnaryExpr(base.Pos, ir.OITAB, c)
+	itab.SetType(types.Types[types.TUINTPTR].PtrTo())
+	itab.SetTypecheck(1)
+	data := ir.NewUnaryExpr(base.Pos, ir.OIDATA, c)
+	data.SetType(types.Types[types.TUINT8].PtrTo()) // Type is generic pointer - we're just passing it through.
+	data.SetTypecheck(1)
+
+	var typeWord ir.Node
+	if toType.IsEmptyInterface() {
+		// Implement interface to empty interface conversion.
+		// res = itab
+		// if res != nil {
+		//    res = res.type
+		// }
+		typeWord = typecheck.Temp(types.NewPtr(types.Types[types.TUINT8]))
+		init.Append(ir.NewAssignStmt(base.Pos, typeWord, itab))
+		nif := ir.NewIfStmt(base.Pos, typecheck.Expr(ir.NewBinaryExpr(base.Pos, ir.ONE, typeWord, typecheck.NodNil())), nil, nil)
+		nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, typeWord, itabType(typeWord))}
+		init.Append(nif)
+	} else {
+		// Must be converting I2I (more specific to less specific interface).
+		// res = convI2I(toType, itab)
+		fn := typecheck.LookupRuntime("convI2I")
+		types.CalcSize(fn.Type())
+		call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
+		call.Args = []ir.Node{reflectdata.TypePtr(toType), itab}
+		typeWord = walkExpr(typecheck.Expr(call), init)
+	}
+
+	// Build the result.
+	// e = iface{typeWord, data}
+	e := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeWord, data)
+	e.SetType(toType) // assign type manually, typecheck doesn't understand OEFACE.
+	e.SetTypecheck(1)
+	return e
+}
+
+// Returns the data word (the second word) used to represent n in an interface.
+// n must not be of interface type.
+// esc describes whether the result escapes.
+func dataWord(n ir.Node, init *ir.Nodes, escapes bool) ir.Node {
+	fromType := n.Type()
+
+	// If it's a pointer, it is its own representation.
+	if types.IsDirectIface(fromType) {
+		return n
+	}
+
+	// Try a bunch of cases to avoid an allocation.
 	var value ir.Node
 	switch {
 	case fromType.Size() == 0:
-		// n.Left is zero-sized. Use zerobase.
-		cheapExpr(n.X, init) // Evaluate n.Left for side-effects. See issue 19246.
+		// n is zero-sized. Use zerobase.
+		cheapExpr(n, init) // Evaluate n for side-effects. See issue 19246.
 		value = ir.NewLinksymExpr(base.Pos, ir.Syms.Zerobase, types.Types[types.TUINTPTR])
 	case fromType.IsBoolean() || (fromType.Size() == 1 && fromType.IsInteger()):
-		// n.Left is a bool/byte. Use staticuint64s[n.Left * 8] on little-endian
-		// and staticuint64s[n.Left * 8 + 7] on big-endian.
-		n.X = cheapExpr(n.X, init)
-		// byteindex widens n.Left so that the multiplication doesn't overflow.
-		index := ir.NewBinaryExpr(base.Pos, ir.OLSH, byteindex(n.X), ir.NewInt(3))
+		// n is a bool/byte. Use staticuint64s[n * 8] on little-endian
+		// and staticuint64s[n * 8 + 7] on big-endian.
+		n = cheapExpr(n, init)
+		// byteindex widens n so that the multiplication doesn't overflow.
+		index := ir.NewBinaryExpr(base.Pos, ir.OLSH, byteindex(n), ir.NewInt(3))
 		if ssagen.Arch.LinkArch.ByteOrder == binary.BigEndian {
 			index = ir.NewBinaryExpr(base.Pos, ir.OADD, index, ir.NewInt(7))
 		}
@@ -98,118 +142,71 @@ func walkConvInterface(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
 		xe := ir.NewIndexExpr(base.Pos, staticuint64s, index)
 		xe.SetBounded(true)
 		value = xe
-	case n.X.Op() == ir.ONAME && n.X.(*ir.Name).Class == ir.PEXTERN && n.X.(*ir.Name).Readonly():
-		// n.Left is a readonly global; use it directly.
-		value = n.X
-	case !fromType.IsInterface() && n.Esc() == ir.EscNone && fromType.Width <= 1024:
-		// n.Left does not escape. Use a stack temporary initialized to n.Left.
+	case n.Op() == ir.ONAME && n.(*ir.Name).Class == ir.PEXTERN && n.(*ir.Name).Readonly():
+		// n is a readonly global; use it directly.
+		value = n
+	case !escapes && fromType.Width <= 1024:
+		// n does not escape. Use a stack temporary initialized to n.
 		value = typecheck.Temp(fromType)
-		init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, value, n.X)))
+		init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, value, n)))
 	}
-
 	if value != nil {
-		// Value is identical to n.Left.
-		// Construct the interface directly: {type/itab, &value}.
-		l := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeword(), typecheck.Expr(typecheck.NodAddr(value)))
-		l.SetType(toType)
-		l.SetTypecheck(n.Typecheck())
-		return l
+		// The interface data word is &value.
+		return typecheck.Expr(typecheck.NodAddr(value))
 	}
 
-	// Implement interface to empty interface conversion.
-	// tmp = i.itab
-	// if tmp != nil {
-	//    tmp = tmp.type
-	// }
-	// e = iface{tmp, i.data}
-	if toType.IsEmptyInterface() && fromType.IsInterface() && !fromType.IsEmptyInterface() {
-		// Evaluate the input interface.
-		c := typecheck.Temp(fromType)
-		init.Append(ir.NewAssignStmt(base.Pos, c, n.X))
+	// Time to do an allocation. We'll call into the runtime for that.
+	fnname, argType, needsaddr := dataWordFuncName(fromType)
+	fn := typecheck.LookupRuntime(fnname)
 
-		// Get the itab out of the interface.
-		tmp := typecheck.Temp(types.NewPtr(types.Types[types.TUINT8]))
-		init.Append(ir.NewAssignStmt(base.Pos, tmp, typecheck.Expr(ir.NewUnaryExpr(base.Pos, ir.OITAB, c))))
-
-		// Get the type out of the itab.
-		nif := ir.NewIfStmt(base.Pos, typecheck.Expr(ir.NewBinaryExpr(base.Pos, ir.ONE, tmp, typecheck.NodNil())), nil, nil)
-		nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, tmp, itabType(tmp))}
-		init.Append(nif)
-
-		// Build the result.
-		e := ir.NewBinaryExpr(base.Pos, ir.OEFACE, tmp, ifaceData(n.Pos(), c, types.NewPtr(types.Types[types.TUINT8])))
-		e.SetType(toType) // assign type manually, typecheck doesn't understand OEFACE.
-		e.SetTypecheck(1)
-		return e
-	}
-
-	fnname, argType, needsaddr := convFuncName(fromType, toType)
-
-	if !needsaddr && !fromType.IsInterface() {
-		// Use a specialized conversion routine that only returns a data pointer.
-		// ptr = convT2X(val)
-		// e = iface{typ/tab, ptr}
-		fn := typecheck.LookupRuntime(fnname)
-		types.CalcSize(fromType)
-
-		arg := n.X
+	var args []ir.Node
+	if needsaddr {
+		// Types of large or unknown size are passed by reference.
+		// Orderexpr arranged for n to be a temporary for all
+		// the conversions it could see. Comparison of an interface
+		// with a non-interface, especially in a switch on interface value
+		// with non-interface cases, is not visible to order.stmt, so we
+		// have to fall back on allocating a temp here.
+		if !ir.IsAddressable(n) {
+			n = copyExpr(n, fromType, init)
+		}
+		fn = typecheck.SubstArgTypes(fn, fromType)
+		args = []ir.Node{reflectdata.TypePtr(fromType), typecheck.NodAddr(n)}
+	} else {
+		// Use a specialized conversion routine that takes the type being
+		// converted by value, not by pointer.
+		var arg ir.Node
 		switch {
 		case fromType == argType:
 			// already in the right type, nothing to do
+			arg = n
 		case fromType.Kind() == argType.Kind(),
 			fromType.IsPtrShaped() && argType.IsPtrShaped():
 			// can directly convert (e.g. named type to underlying type, or one pointer to another)
-			arg = ir.NewConvExpr(n.Pos(), ir.OCONVNOP, argType, arg)
+			// TODO: never happens because pointers are directIface?
+			arg = ir.NewConvExpr(n.Pos(), ir.OCONVNOP, argType, n)
 		case fromType.IsInteger() && argType.IsInteger():
 			// can directly convert (e.g. int32 to uint32)
-			arg = ir.NewConvExpr(n.Pos(), ir.OCONV, argType, arg)
+			arg = ir.NewConvExpr(n.Pos(), ir.OCONV, argType, n)
 		default:
 			// unsafe cast through memory
-			arg = copyExpr(arg, arg.Type(), init)
+			arg = copyExpr(n, fromType, init)
 			var addr ir.Node = typecheck.NodAddr(arg)
 			addr = ir.NewConvExpr(n.Pos(), ir.OCONVNOP, argType.PtrTo(), addr)
 			arg = ir.NewStarExpr(n.Pos(), addr)
 			arg.SetType(argType)
 		}
-
-		call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
-		call.Args = []ir.Node{arg}
-		e := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeword(), safeExpr(walkExpr(typecheck.Expr(call), init), init))
-		e.SetType(toType)
-		e.SetTypecheck(1)
-		return e
+		args = []ir.Node{arg}
 	}
-
-	var tab ir.Node
-	if fromType.IsInterface() {
-		// convI2I
-		tab = reflectdata.TypePtr(toType)
-	} else {
-		// convT2x
-		tab = typeword()
-	}
-
-	v := n.X
-	if needsaddr {
-		// Types of large or unknown size are passed by reference.
-		// Orderexpr arranged for n.Left to be a temporary for all
-		// the conversions it could see. Comparison of an interface
-		// with a non-interface, especially in a switch on interface value
-		// with non-interface cases, is not visible to order.stmt, so we
-		// have to fall back on allocating a temp here.
-		if !ir.IsAddressable(v) {
-			v = copyExpr(v, v.Type(), init)
-		}
-		v = typecheck.NodAddr(v)
-	}
-
-	types.CalcSize(fromType)
-	fn := typecheck.LookupRuntime(fnname)
-	fn = typecheck.SubstArgTypes(fn, fromType, toType)
-	types.CalcSize(fn.Type())
 	call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
-	call.Args = []ir.Node{tab, v}
-	return walkExpr(typecheck.Expr(call), init)
+	call.Args = args
+	return safeExpr(walkExpr(typecheck.Expr(call), init), init)
+}
+
+// walkConvIData walks an OCONVIDATA node.
+func walkConvIData(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
+	n.X = walkExpr(n.X, init)
+	return dataWord(n.X, init, n.Esc() != ir.EscNone)
 }
 
 // walkBytesRunesToString walks an OBYTES2STR or ORUNES2STR node.
@@ -320,50 +317,35 @@ func walkStringToRunes(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
 	return mkcall("stringtoslicerune", n.Type(), init, a, typecheck.Conv(n.X, types.Types[types.TSTRING]))
 }
 
-// convFuncName builds the runtime function name for interface conversion.
-// It also returns the argument type that the runtime function takes, and
-// whether the function expects the data by address.
-// Not all names are possible. For example, we never generate convE2E or convE2I.
-func convFuncName(from, to *types.Type) (fnname string, argType *types.Type, needsaddr bool) {
-	tkind := to.Tie()
-	switch from.Tie() {
-	case 'I':
-		if tkind == 'I' {
-			return "convI2I", types.Types[types.TINTER], false
-		}
-	case 'T':
+// dataWordFuncName returns the name of the function used to convert a value of type "from"
+// to the data word of an interface.
+// argType is the type the argument needs to be coerced to.
+// needsaddr reports whether the value should be passed (needaddr==false) or its address (needsaddr==true).
+func dataWordFuncName(from *types.Type) (fnname string, argType *types.Type, needsaddr bool) {
+	if from.IsInterface() {
+		base.Fatalf("can only handle non-interfaces")
+	}
+	switch {
+	case from.Size() == 2 && from.Align == 2:
+		return "convT16", types.Types[types.TUINT16], false
+	case from.Size() == 4 && from.Align == 4 && !from.HasPointers():
+		return "convT32", types.Types[types.TUINT32], false
+	case from.Size() == 8 && from.Align == types.Types[types.TUINT64].Align && !from.HasPointers():
+		return "convT64", types.Types[types.TUINT64], false
+	}
+	if sc := from.SoleComponent(); sc != nil {
 		switch {
-		case from.Size() == 2 && from.Align == 2:
-			return "convT16", types.Types[types.TUINT16], false
-		case from.Size() == 4 && from.Align == 4 && !from.HasPointers():
-			return "convT32", types.Types[types.TUINT32], false
-		case from.Size() == 8 && from.Align == types.Types[types.TUINT64].Align && !from.HasPointers():
-			return "convT64", types.Types[types.TUINT64], false
-		}
-		if sc := from.SoleComponent(); sc != nil {
-			switch {
-			case sc.IsString():
-				return "convTstring", types.Types[types.TSTRING], false
-			case sc.IsSlice():
-				return "convTslice", types.NewSlice(types.Types[types.TUINT8]), false // the element type doesn't matter
-			}
-		}
-
-		switch tkind {
-		case 'E':
-			if !from.HasPointers() {
-				return "convT2Enoptr", types.Types[types.TUNSAFEPTR], true
-			}
-			return "convT2E", types.Types[types.TUNSAFEPTR], true
-		case 'I':
-			if !from.HasPointers() {
-				return "convT2Inoptr", types.Types[types.TUNSAFEPTR], true
-			}
-			return "convT2I", types.Types[types.TUNSAFEPTR], true
+		case sc.IsString():
+			return "convTstring", types.Types[types.TSTRING], false
+		case sc.IsSlice():
+			return "convTslice", types.NewSlice(types.Types[types.TUINT8]), false // the element type doesn't matter
 		}
 	}
-	base.Fatalf("unknown conv func %c2%c", from.Tie(), to.Tie())
-	panic("unreachable")
+
+	if from.HasPointers() {
+		return "convT", types.Types[types.TUNSAFEPTR], true
+	}
+	return "convTnoptr", types.Types[types.TUNSAFEPTR], true
 }
 
 // rtconvfn returns the parameter and result types that will be used by a
diff --git a/src/cmd/compile/internal/walk/expr.go b/src/cmd/compile/internal/walk/expr.go
index f95b6f4639f..26e225440a7 100644
--- a/src/cmd/compile/internal/walk/expr.go
+++ b/src/cmd/compile/internal/walk/expr.go
@@ -212,10 +212,7 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
 
 	case ir.OCONVIDATA:
 		n := n.(*ir.ConvExpr)
-		r := ir.NewUnaryExpr(n.Pos(), ir.OIDATA, walkConvInterface(n, init))
-		r.SetType(types.Types[types.TUNSAFEPTR])
-		r.SetTypecheck(1)
-		return r
+		return walkConvIData(n, init)
 
 	case ir.OCONV, ir.OCONVNOP:
 		n := n.(*ir.ConvExpr)
diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go
index c5fd0c1e1da..6e336f565cf 100644
--- a/src/cmd/compile/internal/walk/order.go
+++ b/src/cmd/compile/internal/walk/order.go
@@ -1166,11 +1166,7 @@ func (o *orderState) expr1(n, lhs ir.Node) ir.Node {
 		if n.X.Type().IsInterface() {
 			return n
 		}
-		to := n.Type()
-		if n.Op() == ir.OCONVIDATA {
-			to = types.NewInterface(types.LocalPkg, nil)
-		}
-		if _, _, needsaddr := convFuncName(n.X.Type(), to); needsaddr || isStaticCompositeLiteral(n.X) {
+		if _, _, needsaddr := dataWordFuncName(n.X.Type()); needsaddr || isStaticCompositeLiteral(n.X) {
 			// Need a temp if we need to pass the address to the conversion function.
 			// We also process static composite literal node here, making a named static global
 			// whose address we can put directly in an interface (see OCONVIFACE/OCONVIDATA case in walk).
diff --git a/src/runtime/iface.go b/src/runtime/iface.go
index 79a49c0dffb..3d1d9d6ba18 100644
--- a/src/runtime/iface.go
+++ b/src/runtime/iface.go
@@ -316,20 +316,30 @@ var (
 // The convXXX functions succeed on a nil input, whereas the assertXXX
 // functions fail on a nil input.
 
-func convT2E(t *_type, elem unsafe.Pointer) (e eface) {
+// convT converts a value of type t, which is pointed to by v, to a pointer that can
+// be used as the second word of an interface value.
+func convT(t *_type, v unsafe.Pointer) unsafe.Pointer {
 	if raceenabled {
-		raceReadObjectPC(t, elem, getcallerpc(), abi.FuncPCABIInternal(convT2E))
+		raceReadObjectPC(t, v, getcallerpc(), abi.FuncPCABIInternal(convT))
 	}
 	if msanenabled {
-		msanread(elem, t.size)
+		msanread(v, t.size)
 	}
 	x := mallocgc(t.size, t, true)
-	// TODO: We allocate a zeroed object only to overwrite it with actual data.
-	// Figure out how to avoid zeroing. Also below in convT2Eslice, convT2I, convT2Islice.
-	typedmemmove(t, x, elem)
-	e._type = t
-	e.data = x
-	return
+	typedmemmove(t, x, v)
+	return x
+}
+func convTnoptr(t *_type, v unsafe.Pointer) unsafe.Pointer {
+	// TODO: maybe take size instead of type?
+	if raceenabled {
+		raceReadObjectPC(t, v, getcallerpc(), abi.FuncPCABIInternal(convTnoptr))
+	}
+	if msanenabled {
+		msanread(v, t.size)
+	}
+	x := mallocgc(t.size, t, false)
+	memmove(x, v, t.size)
+	return x
 }
 
 func convT16(val uint16) (x unsafe.Pointer) {
@@ -389,63 +399,16 @@ func convTslice(val []byte) (x unsafe.Pointer) {
 	return
 }
 
-func convT2Enoptr(t *_type, elem unsafe.Pointer) (e eface) {
-	if raceenabled {
-		raceReadObjectPC(t, elem, getcallerpc(), abi.FuncPCABIInternal(convT2Enoptr))
+// convI2I returns the new itab to be used for the destination value
+// when converting a value with itab src to the dst interface.
+func convI2I(dst *interfacetype, src *itab) *itab {
+	if src == nil {
+		return nil
 	}
-	if msanenabled {
-		msanread(elem, t.size)
+	if src.inter == dst {
+		return src
 	}
-	x := mallocgc(t.size, t, false)
-	memmove(x, elem, t.size)
-	e._type = t
-	e.data = x
-	return
-}
-
-func convT2I(tab *itab, elem unsafe.Pointer) (i iface) {
-	t := tab._type
-	if raceenabled {
-		raceReadObjectPC(t, elem, getcallerpc(), abi.FuncPCABIInternal(convT2I))
-	}
-	if msanenabled {
-		msanread(elem, t.size)
-	}
-	x := mallocgc(t.size, t, true)
-	typedmemmove(t, x, elem)
-	i.tab = tab
-	i.data = x
-	return
-}
-
-func convT2Inoptr(tab *itab, elem unsafe.Pointer) (i iface) {
-	t := tab._type
-	if raceenabled {
-		raceReadObjectPC(t, elem, getcallerpc(), abi.FuncPCABIInternal(convT2Inoptr))
-	}
-	if msanenabled {
-		msanread(elem, t.size)
-	}
-	x := mallocgc(t.size, t, false)
-	memmove(x, elem, t.size)
-	i.tab = tab
-	i.data = x
-	return
-}
-
-func convI2I(inter *interfacetype, i iface) (r iface) {
-	tab := i.tab
-	if tab == nil {
-		return
-	}
-	if tab.inter == inter {
-		r.tab = tab
-		r.data = i.data
-		return
-	}
-	r.tab = getitab(inter, tab._type, false)
-	r.data = i.data
-	return
+	return getitab(dst, src._type, false)
 }
 
 func assertI2I(inter *interfacetype, tab *itab) *itab {
diff --git a/test/devirt.go b/test/devirt.go
index e0149d82292..d5c815222e4 100644
--- a/test/devirt.go
+++ b/test/devirt.go
@@ -31,9 +31,8 @@ func main() {
 		panic("not 3")
 	}
 
-	// Can't do types that aren't "direct" interfaces (yet).
 	r = indirectiface{3, 4, 5}
-	if r.Value() != 12 {
+	if r.Value() != 12 { // ERROR "de-virtualizing call$"
 		panic("not 12")
 	}
 }
diff --git a/test/fixedbugs/issue20250.go b/test/fixedbugs/issue20250.go
index 1a513bea56d..aed7b25d1bf 100644
--- a/test/fixedbugs/issue20250.go
+++ b/test/fixedbugs/issue20250.go
@@ -17,7 +17,7 @@ type T struct {
 func f(a T) { // ERROR "live at entry to f: a"
 	var e interface{} // ERROR "stack object e interface \{\}$"
 	func() {          // ERROR "live at entry to f.func1: a &e"
-		e = a.s // ERROR "live at call to convT2E: &e" "stack object a T$"
+		e = a.s // ERROR "live at call to convT: &e" "stack object a T$"
 	}()
 	// Before the fix, both a and e were live at the previous line.
 	_ = e
diff --git a/test/live.go b/test/live.go
index 856e56f3d29..6130f7f0694 100644
--- a/test/live.go
+++ b/test/live.go
@@ -144,8 +144,8 @@ var i9 interface{}
 func f9() bool {
 	g8()
 	x := i9
-	y := interface{}(g18()) // ERROR "live at call to convT2E: x.data$" "live at call to g18: x.data$" "stack object .autotmp_[0-9]+ \[2\]string$"
-	i9 = y                  // make y escape so the line above has to call convT2E
+	y := interface{}(g18()) // ERROR "live at call to convT: x.data$" "live at call to g18: x.data$" "stack object .autotmp_[0-9]+ \[2\]string$"
+	i9 = y                  // make y escape so the line above has to call convT
 	return x != y
 }
 
@@ -503,7 +503,7 @@ func f31(b1, b2, b3 bool) {
 		g31(g18()) // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
 	}
 	if b2 {
-		h31(g18()) // ERROR "live at call to convT2E: .autotmp_[0-9]+$" "live at call to newobject: .autotmp_[0-9]+$"
+		h31(g18()) // ERROR "live at call to convT: .autotmp_[0-9]+$" "live at call to newobject: .autotmp_[0-9]+$"
 	}
 	if b3 {
 		panic(g18())
diff --git a/test/live_regabi.go b/test/live_regabi.go
index d362ee287d0..2883b83baed 100644
--- a/test/live_regabi.go
+++ b/test/live_regabi.go
@@ -139,8 +139,8 @@ var i9 interface{}
 func f9() bool {
 	g8()
 	x := i9
-	y := interface{}(g18()) // ERROR "live at call to convT2E: x.data$" "live at call to g18: x.data$" "stack object .autotmp_[0-9]+ \[2\]string$"
-	i9 = y                  // make y escape so the line above has to call convT2E
+	y := interface{}(g18()) // ERROR "live at call to convT: x.data$" "live at call to g18: x.data$" "stack object .autotmp_[0-9]+ \[2\]string$"
+	i9 = y                  // make y escape so the line above has to call convT
 	return x != y
 }
 
@@ -498,7 +498,7 @@ func f31(b1, b2, b3 bool) {
 		g31(g18()) // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
 	}
 	if b2 {
-		h31(g18()) // ERROR "live at call to convT2E: .autotmp_[0-9]+$" "live at call to newobject: .autotmp_[0-9]+$"
+		h31(g18()) // ERROR "live at call to convT: .autotmp_[0-9]+$" "live at call to newobject: .autotmp_[0-9]+$"
 	}
 	if b3 {
 		panic(g18())

From ca3c6985cd143f170699d22ed984b7eed0f68e4d Mon Sep 17 00:00:00 2001
From: Keith Randall 
Date: Tue, 3 Aug 2021 08:10:17 -0700
Subject: [PATCH 890/940] [dev.typeparams] cmd/compile: implement generic type
 switches

Add a new dynamicType node, which is used as a case entry when
the type being switched to is generic.

Change-Id: Ice77c6f224b8fdd3ff574fdf4a8ea5f6c7ddbe75
Reviewed-on: https://go-review.googlesource.com/c/go/+/339429
Trust: Keith Randall 
Trust: Dan Scales 
Run-TryBot: Keith Randall 
Reviewed-by: Dan Scales 
---
 src/cmd/compile/internal/escape/expr.go     |  3 ++
 src/cmd/compile/internal/ir/expr.go         |  9 ++++
 src/cmd/compile/internal/ir/node.go         |  8 ++--
 src/cmd/compile/internal/ir/node_gen.go     | 28 ++++++++++++
 src/cmd/compile/internal/ir/op_string.go    | 15 ++++---
 src/cmd/compile/internal/ir/type.go         | 14 ++++++
 src/cmd/compile/internal/noder/irgen.go     |  4 ++
 src/cmd/compile/internal/noder/stencil.go   | 50 +++++++++++++++++++++
 src/cmd/compile/internal/noder/transform.go |  4 ++
 src/cmd/compile/internal/typecheck/stmt.go  |  4 ++
 src/cmd/compile/internal/walk/switch.go     | 45 +++++++++++++++----
 test/typeparam/typeswitch1.go               | 29 ++++++++++++
 test/typeparam/typeswitch1.out              |  5 +++
 test/typeparam/typeswitch2.go               | 31 +++++++++++++
 test/typeparam/typeswitch2.out              |  5 +++
 test/typeparam/typeswitch3.go               | 35 +++++++++++++++
 test/typeparam/typeswitch3.out              |  3 ++
 test/typeparam/typeswitch4.go               | 33 ++++++++++++++
 test/typeparam/typeswitch4.out              |  3 ++
 test/typeparam/typeswitch5.go               | 28 ++++++++++++
 test/typeparam/typeswitch5.out              |  4 ++
 21 files changed, 342 insertions(+), 18 deletions(-)
 create mode 100644 test/typeparam/typeswitch1.go
 create mode 100644 test/typeparam/typeswitch1.out
 create mode 100644 test/typeparam/typeswitch2.go
 create mode 100644 test/typeparam/typeswitch2.out
 create mode 100644 test/typeparam/typeswitch3.go
 create mode 100644 test/typeparam/typeswitch3.out
 create mode 100644 test/typeparam/typeswitch4.go
 create mode 100644 test/typeparam/typeswitch4.out
 create mode 100644 test/typeparam/typeswitch5.go
 create mode 100644 test/typeparam/typeswitch5.out

diff --git a/src/cmd/compile/internal/escape/expr.go b/src/cmd/compile/internal/escape/expr.go
index 4a6304d47a6..62afb5b9288 100644
--- a/src/cmd/compile/internal/escape/expr.go
+++ b/src/cmd/compile/internal/escape/expr.go
@@ -262,6 +262,9 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
 		// Arguments of OADDSTR never escape;
 		// runtime.concatstrings makes sure of that.
 		e.discards(n.List)
+
+	case ir.ODYNAMICTYPE:
+		// Nothing to do - argument is a *runtime._type (+ maybe a *runtime.itab) pointing to static data section
 	}
 }
 
diff --git a/src/cmd/compile/internal/ir/expr.go b/src/cmd/compile/internal/ir/expr.go
index 9c5fbbc9aa8..dc28483907a 100644
--- a/src/cmd/compile/internal/ir/expr.go
+++ b/src/cmd/compile/internal/ir/expr.go
@@ -700,6 +700,15 @@ func NewDynamicTypeAssertExpr(pos src.XPos, op Op, x, t Node) *DynamicTypeAssert
 	return n
 }
 
+func (n *DynamicTypeAssertExpr) SetOp(op Op) {
+	switch op {
+	default:
+		panic(n.no("SetOp " + op.String()))
+	case ODYNAMICDOTTYPE, ODYNAMICDOTTYPE2:
+		n.op = op
+	}
+}
+
 // A UnaryExpr is a unary expression Op X,
 // or Op(X) for a builtin function that does not end up being a call.
 type UnaryExpr struct {
diff --git a/src/cmd/compile/internal/ir/node.go b/src/cmd/compile/internal/ir/node.go
index e5f0c38f861..f071cb78ce5 100644
--- a/src/cmd/compile/internal/ir/node.go
+++ b/src/cmd/compile/internal/ir/node.go
@@ -258,7 +258,8 @@ const (
 	OBREAK // break [Label]
 	// OCASE:  case List: Body (List==nil means default)
 	//   For OTYPESW, List is a OTYPE node for the specified type (or OLITERAL
-	//   for nil), and, if a type-switch variable is specified, Rlist is an
+	//   for nil) or an ODYNAMICTYPE indicating a runtime type for generics.
+	//   If a type-switch variable is specified, Var is an
 	//   ONAME for the version of the type-switch variable with the specified
 	//   type.
 	OCASE
@@ -320,8 +321,9 @@ const (
 	OLINKSYMOFFSET // offset within a name
 
 	// opcodes for generics
-	ODYNAMICDOTTYPE
-	ODYNAMICDOTTYPE2
+	ODYNAMICDOTTYPE  // x = i.(T) where T is a type parameter (or derived from a type parameter)
+	ODYNAMICDOTTYPE2 // x, ok = i.(T) where T is a type parameter (or derived from a type parameter)
+	ODYNAMICTYPE     // a type node for type switches (represents a dynamic target type for a type switch)
 
 	// arch-specific opcodes
 	OTAILCALL    // tail call to another function
diff --git a/src/cmd/compile/internal/ir/node_gen.go b/src/cmd/compile/internal/ir/node_gen.go
index 56db6bb9cf7..aa41c03beb9 100644
--- a/src/cmd/compile/internal/ir/node_gen.go
+++ b/src/cmd/compile/internal/ir/node_gen.go
@@ -463,6 +463,34 @@ func (n *Decl) editChildren(edit func(Node) Node) {
 	}
 }
 
+func (n *DynamicType) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
+func (n *DynamicType) copy() Node {
+	c := *n
+	c.init = copyNodes(c.init)
+	return &c
+}
+func (n *DynamicType) doChildren(do func(Node) bool) bool {
+	if doNodes(n.init, do) {
+		return true
+	}
+	if n.X != nil && do(n.X) {
+		return true
+	}
+	if n.ITab != nil && do(n.ITab) {
+		return true
+	}
+	return false
+}
+func (n *DynamicType) editChildren(edit func(Node) Node) {
+	editNodes(n.init, edit)
+	if n.X != nil {
+		n.X = edit(n.X).(Node)
+	}
+	if n.ITab != nil {
+		n.ITab = edit(n.ITab).(Node)
+	}
+}
+
 func (n *DynamicTypeAssertExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
 func (n *DynamicTypeAssertExpr) copy() Node {
 	c := *n
diff --git a/src/cmd/compile/internal/ir/op_string.go b/src/cmd/compile/internal/ir/op_string.go
index 7b08ee287a7..b8cee718182 100644
--- a/src/cmd/compile/internal/ir/op_string.go
+++ b/src/cmd/compile/internal/ir/op_string.go
@@ -164,16 +164,17 @@ func _() {
 	_ = x[OLINKSYMOFFSET-153]
 	_ = x[ODYNAMICDOTTYPE-154]
 	_ = x[ODYNAMICDOTTYPE2-155]
-	_ = x[OTAILCALL-156]
-	_ = x[OGETG-157]
-	_ = x[OGETCALLERPC-158]
-	_ = x[OGETCALLERSP-159]
-	_ = x[OEND-160]
+	_ = x[ODYNAMICTYPE-156]
+	_ = x[OTAILCALL-157]
+	_ = x[OGETG-158]
+	_ = x[OGETCALLERPC-159]
+	_ = x[OGETCALLERSP-160]
+	_ = x[OEND-161]
 }
 
-const _Op_name = "XXXNAMENONAMETYPEPACKLITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVIDATACONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFUNSAFEADDUNSAFESLICEMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWFUNCINSTTCHANTMAPTSTRUCTTINTERTFUNCTARRAYTSLICEINLCALLEFACEITABIDATASPTRCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKLINKSYMOFFSETDYNAMICDOTTYPEDYNAMICDOTTYPE2TAILCALLGETGGETCALLERPCGETCALLERSPEND"
+const _Op_name = "XXXNAMENONAMETYPEPACKLITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVIDATACONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFUNSAFEADDUNSAFESLICEMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWFUNCINSTTCHANTMAPTSTRUCTTINTERTFUNCTARRAYTSLICEINLCALLEFACEITABIDATASPTRCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKLINKSYMOFFSETDYNAMICDOTTYPEDYNAMICDOTTYPE2DYNAMICTYPETAILCALLGETGGETCALLERPCGETCALLERSPEND"
 
-var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 37, 39, 42, 48, 52, 58, 64, 73, 85, 94, 103, 115, 124, 136, 138, 141, 151, 158, 165, 172, 176, 180, 188, 196, 205, 208, 213, 220, 227, 233, 242, 250, 258, 264, 268, 277, 286, 293, 297, 300, 307, 315, 322, 328, 331, 337, 344, 352, 356, 363, 371, 373, 375, 377, 379, 381, 383, 388, 393, 401, 404, 413, 416, 420, 428, 435, 444, 457, 460, 463, 466, 469, 472, 475, 481, 484, 487, 493, 497, 500, 504, 509, 514, 520, 525, 529, 534, 542, 550, 556, 565, 576, 583, 592, 596, 603, 611, 615, 619, 623, 630, 637, 645, 651, 660, 671, 679, 688, 693, 698, 702, 710, 715, 719, 722, 730, 734, 736, 741, 743, 748, 754, 760, 766, 772, 780, 785, 789, 796, 802, 807, 813, 819, 826, 831, 835, 840, 844, 849, 857, 863, 870, 877, 883, 890, 903, 917, 932, 940, 944, 955, 966, 969}
+var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 37, 39, 42, 48, 52, 58, 64, 73, 85, 94, 103, 115, 124, 136, 138, 141, 151, 158, 165, 172, 176, 180, 188, 196, 205, 208, 213, 220, 227, 233, 242, 250, 258, 264, 268, 277, 286, 293, 297, 300, 307, 315, 322, 328, 331, 337, 344, 352, 356, 363, 371, 373, 375, 377, 379, 381, 383, 388, 393, 401, 404, 413, 416, 420, 428, 435, 444, 457, 460, 463, 466, 469, 472, 475, 481, 484, 487, 493, 497, 500, 504, 509, 514, 520, 525, 529, 534, 542, 550, 556, 565, 576, 583, 592, 596, 603, 611, 615, 619, 623, 630, 637, 645, 651, 660, 671, 679, 688, 693, 698, 702, 710, 715, 719, 722, 730, 734, 736, 741, 743, 748, 754, 760, 766, 772, 780, 785, 789, 796, 802, 807, 813, 819, 826, 831, 835, 840, 844, 849, 857, 863, 870, 877, 883, 890, 903, 917, 932, 943, 951, 955, 966, 977, 980}
 
 func (i Op) String() string {
 	if i >= Op(len(_Op_index)-1) {
diff --git a/src/cmd/compile/internal/ir/type.go b/src/cmd/compile/internal/ir/type.go
index 431468375a1..63dd673dcdf 100644
--- a/src/cmd/compile/internal/ir/type.go
+++ b/src/cmd/compile/internal/ir/type.go
@@ -319,3 +319,17 @@ func TypeNodeAt(pos src.XPos, t *types.Type) Ntype {
 	}
 	return newTypeNode(pos, t)
 }
+
+// A DynamicType represents the target type in a type switch.
+type DynamicType struct {
+	miniExpr
+	X    Node // a *runtime._type for the targeted type
+	ITab Node // for type switches from nonempty interfaces to non-interfaces, this is the itab for that pair.
+}
+
+func NewDynamicType(pos src.XPos, x Node) *DynamicType {
+	n := &DynamicType{X: x}
+	n.pos = pos
+	n.op = ODYNAMICTYPE
+	return n
+}
diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go
index 571e294416a..7bc8a6bcc32 100644
--- a/src/cmd/compile/internal/noder/irgen.go
+++ b/src/cmd/compile/internal/noder/irgen.go
@@ -107,6 +107,10 @@ type gfInfo struct {
 	// Nodes in generic functions that are a conversion from a typeparam/derived
 	// type to a specific interface.
 	itabConvs []ir.Node
+	// For type switches on nonempty interfaces, a map from OTYPE entries of
+	// HasTParam type, to the interface type we're switching from.
+	// TODO: what if the type we're switching from is a shape type?
+	type2switchType map[ir.Node]*types.Type
 }
 
 // instInfo is information gathered on an gcshape (or fully concrete)
diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go
index b37f76dcee4..5f2250d2f4b 100644
--- a/src/cmd/compile/internal/noder/stencil.go
+++ b/src/cmd/compile/internal/noder/stencil.go
@@ -1140,6 +1140,38 @@ func (subst *subster) node(n ir.Node) ir.Node {
 			m = ir.NewDynamicTypeAssertExpr(dt.Pos(), op, dt.X, rt)
 			m.SetType(dt.Type())
 			m.SetTypecheck(1)
+		case ir.OCASE:
+			if _, ok := x.(*ir.CommClause); ok {
+				// This is not a type switch. TODO: Should we use an OSWITCH case here instead of OCASE?
+				break
+			}
+			x := x.(*ir.CaseClause)
+			m := m.(*ir.CaseClause)
+			for i, c := range x.List {
+				if c.Op() == ir.OTYPE && c.Type().HasTParam() {
+					// Use a *runtime._type for the dynamic type.
+					ix := findDictType(subst.info, c.Type())
+					assert(ix >= 0)
+					dt := ir.NewDynamicType(c.Pos(), getDictionaryEntry(c.Pos(), subst.info.dictParam, ix, subst.info.dictLen))
+
+					// For type switch from nonemoty interfaces to non-interfaces, we need an itab as well.
+					if _, ok := subst.info.gfInfo.type2switchType[c]; ok {
+						// Type switch from nonempty interface. We need a *runtime.itab
+						// for the dynamic type.
+						ix := -1
+						for i, ic := range subst.info.gfInfo.itabConvs {
+							if ic == c {
+								ix = subst.info.startItabConv + i
+								break
+							}
+						}
+						assert(ix >= 0)
+						dt.ITab = getDictionaryEntry(c.Pos(), subst.info.dictParam, ix, subst.info.dictLen)
+					}
+					typed(m.List[i].Type(), dt)
+					m.List[i] = dt
+				}
+			}
 		}
 		return m
 	}
@@ -1483,6 +1515,9 @@ func (g *irgen) finalizeSyms() {
 			case ir.OCONVIFACE:
 				srctype = subst.Typ(n.(*ir.ConvExpr).X.Type())
 				dsttype = subst.Typ(n.Type())
+			case ir.OTYPE:
+				srctype = subst.Typ(n.Type())
+				dsttype = subst.Typ(info.type2switchType[n])
 			default:
 				base.Fatalf("itab entry with unknown op %s", n.Op())
 			}
@@ -1652,6 +1687,21 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo {
 				ir.Visit(n1, visitFunc)
 			}
 		}
+		if n.Op() == ir.OSWITCH && n.(*ir.SwitchStmt).Tag != nil && n.(*ir.SwitchStmt).Tag.Op() == ir.OTYPESW && !n.(*ir.SwitchStmt).Tag.(*ir.TypeSwitchGuard).X.Type().IsEmptyInterface() {
+			for _, cc := range n.(*ir.SwitchStmt).Cases {
+				for _, c := range cc.List {
+					if c.Op() == ir.OTYPE && c.Type().HasTParam() {
+						// Type switch from a non-empty interface to a noninterface.
+						infoPrint("  Itab for type switch: %v\n", c)
+						info.itabConvs = append(info.itabConvs, c)
+						if info.type2switchType == nil {
+							info.type2switchType = map[ir.Node]*types.Type{}
+						}
+						info.type2switchType[c] = n.(*ir.SwitchStmt).Tag.(*ir.TypeSwitchGuard).X.Type()
+					}
+				}
+			}
+		}
 		addType(&info, n, n.Type())
 	}
 
diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go
index 61af92b62a7..ff113877dfc 100644
--- a/src/cmd/compile/internal/noder/transform.go
+++ b/src/cmd/compile/internal/noder/transform.go
@@ -313,6 +313,10 @@ assignOK:
 			r := r.(*ir.TypeAssertExpr)
 			stmt.SetOp(ir.OAS2DOTTYPE)
 			r.SetOp(ir.ODOTTYPE2)
+		case ir.ODYNAMICDOTTYPE:
+			r := r.(*ir.DynamicTypeAssertExpr)
+			stmt.SetOp(ir.OAS2DOTTYPE)
+			r.SetOp(ir.ODYNAMICDOTTYPE2)
 		default:
 			break assignOK
 		}
diff --git a/src/cmd/compile/internal/typecheck/stmt.go b/src/cmd/compile/internal/typecheck/stmt.go
index 01434118222..c322d490e5b 100644
--- a/src/cmd/compile/internal/typecheck/stmt.go
+++ b/src/cmd/compile/internal/typecheck/stmt.go
@@ -172,6 +172,10 @@ assignOK:
 			r := r.(*ir.TypeAssertExpr)
 			stmt.SetOp(ir.OAS2DOTTYPE)
 			r.SetOp(ir.ODOTTYPE2)
+		case ir.ODYNAMICDOTTYPE:
+			r := r.(*ir.DynamicTypeAssertExpr)
+			stmt.SetOp(ir.OAS2DOTTYPE)
+			r.SetOp(ir.ODYNAMICDOTTYPE2)
 		default:
 			break assignOK
 		}
diff --git a/src/cmd/compile/internal/walk/switch.go b/src/cmd/compile/internal/walk/switch.go
index 162de018f63..3705c5b1926 100644
--- a/src/cmd/compile/internal/walk/switch.go
+++ b/src/cmd/compile/internal/walk/switch.go
@@ -360,10 +360,10 @@ func walkSwitchType(sw *ir.SwitchStmt) {
 			}
 
 			if singleType != nil && singleType.IsInterface() {
-				s.Add(ncase.Pos(), n1.Type(), caseVar, jmp)
+				s.Add(ncase.Pos(), n1, caseVar, jmp)
 				caseVarInitialized = true
 			} else {
-				s.Add(ncase.Pos(), n1.Type(), nil, jmp)
+				s.Add(ncase.Pos(), n1, nil, jmp)
 			}
 		}
 
@@ -377,6 +377,17 @@ func walkSwitchType(sw *ir.SwitchStmt) {
 				}
 				val = ifaceData(ncase.Pos(), s.facename, singleType)
 			}
+			if len(ncase.List) == 1 && ncase.List[0].Op() == ir.ODYNAMICTYPE {
+				dt := ncase.List[0].(*ir.DynamicType)
+				x := ir.NewDynamicTypeAssertExpr(ncase.Pos(), ir.ODYNAMICDOTTYPE, val, dt.X)
+				if dt.ITab != nil {
+					// TODO: make ITab a separate field in DynamicTypeAssertExpr?
+					x.T = dt.ITab
+				}
+				x.SetType(caseVar.Type())
+				x.SetTypecheck(1)
+				val = x
+			}
 			l := []ir.Node{
 				ir.NewDecl(ncase.Pos(), ir.ODCL, caseVar),
 				ir.NewAssignStmt(ncase.Pos(), caseVar, val),
@@ -446,7 +457,8 @@ type typeClause struct {
 	body ir.Nodes
 }
 
-func (s *typeSwitch) Add(pos src.XPos, typ *types.Type, caseVar *ir.Name, jmp ir.Node) {
+func (s *typeSwitch) Add(pos src.XPos, n1 ir.Node, caseVar *ir.Name, jmp ir.Node) {
+	typ := n1.Type()
 	var body ir.Nodes
 	if caseVar != nil {
 		l := []ir.Node{
@@ -462,9 +474,25 @@ func (s *typeSwitch) Add(pos src.XPos, typ *types.Type, caseVar *ir.Name, jmp ir
 	// cv, ok = iface.(type)
 	as := ir.NewAssignListStmt(pos, ir.OAS2, nil, nil)
 	as.Lhs = []ir.Node{caseVar, s.okname} // cv, ok =
-	dot := ir.NewTypeAssertExpr(pos, s.facename, nil)
-	dot.SetType(typ) // iface.(type)
-	as.Rhs = []ir.Node{dot}
+	switch n1.Op() {
+	case ir.OTYPE:
+		// Static type assertion (non-generic)
+		dot := ir.NewTypeAssertExpr(pos, s.facename, nil)
+		dot.SetType(typ) // iface.(type)
+		as.Rhs = []ir.Node{dot}
+	case ir.ODYNAMICTYPE:
+		// Dynamic type assertion (generic)
+		dt := n1.(*ir.DynamicType)
+		dot := ir.NewDynamicTypeAssertExpr(pos, ir.ODYNAMICDOTTYPE, s.facename, dt.X)
+		if dt.ITab != nil {
+			dot.T = dt.ITab
+		}
+		dot.SetType(typ)
+		dot.SetTypecheck(1)
+		as.Rhs = []ir.Node{dot}
+	default:
+		base.Fatalf("unhandled type case %s", n1.Op())
+	}
 	appendWalkStmt(&body, as)
 
 	// if ok { goto label }
@@ -473,9 +501,10 @@ func (s *typeSwitch) Add(pos src.XPos, typ *types.Type, caseVar *ir.Name, jmp ir
 	nif.Body = []ir.Node{jmp}
 	body.Append(nif)
 
-	if !typ.IsInterface() {
+	if n1.Op() == ir.OTYPE && !typ.IsInterface() {
+		// Defer static, noninterface cases so they can be binary searched by hash.
 		s.clauses = append(s.clauses, typeClause{
-			hash: types.TypeHash(typ),
+			hash: types.TypeHash(n1.Type()),
 			body: body,
 		})
 		return
diff --git a/test/typeparam/typeswitch1.go b/test/typeparam/typeswitch1.go
new file mode 100644
index 00000000000..27161b3db80
--- /dev/null
+++ b/test/typeparam/typeswitch1.go
@@ -0,0 +1,29 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f[T any](i interface{}) {
+	switch i.(type) {
+	case T:
+		println("T")
+	case int:
+		println("int")
+	case int32, int16:
+		println("int32/int16")
+	case struct { a, b T }:
+		println("struct{T,T}")
+	default:
+		println("other")
+	}
+}
+func main() {
+	f[float64](float64(6))
+	f[float64](int(7))
+	f[float64](int32(8))
+	f[float64](struct{a, b float64}{a:1, b:2})
+	f[float64](int8(9))
+}
diff --git a/test/typeparam/typeswitch1.out b/test/typeparam/typeswitch1.out
new file mode 100644
index 00000000000..4bdbccfddb3
--- /dev/null
+++ b/test/typeparam/typeswitch1.out
@@ -0,0 +1,5 @@
+T
+int
+int32/int16
+struct{T,T}
+other
diff --git a/test/typeparam/typeswitch2.go b/test/typeparam/typeswitch2.go
new file mode 100644
index 00000000000..913c56321cc
--- /dev/null
+++ b/test/typeparam/typeswitch2.go
@@ -0,0 +1,31 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "reflect"
+
+func f[T any](i interface{}) {
+	switch x := i.(type) {
+	case T:
+		println("T", x)
+	case int:
+		println("int", x)
+	case int32, int16:
+		println("int32/int16", reflect.ValueOf(x).Int())
+	case struct { a, b T }:
+		println("struct{T,T}", x.a, x.b)
+	default:
+		println("other", reflect.ValueOf(x).Int())
+	}
+}
+func main() {
+	f[float64](float64(6))
+	f[float64](int(7))
+	f[float64](int32(8))
+	f[float64](struct{a, b float64}{a:1, b:2})
+	f[float64](int8(9))
+}
diff --git a/test/typeparam/typeswitch2.out b/test/typeparam/typeswitch2.out
new file mode 100644
index 00000000000..944cc04cc6e
--- /dev/null
+++ b/test/typeparam/typeswitch2.out
@@ -0,0 +1,5 @@
+T +6.000000e+000
+int 7
+int32/int16 8
+struct{T,T} +1.000000e+000 +2.000000e+000
+other 9
diff --git a/test/typeparam/typeswitch3.go b/test/typeparam/typeswitch3.go
new file mode 100644
index 00000000000..6ab03011409
--- /dev/null
+++ b/test/typeparam/typeswitch3.go
@@ -0,0 +1,35 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I interface { foo() int }
+
+type myint int
+
+func (x myint) foo() int { return int(x) }
+
+type myfloat float64
+func (x myfloat) foo() int { return int(x) }
+
+type myint32 int32
+func (x myint32) foo() int { return int(x) }
+
+func f[T I](i I) {
+	switch x := i.(type) {
+	case T:
+		println("T", x.foo())
+	case myint:
+		println("myint", x.foo())
+	default:
+		println("other", x.foo())
+	}
+}
+func main() {
+	f[myfloat](myint(6))
+	f[myfloat](myfloat(7))
+	f[myfloat](myint32(8))
+}
diff --git a/test/typeparam/typeswitch3.out b/test/typeparam/typeswitch3.out
new file mode 100644
index 00000000000..2c69c72c300
--- /dev/null
+++ b/test/typeparam/typeswitch3.out
@@ -0,0 +1,3 @@
+myint 6
+T 7
+other 8
diff --git a/test/typeparam/typeswitch4.go b/test/typeparam/typeswitch4.go
new file mode 100644
index 00000000000..6113026b658
--- /dev/null
+++ b/test/typeparam/typeswitch4.go
@@ -0,0 +1,33 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I interface { foo() int }
+
+type myint int
+
+func (x myint) foo() int {return int(x)}
+
+type myfloat float64
+func (x myfloat) foo() int {return int(x)}
+
+type myint32 int32
+func (x myint32) foo() int { return int(x) }
+
+func f[T I](i I) {
+	switch x := i.(type) {
+	case T, myint32:
+		println("T/myint32", x.foo())
+	default:
+		println("other", x.foo())
+	}
+}
+func main() {
+	f[myfloat](myint(6))
+	f[myfloat](myfloat(7))
+	f[myfloat](myint32(8))
+}
diff --git a/test/typeparam/typeswitch4.out b/test/typeparam/typeswitch4.out
new file mode 100644
index 00000000000..b0d54077c92
--- /dev/null
+++ b/test/typeparam/typeswitch4.out
@@ -0,0 +1,3 @@
+other 6
+T/myint32 7
+T/myint32 8
diff --git a/test/typeparam/typeswitch5.go b/test/typeparam/typeswitch5.go
new file mode 100644
index 00000000000..1fc6e0a14ee
--- /dev/null
+++ b/test/typeparam/typeswitch5.go
@@ -0,0 +1,28 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type myint int
+func (x myint) foo() int {return int(x)}
+
+type myfloat float64
+func (x myfloat) foo() float64 {return float64(x) }
+
+func f[T any](i interface{}) {
+	switch x := i.(type) {
+	case interface { foo() T }:
+		println("fooer", x.foo())
+	default:
+		println("other")
+	}
+}
+func main() {
+	f[int](myint(6))
+	f[int](myfloat(7))
+	f[float64](myint(8))
+	f[float64](myfloat(9))
+}
diff --git a/test/typeparam/typeswitch5.out b/test/typeparam/typeswitch5.out
new file mode 100644
index 00000000000..6b4cb4416f4
--- /dev/null
+++ b/test/typeparam/typeswitch5.out
@@ -0,0 +1,4 @@
+fooer 6
+other
+other
+fooer +9.000000e+000

From 9f4d6a83594a04f0fc82c33f373b7e7bcf64f7f2 Mon Sep 17 00:00:00 2001
From: Dan Scales 
Date: Fri, 6 Aug 2021 13:24:14 -0700
Subject: [PATCH 891/940] [dev.typeparams] cmd/compile: call transformArgs
 before early typecheckaste in noder

In the cases where we do an early call to typecheckaste() in noder to
expose CONVIFACE nodes, we need a preceding call to transformArgs().
This is needed to allow typecheckaste() to run correctly, in the case of
f(g()), where g has multiple return values.

I also cleaned up the code a bit and commented the code in Call(), and
we do the call to typecheckaste() in several more cases.

In stencil.go:stencil(), I moved the transformCall earlier for the
OCALLMETH/ODOTMETH case, just as I did in my previous CL for
OCALL/OFUNCINST. By doing this, transformArgs no longer needs to deal
with the extra dictionary args. Therefore, I was able to simply
transformArgs() to look like typecheckargs() again, and make use of
RewriteMultiValue directly.

Updates #47514

Change-Id: I49eb82ac05707e50c2e2fb03e39458a70491d406
Reviewed-on: https://go-review.googlesource.com/c/go/+/340531
Trust: Dan Scales 
Run-TryBot: Dan Scales 
TryBot-Result: Go Bot 
Reviewed-by: Keith Randall 
---
 src/cmd/compile/internal/noder/helpers.go   | 45 ++++++-------
 src/cmd/compile/internal/noder/stencil.go   | 11 ++--
 src/cmd/compile/internal/noder/stmt.go      |  1 +
 src/cmd/compile/internal/noder/transform.go | 70 +++------------------
 test/typeparam/issue47514b.go               | 19 ++++++
 5 files changed, 55 insertions(+), 91 deletions(-)
 create mode 100644 test/typeparam/issue47514b.go

diff --git a/src/cmd/compile/internal/noder/helpers.go b/src/cmd/compile/internal/noder/helpers.go
index 2b00a9d7a63..b9dbd030af1 100644
--- a/src/cmd/compile/internal/noder/helpers.go
+++ b/src/cmd/compile/internal/noder/helpers.go
@@ -171,39 +171,34 @@ func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool)
 		}
 	}
 
-	if fun.Type().HasTParam() {
+	if fun.Type().HasTParam() || fun.Op() == ir.OXDOT || fun.Op() == ir.OFUNCINST {
 		// If the fun arg is or has a type param, we can't do all the
-		// transformations, since we may not have needed properties yet.
-		// (e.g. number of return values, etc). However, if we do have the
-		// function type (even though it is parameterized), then can add in
-		// any needed CONVIFACE nodes. We can't do anything if fun is a type
-		// param (which is probably described by a structural constraint)
+		// transformations, since we may not have needed properties yet
+		// (e.g. number of return values, etc). The same applies if a fun
+		// which is an XDOT could not be transformed yet because of a generic
+		// type in the X of the selector expression.
+		//
+		// A function instantiation (even if fully concrete) shouldn't be
+		// transformed yet, because we need to add the dictionary during the
+		// transformation.
+		//
+		// However, if we have a function type (even though it is
+		// parameterized), then we can add in any needed CONVIFACE nodes via
+		// typecheckaste(). We need to call transformArgs() to deal first
+		// with the f(g(()) case where g returns multiple return values. We
+		// can't do anything if fun is a type param (which is probably
+		// described by a structural constraint)
 		if fun.Type().Kind() == types.TFUNC {
+			transformArgs(n)
 			typecheckaste(ir.OCALL, fun, n.IsDDD, fun.Type().Params(), n.Args, true)
 		}
 		return typed(typ, n)
 	}
 
-	if fun.Op() == ir.OXDOT {
-		if !fun.(*ir.SelectorExpr).X.Type().HasTParam() {
-			base.FatalfAt(pos, "Expecting type param receiver in %v", fun)
-		}
-		// For methods called in a generic function, don't do any extra
-		// transformations. We will do those later when we create the
-		// instantiated function and have the correct receiver type.
-		typed(typ, n)
-		return n
-	}
-	if fun.Op() != ir.OFUNCINST {
-		// If no type params, do the normal call transformations. This
-		// will convert OCALL to OCALLFUNC.
-		typed(typ, n)
-		transformCall(n)
-		return n
-	}
-
-	// Leave the op as OCALL, which indicates the call still needs typechecking.
+	// If no type params, do the normal call transformations. This
+	// will convert OCALL to OCALLFUNC.
 	typed(typ, n)
+	transformCall(n)
 	return n
 }
 
diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go
index 5f2250d2f4b..23e8090136f 100644
--- a/src/cmd/compile/internal/noder/stencil.go
+++ b/src/cmd/compile/internal/noder/stencil.go
@@ -161,18 +161,21 @@ func (g *irgen) stencil() {
 					}
 				}
 
+				// Transform the Call now, which changes OCALL
+				// to OCALLFUNC and does typecheckaste/assignconvfn.
+				transformCall(call)
+
 				st := g.getInstantiation(gf, targs, true)
 				dictValue, usingSubdict := g.getDictOrSubdict(declInfo, n, gf, targs, true)
 				// We have to be using a subdictionary, since this is
 				// a generic method call.
 				assert(usingSubdict)
 
-				call.SetOp(ir.OCALL)
+				// Transform to a function call, by appending the
+				// dictionary and the receiver to the args.
+				call.SetOp(ir.OCALLFUNC)
 				call.X = st.Nname
 				call.Args.Prepend(dictValue, meth.X)
-				// Transform the Call now, which changes OCALL
-				// to OCALLFUNC and does typecheckaste/assignconvfn.
-				transformCall(call)
 				modified = true
 			}
 		})
diff --git a/src/cmd/compile/internal/noder/stmt.go b/src/cmd/compile/internal/noder/stmt.go
index 5af4a2da9c6..1949f56095f 100644
--- a/src/cmd/compile/internal/noder/stmt.go
+++ b/src/cmd/compile/internal/noder/stmt.go
@@ -129,6 +129,7 @@ func (g *irgen) stmt(stmt syntax.Stmt) ir.Node {
 				// Delay transforming the return statement if any of the
 				// return values have a type param.
 				if !ir.HasNamedResults(ir.CurFunc) {
+					transformArgs(n)
 					// But add CONVIFACE nodes where needed if
 					// any of the return values have interface type.
 					typecheckaste(ir.ORETURN, nil, false, ir.CurFunc.Type().Results(), n.Results, true)
diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go
index ff113877dfc..e1eeb8e7394 100644
--- a/src/cmd/compile/internal/noder/transform.go
+++ b/src/cmd/compile/internal/noder/transform.go
@@ -365,7 +365,7 @@ assignOK:
 	}
 }
 
-// Corresponds to, but slightly more general than, typecheck.typecheckargs.
+// Corresponds to typecheck.typecheckargs.  Really just deals with multi-value calls.
 func transformArgs(n ir.InitNode) {
 	var list []ir.Node
 	switch n := n.(type) {
@@ -379,76 +379,22 @@ func transformArgs(n ir.InitNode) {
 	case *ir.ReturnStmt:
 		list = n.Results
 	}
-
-	// Look to see if we have any multi-return functions as arguments.
-	extra := 0
-	for _, arg := range list {
-		t := arg.Type()
-		if t.IsFuncArgStruct() {
-			num := t.Fields().Len()
-			if num <= 1 {
-				base.Fatalf("multi-return type with only %d parts", num)
-			}
-			extra += num - 1
-		}
-	}
-	// If not, nothing to do.
-	if extra == 0 {
+	if len(list) != 1 {
 		return
 	}
 
-	// Rewrite f(..., g(), ...) into t1, ..., tN = g(); f(..., t1, ..., tN, ...).
+	t := list[0].Type()
+	if t == nil || !t.IsFuncArgStruct() {
+		return
+	}
 
 	// Save n as n.Orig for fmt.go.
 	if ir.Orig(n) == n {
 		n.(ir.OrigNode).SetOrig(ir.SepCopy(n))
 	}
 
-	// If we're outside of function context, then this call will
-	// be executed during the generated init function. However,
-	// init.go hasn't yet created it. Instead, associate the
-	// temporary variables with  InitTodoFunc for now, and init.go
-	// will reassociate them later when it's appropriate.
-	static := ir.CurFunc == nil
-	if static {
-		ir.CurFunc = typecheck.InitTodoFunc
-	}
-
-	// Expand multi-return function calls.
-	// The spec only allows a multi-return function as an argument
-	// if it is the only argument. This code must handle calls to
-	// stenciled generic functions which have extra arguments
-	// (like the dictionary) so it must handle a slightly more general
-	// cases, like f(n, g()) where g is multi-return.
-	newList := make([]ir.Node, 0, len(list)+extra)
-	for _, arg := range list {
-		t := arg.Type()
-		if t.IsFuncArgStruct() {
-			as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, []ir.Node{arg})
-			for _, f := range t.FieldSlice() {
-				t := typecheck.Temp(f.Type)
-				as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, t))
-				as.Lhs.Append(t)
-				newList = append(newList, t)
-			}
-			transformAssign(as, as.Lhs, as.Rhs)
-			as.SetTypecheck(1)
-			n.PtrInit().Append(as)
-		} else {
-			newList = append(newList, arg)
-		}
-	}
-
-	if static {
-		ir.CurFunc = nil
-	}
-
-	switch n := n.(type) {
-	case *ir.CallExpr:
-		n.Args = newList
-	case *ir.ReturnStmt:
-		n.Results = newList
-	}
+	// Rewrite f(g()) into t1, t2, ... = g(); f(t1, t2, ...).
+	typecheck.RewriteMultiValueCall(n, list[0])
 }
 
 // assignconvfn converts node n for assignment to type t. Corresponds to
diff --git a/test/typeparam/issue47514b.go b/test/typeparam/issue47514b.go
new file mode 100644
index 00000000000..5428a0edc5f
--- /dev/null
+++ b/test/typeparam/issue47514b.go
@@ -0,0 +1,19 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func Do[T any](do func() (T, string)) {
+	_ = func() (T, string) {
+		return do()
+	}
+}
+
+func main() {
+	Do[int](func() (int, string) {
+		return 3, "3"
+	})
+}

From f1dce319ffd9d3663f522141abfb9c1ec9d92e04 Mon Sep 17 00:00:00 2001
From: Jay Conrod 
Date: Thu, 5 Aug 2021 15:18:42 -0700
Subject: [PATCH 892/940] cmd/go: with -mod=vendor, don't panic if there are
 duplicate requirements

In loadModFile with -mod=vendor, load the vendor list and use it to
initialize the module graph before calling updateRoots.

In updateLazyRoots with any mode other than "mod", return the original
*Requirements if no roots needed to be upgraded, even if there are
inconsistencies. This means 'go list -m -mod=readonly' and -mod=vendor
may succeed if there are duplicate requirements or requirements on
versions of the main module.

Fixes #47565

Change-Id: I4640dffc4a7359367cc910da0d29e3538bfd1ca4
Reviewed-on: https://go-review.googlesource.com/c/go/+/340252
Trust: Jay Conrod 
Trust: Bryan C. Mills 
Reviewed-by: Bryan C. Mills 
---
 src/cmd/go/internal/modload/buildlist.go      | 19 +++++++++
 src/cmd/go/internal/modload/init.go           | 39 +++++++++----------
 .../go/testdata/script/mod_tidy_lazy_self.txt | 17 +++-----
 .../mod_vendor_redundant_requirement.txt      | 29 ++++++++++++++
 4 files changed, 72 insertions(+), 32 deletions(-)
 create mode 100644 src/cmd/go/testdata/script/mod_vendor_redundant_requirement.txt

diff --git a/src/cmd/go/internal/modload/buildlist.go b/src/cmd/go/internal/modload/buildlist.go
index 604a57b4373..bf695673167 100644
--- a/src/cmd/go/internal/modload/buildlist.go
+++ b/src/cmd/go/internal/modload/buildlist.go
@@ -191,6 +191,19 @@ func (rs *Requirements) rootSelected(path string) (version string, ok bool) {
 	return "", false
 }
 
+// hasRedundantRoot returns true if the root list contains multiple requirements
+// of the same module or a requirement on any version of the main module.
+// Redundant requirements should be pruned, but they may influence version
+// selection.
+func (rs *Requirements) hasRedundantRoot() bool {
+	for i, m := range rs.rootModules {
+		if m.Path == Target.Path || (i > 0 && m.Path == rs.rootModules[i-1].Path) {
+			return true
+		}
+	}
+	return false
+}
+
 // Graph returns the graph of module requirements loaded from the current
 // root modules (as reported by RootModules).
 //
@@ -882,6 +895,12 @@ func updateLazyRoots(ctx context.Context, direct map[string]bool, rs *Requiremen
 		// and (trivially) version.
 
 		if !rootsUpgraded {
+			if cfg.BuildMod != "mod" {
+				// The only changes to the root set (if any) were to remove duplicates.
+				// The requirements are consistent (if perhaps redundant), so keep the
+				// original rs to preserve its ModuleGraph.
+				return rs, nil
+			}
 			// The root set has converged: every root going into this iteration was
 			// already at its selected version, although we have have removed other
 			// (redundant) roots for the same path.
diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go
index a8cbd9fe16d..45f724d5e36 100644
--- a/src/cmd/go/internal/modload/init.go
+++ b/src/cmd/go/internal/modload/init.go
@@ -449,13 +449,22 @@ func loadModFile(ctx context.Context) (rs *Requirements, needCommit bool) {
 	}
 
 	setDefaultBuildMod() // possibly enable automatic vendoring
-	rs = requirementsFromModFile(ctx)
-
+	rs = requirementsFromModFile()
 	if cfg.BuildMod == "vendor" {
 		readVendorList()
 		checkVendorConsistency()
 		rs.initVendor(vendorList)
 	}
+	if rs.hasRedundantRoot() {
+		// If any module path appears more than once in the roots, we know that the
+		// go.mod file needs to be updated even though we have not yet loaded any
+		// transitive dependencies.
+		rs, err = updateRoots(ctx, rs.direct, rs, nil, nil, false)
+		if err != nil {
+			base.Fatalf("go: %v", err)
+		}
+	}
+
 	if index.goVersionV == "" {
 		// TODO(#45551): Do something more principled instead of checking
 		// cfg.CmdName directly here.
@@ -530,7 +539,12 @@ func CreateModFile(ctx context.Context, modPath string) {
 		base.Fatalf("go: %v", err)
 	}
 
-	commitRequirements(ctx, modFileGoVersion(), requirementsFromModFile(ctx))
+	rs := requirementsFromModFile()
+	rs, err = updateRoots(ctx, rs.direct, rs, nil, nil, false)
+	if err != nil {
+		base.Fatalf("go: %v", err)
+	}
+	commitRequirements(ctx, modFileGoVersion(), rs)
 
 	// Suggest running 'go mod tidy' unless the project is empty. Even if we
 	// imported all the correct requirements above, we're probably missing
@@ -641,9 +655,8 @@ func initTarget(m module.Version) {
 
 // requirementsFromModFile returns the set of non-excluded requirements from
 // the global modFile.
-func requirementsFromModFile(ctx context.Context) *Requirements {
+func requirementsFromModFile() *Requirements {
 	roots := make([]module.Version, 0, len(modFile.Require))
-	mPathCount := map[string]int{Target.Path: 1}
 	direct := map[string]bool{}
 	for _, r := range modFile.Require {
 		if index != nil && index.exclude[r.Mod] {
@@ -656,28 +669,12 @@ func requirementsFromModFile(ctx context.Context) *Requirements {
 		}
 
 		roots = append(roots, r.Mod)
-		mPathCount[r.Mod.Path]++
 		if !r.Indirect {
 			direct[r.Mod.Path] = true
 		}
 	}
 	module.Sort(roots)
 	rs := newRequirements(modDepthFromGoVersion(modFileGoVersion()), roots, direct)
-
-	// If any module path appears more than once in the roots, we know that the
-	// go.mod file needs to be updated even though we have not yet loaded any
-	// transitive dependencies.
-	for _, n := range mPathCount {
-		if n > 1 {
-			var err error
-			rs, err = updateRoots(ctx, rs.direct, rs, nil, nil, false)
-			if err != nil {
-				base.Fatalf("go: %v", err)
-			}
-			break
-		}
-	}
-
 	return rs
 }
 
diff --git a/src/cmd/go/testdata/script/mod_tidy_lazy_self.txt b/src/cmd/go/testdata/script/mod_tidy_lazy_self.txt
index ffcea186035..9abbabd2ebe 100644
--- a/src/cmd/go/testdata/script/mod_tidy_lazy_self.txt
+++ b/src/cmd/go/testdata/script/mod_tidy_lazy_self.txt
@@ -2,18 +2,13 @@
 # 'go mod tidy' should not panic if the main module initially
 # requires an older version of itself.
 
+# A module may require an older version of itself without error. This is
+# inconsistent (the required version is never selected), but we still get
+# a reproducible build list.
+go list -m all
+stdout '^golang.org/issue/46078$'
 
-# A module that explicitly requires an older version of itself should be
-# rejected as inconsistent: we enforce that every explicit requirement is the
-# selected version of its module path, but the selected version of the main
-# module is always itself — not some explicit version.
-
-! go list -m all
-stderr '^go: updates to go\.mod needed; to update it:\n\tgo mod tidy$'
-
-
-# The suggested 'go mod tidy' command should succeed (not crash).
-
+# 'go mod tidy' should fix this (and not crash).
 go mod tidy
 
 
diff --git a/src/cmd/go/testdata/script/mod_vendor_redundant_requirement.txt b/src/cmd/go/testdata/script/mod_vendor_redundant_requirement.txt
new file mode 100644
index 00000000000..3f6f5c5276b
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_vendor_redundant_requirement.txt
@@ -0,0 +1,29 @@
+# 'go list -mod=vendor' should succeed even when go.mod contains redundant
+# requirements. Verifies #47565.
+go list -mod=vendor
+
+-- go.mod --
+module m
+
+go 1.17
+
+require example.com/m v0.0.0
+require example.com/m v0.0.0
+
+replace example.com/m v0.0.0 => ./m
+-- m/go.mod --
+module example.com/m
+
+go 1.17
+-- m/m.go --
+package m
+-- use.go --
+package use
+
+import _ "example.com/m"
+-- vendor/example.com/m/m.go --
+package m
+-- vendor/modules.txt --
+# example.com/m v0.0.0 => ./m
+## explicit; go 1.17
+example.com/m

From f5f79c47f900300e8ac962e73ae7c2c706489d67 Mon Sep 17 00:00:00 2001
From: Dan Scales 
Date: Sat, 7 Aug 2021 22:26:46 -0700
Subject: [PATCH 893/940] [dev.typeparams] cmd/compile: use types2.Constraint()
 rather than types2.Bound()

types2.Constraint() returns the top-level constraint type, including any
unions or other interface elements. Because of that, we needed to
add/fix some code in the type substituter and generic type instantiater
in the importer to deal with unions and non-method members of an
interface. Also, NewUnion was not correctly setting the HasTParam flag.

I also added a better error message when a symbol is not found in
(*deadcodePass).decodeIfaceMethod().

Change-Id: Id3668dc596dce63690fa05a9e5e42295b5e2bbb5
Reviewed-on: https://go-review.googlesource.com/c/go/+/340670
Trust: Dan Scales 
Run-TryBot: Dan Scales 
Reviewed-by: Keith Randall 
---
 src/cmd/compile/internal/noder/types.go       |  2 +-
 src/cmd/compile/internal/typecheck/iimport.go | 12 +++++++++--
 src/cmd/compile/internal/typecheck/subr.go    | 20 ++++++++++++++++++-
 src/cmd/compile/internal/types/type.go        |  9 +++++++++
 src/cmd/link/internal/ld/deadcode.go          |  3 +++
 5 files changed, 42 insertions(+), 4 deletions(-)

diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go
index 4e80b1a0ffe..8d596e599ed 100644
--- a/src/cmd/compile/internal/noder/types.go
+++ b/src/cmd/compile/internal/noder/types.go
@@ -227,7 +227,7 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
 		// Set g.typs[typ] in case the bound methods reference typ.
 		g.typs[typ] = tp
 
-		bound := g.typ1(typ.Bound())
+		bound := g.typ1(typ.Constraint())
 		tp.SetBound(bound)
 		return tp
 
diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go
index 2e8b18c0b7c..d5f4bba98b2 100644
--- a/src/cmd/compile/internal/typecheck/iimport.go
+++ b/src/cmd/compile/internal/typecheck/iimport.go
@@ -1858,18 +1858,26 @@ func substInstType(t *types.Type, baseType *types.Type, targs []*types.Type) {
 
 	newfields := make([]*types.Field, baseType.Methods().Len())
 	for i, f := range baseType.Methods().Slice() {
+		if !f.IsMethod() || types.IsInterfaceMethod(f.Type) {
+			// Do a normal substitution if this is a non-method (which
+			// means this must be an interface used as a constraint) or
+			// an interface method.
+			t2 := subst.Typ(f.Type)
+			newfields[i] = types.NewField(f.Pos, f.Sym, t2)
+			continue
+		}
 		recvType := f.Type.Recv().Type
 		if recvType.IsPtr() {
 			recvType = recvType.Elem()
 		}
 		// Substitute in the method using the type params used in the
 		// method (not the type params in the definition of the generic type).
-		subst := Tsubster{
+		msubst := Tsubster{
 			Tparams:       recvType.RParams(),
 			Targs:         targs,
 			SubstForwFunc: doInst,
 		}
-		t2 := subst.Typ(f.Type)
+		t2 := msubst.Typ(f.Type)
 		oldsym := f.Nname.Sym()
 		newsym := MakeInstName(oldsym, targs, true)
 		var nname *ir.Name
diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go
index e840df56dc2..e86c4c6bca7 100644
--- a/src/cmd/compile/internal/typecheck/subr.go
+++ b/src/cmd/compile/internal/typecheck/subr.go
@@ -1165,7 +1165,7 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type {
 
 	case types.TINTER:
 		newt = ts.tinter(t)
-		if newt == t {
+		if newt == t && !targsChanged {
 			newt = nil
 		}
 
@@ -1197,6 +1197,24 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type {
 		types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64,
 		types.TUINTPTR, types.TBOOL, types.TSTRING, types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128:
 		newt = t.Underlying()
+	case types.TUNION:
+		nt := t.NumTerms()
+		newterms := make([]*types.Type, nt)
+		tildes := make([]bool, nt)
+		changed := false
+		for i := 0; i < nt; i++ {
+			term, tilde := t.Term(i)
+			tildes[i] = tilde
+			newterms[i] = ts.Typ(term)
+			if newterms[i] != term {
+				changed = true
+			}
+		}
+		if changed {
+			newt = types.NewUnion(newterms, tildes)
+		}
+	default:
+		panic(fmt.Sprintf("Bad type in (*TSubster).Typ: %v", t.Kind()))
 	}
 	if newt == nil {
 		// Even though there were typeparams in the type, there may be no
diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go
index 099080f48f3..875b0ba82f1 100644
--- a/src/cmd/compile/internal/types/type.go
+++ b/src/cmd/compile/internal/types/type.go
@@ -1912,6 +1912,15 @@ func NewUnion(terms []*Type, tildes []bool) *Type {
 	}
 	t.Extra.(*Union).terms = terms
 	t.Extra.(*Union).tildes = tildes
+	nt := len(terms)
+	for i := 0; i < nt; i++ {
+		if terms[i].HasTParam() {
+			t.SetHasTParam(true)
+		}
+		if terms[i].HasShape() {
+			t.SetHasShape(true)
+		}
+	}
 	return t
 }
 
diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go
index 416e5da3983..dd5dafc21b2 100644
--- a/src/cmd/link/internal/ld/deadcode.go
+++ b/src/cmd/link/internal/ld/deadcode.go
@@ -408,6 +408,9 @@ func (d *deadcodePass) decodeMethodSig(ldr *loader.Loader, arch *sys.Arch, symId
 // Decode the method of interface type symbol symIdx at offset off.
 func (d *deadcodePass) decodeIfaceMethod(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, off int64) methodsig {
 	p := ldr.Data(symIdx)
+	if p == nil {
+		panic(fmt.Sprintf("missing symbol %q", ldr.SymName(symIdx)))
+	}
 	if decodetypeKind(arch, p)&kindMask != kindInterface {
 		panic(fmt.Sprintf("symbol %q is not an interface", ldr.SymName(symIdx)))
 	}

From 1f9c9d853067635305f72e247c5b49e3fa5da8af Mon Sep 17 00:00:00 2001
From: fanzha02 
Date: Tue, 3 Aug 2021 12:11:29 +0800
Subject: [PATCH 894/940] doc: use "high address/low address" instead of
 "top/bottom"

The current document uses the "top" and "bottom" when talking
about the address within a frame, which may easily lead to
misunderstandings. This patch directly uses "high address"
and "low address" to make the expression clearer.

Change-Id: I7469330bbdc158672d7f0314fe6680ebdd9ab79a
Reviewed-on: https://go-review.googlesource.com/c/go/+/339369
Trust: fannie zhang 
Reviewed-by: Austin Clements 
Reviewed-by: Cherry Mui 
---
 doc/asm.html                     | 8 ++++----
 src/cmd/internal/obj/textflag.go | 4 ++--
 src/runtime/textflag.h           | 4 ++--
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/doc/asm.html b/doc/asm.html
index d5788000861..51f85eb9482 100644
--- a/doc/asm.html
+++ b/doc/asm.html
@@ -166,7 +166,7 @@ jumps and branches.
 
 
 
  • -SP: Stack pointer: top of stack. +SP: Stack pointer: the highest address within the local stack frame.
  • @@ -216,7 +216,7 @@ If a Go prototype does not name its result, the expected assembly name is The SP pseudo-register is a virtual stack pointer used to refer to frame-local variables and the arguments being prepared for function calls. -It points to the top of the local stack frame, so references should use negative offsets +It points to the highest address within the local stack frame, so references should use negative offsets in the range [−framesize, 0): x-8(SP), y-4(SP), and so on.

    @@ -409,7 +409,7 @@ The linker will choose one of the duplicates to use. (For TEXT items.) Don't insert the preamble to check if the stack must be split. The frame for the routine, plus anything it calls, must fit in the -spare space at the top of the stack segment. +spare space remaining in the current stack segment. Used to protect routines such as the stack splitting code itself.
  • @@ -460,7 +460,7 @@ Only valid on functions that declare a frame size of 0. TOPFRAME = 2048
    (For TEXT items.) -Function is the top of the call stack. Traceback should stop at this function. +Function is the outermost frame of the call stack. Traceback should stop at this function.
  • diff --git a/src/cmd/internal/obj/textflag.go b/src/cmd/internal/obj/textflag.go index 881e1922031..5ae75027c2f 100644 --- a/src/cmd/internal/obj/textflag.go +++ b/src/cmd/internal/obj/textflag.go @@ -49,8 +49,8 @@ const ( // Function can call reflect.Type.Method or reflect.Type.MethodByName. REFLECTMETHOD = 1024 - // Function is the top of the call stack. Call stack unwinders should stop - // at this function. + // Function is the outermost frame of the call stack. Call stack unwinders + // should stop at this function. TOPFRAME = 2048 // Function is an ABI wrapper. diff --git a/src/runtime/textflag.h b/src/runtime/textflag.h index e727208cd03..214075e360c 100644 --- a/src/runtime/textflag.h +++ b/src/runtime/textflag.h @@ -32,8 +32,8 @@ #define NOFRAME 512 // Function can call reflect.Type.Method or reflect.Type.MethodByName. #define REFLECTMETHOD 1024 -// Function is the top of the call stack. Call stack unwinders should stop -// at this function. +// Function is the outermost frame of the call stack. Call stack unwinders +// should stop at this function. #define TOPFRAME 2048 // Function is an ABI wrapper. #define ABIWRAPPER 4096 From 508624f359f168cab32814f63d29a4305fb01588 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Sun, 8 Aug 2021 12:37:35 -0700 Subject: [PATCH 895/940] [dev.typeparams] cmd/compile/internal/types2: expand is only required for *Named types Now that the pointer identity for a *Named type doesn't change anymore when going from lazy instantiated to actually instantiated (= expanded) state, expand() only needs to be called when we deal with *Named types and only if we care about a *Named type's internals. Remove the expand function and respective calls for all types and replace with specific t.expand() method calls where t is a *Named. Change-Id: If82299360d60108b00adc4013b29399aec90b940 Reviewed-on: https://go-review.googlesource.com/c/go/+/340749 Trust: Robert Griesemer Run-TryBot: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/builtins.go | 2 +- src/cmd/compile/internal/types2/expr.go | 1 - src/cmd/compile/internal/types2/named.go | 9 --------- src/cmd/compile/internal/types2/predicates.go | 6 ++---- src/cmd/compile/internal/types2/signature.go | 2 +- src/cmd/compile/internal/types2/type.go | 5 ++++- src/cmd/compile/internal/types2/typexpr.go | 3 +-- src/cmd/compile/internal/types2/unify.go | 6 ++---- src/cmd/compile/internal/types2/union.go | 11 +++++------ 9 files changed, 16 insertions(+), 29 deletions(-) diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index eafe6e9eb82..da2dcf54aa3 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -46,7 +46,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( default: // make argument getter xlist, _ := check.exprList(call.ArgList, false) - arg = func(x *operand, i int) { *x = *xlist[i]; x.typ = expand(x.typ) } + arg = func(x *operand, i int) { *x = *xlist[i] } nargs = len(xlist) // evaluate first argument, if present if nargs > 0 { diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go index 008c2446fcd..3c2b10cd7e0 100644 --- a/src/cmd/compile/internal/types2/expr.go +++ b/src/cmd/compile/internal/types2/expr.go @@ -682,7 +682,6 @@ func (check *Checker) convertUntyped(x *operand, target Type) { // If x is a constant operand, the returned constant.Value will be the // representation of x in this context. func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, constant.Value, errorCode) { - target = expand(target) if x.mode == invalid || isTyped(x.typ) || target == Typ[Invalid] { return x.typ, nil, 0 } diff --git a/src/cmd/compile/internal/types2/named.go b/src/cmd/compile/internal/types2/named.go index 14e073bfaeb..e0996604819 100644 --- a/src/cmd/compile/internal/types2/named.go +++ b/src/cmd/compile/internal/types2/named.go @@ -279,12 +279,3 @@ func (n *Named) expand() { n.instance = nil } } - -// expand expands uninstantiated named types and leaves all other types alone. -// expand does not recurse. -func expand(typ Type) Type { - if t, _ := typ.(*Named); t != nil { - t.expand() - } - return typ -} diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go index afef488b964..1541b3f416d 100644 --- a/src/cmd/compile/internal/types2/predicates.go +++ b/src/cmd/compile/internal/types2/predicates.go @@ -140,10 +140,6 @@ func (p *ifacePair) identical(q *ifacePair) bool { // For changes to this code the corresponding changes should be made to unifier.nify. func identical(x, y Type, cmpTags bool, p *ifacePair) bool { - // types must be expanded for comparison - x = expand(x) - y = expand(y) - if x == y { return true } @@ -306,6 +302,8 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { // Two named types are identical if their type names originate // in the same type declaration. if y, ok := y.(*Named); ok { + x.expand() + y.expand() // TODO(gri) Why is x == y not sufficient? And if it is, // we can just return false here because x == y // is caught in the very beginning of this function. diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go index 14112462e18..48b11b289cd 100644 --- a/src/cmd/compile/internal/types2/signature.go +++ b/src/cmd/compile/internal/types2/signature.go @@ -208,7 +208,6 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams [] // TODO(gri) We should delay rtyp expansion to when we actually need the // receiver; thus all checks here should be delayed to later. rtyp, _ := deref(recv.typ) - rtyp = expand(rtyp) // spec: "The receiver type must be of the form T or *T where T is a type name." // (ignore invalid types - error was reported before) @@ -216,6 +215,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams [] var err string switch T := rtyp.(type) { case *Named: + T.expand() // spec: "The type denoted by T is called the receiver base type; it must not // be a pointer or interface type and it must be declared in the same package // as the method." diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index 7ae2db3412d..637829613b1 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -114,7 +114,10 @@ func asInterface(t Type) *Interface { } func asNamed(t Type) *Named { - e, _ := expand(t).(*Named) + e, _ := t.(*Named) + if e != nil { + e.expand() + } return e } diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index fa4a1638b6c..6a9eacd31df 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -446,8 +446,7 @@ func (check *Checker) instantiatedType(x syntax.Expr, targsx []syntax.Expr, def // make sure we check instantiation works at least once // and that the resulting type is valid check.later(func() { - t := expand(typ) - check.validType(t, nil) + check.validType(typ, nil) }) return typ diff --git a/src/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go index 75b9a121979..ae81382fb0e 100644 --- a/src/cmd/compile/internal/types2/unify.go +++ b/src/cmd/compile/internal/types2/unify.go @@ -229,10 +229,6 @@ func (u *unifier) nifyEq(x, y Type, p *ifacePair) bool { // code the corresponding changes should be made here. // Must not be called directly from outside the unifier. func (u *unifier) nify(x, y Type, p *ifacePair) bool { - // types must be expanded for comparison - x = expand(x) - y = expand(y) - if !u.exact { // If exact unification is known to fail because we attempt to // match a type name against an unnamed type literal, consider @@ -436,6 +432,8 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool { // return x.obj == y.obj // } if y, ok := y.(*Named); ok { + x.expand() + y.expand() // TODO(gri) This is not always correct: two types may have the same names // in the same package if one of them is nested in a function. // Extremely unlikely but we need an always correct solution. diff --git a/src/cmd/compile/internal/types2/union.go b/src/cmd/compile/internal/types2/union.go index 85aa3d91040..f61c37a6afd 100644 --- a/src/cmd/compile/internal/types2/union.go +++ b/src/cmd/compile/internal/types2/union.go @@ -68,8 +68,7 @@ func parseUnion(check *Checker, tlist []syntax.Expr) Type { // Note: This is a quadratic algorithm, but unions tend to be short. check.later(func() { for i, t := range terms { - typ := expand(t.typ) - if typ == Typ[Invalid] { + if t.typ == Typ[Invalid] { continue } @@ -85,16 +84,16 @@ func parseUnion(check *Checker, tlist []syntax.Expr) Type { } } - u := under(typ) + u := under(t.typ) f, _ := u.(*Interface) if t.tilde { if f != nil { - check.errorf(x, "invalid use of ~ (%s is an interface)", typ) + check.errorf(x, "invalid use of ~ (%s is an interface)", t.typ) continue // don't report another error for t } - if !Identical(u, typ) { - check.errorf(x, "invalid use of ~ (underlying type of %s is %s)", typ, u) + if !Identical(u, t.typ) { + check.errorf(x, "invalid use of ~ (underlying type of %s is %s)", t.typ, u) continue // don't report another error for t } } From e4cfa2f6dad8c73e98a4149948ded424df9c8501 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 9 Aug 2021 10:53:43 -0700 Subject: [PATCH 896/940] [dev.typeparams] cmd/compile/internal/types2: parameterized functions must have a body Add the respective check and add missing bodies to tests. Use {} as body for functions that don't return a result. Use { panic(0) } as body for functions that return a result. For #47069. Change-Id: Ia5d7525c9c036baf8a955d13bff448401e08235e Reviewed-on: https://go-review.googlesource.com/c/go/+/340911 Trust: Robert Griesemer Run-TryBot: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/api_test.go | 44 +++++++++---------- src/cmd/compile/internal/types2/decl.go | 4 ++ .../internal/types2/testdata/check/issues.go2 | 6 +-- .../internal/types2/testdata/check/map2.go2 | 2 +- .../types2/testdata/check/mtypeparams.go2 | 2 +- .../types2/testdata/check/tinference.go2 | 8 ++-- .../types2/testdata/check/typeinst2.go2 | 14 +++--- .../types2/testdata/check/typeparams.go2 | 42 +++++++++--------- .../types2/testdata/examples/functions.go2 | 28 +++++++----- .../types2/testdata/examples/inference.go2 | 8 ++-- .../types2/testdata/examples/types.go2 | 14 +++--- .../types2/testdata/fixedbugs/issue39634.go2 | 6 +-- .../types2/testdata/fixedbugs/issue39723.go2 | 2 +- .../types2/testdata/fixedbugs/issue39725.go2 | 4 +- .../types2/testdata/fixedbugs/issue39976.go2 | 2 +- .../types2/testdata/fixedbugs/issue40038.go2 | 2 +- .../types2/testdata/fixedbugs/issue40056.go2 | 2 +- .../types2/testdata/fixedbugs/issue40684.go2 | 4 +- .../types2/testdata/fixedbugs/issue41124.go2 | 4 +- .../types2/testdata/fixedbugs/issue47127.go2 | 10 ++--- .../types2/testdata/fixedbugs/issue47411.go2 | 4 +- test/typeparam/smoketest.go | 6 +-- test/typeparam/tparam1.go | 14 +++--- test/typeparam/typelist.go | 8 ++-- 24 files changed, 124 insertions(+), 116 deletions(-) diff --git a/src/cmd/compile/internal/types2/api_test.go b/src/cmd/compile/internal/types2/api_test.go index c625bd49594..d8844956afb 100644 --- a/src/cmd/compile/internal/types2/api_test.go +++ b/src/cmd/compile/internal/types2/api_test.go @@ -329,10 +329,10 @@ func TestTypesInfo(t *testing.T) { {brokenPkg + `x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string]invalid type`}, // parameterized functions - {genericPkg + `p0; func f[T any](T); var _ = f[int]`, `f`, `func[generic_p0.T₁ interface{}](generic_p0.T₁)`}, - {genericPkg + `p1; func f[T any](T); var _ = f[int]`, `f[int]`, `func(int)`}, - {genericPkg + `p2; func f[T any](T); func _() { f(42) }`, `f`, `func[generic_p2.T₁ interface{}](generic_p2.T₁)`}, - {genericPkg + `p3; func f[T any](T); func _() { f(42) }`, `f(42)`, `()`}, + {genericPkg + `p0; func f[T any](T) {}; var _ = f[int]`, `f`, `func[generic_p0.T₁ interface{}](generic_p0.T₁)`}, + {genericPkg + `p1; func f[T any](T) {}; var _ = f[int]`, `f[int]`, `func(int)`}, + {genericPkg + `p2; func f[T any](T) {}; func _() { f(42) }`, `f`, `func[generic_p2.T₁ interface{}](generic_p2.T₁)`}, + {genericPkg + `p3; func f[T any](T) {}; func _() { f(42) }`, `f(42)`, `()`}, // type parameters {genericPkg + `t0; type t[] int; var _ t`, `t`, `generic_t0.t`}, // t[] is a syntax error that is ignored in this test in favor of t @@ -389,60 +389,60 @@ func TestInferredInfo(t *testing.T) { targs []string sig string }{ - {genericPkg + `p0; func f[T any](T); func _() { f(42) }`, + {genericPkg + `p0; func f[T any](T) {}; func _() { f(42) }`, `f`, []string{`int`}, `func(int)`, }, - {genericPkg + `p1; func f[T any](T) T; func _() { f('@') }`, + {genericPkg + `p1; func f[T any](T) T { panic(0) }; func _() { f('@') }`, `f`, []string{`rune`}, `func(rune) rune`, }, - {genericPkg + `p2; func f[T any](...T) T; func _() { f(0i) }`, + {genericPkg + `p2; func f[T any](...T) T { panic(0) }; func _() { f(0i) }`, `f`, []string{`complex128`}, `func(...complex128) complex128`, }, - {genericPkg + `p3; func f[A, B, C any](A, *B, []C); func _() { f(1.2, new(string), []byte{}) }`, + {genericPkg + `p3; func f[A, B, C any](A, *B, []C) {}; func _() { f(1.2, new(string), []byte{}) }`, `f`, []string{`float64`, `string`, `byte`}, `func(float64, *string, []byte)`, }, - {genericPkg + `p4; func f[A, B any](A, *B, ...[]B); func _() { f(1.2, new(byte)) }`, + {genericPkg + `p4; func f[A, B any](A, *B, ...[]B) {}; func _() { f(1.2, new(byte)) }`, `f`, []string{`float64`, `byte`}, `func(float64, *byte, ...[]byte)`, }, // we don't know how to translate these but we can type-check them - {genericPkg + `q0; type T struct{}; func (T) m[P any](P); func _(x T) { x.m(42) }`, + {genericPkg + `q0; type T struct{}; func (T) m[P any](P) {}; func _(x T) { x.m(42) }`, `x.m`, []string{`int`}, `func(int)`, }, - {genericPkg + `q1; type T struct{}; func (T) m[P any](P) P; func _(x T) { x.m(42) }`, + {genericPkg + `q1; type T struct{}; func (T) m[P any](P) P { panic(0) }; func _(x T) { x.m(42) }`, `x.m`, []string{`int`}, `func(int) int`, }, - {genericPkg + `q2; type T struct{}; func (T) m[P any](...P) P; func _(x T) { x.m(42) }`, + {genericPkg + `q2; type T struct{}; func (T) m[P any](...P) P { panic(0) }; func _(x T) { x.m(42) }`, `x.m`, []string{`int`}, `func(...int) int`, }, - {genericPkg + `q3; type T struct{}; func (T) m[A, B, C any](A, *B, []C); func _(x T) { x.m(1.2, new(string), []byte{}) }`, + {genericPkg + `q3; type T struct{}; func (T) m[A, B, C any](A, *B, []C) {}; func _(x T) { x.m(1.2, new(string), []byte{}) }`, `x.m`, []string{`float64`, `string`, `byte`}, `func(float64, *string, []byte)`, }, - {genericPkg + `q4; type T struct{}; func (T) m[A, B any](A, *B, ...[]B); func _(x T) { x.m(1.2, new(byte)) }`, + {genericPkg + `q4; type T struct{}; func (T) m[A, B any](A, *B, ...[]B) {}; func _(x T) { x.m(1.2, new(byte)) }`, `x.m`, []string{`float64`, `byte`}, `func(float64, *byte, ...[]byte)`, }, - {genericPkg + `r0; type T[P any] struct{}; func (_ T[P]) m[Q any](Q); func _[P any](x T[P]) { x.m(42) }`, + {genericPkg + `r0; type T[P any] struct{}; func (_ T[P]) m[Q any](Q) {}; func _[P any](x T[P]) { x.m(42) }`, `x.m`, []string{`int`}, `func(int)`, @@ -454,38 +454,38 @@ func TestInferredInfo(t *testing.T) { // `func(float64)`, // }, - {genericPkg + `s1; func f[T any, P interface{~*T}](x T); func _(x string) { f(x) }`, + {genericPkg + `s1; func f[T any, P interface{~*T}](x T) {}; func _(x string) { f(x) }`, `f`, []string{`string`, `*string`}, `func(x string)`, }, - {genericPkg + `s2; func f[T any, P interface{~*T}](x []T); func _(x []int) { f(x) }`, + {genericPkg + `s2; func f[T any, P interface{~*T}](x []T) {}; func _(x []int) { f(x) }`, `f`, []string{`int`, `*int`}, `func(x []int)`, }, - {genericPkg + `s3; type C[T any] interface{~chan<- T}; func f[T any, P C[T]](x []T); func _(x []int) { f(x) }`, + {genericPkg + `s3; type C[T any] interface{~chan<- T}; func f[T any, P C[T]](x []T) {}; func _(x []int) { f(x) }`, `f`, []string{`int`, `chan<- int`}, `func(x []int)`, }, - {genericPkg + `s4; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T); func _(x []int) { f(x) }`, + {genericPkg + `s4; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T) {}; func _(x []int) { f(x) }`, `f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func(x []int)`, }, - {genericPkg + `t1; func f[T any, P interface{~*T}]() T; func _() { _ = f[string] }`, + {genericPkg + `t1; func f[T any, P interface{~*T}]() T { panic(0) }; func _() { _ = f[string] }`, `f`, []string{`string`, `*string`}, `func() string`, }, - {genericPkg + `t2; type C[T any] interface{~chan<- T}; func f[T any, P C[T]]() []T; func _() { _ = f[int] }`, + {genericPkg + `t2; type C[T any] interface{~chan<- T}; func f[T any, P C[T]]() []T { return nil }; func _() { _ = f[int] }`, `f`, []string{`int`, `chan<- int`}, `func() []int`, }, - {genericPkg + `t3; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T; func _() { _ = f[int] }`, + {genericPkg + `t3; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T { return nil }; func _() { _ = f[int] }`, `f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func() []int`, diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go index bb33c287f32..bfccbc5dbf2 100644 --- a/src/cmd/compile/internal/types2/decl.go +++ b/src/cmd/compile/internal/types2/decl.go @@ -719,6 +719,10 @@ func (check *Checker) funcDecl(obj *Func, decl *declInfo) { check.funcType(sig, fdecl.Recv, fdecl.TParamList, fdecl.Type) obj.color_ = saved + if len(fdecl.TParamList) > 0 && fdecl.Body == nil { + check.softErrorf(fdecl, "parameterized function is missing function body") + } + // function body must be type-checked after global declarations // (functions implemented elsewhere have no body) if !check.conf.IgnoreFuncBodies && fdecl.Body != nil { diff --git a/src/cmd/compile/internal/types2/testdata/check/issues.go2 b/src/cmd/compile/internal/types2/testdata/check/issues.go2 index 1ede383ebe5..effc2db7ae3 100644 --- a/src/cmd/compile/internal/types2/testdata/check/issues.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/issues.go2 @@ -40,7 +40,7 @@ func _[T interface{ m() }](x *T) { x.m /* ERROR x\.m undefined */ () } -func f2[_ interface{ m1(); m2() }]() +func f2[_ interface{ m1(); m2() }]() {} type T struct{} func (T) m1() @@ -232,7 +232,7 @@ func _[T interface{ ~func() }](f T) { type sliceOf[E any] interface{ ~[]E } -func append[T interface{}, S sliceOf[T], T2 interface{}](s S, t ...T2) S +func append[T interface{}, S sliceOf[T], T2 interface{}](s S, t ...T2) S { panic(0) } var f func() var cancelSlice []context.CancelFunc @@ -240,7 +240,7 @@ var _ = append[context.CancelFunc, []context.CancelFunc, context.CancelFunc](can // A generic function must be instantiated with a type, not a value. -func g[T any](T) T +func g[T any](T) T { panic(0) } var _ = g[int] var _ = g[nil /* ERROR is not a type */ ] diff --git a/src/cmd/compile/internal/types2/testdata/check/map2.go2 b/src/cmd/compile/internal/types2/testdata/check/map2.go2 index 2833445662d..be2c49f621e 100644 --- a/src/cmd/compile/internal/types2/testdata/check/map2.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/map2.go2 @@ -114,7 +114,7 @@ func (it *Iterator[K, V]) Next() (K, V, bool) { // chans -func chans_Ranger[T any]() (*chans_Sender[T], *chans_Receiver[T]) +func chans_Ranger[T any]() (*chans_Sender[T], *chans_Receiver[T]) { panic(0) } // A sender is used to send values to a Receiver. type chans_Sender[T any] struct { diff --git a/src/cmd/compile/internal/types2/testdata/check/mtypeparams.go2 b/src/cmd/compile/internal/types2/testdata/check/mtypeparams.go2 index c2f282bae11..1b406593f88 100644 --- a/src/cmd/compile/internal/types2/testdata/check/mtypeparams.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/mtypeparams.go2 @@ -10,7 +10,7 @@ package p type S struct{} -func (S) m[T any](v T) +func (S) m[T any](v T) {} // TODO(gri) Once we collect interface method type parameters // in the parser, we can enable these tests again. diff --git a/src/cmd/compile/internal/types2/testdata/check/tinference.go2 b/src/cmd/compile/internal/types2/testdata/check/tinference.go2 index 1b709817595..0afb77c1e41 100644 --- a/src/cmd/compile/internal/types2/testdata/check/tinference.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/tinference.go2 @@ -23,7 +23,7 @@ type any interface{} // f1(int(0), int(0)) // } -func f2[A any, B interface{~[]A}](A, B) +func f2[A any, B interface{~[]A}](A, B) {} func _() { f := f2[byte] f(byte(0), []byte{}) @@ -39,7 +39,7 @@ func _() { // f3(x, &x, &x) // } -func f4[A any, B interface{~[]C}, C interface{~*A}](A, B, C) +func f4[A any, B interface{~[]C}, C interface{~*A}](A, B, C) {} func _() { f := f4[int] var x int @@ -47,14 +47,14 @@ func _() { f4(x, []*int{}, &x) } -func f5[A interface{~struct{b B; c C}}, B any, C interface{~*B}](x B) A +func f5[A interface{~struct{b B; c C}}, B any, C interface{~*B}](x B) A { panic(0) } func _() { x := f5(1.2) var _ float64 = x.b var _ float64 = *x.c } -func f6[A any, B interface{~struct{f []A}}](B) A +func f6[A any, B interface{~struct{f []A}}](B) A { panic(0) } func _() { x := f6(struct{f []string}{}) var _ string = x diff --git a/src/cmd/compile/internal/types2/testdata/check/typeinst2.go2 b/src/cmd/compile/internal/types2/testdata/check/typeinst2.go2 index e90e4dde448..d087c26a47e 100644 --- a/src/cmd/compile/internal/types2/testdata/check/typeinst2.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/typeinst2.go2 @@ -85,7 +85,7 @@ type NumericAbs[T any] interface { Abs() T } -func AbsDifference[T NumericAbs[T]](x T) +func AbsDifference[T NumericAbs[T]](x T) { panic(0) } type OrderedAbs[T any] T @@ -97,7 +97,7 @@ func OrderedAbsDifference[T any](x T) { // same code, reduced to essence -func g[P interface{ m() P }](x P) +func g[P interface{ m() P }](x P) { panic(0) } type T4[P any] P @@ -205,7 +205,7 @@ type I0 interface { E0 } -func f0[T I0]() +func f0[T I0]() {} var _ = f0[int] var _ = f0[bool] var _ = f0[string] @@ -216,7 +216,7 @@ type I01 interface { E1 } -func f01[T I01]() +func f01[T I01]() {} var _ = f01[int] var _ = f01[bool /* ERROR does not satisfy I0 */ ] var _ = f01[string] @@ -228,7 +228,7 @@ type I012 interface { E2 } -func f012[T I012]() +func f012[T I012]() {} var _ = f012[int /* ERROR does not satisfy I012 */ ] var _ = f012[bool /* ERROR does not satisfy I012 */ ] var _ = f012[string /* ERROR does not satisfy I012 */ ] @@ -239,7 +239,7 @@ type I12 interface { E2 } -func f12[T I12]() +func f12[T I12]() {} var _ = f12[int /* ERROR does not satisfy I12 */ ] var _ = f12[bool /* ERROR does not satisfy I12 */ ] var _ = f12[string /* ERROR does not satisfy I12 */ ] @@ -250,7 +250,7 @@ type I0_ interface { ~int } -func f0_[T I0_]() +func f0_[T I0_]() {} var _ = f0_[int] var _ = f0_[bool /* ERROR does not satisfy I0_ */ ] var _ = f0_[string /* ERROR does not satisfy I0_ */ ] diff --git a/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 b/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 index ba8e8373464..1ad80b1e1b9 100644 --- a/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 @@ -15,9 +15,9 @@ func _[_ any /* ok here */ , _ interface{any /* ERROR constraint */ }](any /* ER func identity[T any](x T) T { return x } -func _[_ any](x int) int -func _[T any](T /* ERROR redeclared */ T)() -func _[T, T /* ERROR redeclared */ any]() +func _[_ any](x int) int { panic(0) } +func _[T any](T /* ERROR redeclared */ T)() {} +func _[T, T /* ERROR redeclared */ any]() {} // Constraints (incl. any) may be parenthesized. func _[_ (any)]() {} @@ -77,18 +77,18 @@ func new[T any]() *T { var _ = new /* ERROR cannot use generic function new */ var _ *int = new[int]() -func _[T any](map[T /* ERROR invalid map key type T \(missing comparable constraint\) */]int) // w/o constraint we don't know if T is comparable +func _[T any](map[T /* ERROR invalid map key type T \(missing comparable constraint\) */]int) {} // w/o constraint we don't know if T is comparable -func f1[T1 any](struct{T1 /* ERROR cannot be a .* type parameter */ }) int +func f1[T1 any](struct{T1 /* ERROR cannot be a .* type parameter */ }) int { panic(0) } var _ = f1[int](struct{T1}{}) type T1 = int -func f2[t1 any](struct{t1 /* ERROR cannot be a .* type parameter */ ; x float32}) int +func f2[t1 any](struct{t1 /* ERROR cannot be a .* type parameter */ ; x float32}) int { panic(0) } var _ = f2[t1](struct{t1; x float32}{}) type t1 = int -func f3[A, B, C any](A, struct{x B}, func(A, struct{x B}, *C)) int +func f3[A, B, C any](A, struct{x B}, func(A, struct{x B}, *C)) int { panic(0) } var _ = f3[int, rune, bool](1, struct{x rune}{}, nil) @@ -257,28 +257,28 @@ func _[ var _ = new() /* ERROR cannot infer T */ -func f4[A, B, C any](A, B) C +func f4[A, B, C any](A, B) C { panic(0) } var _ = f4(1, 2) /* ERROR cannot infer C */ var _ = f4[int, float32, complex128](1, 2) -func f5[A, B, C any](A, []*B, struct{f []C}) int +func f5[A, B, C any](A, []*B, struct{f []C}) int { panic(0) } var _ = f5[int, float32, complex128](0, nil, struct{f []complex128}{}) var _ = f5(0, nil, struct{f []complex128}{}) // ERROR cannot infer var _ = f5(0, []*float32{new[float32]()}, struct{f []complex128}{}) -func f6[A any](A, []A) int +func f6[A any](A, []A) int { panic(0) } var _ = f6(0, nil) -func f6nil[A any](A) int +func f6nil[A any](A) int { panic(0) } var _ = f6nil(nil) // ERROR cannot infer // type inference with variadic functions -func f7[T any](...T) T +func f7[T any](...T) T { panic(0) } var _ int = f7() /* ERROR cannot infer T */ var _ int = f7(1) @@ -291,7 +291,7 @@ var _ = f7(float64(1), 2.3) var _ = f7(1, 2.3 /* ERROR does not match */ ) var _ = f7(1.2, 3 /* ERROR does not match */ ) -func f8[A, B any](A, B, ...B) int +func f8[A, B any](A, B, ...B) int { panic(0) } var _ = f8(1) /* ERROR not enough arguments */ var _ = f8(1, 2.3) @@ -318,7 +318,7 @@ func (T) m3[P any]() {} type S1[P any] struct { f P } -func f9[P any](x S1[P]) +func f9[P any](x S1[P]) {} func _() { f9[int](S1[int]{42}) @@ -327,7 +327,7 @@ func _() { type S2[A, B, C any] struct{} -func f10[X, Y, Z any](a S2[X, int, Z], b S2[X, Y, bool]) +func f10[X, Y, Z any](a S2[X, int, Z], b S2[X, Y, bool]) {} func _[P any]() { f10[int, float32, string](S2[int, int, string]{}, S2[int, float32, bool]{}) @@ -338,7 +338,7 @@ func _[P any]() { // corner case for type inference // (was bug: after instanting f11, the type-checker didn't mark f11 as non-generic) -func f11[T any]() +func f11[T any]() {} func _() { f11[int]() @@ -346,7 +346,7 @@ func _() { // the previous example was extracted from -func f12[T interface{m() T}]() +func f12[T interface{m() T}]() {} type A[T any] T @@ -374,15 +374,15 @@ func _[T any] (x T) { type R0 struct{} -func (R0) _[T any](x T) -func (R0 /* ERROR invalid receiver */ ) _[R0 any]() // scope of type parameters starts at "func" +func (R0) _[T any](x T) {} +func (R0 /* ERROR invalid receiver */ ) _[R0 any]() {} // scope of type parameters starts at "func" type R1[A, B any] struct{} func (_ R1[A, B]) m0(A, B) -func (_ R1[A, B]) m1[T any](A, B, T) T +func (_ R1[A, B]) m1[T any](A, B, T) T { panic(0) } func (_ R1 /* ERROR not a generic type */ [R1, _]) _() -func (_ R1[A, B]) _[A /* ERROR redeclared */ any](B) +func (_ R1[A, B]) _[A /* ERROR redeclared */ any](B) {} func _() { var r R1[int, string] diff --git a/src/cmd/compile/internal/types2/testdata/examples/functions.go2 b/src/cmd/compile/internal/types2/testdata/examples/functions.go2 index 154d09f5287..ef8953cb43b 100644 --- a/src/cmd/compile/internal/types2/testdata/examples/functions.go2 +++ b/src/cmd/compile/internal/types2/testdata/examples/functions.go2 @@ -66,7 +66,7 @@ var _ float64 = foo(42, []float64{1.0}, &s) // Type inference works in a straight-forward manner even // for variadic functions. -func variadic[A, B any](A, B, ...B) int +func variadic[A, B any](A, B, ...B) int { panic(0) } // var _ = variadic(1) // ERROR not enough arguments var _ = variadic(1, 2.3) @@ -118,9 +118,9 @@ func max[T interface{ ~int }](x ...T) T { // Thus even if a type can be inferred successfully, the function // call may not be valid. -func fboth[T any](chan T) -func frecv[T any](<-chan T) -func fsend[T any](chan<- T) +func fboth[T any](chan T) {} +func frecv[T any](<-chan T) {} +func fsend[T any](chan<- T) {} func _() { var both chan int @@ -140,9 +140,9 @@ func _() { fsend(send) } -func ffboth[T any](func(chan T)) -func ffrecv[T any](func(<-chan T)) -func ffsend[T any](func(chan<- T)) +func ffboth[T any](func(chan T)) {} +func ffrecv[T any](func(<-chan T)) {} +func ffsend[T any](func(chan<- T)) {} func _() { var both func(chan int) @@ -169,9 +169,9 @@ func _() { // assignment is permitted, parameter passing is permitted as well, // so type inference should be able to handle these cases well. -func g1[T any]([]T) -func g2[T any]([]T, T) -func g3[T any](*T, ...T) +func g1[T any]([]T) {} +func g2[T any]([]T, T) {} +func g3[T any](*T, ...T) {} func _() { type intSlize []int @@ -195,7 +195,7 @@ func _() { // Here's a realistic example. -func append[T any](s []T, t ...T) []T +func append[T any](s []T, t ...T) []T { panic(0) } func _() { var f func() @@ -208,8 +208,12 @@ func _() { // (that would indicate a slice type). Thus, generic functions cannot // have empty type parameter lists, either. This is a syntax error. -func h[] /* ERROR empty type parameter list */ () +func h[] /* ERROR empty type parameter list */ () {} func _() { h[] /* ERROR operand */ () } + +// Parameterized functions must have a function body. + +func _ /* ERROR missing function body */ [P any]() diff --git a/src/cmd/compile/internal/types2/testdata/examples/inference.go2 b/src/cmd/compile/internal/types2/testdata/examples/inference.go2 index 75d47d2c9b4..e169aec7466 100644 --- a/src/cmd/compile/internal/types2/testdata/examples/inference.go2 +++ b/src/cmd/compile/internal/types2/testdata/examples/inference.go2 @@ -10,7 +10,7 @@ type Ordered interface { ~int|~float64|~string } -func min[T Ordered](x, y T) T +func min[T Ordered](x, y T) T { panic(0) } func _() { // min can be called with explicit instantiation. @@ -37,7 +37,7 @@ func _() { _ = min("foo", "bar") } -func mixed[T1, T2, T3 any](T1, T2, T3) +func mixed[T1, T2, T3 any](T1, T2, T3) {} func _() { // mixed can be called with explicit instantiation. @@ -54,7 +54,7 @@ func _() { mixed[int, string](1.1 /* ERROR cannot use 1.1 */ , "", false) } -func related1[Slice interface{~[]Elem}, Elem any](s Slice, e Elem) +func related1[Slice interface{~[]Elem}, Elem any](s Slice, e Elem) {} func _() { // related1 can be called with explicit instantiation. @@ -78,7 +78,7 @@ func _() { related1(si, "foo" /* ERROR cannot use "foo" */ ) } -func related2[Elem any, Slice interface{~[]Elem}](e Elem, s Slice) +func related2[Elem any, Slice interface{~[]Elem}](e Elem, s Slice) {} func _() { // related2 can be called with explicit instantiation. diff --git a/src/cmd/compile/internal/types2/testdata/examples/types.go2 b/src/cmd/compile/internal/types2/testdata/examples/types.go2 index 4ecc34dfa45..d662444ead8 100644 --- a/src/cmd/compile/internal/types2/testdata/examples/types.go2 +++ b/src/cmd/compile/internal/types2/testdata/examples/types.go2 @@ -216,15 +216,15 @@ type B0 interface {} type B1[_ any] interface{} type B2[_, _ any] interface{} -func _[T1 B0]() -func _[T1 B1[T1]]() -func _[T1 B2 /* ERROR cannot use generic type .* without instantiation */ ]() +func _[T1 B0]() {} +func _[T1 B1[T1]]() {} +func _[T1 B2 /* ERROR cannot use generic type .* without instantiation */ ]() {} -func _[T1, T2 B0]() -func _[T1 B1[T1], T2 B1[T2]]() -func _[T1, T2 B2 /* ERROR cannot use generic type .* without instantiation */ ]() +func _[T1, T2 B0]() {} +func _[T1 B1[T1], T2 B1[T2]]() {} +func _[T1, T2 B2 /* ERROR cannot use generic type .* without instantiation */ ]() {} -func _[T1 B0, T2 B1[T2]]() // here B1 applies to T2 +func _[T1 B0, T2 B1[T2]]() {} // here B1 applies to T2 // When the type argument is left away, the type bound is // instantiated for each type parameter with that type diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2 index 5cb15e7e58a..8d14f8acaf8 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2 @@ -50,7 +50,7 @@ func (G15 /* ERROR generic type .* without instantiation */ ) p() // crash 16 type Foo16[T any] r16 /* ERROR not a type */ -func r16[T any]() Foo16[Foo16[T]] +func r16[T any]() Foo16[Foo16[T]] { panic(0) } // crash 17 type Y17 interface{ c() } @@ -58,7 +58,7 @@ type Z17 interface { c() Y17 Y17 /* ERROR duplicate method */ } -func F17[T Z17](T) +func F17[T Z17](T) {} // crash 18 type o18[T any] []func(_ o18[[]_ /* ERROR cannot use _ */ ]) @@ -88,5 +88,5 @@ type T26 = interface{ F26[ /* ERROR cannot have type parameters */ Z any]() } func F26[Z any]() T26 { return F26 /* ERROR without instantiation */ /* ERROR missing method */ [] /* ERROR operand */ } // crash 27 -func e27[T any]() interface{ x27 /* ERROR not a type */ } +func e27[T any]() interface{ x27 /* ERROR not a type */ } { panic(0) } func x27() { e27( /* ERROR cannot infer T */ ) } \ No newline at end of file diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39723.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39723.go2 index 367b3f1360f..d5311ed3e75 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39723.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39723.go2 @@ -6,4 +6,4 @@ package p // A constraint must be an interface; it cannot // be a type parameter, for instance. -func _[A interface{ ~int }, B A /* ERROR not an interface */ ]() +func _[A interface{ ~int }, B A /* ERROR not an interface */ ]() {} diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39725.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39725.go2 index e19b6770bfe..62dc45a5960 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39725.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39725.go2 @@ -4,13 +4,13 @@ package p -func f1[T1, T2 any](T1, T2, struct{a T1; b T2}) +func f1[T1, T2 any](T1, T2, struct{a T1; b T2}) {} func _() { f1(42, string("foo"), struct /* ERROR does not match inferred type struct\{a int; b string\} */ {a, b int}{}) } // simplified test case from issue -func f2[T any](_ []T, _ func(T)) +func f2[T any](_ []T, _ func(T)) {} func _() { f2([]string{}, func /* ERROR does not match inferred type func\(string\) */ (f []byte) {}) } diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39976.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39976.go2 index 3db4eae0123..d703da90a21 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39976.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39976.go2 @@ -7,7 +7,7 @@ package p type policy[K, V any] interface{} type LRU[K, V any] struct{} -func NewCache[K, V any](p policy[K, V]) +func NewCache[K, V any](p policy[K, V]) {} func _() { var lru LRU[int, string] diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40038.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40038.go2 index 8948d61caa4..0981a335da3 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40038.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40038.go2 @@ -8,7 +8,7 @@ type A[T any] int func (A[T]) m(A[T]) -func f[P interface{m(P)}]() +func f[P interface{m(P)}]() {} func _() { _ = f[A[int]] diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40056.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40056.go2 index 747aab49dd1..a3f3eecca09 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40056.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40056.go2 @@ -10,6 +10,6 @@ func _() { type S struct {} -func NewS[T any]() *S +func NewS[T any]() *S { panic(0) } func (_ *S /* ERROR S is not a generic type */ [T]) M() diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40684.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40684.go2 index 0269c3a62ce..58d0f69f650 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40684.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40684.go2 @@ -6,8 +6,8 @@ package p type T[_ any] int -func f[_ any]() -func g[_, _ any]() +func f[_ any]() {} +func g[_, _ any]() {} func _() { _ = f[T /* ERROR without instantiation */ ] diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue41124.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue41124.go2 index 60650432a47..4642ab60fc8 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue41124.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue41124.go2 @@ -79,9 +79,9 @@ type T3[_, _, _ any] struct{} var _ T1[I2 /* ERROR interface contains type constraints */ ] var _ T3[int, I2 /* ERROR interface contains type constraints */ , float32] -func f1[_ any]() int +func f1[_ any]() int { panic(0) } var _ = f1[I2 /* ERROR interface contains type constraints */ ]() -func f3[_, _, _ any]() int +func f3[_, _, _ any]() int { panic(0) } var _ = f3[int, I2 /* ERROR interface contains type constraints */ , float32]() func _(x interface{}) { diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47127.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47127.go2 index 387c946957c..108d600a38a 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47127.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47127.go2 @@ -30,8 +30,8 @@ func _[P any]() { ) } -func _[P any, Q interface{ *P | []P | chan P | map[string]P }]() -func _[P any, Q interface{ P /* ERROR "cannot embed a type parameter" */ }]() -func _[P any, Q interface{ ~P /* ERROR "cannot embed a type parameter" */ }]() -func _[P any, Q interface{ int | P /* ERROR "cannot embed a type parameter" */ }]() -func _[P any, Q interface{ int | ~P /* ERROR "cannot embed a type parameter" */ }]() +func _[P any, Q interface{ *P | []P | chan P | map[string]P }]() {} +func _[P any, Q interface{ P /* ERROR "cannot embed a type parameter" */ }]() {} +func _[P any, Q interface{ ~P /* ERROR "cannot embed a type parameter" */ }]() {} +func _[P any, Q interface{ int | P /* ERROR "cannot embed a type parameter" */ }]() {} +func _[P any, Q interface{ int | ~P /* ERROR "cannot embed a type parameter" */ }]() {} diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47411.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47411.go2 index 72968f9d43f..77281a19a20 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47411.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47411.go2 @@ -4,8 +4,8 @@ package p -func f[_ comparable]() -func g[_ interface{interface{comparable; ~int|~string}}]() +func f[_ comparable]() {} +func g[_ interface{interface{comparable; ~int|~string}}]() {} func _[P comparable, Q interface{ comparable; ~int|~string }, diff --git a/test/typeparam/smoketest.go b/test/typeparam/smoketest.go index eeda25964f4..5243dc5c3c1 100644 --- a/test/typeparam/smoketest.go +++ b/test/typeparam/smoketest.go @@ -9,9 +9,9 @@ package smoketest // type parameters for functions -func f1[P any]() -func f2[P1, P2 any, P3 any]() -func f3[P interface{}](x P, y T1[int]) +func f1[P any]() {} +func f2[P1, P2 any, P3 any]() {} +func f3[P interface{}](x P, y T1[int]) {} // function instantiations var _ = f1[int] diff --git a/test/typeparam/tparam1.go b/test/typeparam/tparam1.go index a196caf976b..698877a6f00 100644 --- a/test/typeparam/tparam1.go +++ b/test/typeparam/tparam1.go @@ -24,17 +24,17 @@ type ( _[T1, T2 any, T3 any] struct{} ) -func _[T any]() -func _[T, T any]() // ERROR "T redeclared" -func _[T1, T2 any](x T1) T2 +func _[T any]() {} +func _[T, T any]() {} // ERROR "T redeclared" +func _[T1, T2 any](x T1) T2 { panic(0) } // Type parameters are visible from opening [ to end of function. type C interface{} -func _[T interface{}]() -func _[T C]() -func _[T struct{}]() // ERROR "not an interface" -func _[T interface{ m() T }]() +func _[T interface{}]() {} +func _[T C]() {} +func _[T struct{}]() {}// ERROR "not an interface" +func _[T interface{ m() T }]() {} func _[T1 interface{ m() T2 }, T2 interface{ m() T1 }]() { var _ T1 } diff --git a/test/typeparam/typelist.go b/test/typeparam/typelist.go index a68ae1b5cd0..5ba14261ab0 100644 --- a/test/typeparam/typelist.go +++ b/test/typeparam/typelist.go @@ -85,7 +85,7 @@ func f1x() { } */ -func f2[A any, B interface{ type []A }](_ A, _ B) +func f2[A any, B interface{ type []A }](_ A, _ B) {} func f2x() { f := f2[byte] f(byte(0), []byte{}) @@ -105,7 +105,7 @@ func f3x() { } */ -func f4[A any, B interface{ type []C }, C interface{ type *A }](_ A, _ B, c C) +func f4[A any, B interface{ type []C }, C interface{ type *A }](_ A, _ B, c C) {} func f4x() { f := f4[int] var x int @@ -118,14 +118,14 @@ func f5[A interface { b B c C } -}, B any, C interface{ type *B }](x B) A +}, B any, C interface{ type *B }](x B) A { panic(0) } func f5x() { x := f5(1.2) var _ float64 = x.b var _ float64 = *x.c } -func f6[A any, B interface{ type struct{ f []A } }](B) A +func f6[A any, B interface{ type struct{ f []A } }](B) A { panic(0) } func f6x() { x := f6(struct{ f []string }{}) var _ string = x From 2fbf6aafe7de215a1d03e14aa488aa8fd31f56a7 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 9 Aug 2021 11:40:46 -0700 Subject: [PATCH 897/940] [dev.typeparams] cmd/compile: handle interface type parameters in type switches Change-Id: I9bba21a64d7e9f42395b6fcdf8aa3ca01cf131dc Reviewed-on: https://go-review.googlesource.com/c/go/+/340912 Trust: Keith Randall Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/noder/stencil.go | 30 ++++++++++-------- test/typeparam/typeswitch6.go | 30 ++++++++++++++++++ test/typeparam/typeswitch6.out | 5 +++ test/typeparam/typeswitch7.go | 37 +++++++++++++++++++++++ test/typeparam/typeswitch7.out | 3 ++ 5 files changed, 93 insertions(+), 12 deletions(-) create mode 100644 test/typeparam/typeswitch6.go create mode 100644 test/typeparam/typeswitch6.out create mode 100644 test/typeparam/typeswitch7.go create mode 100644 test/typeparam/typeswitch7.out diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 23e8090136f..6736f128e31 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -1157,19 +1157,21 @@ func (subst *subster) node(n ir.Node) ir.Node { assert(ix >= 0) dt := ir.NewDynamicType(c.Pos(), getDictionaryEntry(c.Pos(), subst.info.dictParam, ix, subst.info.dictLen)) - // For type switch from nonemoty interfaces to non-interfaces, we need an itab as well. - if _, ok := subst.info.gfInfo.type2switchType[c]; ok { - // Type switch from nonempty interface. We need a *runtime.itab - // for the dynamic type. - ix := -1 - for i, ic := range subst.info.gfInfo.itabConvs { - if ic == c { - ix = subst.info.startItabConv + i - break + // For type switch from nonempty interfaces to non-interfaces, we need an itab as well. + if !m.List[i].Type().IsInterface() { + if _, ok := subst.info.gfInfo.type2switchType[c]; ok { + // Type switch from nonempty interface. We need a *runtime.itab + // for the dynamic type. + ix := -1 + for i, ic := range subst.info.gfInfo.itabConvs { + if ic == c { + ix = subst.info.startItabConv + i + break + } } + assert(ix >= 0) + dt.ITab = getDictionaryEntry(c.Pos(), subst.info.dictParam, ix, subst.info.dictLen) } - assert(ix >= 0) - dt.ITab = getDictionaryEntry(c.Pos(), subst.info.dictParam, ix, subst.info.dictLen) } typed(m.List[i].Type(), dt) m.List[i] = dt @@ -1484,6 +1486,8 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) // instantiations have been created. func (g *irgen) finalizeSyms() { for _, d := range g.dictSymsToFinalize { + infoPrint("=== Finalizing dictionary %s\n", d.sym.Name) + lsym := d.sym.Linksym() info := g.getGfInfo(d.gf) @@ -1528,9 +1532,11 @@ func (g *irgen) finalizeSyms() { // No itab is wanted if src type is an interface. We // will use a type assert instead. d.off = objw.Uintptr(lsym, d.off, 0) + infoPrint(" + Unused itab entry for %v\n", srctype) } else { itabLsym := reflectdata.ITabLsym(srctype, dsttype) d.off = objw.SymPtr(lsym, d.off, itabLsym, 0) + infoPrint(" + Itab for (%v,%v)\n", srctype, dsttype) } } @@ -1694,7 +1700,7 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo { for _, cc := range n.(*ir.SwitchStmt).Cases { for _, c := range cc.List { if c.Op() == ir.OTYPE && c.Type().HasTParam() { - // Type switch from a non-empty interface to a noninterface. + // Type switch from a non-empty interface - might need an itab. infoPrint(" Itab for type switch: %v\n", c) info.itabConvs = append(info.itabConvs, c) if info.type2switchType == nil { diff --git a/test/typeparam/typeswitch6.go b/test/typeparam/typeswitch6.go new file mode 100644 index 00000000000..574f4aa819e --- /dev/null +++ b/test/typeparam/typeswitch6.go @@ -0,0 +1,30 @@ +// run -gcflags=-G=3 + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func f[T any](i interface{}) { + switch i.(type) { + case T: + println("T") + case int: + println("int") + default: + println("other") + } +} + +type myint int +func (myint) foo() { +} + +func main() { + f[interface{}](nil) + f[interface{}](6) + f[interface{foo()}](nil) + f[interface{foo()}](7) + f[interface{foo()}](myint(8)) +} diff --git a/test/typeparam/typeswitch6.out b/test/typeparam/typeswitch6.out new file mode 100644 index 00000000000..441add5ec5b --- /dev/null +++ b/test/typeparam/typeswitch6.out @@ -0,0 +1,5 @@ +other +T +other +int +T diff --git a/test/typeparam/typeswitch7.go b/test/typeparam/typeswitch7.go new file mode 100644 index 00000000000..f2e1279fb41 --- /dev/null +++ b/test/typeparam/typeswitch7.go @@ -0,0 +1,37 @@ +// run -gcflags=-G=3 + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func f[T any](i interface{foo()}) { + switch i.(type) { + case interface{bar() T}: + println("barT") + case myint: + println("myint") + case myfloat: + println("myfloat") + default: + println("other") + } +} + +type myint int +func (myint) foo() { +} +func (x myint) bar() int { + return int(x) +} + +type myfloat float64 +func (myfloat) foo() { +} + +func main() { + f[int](nil) + f[int](myint(6)) + f[int](myfloat(7)) +} diff --git a/test/typeparam/typeswitch7.out b/test/typeparam/typeswitch7.out new file mode 100644 index 00000000000..d7fcad4fee1 --- /dev/null +++ b/test/typeparam/typeswitch7.out @@ -0,0 +1,3 @@ +other +barT +myfloat From 2e250cc95760e75a3f1fa082920eecd9f88fd096 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 10 Aug 2021 11:02:34 -0400 Subject: [PATCH 898/940] [dev.typeparams] cmd: update vendored golang.org/x/tools to 337cebd2c151 Update vendored golang.org/x/tools repo to pick up CL 339250 for assembly function check for register ABI. This is done with cd GOROOT/cmd go get golang.org/x/tools@master go mod tidy go mod vendor Update cmd/vet tests as the error ouput changes in CL 301949. The error message now includes full package-qualified name. Change-Id: I52dc7223aee9e011214254488bacf02dc5b4c2ef Reviewed-on: https://go-review.googlesource.com/c/go/+/341149 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Dmitri Shuralyov Reviewed-by: Than McIntosh --- src/cmd/go.mod | 2 +- src/cmd/go.sum | 4 +- .../go/analysis/passes/asmdecl/asmdecl.go | 37 ++- .../tools/go/analysis/passes/printf/printf.go | 28 ++- .../x/tools/go/ast/astutil/rewrite.go | 10 +- .../x/tools/go/types/objectpath/objectpath.go | 2 +- .../x/tools/internal/lsp/fuzzy/input.go | 37 ++- .../x/tools/internal/lsp/fuzzy/matcher.go | 23 +- .../x/tools/internal/lsp/fuzzy/symbol.go | 224 ++++++++++++++++++ .../x/tools/internal/typeparams/common.go | 25 ++ .../tools/internal/typeparams/notypeparams.go | 93 ++++++++ .../x/tools/internal/typeparams/typeparams.go | 115 +++++++++ src/cmd/vendor/modules.txt | 3 +- src/cmd/vet/testdata/print/print.go | 8 +- 14 files changed, 563 insertions(+), 48 deletions(-) create mode 100644 src/cmd/vendor/golang.org/x/tools/internal/lsp/fuzzy/symbol.go create mode 100644 src/cmd/vendor/golang.org/x/tools/internal/typeparams/common.go create mode 100644 src/cmd/vendor/golang.org/x/tools/internal/typeparams/notypeparams.go create mode 100644 src/cmd/vendor/golang.org/x/tools/internal/typeparams/typeparams.go diff --git a/src/cmd/go.mod b/src/cmd/go.mod index da304e292b5..ccfff098857 100644 --- a/src/cmd/go.mod +++ b/src/cmd/go.mod @@ -10,6 +10,6 @@ require ( golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 // indirect golang.org/x/term v0.0.0-20210503060354-a79de5458b56 - golang.org/x/tools v0.1.2-0.20210519160823-49064d2332f9 + golang.org/x/tools v0.1.6-0.20210809225032-337cebd2c151 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect ) diff --git a/src/cmd/go.sum b/src/cmd/go.sum index 7f0d978ef0b..f4d41f0d102 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -16,7 +16,7 @@ golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 h1:yhBbb4IRs2HS9PPlAg6DMC6mU golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= -golang.org/x/tools v0.1.2-0.20210519160823-49064d2332f9 h1:2XlR/j4I4xz5GQZI7zBjqTfezYyRIE2jD5IMousB2rg= -golang.org/x/tools v0.1.2-0.20210519160823-49064d2332f9/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6-0.20210809225032-337cebd2c151 h1:jHjT6WuVKEMzjJgrS1+r1wk54oxwqumUnvtn0QZXyXE= +golang.org/x/tools v0.1.6-0.20210809225032-337cebd2c151/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go index eb0016b18f1..7b82d0b6ddb 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go @@ -51,6 +51,11 @@ type asmArch struct { bigEndian bool stack string lr bool + // retRegs is a list of registers for return value in register ABI (ABIInternal). + // For now, as we only check whether we write to any result, here we only need to + // include the first integer register and first floating-point register. Accessing + // any of them counts as writing to result. + retRegs []string // calculated during initialization sizes types.Sizes intSize int @@ -79,8 +84,8 @@ type asmVar struct { var ( asmArch386 = asmArch{name: "386", bigEndian: false, stack: "SP", lr: false} asmArchArm = asmArch{name: "arm", bigEndian: false, stack: "R13", lr: true} - asmArchArm64 = asmArch{name: "arm64", bigEndian: false, stack: "RSP", lr: true} - asmArchAmd64 = asmArch{name: "amd64", bigEndian: false, stack: "SP", lr: false} + asmArchArm64 = asmArch{name: "arm64", bigEndian: false, stack: "RSP", lr: true, retRegs: []string{"R0", "F0"}} + asmArchAmd64 = asmArch{name: "amd64", bigEndian: false, stack: "SP", lr: false, retRegs: []string{"AX", "X0"}} asmArchMips = asmArch{name: "mips", bigEndian: true, stack: "R29", lr: true} asmArchMipsLE = asmArch{name: "mipsle", bigEndian: false, stack: "R29", lr: true} asmArchMips64 = asmArch{name: "mips64", bigEndian: true, stack: "R29", lr: true} @@ -137,7 +142,7 @@ var ( asmSP = re(`[^+\-0-9](([0-9]+)\(([A-Z0-9]+)\))`) asmOpcode = re(`^\s*(?:[A-Z0-9a-z_]+:)?\s*([A-Z]+)\s*([^,]*)(?:,\s*(.*))?`) ppc64Suff = re(`([BHWD])(ZU|Z|U|BR)?$`) - abiSuff = re(`^(.+)$`) + abiSuff = re(`^(.+)<(ABI.+)>$`) ) func run(pass *analysis.Pass) (interface{}, error) { @@ -185,6 +190,7 @@ Files: var ( fn *asmFunc fnName string + abi string localSize, argSize int wroteSP bool noframe bool @@ -195,18 +201,22 @@ Files: flushRet := func() { if fn != nil && fn.vars["ret"] != nil && !haveRetArg && len(retLine) > 0 { v := fn.vars["ret"] + resultStr := fmt.Sprintf("%d-byte ret+%d(FP)", v.size, v.off) + if abi == "ABIInternal" { + resultStr = "result register" + } for _, line := range retLine { - pass.Reportf(analysisutil.LineStart(tf, line), "[%s] %s: RET without writing to %d-byte ret+%d(FP)", arch, fnName, v.size, v.off) + pass.Reportf(analysisutil.LineStart(tf, line), "[%s] %s: RET without writing to %s", arch, fnName, resultStr) } } retLine = nil } - trimABI := func(fnName string) string { + trimABI := func(fnName string) (string, string) { m := abiSuff.FindStringSubmatch(fnName) if m != nil { - return m[1] + return m[1], m[2] } - return fnName + return fnName, "" } for lineno, line := range lines { lineno++ @@ -273,11 +283,12 @@ Files: // log.Printf("%s:%d: [%s] cannot check cross-package assembly function: %s is in package %s", fname, lineno, arch, fnName, pkgPath) fn = nil fnName = "" + abi = "" continue } } // Trim off optional ABI selector. - fnName := trimABI(fnName) + fnName, abi = trimABI(fnName) flag := m[3] fn = knownFunc[fnName][arch] if fn != nil { @@ -305,6 +316,7 @@ Files: flushRet() fn = nil fnName = "" + abi = "" continue } @@ -335,6 +347,15 @@ Files: haveRetArg = true } + if abi == "ABIInternal" && !haveRetArg { + for _, reg := range archDef.retRegs { + if strings.Contains(line, reg) { + haveRetArg = true + break + } + } + } + for _, m := range asmSP.FindAllStringSubmatch(line, -1) { if m[3] != archDef.stack || wroteSP || noframe { continue diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go index 822820f06e9..6589478af0f 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go @@ -555,7 +555,7 @@ func checkPrintf(pass *analysis.Pass, kind Kind, call *ast.CallExpr, fn *types.F format, idx := formatString(pass, call) if idx < 0 { if false { - pass.Reportf(call.Lparen, "can't check non-constant format in call to %s", fn.Name()) + pass.Reportf(call.Lparen, "can't check non-constant format in call to %s", fn.FullName()) } return } @@ -563,7 +563,7 @@ func checkPrintf(pass *analysis.Pass, kind Kind, call *ast.CallExpr, fn *types.F firstArg := idx + 1 // Arguments are immediately after format string. if !strings.Contains(format, "%") { if len(call.Args) > firstArg { - pass.Reportf(call.Lparen, "%s call has arguments but no formatting directives", fn.Name()) + pass.Reportf(call.Lparen, "%s call has arguments but no formatting directives", fn.FullName()) } return } @@ -577,7 +577,7 @@ func checkPrintf(pass *analysis.Pass, kind Kind, call *ast.CallExpr, fn *types.F if format[i] != '%' { continue } - state := parsePrintfVerb(pass, call, fn.Name(), format[i:], firstArg, argNum) + state := parsePrintfVerb(pass, call, fn.FullName(), format[i:], firstArg, argNum) if state == nil { return } @@ -589,8 +589,12 @@ func checkPrintf(pass *analysis.Pass, kind Kind, call *ast.CallExpr, fn *types.F anyIndex = true } if state.verb == 'w' { - if kind != KindErrorf { - pass.Reportf(call.Pos(), "%s call has error-wrapping directive %%w, which is only supported by Errorf", state.name) + switch kind { + case KindNone, KindPrint: + pass.Reportf(call.Pos(), "%s does not support error-wrapping directive %%w", state.name) + return + case KindPrintf: + pass.Reportf(call.Pos(), "%s call has error-wrapping directive %%w, which is only supported for functions backed by fmt.Errorf", state.name) return } if anyW { @@ -621,7 +625,7 @@ func checkPrintf(pass *analysis.Pass, kind Kind, call *ast.CallExpr, fn *types.F if maxArgNum != len(call.Args) { expect := maxArgNum - firstArg numArgs := len(call.Args) - firstArg - pass.ReportRangef(call, "%s call needs %v but has %v", fn.Name(), count(expect, "arg"), count(numArgs, "arg")) + pass.ReportRangef(call, "%s call needs %v but has %v", fn.FullName(), count(expect, "arg"), count(numArgs, "arg")) } } @@ -949,7 +953,7 @@ func recursiveStringer(pass *analysis.Pass, e ast.Expr) (string, bool) { } if id, ok := e.(*ast.Ident); ok { if pass.TypesInfo.Uses[id] == sig.Recv() { - return method.Name(), true + return method.FullName(), true } } return "", false @@ -1044,7 +1048,7 @@ func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) { if sel, ok := call.Args[0].(*ast.SelectorExpr); ok { if x, ok := sel.X.(*ast.Ident); ok { if x.Name == "os" && strings.HasPrefix(sel.Sel.Name, "Std") { - pass.ReportRangef(call, "%s does not take io.Writer but has first arg %s", fn.Name(), analysisutil.Format(pass.Fset, call.Args[0])) + pass.ReportRangef(call, "%s does not take io.Writer but has first arg %s", fn.FullName(), analysisutil.Format(pass.Fset, call.Args[0])) } } } @@ -1058,7 +1062,7 @@ func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) { if strings.Contains(s, "%") { m := printFormatRE.FindStringSubmatch(s) if m != nil { - pass.ReportRangef(call, "%s call has possible formatting directive %s", fn.Name(), m[0]) + pass.ReportRangef(call, "%s call has possible formatting directive %s", fn.FullName(), m[0]) } } } @@ -1068,16 +1072,16 @@ func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) { if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { str, _ := strconv.Unquote(lit.Value) if strings.HasSuffix(str, "\n") { - pass.ReportRangef(call, "%s arg list ends with redundant newline", fn.Name()) + pass.ReportRangef(call, "%s arg list ends with redundant newline", fn.FullName()) } } } for _, arg := range args { if isFunctionValue(pass, arg) { - pass.ReportRangef(call, "%s arg %s is a func value, not called", fn.Name(), analysisutil.Format(pass.Fset, arg)) + pass.ReportRangef(call, "%s arg %s is a func value, not called", fn.FullName(), analysisutil.Format(pass.Fset, arg)) } if methodName, ok := recursiveStringer(pass, arg); ok { - pass.ReportRangef(call, "%s arg %s causes recursive call to %s method", fn.Name(), analysisutil.Format(pass.Fset, arg), methodName) + pass.ReportRangef(call, "%s arg %s causes recursive call to %s method", fn.FullName(), analysisutil.Format(pass.Fset, arg), methodName) } } } diff --git a/src/cmd/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go b/src/cmd/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go index cf72ea990bd..5fe75b14c75 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go +++ b/src/cmd/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go @@ -9,6 +9,8 @@ import ( "go/ast" "reflect" "sort" + + "golang.org/x/tools/internal/typeparams" ) // An ApplyFunc is invoked by Apply for each node n, even if n is nil, @@ -437,7 +439,13 @@ func (a *application) apply(parent ast.Node, name string, iter *iterator, n ast. } default: - panic(fmt.Sprintf("Apply: unexpected node type %T", n)) + if ix := typeparams.GetIndexExprData(n); ix != nil { + a.apply(n, "X", nil, ix.X) + // *ast.IndexExpr was handled above, so n must be an *ast.MultiIndexExpr. + a.applyList(n, "Indices") + } else { + panic(fmt.Sprintf("Apply: unexpected node type %T", n)) + } } if a.post != nil && !a.post(&a.cursor) { diff --git a/src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go b/src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go index cffd7acbee7..81e8fdcf0c1 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go +++ b/src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go @@ -58,7 +58,7 @@ type Path string // - The only OT operator is Object.Type, // which we encode as '.' because dot cannot appear in an identifier. // - The TT operators are encoded as [EKPRU]. -// - The OT operators are encoded as [AFMO]; +// - The TO operators are encoded as [AFMO]; // three of these (At,Field,Method) require an integer operand, // which is encoded as a string of decimal digits. // These indices are stable across different representations diff --git a/src/cmd/vendor/golang.org/x/tools/internal/lsp/fuzzy/input.go b/src/cmd/vendor/golang.org/x/tools/internal/lsp/fuzzy/input.go index ac377035ec6..c1038163f1a 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/lsp/fuzzy/input.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/lsp/fuzzy/input.go @@ -27,23 +27,23 @@ const ( // RuneRoles detects the roles of each byte rune in an input string and stores it in the output // slice. The rune role depends on the input type. Stops when it parsed all the runes in the string // or when it filled the output. If output is nil, then it gets created. -func RuneRoles(str string, reuse []RuneRole) []RuneRole { +func RuneRoles(candidate []byte, reuse []RuneRole) []RuneRole { var output []RuneRole - if cap(reuse) < len(str) { - output = make([]RuneRole, 0, len(str)) + if cap(reuse) < len(candidate) { + output = make([]RuneRole, 0, len(candidate)) } else { output = reuse[:0] } prev, prev2 := rtNone, rtNone - for i := 0; i < len(str); i++ { - r := rune(str[i]) + for i := 0; i < len(candidate); i++ { + r := rune(candidate[i]) role := RNone curr := rtLower - if str[i] <= unicode.MaxASCII { - curr = runeType(rt[str[i]] - '0') + if candidate[i] <= unicode.MaxASCII { + curr = runeType(rt[candidate[i]] - '0') } if curr == rtLower { @@ -58,7 +58,7 @@ func RuneRoles(str string, reuse []RuneRole) []RuneRole { if prev == rtUpper { // This and previous characters are both upper case. - if i+1 == len(str) { + if i+1 == len(candidate) { // This is last character, previous was also uppercase -> this is UCTail // i.e., (current char is C): aBC / BC / ABC role = RUCTail @@ -118,11 +118,26 @@ func LastSegment(input string, roles []RuneRole) string { return input[start+1 : end+1] } -// ToLower transforms the input string to lower case, which is stored in the output byte slice. +// fromChunks copies string chunks into the given buffer. +func fromChunks(chunks []string, buffer []byte) []byte { + ii := 0 + for _, chunk := range chunks { + for i := 0; i < len(chunk); i++ { + if ii >= cap(buffer) { + break + } + buffer[ii] = chunk[i] + ii++ + } + } + return buffer[:ii] +} + +// toLower transforms the input string to lower case, which is stored in the output byte slice. // The lower casing considers only ASCII values - non ASCII values are left unmodified. // Stops when parsed all input or when it filled the output slice. If output is nil, then it gets // created. -func ToLower(input string, reuse []byte) []byte { +func toLower(input []byte, reuse []byte) []byte { output := reuse if cap(reuse) < len(input) { output = make([]byte, len(input)) @@ -130,7 +145,7 @@ func ToLower(input string, reuse []byte) []byte { for i := 0; i < len(input); i++ { r := rune(input[i]) - if r <= unicode.MaxASCII { + if input[i] <= unicode.MaxASCII { if 'A' <= r && r <= 'Z' { r += 'a' - 'A' } diff --git a/src/cmd/vendor/golang.org/x/tools/internal/lsp/fuzzy/matcher.go b/src/cmd/vendor/golang.org/x/tools/internal/lsp/fuzzy/matcher.go index 16a643097de..265cdcf1604 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/lsp/fuzzy/matcher.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/lsp/fuzzy/matcher.go @@ -51,8 +51,12 @@ type Matcher struct { lastCandidateLen int // in bytes lastCandidateMatched bool - // Here we save the last candidate in lower-case. This is basically a byte slice we reuse for - // performance reasons, so the slice is not reallocated for every candidate. + // Reusable buffers to avoid allocating for every candidate. + // - inputBuf stores the concatenated input chunks + // - lowerBuf stores the last candidate in lower-case + // - rolesBuf stores the calculated roles for each rune in the last + // candidate. + inputBuf [MaxInputSize]byte lowerBuf [MaxInputSize]byte rolesBuf [MaxInputSize]RuneRole } @@ -72,7 +76,7 @@ func NewMatcher(pattern string) *Matcher { m := &Matcher{ pattern: pattern, - patternLower: ToLower(pattern, nil), + patternLower: toLower([]byte(pattern), nil), } for i, c := range m.patternLower { @@ -88,7 +92,7 @@ func NewMatcher(pattern string) *Matcher { m.patternShort = m.patternLower } - m.patternRoles = RuneRoles(pattern, nil) + m.patternRoles = RuneRoles([]byte(pattern), nil) if len(pattern) > 0 { maxCharScore := 4 @@ -102,10 +106,15 @@ func NewMatcher(pattern string) *Matcher { // This is not designed for parallel use. Multiple candidates must be scored sequentially. // Returns a score between 0 and 1 (0 - no match, 1 - perfect match). func (m *Matcher) Score(candidate string) float32 { + return m.ScoreChunks([]string{candidate}) +} + +func (m *Matcher) ScoreChunks(chunks []string) float32 { + candidate := fromChunks(chunks, m.inputBuf[:]) if len(candidate) > MaxInputSize { candidate = candidate[:MaxInputSize] } - lower := ToLower(candidate, m.lowerBuf[:]) + lower := toLower(candidate, m.lowerBuf[:]) m.lastCandidateLen = len(candidate) if len(m.pattern) == 0 { @@ -174,7 +183,7 @@ func (m *Matcher) MatchedRanges() []int { return ret } -func (m *Matcher) match(candidate string, candidateLower []byte) bool { +func (m *Matcher) match(candidate []byte, candidateLower []byte) bool { i, j := 0, 0 for ; i < len(candidateLower) && j < len(m.patternLower); i++ { if candidateLower[i] == m.patternLower[j] { @@ -192,7 +201,7 @@ func (m *Matcher) match(candidate string, candidateLower []byte) bool { return true } -func (m *Matcher) computeScore(candidate string, candidateLower []byte) int { +func (m *Matcher) computeScore(candidate []byte, candidateLower []byte) int { pattLen, candLen := len(m.pattern), len(candidate) for j := 0; j <= len(m.pattern); j++ { diff --git a/src/cmd/vendor/golang.org/x/tools/internal/lsp/fuzzy/symbol.go b/src/cmd/vendor/golang.org/x/tools/internal/lsp/fuzzy/symbol.go new file mode 100644 index 00000000000..062f491fb5c --- /dev/null +++ b/src/cmd/vendor/golang.org/x/tools/internal/lsp/fuzzy/symbol.go @@ -0,0 +1,224 @@ +// Copyright 2021 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 fuzzy + +import ( + "unicode" +) + +// SymbolMatcher implements a fuzzy matching algorithm optimized for Go symbols +// of the form: +// example.com/path/to/package.object.field +// +// Knowing that we are matching symbols like this allows us to make the +// following optimizations: +// - We can incorporate right-to-left relevance directly into the score +// calculation. +// - We can match from right to left, discarding leading bytes if the input is +// too long. +// - We just take the right-most match without losing too much precision. This +// allows us to use an O(n) algorithm. +// - We can operate directly on chunked strings; in many cases we will +// be storing the package path and/or package name separately from the +// symbol or identifiers, so doing this avoids allocating strings. +// - We can return the index of the right-most match, allowing us to trim +// irrelevant qualification. +// +// This implementation is experimental, serving as a reference fast algorithm +// to compare to the fuzzy algorithm implemented by Matcher. +type SymbolMatcher struct { + // Using buffers of length 256 is both a reasonable size for most qualified + // symbols, and makes it easy to avoid bounds checks by using uint8 indexes. + pattern [256]rune + patternLen uint8 + inputBuffer [256]rune // avoid allocating when considering chunks + roles [256]uint32 // which roles does a rune play (word start, etc.) + segments [256]uint8 // how many segments from the right is each rune +} + +const ( + segmentStart uint32 = 1 << iota + wordStart + separator +) + +// NewSymbolMatcher creates a SymbolMatcher that may be used to match the given +// search pattern. +// +// Currently this matcher only accepts case-insensitive fuzzy patterns. +// +// TODO(rfindley): +// - implement smart-casing +// - implement space-separated groups +// - implement ', ^, and $ modifiers +// +// An empty pattern matches no input. +func NewSymbolMatcher(pattern string) *SymbolMatcher { + m := &SymbolMatcher{} + for _, p := range pattern { + m.pattern[m.patternLen] = unicode.ToLower(p) + m.patternLen++ + if m.patternLen == 255 || int(m.patternLen) == len(pattern) { + // break at 255 so that we can represent patternLen with a uint8. + break + } + } + return m +} + +// Match looks for the right-most match of the search pattern within the symbol +// represented by concatenating the given chunks, returning its offset and +// score. +// +// If a match is found, the first return value will hold the absolute byte +// offset within all chunks for the start of the symbol. In other words, the +// index of the match within strings.Join(chunks, ""). If no match is found, +// the first return value will be -1. +// +// The second return value will be the score of the match, which is always +// between 0 and 1, inclusive. A score of 0 indicates no match. +func (m *SymbolMatcher) Match(chunks []string) (int, float64) { + // Explicit behavior for an empty pattern. + // + // As a minor optimization, this also avoids nilness checks later on, since + // the compiler can prove that m != nil. + if m.patternLen == 0 { + return -1, 0 + } + + // First phase: populate the input buffer with lower-cased runes. + // + // We could also check for a forward match here, but since we'd have to write + // the entire input anyway this has negligible impact on performance. + + var ( + inputLen = uint8(0) + modifiers = wordStart | segmentStart + ) + +input: + for _, chunk := range chunks { + for _, r := range chunk { + if r == '.' || r == '/' { + modifiers |= separator + } + // optimization: avoid calls to unicode.ToLower, which can't be inlined. + l := r + if r <= unicode.MaxASCII { + if 'A' <= r && r <= 'Z' { + l = r + 'a' - 'A' + } + } else { + l = unicode.ToLower(r) + } + if l != r { + modifiers |= wordStart + } + m.inputBuffer[inputLen] = l + m.roles[inputLen] = modifiers + inputLen++ + if m.roles[inputLen-1]&separator != 0 { + modifiers = wordStart | segmentStart + } else { + modifiers = 0 + } + // TODO: we should prefer the right-most input if it overflows, rather + // than the left-most as we're doing here. + if inputLen == 255 { + break input + } + } + } + + // Second phase: find the right-most match, and count segments from the + // right. + + var ( + pi = uint8(m.patternLen - 1) // pattern index + p = m.pattern[pi] // pattern rune + start = -1 // start offset of match + rseg = uint8(0) + ) + const maxSeg = 3 // maximum number of segments from the right to count, for scoring purposes. + + for ii := inputLen - 1; ; ii-- { + r := m.inputBuffer[ii] + if rseg < maxSeg && m.roles[ii]&separator != 0 { + rseg++ + } + m.segments[ii] = rseg + if p == r { + if pi == 0 { + start = int(ii) + break + } + pi-- + p = m.pattern[pi] + } + // Don't check ii >= 0 in the loop condition: ii is a uint8. + if ii == 0 { + break + } + } + + if start < 0 { + // no match: skip scoring + return -1, 0 + } + + // Third phase: find the shortest match, and compute the score. + + // Score is the average score for each character. + // + // A character score is the multiple of: + // 1. 1.0 if the character starts a segment, .8 if the character start a + // mid-segment word, otherwise 0.6. This carries over to immediately + // following characters. + // 2. 1.0 if the character is part of the last segment, otherwise + // 1.0-.2*, with a max segment count of 3. + // + // This is a very naive algorithm, but it is fast. There's lots of prior art + // here, and we should leverage it. For example, we could explicitly consider + // character distance, and exact matches of words or segments. + // + // Also note that this might not actually find the highest scoring match, as + // doing so could require a non-linear algorithm, depending on how the score + // is calculated. + + pi = 0 + p = m.pattern[pi] + + const ( + segStreak = 1.0 + wordStreak = 0.8 + noStreak = 0.6 + perSegment = 0.2 // we count at most 3 segments above + ) + + streakBonus := noStreak + totScore := 0.0 + for ii := uint8(start); ii < inputLen; ii++ { + r := m.inputBuffer[ii] + if r == p { + pi++ + p = m.pattern[pi] + // Note: this could be optimized with some bit operations. + switch { + case m.roles[ii]&segmentStart != 0 && segStreak > streakBonus: + streakBonus = segStreak + case m.roles[ii]&wordStart != 0 && wordStreak > streakBonus: + streakBonus = wordStreak + } + totScore += streakBonus * (1.0 - float64(m.segments[ii])*perSegment) + if pi >= m.patternLen { + break + } + } else { + streakBonus = noStreak + } + } + + return start, totScore / float64(m.patternLen) +} diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typeparams/common.go b/src/cmd/vendor/golang.org/x/tools/internal/typeparams/common.go new file mode 100644 index 00000000000..9fc6b4beb88 --- /dev/null +++ b/src/cmd/vendor/golang.org/x/tools/internal/typeparams/common.go @@ -0,0 +1,25 @@ +// Copyright 2021 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 typeparams provides functions to work indirectly with type parameter +// data stored in go/ast and go/types objects, while these API are guarded by a +// build constraint. +// +// This package exists to make it easier for tools to work with generic code, +// while also compiling against older Go versions. +package typeparams + +import ( + "go/ast" + "go/token" +) + +// A IndexExprData holds data from both ast.IndexExpr and the new +// ast.MultiIndexExpr, which was introduced in Go 1.18. +type IndexExprData struct { + X ast.Expr // expression + Lbrack token.Pos // position of "[" + Indices []ast.Expr // index expressions + Rbrack token.Pos // position of "]" +} diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typeparams/notypeparams.go b/src/cmd/vendor/golang.org/x/tools/internal/typeparams/notypeparams.go new file mode 100644 index 00000000000..e975e476f66 --- /dev/null +++ b/src/cmd/vendor/golang.org/x/tools/internal/typeparams/notypeparams.go @@ -0,0 +1,93 @@ +// Copyright 2021 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 !typeparams || !go1.18 +// +build !typeparams !go1.18 + +package typeparams + +import ( + "go/ast" + "go/types" +) + +// NOTE: doc comments must be kept in sync with typeparams.go. + +// Enabled reports whether type parameters are enabled in the current build +// environment. +const Enabled = false + +// GetIndexExprData extracts data from AST nodes that represent index +// expressions. +// +// For an ast.IndexExpr, the resulting IndexExprData will have exactly one +// index expression. For an ast.MultiIndexExpr (go1.18+), it may have a +// variable number of index expressions. +// +// For nodes that don't represent index expressions, GetIndexExprData returns +// nil. +func GetIndexExprData(n ast.Node) *IndexExprData { + if e, _ := n.(*ast.IndexExpr); e != nil { + return &IndexExprData{ + X: e.X, + Lbrack: e.Lbrack, + Indices: []ast.Expr{e.Index}, + Rbrack: e.Rbrack, + } + } + return nil +} + +// ForTypeDecl extracts the (possibly nil) type parameter node list from n. +func ForTypeDecl(*ast.TypeSpec) *ast.FieldList { + return nil +} + +// ForFuncDecl extracts the (possibly nil) type parameter node list from n. +func ForFuncDecl(*ast.FuncDecl) *ast.FieldList { + return nil +} + +// ForSignature extracts the (possibly empty) type parameter object list from +// sig. +func ForSignature(*types.Signature) []*types.TypeName { + return nil +} + +// IsComparable reports if iface is the comparable interface. +func IsComparable(*types.Interface) bool { + return false +} + +// IsConstraint reports whether iface may only be used as a type parameter +// constraint (i.e. has a type set or is the comparable interface). +func IsConstraint(*types.Interface) bool { + return false +} + +// ForNamed extracts the (possibly empty) type parameter object list from +// named. +func ForNamed(*types.Named) []*types.TypeName { + return nil +} + +// NamedTArgs extracts the (possibly empty) type argument list from named. +func NamedTArgs(*types.Named) []types.Type { + return nil +} + +// InitInferred initializes info to record inferred type information. +func InitInferred(*types.Info) { +} + +// GetInferred extracts inferred type information from info for e. +// +// The expression e may have an inferred type if it is an *ast.IndexExpr +// representing partial instantiation of a generic function type for which type +// arguments have been inferred using constraint type inference, or if it is an +// *ast.CallExpr for which type type arguments have be inferred using both +// constraint type inference and function argument inference. +func GetInferred(*types.Info, ast.Expr) ([]types.Type, *types.Signature) { + return nil, nil +} diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typeparams/typeparams.go b/src/cmd/vendor/golang.org/x/tools/internal/typeparams/typeparams.go new file mode 100644 index 00000000000..be6b0525f61 --- /dev/null +++ b/src/cmd/vendor/golang.org/x/tools/internal/typeparams/typeparams.go @@ -0,0 +1,115 @@ +// Copyright 2021 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 typeparams && go1.18 +// +build typeparams,go1.18 + +package typeparams + +import ( + "go/ast" + "go/types" +) + +// NOTE: doc comments must be kept in sync with notypeparams.go. + +// Enabled reports whether type parameters are enabled in the current build +// environment. +const Enabled = true + +// GetIndexExprData extracts data from AST nodes that represent index +// expressions. +// +// For an ast.IndexExpr, the resulting IndexExprData will have exactly one +// index expression. For an ast.MultiIndexExpr (go1.18+), it may have a +// variable number of index expressions. +// +// For nodes that don't represent index expressions, GetIndexExprData returns +// nil. +func GetIndexExprData(n ast.Node) *IndexExprData { + switch e := n.(type) { + case *ast.IndexExpr: + return &IndexExprData{ + X: e.X, + Lbrack: e.Lbrack, + Indices: []ast.Expr{e.Index}, + Rbrack: e.Rbrack, + } + case *ast.MultiIndexExpr: + return (*IndexExprData)(e) + } + return nil +} + +// ForTypeDecl extracts the (possibly nil) type parameter node list from n. +func ForTypeDecl(n *ast.TypeSpec) *ast.FieldList { + return n.TParams +} + +// ForFuncDecl extracts the (possibly nil) type parameter node list from n. +func ForFuncDecl(n *ast.FuncDecl) *ast.FieldList { + if n.Type != nil { + return n.Type.TParams + } + return nil +} + +// ForSignature extracts the (possibly empty) type parameter object list from +// sig. +func ForSignature(sig *types.Signature) []*types.TypeName { + return tparamsSlice(sig.TParams()) +} + +// IsComparable reports if iface is the comparable interface. +func IsComparable(iface *types.Interface) bool { + return iface.IsComparable() +} + +// IsConstraint reports whether iface may only be used as a type parameter +// constraint (i.e. has a type set or is the comparable interface). +func IsConstraint(iface *types.Interface) bool { + return iface.IsConstraint() +} + +// ForNamed extracts the (possibly empty) type parameter object list from +// named. +func ForNamed(named *types.Named) []*types.TypeName { + return tparamsSlice(named.TParams()) +} + +func tparamsSlice(tparams *types.TypeParams) []*types.TypeName { + if tparams.Len() == 0 { + return nil + } + result := make([]*types.TypeName, tparams.Len()) + for i := 0; i < tparams.Len(); i++ { + result[i] = tparams.At(i) + } + return result +} + +// NamedTArgs extracts the (possibly empty) type argument list from named. +func NamedTArgs(named *types.Named) []types.Type { + return named.TArgs() +} + +// InitInferred initializes info to record inferred type information. +func InitInferred(info *types.Info) { + info.Inferred = make(map[ast.Expr]types.Inferred) +} + +// GetInferred extracts inferred type information from info for e. +// +// The expression e may have an inferred type if it is an *ast.IndexExpr +// representing partial instantiation of a generic function type for which type +// arguments have been inferred using constraint type inference, or if it is an +// *ast.CallExpr for which type type arguments have be inferred using both +// constraint type inference and function argument inference. +func GetInferred(info *types.Info, e ast.Expr) ([]types.Type, *types.Signature) { + if info.Inferred == nil { + return nil, nil + } + inf := info.Inferred[e] + return inf.TArgs, inf.Sig +} diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt index 34dbdaf5dd3..c98bdcd3440 100644 --- a/src/cmd/vendor/modules.txt +++ b/src/cmd/vendor/modules.txt @@ -48,7 +48,7 @@ golang.org/x/sys/windows # golang.org/x/term v0.0.0-20210503060354-a79de5458b56 ## explicit; go 1.17 golang.org/x/term -# golang.org/x/tools v0.1.2-0.20210519160823-49064d2332f9 +# golang.org/x/tools v0.1.6-0.20210809225032-337cebd2c151 ## explicit; go 1.17 golang.org/x/tools/cover golang.org/x/tools/go/analysis @@ -92,6 +92,7 @@ golang.org/x/tools/go/types/objectpath golang.org/x/tools/go/types/typeutil golang.org/x/tools/internal/analysisinternal golang.org/x/tools/internal/lsp/fuzzy +golang.org/x/tools/internal/typeparams # golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 ## explicit; go 1.11 golang.org/x/xerrors diff --git a/src/cmd/vet/testdata/print/print.go b/src/cmd/vet/testdata/print/print.go index fca594925f7..46240e87bfd 100644 --- a/src/cmd/vet/testdata/print/print.go +++ b/src/cmd/vet/testdata/print/print.go @@ -491,10 +491,10 @@ type recursiveStringer int func (s recursiveStringer) String() string { _ = fmt.Sprintf("%d", s) _ = fmt.Sprintf("%#v", s) - _ = fmt.Sprintf("%v", s) // ERROR "Sprintf format %v with arg s causes recursive String method call" - _ = fmt.Sprintf("%v", &s) // ERROR "Sprintf format %v with arg &s causes recursive String method call" + _ = fmt.Sprintf("%v", s) // ERROR "Sprintf format %v with arg s causes recursive .*String method call" + _ = fmt.Sprintf("%v", &s) // ERROR "Sprintf format %v with arg &s causes recursive .*String method call" _ = fmt.Sprintf("%T", s) // ok; does not recursively call String - return fmt.Sprintln(s) // ERROR "Sprintln arg s causes recursive call to String method" + return fmt.Sprintln(s) // ERROR "Sprintln arg s causes recursive call to .*String method" } type recursivePtrStringer int @@ -502,7 +502,7 @@ type recursivePtrStringer int func (p *recursivePtrStringer) String() string { _ = fmt.Sprintf("%v", *p) _ = fmt.Sprint(&p) // ok; prints address - return fmt.Sprintln(p) // ERROR "Sprintln arg p causes recursive call to String method" + return fmt.Sprintln(p) // ERROR "Sprintln arg p causes recursive call to .*String method" } type BoolFormatter bool From fb8579746c9de74a6faa70de544286e45bc8386e Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Mon, 2 Aug 2021 12:17:13 -0400 Subject: [PATCH 899/940] [dev.typeparams] internal/goexperiment: update comment for RegabiArgs requirements RegabiG and regabiDefer have been always enabled and removed from experiments. Update the comment. Change-Id: Ieaf4b4f0a7e0e9d6733a18932ca457be4f150d08 Reviewed-on: https://go-review.googlesource.com/c/go/+/341150 Trust: Cherry Mui Reviewed-by: Michael Knyszek --- src/internal/goexperiment/flags.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/internal/goexperiment/flags.go b/src/internal/goexperiment/flags.go index b7a62b3e268..0a61a0e5fc1 100644 --- a/src/internal/goexperiment/flags.go +++ b/src/internal/goexperiment/flags.go @@ -80,10 +80,7 @@ type Flags struct { // RegabiArgs enables register arguments/results in all // compiled Go functions. // - // Requires wrappers (to do ABI translation), g (because - // runtime assembly that's been ported to ABIInternal uses the - // G register), reflect (so reflection calls use registers), - // and defer (because the runtime doesn't support passing - // register arguments to defer/go). + // Requires wrappers (to do ABI translation), and reflect (so + // reflection calls use registers). RegabiArgs bool } From 40ba119e3f990fd570ec928307e92a5b6a76bd0e Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Mon, 9 Aug 2021 16:00:29 -0700 Subject: [PATCH 900/940] [dev.typeparams] cmd/compile: keep export format unchanged if no type params are exported Added new export tags 'G' and 'U' to export parameterized functions/methods and parameterized types respectively. This has the advantage that the Go 1.18 format remains backward-compatible with the Go 1.17 format if no type parameters are exported. Change-Id: I9dba8faaa65609eb3f9c693bd0c79daee98bd865 Reviewed-on: https://go-review.googlesource.com/c/go/+/340989 Trust: Dan Scales Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Robert Griesemer Reviewed-by: Robert Findley Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/importer/iimport.go | 13 ++++++----- src/cmd/compile/internal/typecheck/iexport.go | 23 +++++++++++-------- src/cmd/compile/internal/typecheck/iimport.go | 10 ++++---- src/go/internal/gcimporter/iimport.go | 19 +++++---------- 4 files changed, 31 insertions(+), 34 deletions(-) diff --git a/src/cmd/compile/internal/importer/iimport.go b/src/cmd/compile/internal/importer/iimport.go index 99eb9644159..6051cdaf231 100644 --- a/src/cmd/compile/internal/importer/iimport.go +++ b/src/cmd/compile/internal/importer/iimport.go @@ -308,19 +308,18 @@ func (r *importReader) obj(name string) { r.declare(types2.NewConst(pos, r.currPkg, name, typ, val)) - case 'F': + case 'F', 'G': var tparams []*types2.TypeName - if r.p.exportVersion >= iexportVersionGenerics { + if tag == 'G' { tparams = r.tparamList() } sig := r.signature(nil) sig.SetTParams(tparams) - r.declare(types2.NewFunc(pos, r.currPkg, name, sig)) - case 'T': + case 'T', 'U': var tparams []*types2.TypeName - if r.p.exportVersion >= iexportVersionGenerics { + if tag == 'U' { tparams = r.tparamList() } @@ -328,7 +327,9 @@ func (r *importReader) obj(name string) { // declaration before recursing. obj := types2.NewTypeName(pos, r.currPkg, name, nil) named := types2.NewNamed(obj, nil, nil) - named.SetTParams(tparams) + if tag == 'U' { + named.SetTParams(tparams) + } r.declare(obj) underlying := r.p.typAt(r.uint64(), named).Underlying() diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index 2944908bcbc..5f510a0a250 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -314,12 +314,7 @@ func WriteExports(out io.Writer, extensions bool) { // Assemble header. var hdr intWriter hdr.WriteByte('i') - if base.Flag.G > 0 { - hdr.uint64(iexportVersionCurrent) - } else { - // Use old export format if doing -G=0 (no generics) - hdr.uint64(iexportVersionPosCol) - } + hdr.uint64(iexportVersionCurrent) hdr.uint64(uint64(p.strings.Len())) hdr.uint64(dataLen) @@ -487,7 +482,11 @@ func (p *iexporter) doDecl(n *ir.Name) { } // Function. - w.tag('F') + if n.Type().TParams().NumFields() == 0 { + w.tag('F') + } else { + w.tag('G') + } w.pos(n.Pos()) // The tparam list of the function type is the // declaration of the type params. So, write out the type @@ -495,7 +494,7 @@ func (p *iexporter) doDecl(n *ir.Name) { // referenced via their type offset (via typOff) in all // other places in the signature and function that they // are used. - if base.Flag.G > 0 { + if n.Type().TParams().NumFields() > 0 { w.tparamList(n.Type().TParams().FieldSlice()) } w.signature(n.Type()) @@ -544,10 +543,14 @@ func (p *iexporter) doDecl(n *ir.Name) { } // Defined type. - w.tag('T') + if len(n.Type().RParams()) == 0 { + w.tag('T') + } else { + w.tag('U') + } w.pos(n.Pos()) - if base.Flag.G > 0 { + if len(n.Type().RParams()) > 0 { // Export type parameters, if any, needed for this type w.typeList(n.Type().RParams()) } diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index d5f4bba98b2..83974b6d567 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -305,9 +305,9 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name { r.constExt(n) return n - case 'F': + case 'F', 'G': var tparams []*types.Field - if r.p.exportVersion >= iexportVersionGenerics { + if tag == 'G' { tparams = r.tparamList() } typ := r.signature(nil, tparams) @@ -316,9 +316,9 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name { r.funcExt(n) return n - case 'T': + case 'T', 'U': var rparams []*types.Type - if r.p.exportVersion >= iexportVersionGenerics { + if tag == 'U' { rparams = r.typeList() } @@ -326,7 +326,7 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name { // declaration before recursing. n := importtype(pos, sym) t := n.Type() - if rparams != nil { + if tag == 'U' { t.SetRParams(rparams) } diff --git a/src/go/internal/gcimporter/iimport.go b/src/go/internal/gcimporter/iimport.go index b300860e940..d4778d3a745 100644 --- a/src/go/internal/gcimporter/iimport.go +++ b/src/go/internal/gcimporter/iimport.go @@ -290,24 +290,14 @@ func (r *importReader) obj(name string) { r.declare(types.NewConst(pos, r.currPkg, name, typ, val)) case 'F': - if r.p.exportVersion >= iexportVersionGenerics { - numTparams := r.uint64() - if numTparams > 0 { - errorf("unexpected tparam") - } - } sig := r.signature(nil) r.declare(types.NewFunc(pos, r.currPkg, name, sig)) - case 'T': - if r.p.exportVersion >= iexportVersionGenerics { - numTparams := r.uint64() - if numTparams > 0 { - errorf("unexpected tparam") - } - } + case 'G': + errorf("unexpected parameterized function/method") + case 'T': // Types can be recursive. We need to setup a stub // declaration before recursing. obj := types.NewTypeName(pos, r.currPkg, name, nil) @@ -328,6 +318,9 @@ func (r *importReader) obj(name string) { } } + case 'U': + errorf("unexpected parameterized type") + case 'V': typ := r.typ() From 0f34a92df76a7946e55d437264bbf5459b30f302 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Wed, 4 Aug 2021 10:45:16 -0400 Subject: [PATCH 901/940] [dev.typeparams] go/types: don't expose the TypeSet API for 1.18 The TypeSet API is very new and probably not necessary to expose outside of go/types, at least for 1.18. Users can check whether a type is contained within a type set via Implements, and can access the representation of the type set via the embedded Unions. Change-Id: Icc7355285785bee5aa7a8fe74052bcb0fedcd0a1 Reviewed-on: https://go-review.googlesource.com/c/go/+/341289 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/builtins.go | 2 +- src/go/types/interface.go | 4 ++-- src/go/types/sizeof_test.go | 2 +- src/go/types/typeset.go | 28 ++++++++++++++-------------- src/go/types/universe.go | 2 +- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index aae05438cd3..c73d94658ab 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -844,7 +844,7 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { ptyp := check.NewTypeParam(tpar, &emptyInterface) // assigns type to tpar as a side-effect ptyp.index = tp.index tsum := newUnion(rtypes, tildes) - ptyp.bound = &Interface{complete: true, tset: &TypeSet{types: tsum}} + ptyp.bound = &Interface{complete: true, tset: &_TypeSet{types: tsum}} return ptyp } diff --git a/src/go/types/interface.go b/src/go/types/interface.go index e98e40179ca..d8f96718571 100644 --- a/src/go/types/interface.go +++ b/src/go/types/interface.go @@ -21,11 +21,11 @@ type Interface struct { embedPos *[]token.Pos // positions of embedded elements; or nil (for error messages) - use pointer to save space complete bool // indicates that obj, methods, and embeddeds are set and type set can be computed - tset *TypeSet // type set described by this interface, computed lazily + tset *_TypeSet // type set described by this interface, computed lazily } // typeSet returns the type set for interface t. -func (t *Interface) typeSet() *TypeSet { return computeTypeSet(nil, token.NoPos, t) } +func (t *Interface) typeSet() *_TypeSet { return computeTypeSet(nil, token.NoPos, t) } // is reports whether interface t represents types that all satisfy f. func (t *Interface) is(f func(Type, bool) bool) bool { diff --git a/src/go/types/sizeof_test.go b/src/go/types/sizeof_test.go index 75122b02735..67a9b39558e 100644 --- a/src/go/types/sizeof_test.go +++ b/src/go/types/sizeof_test.go @@ -48,7 +48,7 @@ func TestSizeof(t *testing.T) { // Misc {Scope{}, 44, 88}, {Package{}, 40, 80}, - {TypeSet{}, 24, 48}, + {_TypeSet{}, 24, 48}, } for _, test := range tests { got := reflect.TypeOf(test.val).Size() diff --git a/src/go/types/typeset.go b/src/go/types/typeset.go index cbd867dd953..836f93047a2 100644 --- a/src/go/types/typeset.go +++ b/src/go/types/typeset.go @@ -14,8 +14,8 @@ import ( // ---------------------------------------------------------------------------- // API -// A TypeSet represents the type set of an interface. -type TypeSet struct { +// A _TypeSet represents the type set of an interface. +type _TypeSet struct { comparable bool // if set, the interface is or embeds comparable // TODO(gri) consider using a set for the methods for faster lookup methods []*Func // all methods of the interface; sorted by unique ID @@ -23,14 +23,14 @@ type TypeSet struct { } // IsTop reports whether type set s is the top type set (corresponding to the empty interface). -func (s *TypeSet) IsTop() bool { return !s.comparable && len(s.methods) == 0 && s.types == nil } +func (s *_TypeSet) IsTop() bool { return !s.comparable && len(s.methods) == 0 && s.types == nil } // IsMethodSet reports whether the type set s is described by a single set of methods. -func (s *TypeSet) IsMethodSet() bool { return !s.comparable && s.types == nil } +func (s *_TypeSet) IsMethodSet() bool { return !s.comparable && s.types == nil } // IsComparable reports whether each type in the set is comparable. // TODO(gri) this is not correct - there may be s.types values containing non-comparable types -func (s *TypeSet) IsComparable() bool { +func (s *_TypeSet) IsComparable() bool { if s.types == nil { return s.comparable } @@ -46,24 +46,24 @@ func (s *TypeSet) IsComparable() bool { // TODO(gri) IsTypeSet is not a great name. Find a better one. // IsTypeSet reports whether the type set s is represented by a finite set of underlying types. -func (s *TypeSet) IsTypeSet() bool { +func (s *_TypeSet) IsTypeSet() bool { return !s.comparable && len(s.methods) == 0 } // NumMethods returns the number of methods available. -func (s *TypeSet) NumMethods() int { return len(s.methods) } +func (s *_TypeSet) NumMethods() int { return len(s.methods) } // Method returns the i'th method of type set s for 0 <= i < s.NumMethods(). // The methods are ordered by their unique ID. -func (s *TypeSet) Method(i int) *Func { return s.methods[i] } +func (s *_TypeSet) Method(i int) *Func { return s.methods[i] } // LookupMethod returns the index of and method with matching package and name, or (-1, nil). -func (s *TypeSet) LookupMethod(pkg *Package, name string) (int, *Func) { +func (s *_TypeSet) LookupMethod(pkg *Package, name string) (int, *Func) { // TODO(gri) s.methods is sorted - consider binary search return lookupMethod(s.methods, pkg, name) } -func (s *TypeSet) String() string { +func (s *_TypeSet) String() string { if s.IsTop() { return "⊤" } @@ -102,7 +102,7 @@ func (s *TypeSet) String() string { // enumerable types in the type set s. If the type set comprises all types // f is called once with the top type; if the type set is empty, the result // is false. -func (s *TypeSet) underIs(f func(Type) bool) bool { +func (s *_TypeSet) underIs(f func(Type) bool) bool { switch t := s.types.(type) { case nil: return f(theTop) @@ -114,10 +114,10 @@ func (s *TypeSet) underIs(f func(Type) bool) bool { } // topTypeSet may be used as type set for the empty interface. -var topTypeSet TypeSet +var topTypeSet _TypeSet // computeTypeSet may be called with check == nil. -func computeTypeSet(check *Checker, pos token.Pos, ityp *Interface) *TypeSet { +func computeTypeSet(check *Checker, pos token.Pos, ityp *Interface) *_TypeSet { if ityp.tset != nil { return ityp.tset } @@ -157,7 +157,7 @@ func computeTypeSet(check *Checker, pos token.Pos, ityp *Interface) *TypeSet { // have valid interfaces. Mark the interface as complete to avoid // infinite recursion if the validType check occurs later for some // reason. - ityp.tset = new(TypeSet) // TODO(gri) is this sufficient? + ityp.tset = new(_TypeSet) // TODO(gri) is this sufficient? // Methods of embedded interfaces are collected unchanged; i.e., the identity // of a method I.m's Func Object of an interface I is the same as that of diff --git a/src/go/types/universe.go b/src/go/types/universe.go index e2b3bd7c187..83c54c8cd33 100644 --- a/src/go/types/universe.go +++ b/src/go/types/universe.go @@ -100,7 +100,7 @@ func defPredeclaredTypes() { { obj := NewTypeName(token.NoPos, nil, "comparable", nil) obj.setColor(black) - ityp := &Interface{obj, nil, nil, nil, true, &TypeSet{true, nil, nil}} + ityp := &Interface{obj, nil, nil, nil, true, &_TypeSet{true, nil, nil}} NewNamed(obj, ityp, nil) def(obj) } From 7308d747e7914b1dbb446988c2094f96b8e5116d Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Mon, 9 Aug 2021 13:39:32 -0400 Subject: [PATCH 902/940] [dev.typeparams] cmd/compile/internal/types2: remove Named.SetTArgs Calling SetTArgs without substituting can leave the type in incoherent state, so we should avoid exposing this API unless necessary. Since it is currently not used by the importer(s), it is probably not necessary to expose for 1.18, so remove it. Change-Id: I06bd7b5bbfacd3c65e2e66a9d5980f20cd1c10c1 Reviewed-on: https://go-review.googlesource.com/c/go/+/341290 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types2/named.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/cmd/compile/internal/types2/named.go b/src/cmd/compile/internal/types2/named.go index e0996604819..adf3eb38229 100644 --- a/src/cmd/compile/internal/types2/named.go +++ b/src/cmd/compile/internal/types2/named.go @@ -128,9 +128,6 @@ func (t *Named) SetTParams(tparams []*TypeName) { t.load().tparams = bindTParams // TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated. func (t *Named) TArgs() []Type { return t.targs } -// SetTArgs sets the type arguments of the named type t. -func (t *Named) SetTArgs(args []Type) { t.targs = args } - // NumMethods returns the number of explicit methods whose receiver is named type t. func (t *Named) NumMethods() int { return len(t.load().methods) } From 0888a8cd2dc3ad66e30ccb30eae8fbed065ea0f7 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 9 Aug 2021 15:13:22 -0700 Subject: [PATCH 903/940] [dev.typeparams] cmd/compile/internal/types2: remove unused TypeParam.Bound method Use TypeParam.Constraint instead. Change-Id: Iebd77d304f2b7238baa231fb9869c964f66ea355 Reviewed-on: https://go-review.googlesource.com/c/go/+/340990 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/typeparam.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/cmd/compile/internal/types2/typeparam.go b/src/cmd/compile/internal/types2/typeparam.go index 12513ed6dda..4b4282efe0b 100644 --- a/src/cmd/compile/internal/types2/typeparam.go +++ b/src/cmd/compile/internal/types2/typeparam.go @@ -80,13 +80,6 @@ func (t *TypeParam) SetConstraint(bound Type) { t.bound = bound } -// Bound returns the constraint interface of t. -// Deprecated. Only here for the compiler. -// TODO(gri) remove in favor of uses of Constraint. -func (t *TypeParam) Bound() *Interface { - return t.iface() -} - func (t *TypeParam) Underlying() Type { return t } func (t *TypeParam) String() string { return TypeString(t, nil) } From d4c0ed26ace91cb21fc0a67f088648674052aa3d Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 11 Aug 2021 09:10:55 -0700 Subject: [PATCH 904/940] doc/go1.17: linker passes -I to extld as -Wl,--dynamic-linker For #22446 Change-Id: I71a30761a28e81c50b7089d5a28be99c736c2dc8 Reviewed-on: https://go-review.googlesource.com/c/go/+/341332 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor Reviewed-by: Heschi Kreinick TryBot-Result: Go Bot --- doc/go1.17.html | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/go1.17.html b/doc/go1.17.html index d469f400ad9..972f9c35594 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -488,6 +488,15 @@ func Foo() bool { and compare functions by code pointer.

    + + +

    + When the linker uses external linking mode, which is the default + when linking a program that uses cgo, and the linker is invoked + with a -I option, the option will now be passed to the + external linker as a -Wl,--dynamic-linker option. +

    +

    Core library

    Cgo

    From eeb7899137cda1c2cd60dab65ff41f627436db5b Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Mon, 2 Aug 2021 12:18:19 -0400 Subject: [PATCH 905/940] [dev.typeparams] internal/buildcfg: always enable regabi on AMD64 In Go 1.17 we added register ABI on AMD64 on Linux/macOS/Windows as a GOEXPERIMENT, on by default. In Go 1.18, we commit to always enabling register ABI on AMD64. Now "go build" for AMD64 always have goexperiment.regabi* tags set. However, at bootstrapping cmd/dist does not set the tags when building go_bootstrap. For this to work, unfortunately, we need to hard-code AMD64 to use register ABI in runtime code. Change-Id: I0b31e678e186b9cdeeb8502cd9e38ed0d7e72d4f Reviewed-on: https://go-review.googlesource.com/c/go/+/341151 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek Reviewed-by: Austin Clements --- src/internal/abi/abi_amd64.go | 3 --- src/internal/abi/abi_generic.go | 4 ++-- src/internal/buildcfg/exp.go | 4 +++- src/runtime/stubs.go | 10 ++-------- 4 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/internal/abi/abi_amd64.go b/src/internal/abi/abi_amd64.go index aff71f6a58a..d3c56782231 100644 --- a/src/internal/abi/abi_amd64.go +++ b/src/internal/abi/abi_amd64.go @@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build goexperiment.regabireflect -// +build goexperiment.regabireflect - package abi const ( diff --git a/src/internal/abi/abi_generic.go b/src/internal/abi/abi_generic.go index 69400f930fb..e8f94f805f5 100644 --- a/src/internal/abi/abi_generic.go +++ b/src/internal/abi/abi_generic.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !goexperiment.regabireflect -// +build !goexperiment.regabireflect +//go:build !goexperiment.regabireflect && !amd64 +// +build !goexperiment.regabireflect,!amd64 package abi diff --git a/src/internal/buildcfg/exp.go b/src/internal/buildcfg/exp.go index 0245574ec1c..384f2f96af1 100644 --- a/src/internal/buildcfg/exp.go +++ b/src/internal/buildcfg/exp.go @@ -105,9 +105,11 @@ func ParseGOEXPERIMENT(goos, goarch, goexp string) (flags, baseline goexperiment } } - // regabiwrappers is always enabled on amd64. + // regabi is always enabled on amd64. if goarch == "amd64" { flags.RegabiWrappers = true + flags.RegabiReflect = true + flags.RegabiArgs = true } // regabi is only supported on amd64 and arm64. if goarch != "amd64" && goarch != "arm64" { diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index fc29a1bac31..8a520d7839e 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -6,6 +6,7 @@ package runtime import ( "internal/abi" + "internal/goarch" "internal/goexperiment" "unsafe" ) @@ -419,12 +420,5 @@ func sigpanic0() // structure that is at least large enough to hold the // registers the system supports. // -// Currently it's set to zero because using the actual -// constant will break every part of the toolchain that -// uses finalizers or Windows callbacks to call functions -// The value that is currently commented out there should be -// the actual value once we're ready to use the register ABI -// everywhere. -// // Protected by finlock. -var intArgRegs = abi.IntArgRegs * goexperiment.RegabiArgsInt +var intArgRegs = abi.IntArgRegs * (goexperiment.RegabiArgsInt | goarch.IsAmd64) From d7d4f28a06b8633d433a925b0dfaeadf6530ae97 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Mon, 2 Aug 2021 18:28:40 -0400 Subject: [PATCH 906/940] [dev.typeparams] runtime, internal/bytealg: remove regabi fallback code on AMD64 As we commit to always enabling register ABI on AMD64, remove the fallback code. Change-Id: I30556858ba4bac367495fa94f6a8682ecd771196 Reviewed-on: https://go-review.googlesource.com/c/go/+/341152 Trust: Cherry Mui Run-TryBot: Cherry Mui TryBot-Result: Go Bot Reviewed-by: Michael Knyszek Reviewed-by: Austin Clements --- src/internal/bytealg/compare_amd64.s | 32 ----- src/internal/bytealg/equal_amd64.s | 51 ------- src/runtime/asm_amd64.s | 202 --------------------------- src/runtime/memclr_amd64.s | 5 - src/runtime/memmove_amd64.s | 6 - src/runtime/race_amd64.s | 13 -- 6 files changed, 309 deletions(-) diff --git a/src/internal/bytealg/compare_amd64.s b/src/internal/bytealg/compare_amd64.s index 8295acb03a1..4ccaca5e87b 100644 --- a/src/internal/bytealg/compare_amd64.s +++ b/src/internal/bytealg/compare_amd64.s @@ -6,7 +6,6 @@ #include "textflag.h" TEXT ·Compare(SB),NOSPLIT,$0-56 -#ifdef GOEXPERIMENT_regabiargs // AX = a_base (want in SI) // BX = a_len (want in BX) // CX = a_cap (unused) @@ -15,17 +14,9 @@ TEXT ·Compare(SB),NOSPLIT,$0-56 // R8 = b_cap (unused) MOVQ SI, DX MOVQ AX, SI -#else - MOVQ a_base+0(FP), SI - MOVQ a_len+8(FP), BX - MOVQ b_base+24(FP), DI - MOVQ b_len+32(FP), DX - LEAQ ret+48(FP), R9 -#endif JMP cmpbody<>(SB) TEXT runtime·cmpstring(SB),NOSPLIT,$0-40 -#ifdef GOEXPERIMENT_regabiargs // AX = a_base (want in SI) // BX = a_len (want in BX) // CX = b_base (want in DI) @@ -33,13 +24,6 @@ TEXT runtime·cmpstring(SB),NOSPLIT,$0-40 MOVQ AX, SI MOVQ DI, DX MOVQ CX, DI -#else - MOVQ a_base+0(FP), SI - MOVQ a_len+8(FP), BX - MOVQ b_base+16(FP), DI - MOVQ b_len+24(FP), DX - LEAQ ret+32(FP), R9 -#endif JMP cmpbody<>(SB) // input: @@ -47,12 +31,8 @@ TEXT runtime·cmpstring(SB),NOSPLIT,$0-40 // DI = b // BX = alen // DX = blen -#ifndef GOEXPERIMENT_regabiargs -// R9 = address of output word (stores -1/0/1 here) -#else // output: // AX = output (-1/0/1) -#endif TEXT cmpbody<>(SB),NOSPLIT,$0-0 CMPQ SI, DI JEQ allsame @@ -100,9 +80,6 @@ diff16: CMPB CX, (DI)(BX*1) SETHI AX LEAQ -1(AX*2), AX // convert 1/0 to +1/-1 -#ifndef GOEXPERIMENT_regabiargs - MOVQ AX, (R9) -#endif RET // 0 through 16 bytes left, alen>=8, blen>=8 @@ -128,9 +105,6 @@ diff8: SHRQ CX, AX // move a's bit to bottom ANDQ $1, AX // mask bit LEAQ -1(AX*2), AX // 1/0 => +1/-1 -#ifndef GOEXPERIMENT_regabiargs - MOVQ AX, (R9) -#endif RET // 0-7 bytes in common @@ -169,9 +143,6 @@ di_finish: SHRQ CX, SI // move a's bit to bottom ANDQ $1, SI // mask bit LEAQ -1(SI*2), AX // 1/0 => +1/-1 -#ifndef GOEXPERIMENT_regabiargs - MOVQ AX, (R9) -#endif RET allsame: @@ -181,9 +152,6 @@ allsame: SETGT AX // 1 if alen > blen SETEQ CX // 1 if alen == blen LEAQ -1(CX)(AX*2), AX // 1,0,-1 result -#ifndef GOEXPERIMENT_regabiargs - MOVQ AX, (R9) -#endif RET // this works for >= 64 bytes of data. diff --git a/src/internal/bytealg/equal_amd64.s b/src/internal/bytealg/equal_amd64.s index 6f12d2a1690..dd46e2e0fdf 100644 --- a/src/internal/bytealg/equal_amd64.s +++ b/src/internal/bytealg/equal_amd64.s @@ -7,7 +7,6 @@ // memequal(a, b unsafe.Pointer, size uintptr) bool TEXT runtime·memequal(SB),NOSPLIT,$0-25 -#ifdef GOEXPERIMENT_regabiargs // AX = a (want in SI) // BX = b (want in DI) // CX = size (want in BX) @@ -20,22 +19,9 @@ neq: MOVQ BX, DI MOVQ CX, BX JMP memeqbody<>(SB) -#else - MOVQ a+0(FP), SI - MOVQ b+8(FP), DI - CMPQ SI, DI - JEQ eq - MOVQ size+16(FP), BX - LEAQ ret+24(FP), AX - JMP memeqbody<>(SB) -eq: - MOVB $1, ret+24(FP) - RET -#endif // memequal_varlen(a, b unsafe.Pointer) bool TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-17 -#ifdef GOEXPERIMENT_regabiargs // AX = a (want in SI) // BX = b (want in DI) // 8(DX) = size (want in BX) @@ -48,29 +34,13 @@ neq: MOVQ BX, DI MOVQ 8(DX), BX // compiler stores size at offset 8 in the closure JMP memeqbody<>(SB) -#else - MOVQ a+0(FP), SI - MOVQ b+8(FP), DI - CMPQ SI, DI - JEQ eq - MOVQ 8(DX), BX // compiler stores size at offset 8 in the closure - LEAQ ret+16(FP), AX - JMP memeqbody<>(SB) -eq: - MOVB $1, ret+16(FP) - RET -#endif // Input: // a in SI // b in DI // count in BX -#ifndef GOEXPERIMENT_regabiargs -// address of result byte in AX -#else // Output: // result in AX -#endif TEXT memeqbody<>(SB),NOSPLIT,$0-0 CMPQ BX, $8 JB small @@ -104,11 +74,7 @@ hugeloop: SUBQ $64, BX CMPL DX, $0xffff JEQ hugeloop -#ifdef GOEXPERIMENT_regabiargs XORQ AX, AX // return 0 -#else - MOVB $0, (AX) -#endif RET // 64 bytes at a time using ymm registers @@ -129,11 +95,7 @@ hugeloop_avx2: CMPL DX, $0xffffffff JEQ hugeloop_avx2 VZEROUPPER -#ifdef GOEXPERIMENT_regabiargs XORQ AX, AX // return 0 -#else - MOVB $0, (AX) -#endif RET bigloop_avx2: @@ -150,11 +112,7 @@ bigloop: SUBQ $8, BX CMPQ CX, DX JEQ bigloop -#ifdef GOEXPERIMENT_regabiargs XORQ AX, AX // return 0 -#else - MOVB $0, (AX) -#endif RET // remaining 0-8 bytes @@ -162,11 +120,7 @@ leftover: MOVQ -8(SI)(BX*1), CX MOVQ -8(DI)(BX*1), DX CMPQ CX, DX -#ifdef GOEXPERIMENT_regabiargs SETEQ AX -#else - SETEQ (AX) -#endif RET small: @@ -201,10 +155,5 @@ di_finish: SUBQ SI, DI SHLQ CX, DI equal: -#ifdef GOEXPERIMENT_regabiargs SETEQ AX -#else - SETEQ (AX) -#endif RET - diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index 2d8f4c24120..2083ecb53e8 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -277,7 +277,6 @@ TEXT gogo<>(SB), NOSPLIT, $0 // Switch to m->g0's stack, call fn(g). // Fn must never return. It should gogo(&g->sched) // to keep running g. -#ifdef GOEXPERIMENT_regabiargs TEXT runtime·mcall(SB), NOSPLIT, $0-8 MOVQ AX, DX // DX = fn @@ -306,38 +305,6 @@ goodm: POPQ AX JMP runtime·badmcall2(SB) RET -#else -TEXT runtime·mcall(SB), NOSPLIT, $0-8 - MOVQ fn+0(FP), DI - - get_tls(CX) - MOVQ g(CX), AX // save state in g->sched - MOVQ 0(SP), BX // caller's PC - MOVQ BX, (g_sched+gobuf_pc)(AX) - LEAQ fn+0(FP), BX // caller's SP - MOVQ BX, (g_sched+gobuf_sp)(AX) - MOVQ BP, (g_sched+gobuf_bp)(AX) - - // switch to m->g0 & its stack, call fn - MOVQ g(CX), BX - MOVQ g_m(BX), BX - MOVQ m_g0(BX), SI - CMPQ SI, AX // if g == m->g0 call badmcall - JNE 3(PC) - MOVQ $runtime·badmcall(SB), AX - JMP AX - MOVQ SI, g(CX) // g = m->g0 - MOVQ SI, R14 // set the g register - MOVQ (g_sched+gobuf_sp)(SI), SP // sp = m->g0->sched.sp - PUSHQ AX - MOVQ DI, DX - MOVQ 0(DI), DI - CALL DI - POPQ AX - MOVQ $runtime·badmcall2(SB), AX - JMP AX - RET -#endif // systemstack_switch is a dummy routine that systemstack leaves at the bottom // of the G stack. We need to distinguish the routine that @@ -465,7 +432,6 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0 MOVL $0, DX JMP runtime·morestack(SB) -#ifdef GOEXPERIMENT_regabireflect // spillArgs stores return values from registers to a *internal/abi.RegArgs in R12. TEXT ·spillArgs(SB),NOSPLIT,$0-0 MOVQ AX, 0(R12) @@ -521,15 +487,6 @@ TEXT ·unspillArgs(SB),NOSPLIT,$0-0 MOVQ 176(R12), X13 MOVQ 184(R12), X14 RET -#else -// spillArgs stores return values from registers to a pointer in R12. -TEXT ·spillArgs(SB),NOSPLIT,$0-0 - RET - -// unspillArgs loads args into registers from a pointer in R12. -TEXT ·unspillArgs(SB),NOSPLIT,$0-0 - RET -#endif // reflectcall: call a function with the given argument list // func call(stackArgsType *_type, f *FuncVal, stackArgs *byte, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs). @@ -988,61 +945,34 @@ done: // func memhash(p unsafe.Pointer, h, s uintptr) uintptr // hash function using AES hardware instructions TEXT runtime·memhash(SB),NOSPLIT,$0-32 -#ifdef GOEXPERIMENT_regabiargs // AX = ptr to data // BX = seed // CX = size -#endif CMPB runtime·useAeshash(SB), $0 JEQ noaes -#ifndef GOEXPERIMENT_regabiargs - MOVQ p+0(FP), AX // ptr to data - MOVQ s+16(FP), CX // size - LEAQ ret+24(FP), DX -#endif JMP aeshashbody<>(SB) noaes: JMP runtime·memhashFallback(SB) // func strhash(p unsafe.Pointer, h uintptr) uintptr TEXT runtime·strhash(SB),NOSPLIT,$0-24 -#ifdef GOEXPERIMENT_regabiargs // AX = ptr to string struct // BX = seed -#endif CMPB runtime·useAeshash(SB), $0 JEQ noaes -#ifndef GOEXPERIMENT_regabiargs - MOVQ p+0(FP), AX // ptr to string struct -#endif MOVQ 8(AX), CX // length of string MOVQ (AX), AX // string data -#ifndef GOEXPERIMENT_regabiargs - LEAQ ret+16(FP), DX -#endif JMP aeshashbody<>(SB) noaes: JMP runtime·strhashFallback(SB) // AX: data -#ifdef GOEXPERIMENT_regabiargs // BX: hash seed -#else -// h+8(FP): hash seed -#endif // CX: length -#ifdef GOEXPERIMENT_regabiargs // At return: AX = return value -#else -// DX: address to put return value -#endif TEXT aeshashbody<>(SB),NOSPLIT,$0-0 // Fill an SSE register with our seeds. -#ifdef GOEXPERIMENT_regabiargs MOVQ BX, X0 // 64 bits of per-table hash seed -#else - MOVQ h+8(FP), X0 // 64 bits of per-table hash seed -#endif PINSRW $4, CX, X0 // 16 bits of length PSHUFHW $0, X0, X0 // repeat length 4 times total MOVO X0, X1 // save unscrambled seed @@ -1079,11 +1009,7 @@ final1: AESENC X1, X1 // scramble combo 3 times AESENC X1, X1 AESENC X1, X1 -#ifdef GOEXPERIMENT_regabiargs MOVQ X1, AX // return X1 -#else - MOVQ X1, (DX) -#endif RET endofpage: @@ -1099,11 +1025,7 @@ endofpage: aes0: // Return scrambled input seed AESENC X0, X0 -#ifdef GOEXPERIMENT_regabiargs MOVQ X0, AX // return X0 -#else - MOVQ X0, (DX) -#endif RET aes16: @@ -1133,11 +1055,7 @@ aes17to32: // combine results PXOR X3, X2 -#ifdef GOEXPERIMENT_regabiargs MOVQ X2, AX // return X2 -#else - MOVQ X2, (DX) -#endif RET aes33to64: @@ -1179,11 +1097,7 @@ aes33to64: PXOR X6, X4 PXOR X7, X5 PXOR X5, X4 -#ifdef GOEXPERIMENT_regabiargs MOVQ X4, AX // return X4 -#else - MOVQ X4, (DX) -#endif RET aes65to128: @@ -1267,11 +1181,7 @@ aes65to128: PXOR X9, X8 // X15 must be zero on return PXOR X15, X15 -#ifdef GOEXPERIMENT_regabiargs MOVQ X8, AX // return X8 -#else - MOVQ X8, (DX) -#endif RET aes129plus: @@ -1389,37 +1299,22 @@ aesloop: PXOR X9, X8 // X15 must be zero on return PXOR X15, X15 -#ifdef GOEXPERIMENT_regabiargs MOVQ X8, AX // return X8 -#else - MOVQ X8, (DX) -#endif RET // func memhash32(p unsafe.Pointer, h uintptr) uintptr // ABIInternal for performance. TEXT runtime·memhash32(SB),NOSPLIT,$0-24 -#ifdef GOEXPERIMENT_regabiargs // AX = ptr to data // BX = seed -#endif CMPB runtime·useAeshash(SB), $0 JEQ noaes -#ifdef GOEXPERIMENT_regabiargs MOVQ BX, X0 // X0 = seed -#else - MOVQ p+0(FP), AX // ptr to data - MOVQ h+8(FP), X0 // seed -#endif PINSRD $2, (AX), X0 // data AESENC runtime·aeskeysched+0(SB), X0 AESENC runtime·aeskeysched+16(SB), X0 AESENC runtime·aeskeysched+32(SB), X0 -#ifdef GOEXPERIMENT_regabiargs MOVQ X0, AX // return X0 -#else - MOVQ X0, ret+16(FP) -#endif RET noaes: JMP runtime·memhash32Fallback(SB) @@ -1427,28 +1322,16 @@ noaes: // func memhash64(p unsafe.Pointer, h uintptr) uintptr // ABIInternal for performance. TEXT runtime·memhash64(SB),NOSPLIT,$0-24 -#ifdef GOEXPERIMENT_regabiargs // AX = ptr to data // BX = seed -#else -#endif CMPB runtime·useAeshash(SB), $0 JEQ noaes -#ifdef GOEXPERIMENT_regabiargs MOVQ BX, X0 // X0 = seed -#else - MOVQ p+0(FP), AX // ptr to data - MOVQ h+8(FP), X0 // seed -#endif PINSRQ $1, (AX), X0 // data AESENC runtime·aeskeysched+0(SB), X0 AESENC runtime·aeskeysched+16(SB), X0 AESENC runtime·aeskeysched+32(SB), X0 -#ifdef GOEXPERIMENT_regabiargs MOVQ X0, AX // return X0 -#else - MOVQ X0, ret+16(FP) -#endif RET noaes: JMP runtime·memhash64Fallback(SB) @@ -1925,146 +1808,61 @@ TEXT runtime·debugCallPanicked(SB),NOSPLIT,$16-16 // The tail call makes these stubs disappear in backtraces. // Defined as ABIInternal since they do not use the stack-based Go ABI. TEXT runtime·panicIndex(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVQ CX, BX -#else - MOVQ AX, x+0(FP) - MOVQ CX, y+8(FP) -#endif JMP runtime·goPanicIndex(SB) TEXT runtime·panicIndexU(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVQ CX, BX -#else - MOVQ AX, x+0(FP) - MOVQ CX, y+8(FP) -#endif JMP runtime·goPanicIndexU(SB) TEXT runtime·panicSliceAlen(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVQ CX, AX MOVQ DX, BX -#else - MOVQ CX, x+0(FP) - MOVQ DX, y+8(FP) -#endif JMP runtime·goPanicSliceAlen(SB) TEXT runtime·panicSliceAlenU(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVQ CX, AX MOVQ DX, BX -#else - MOVQ CX, x+0(FP) - MOVQ DX, y+8(FP) -#endif JMP runtime·goPanicSliceAlenU(SB) TEXT runtime·panicSliceAcap(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVQ CX, AX MOVQ DX, BX -#else - MOVQ CX, x+0(FP) - MOVQ DX, y+8(FP) -#endif JMP runtime·goPanicSliceAcap(SB) TEXT runtime·panicSliceAcapU(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVQ CX, AX MOVQ DX, BX -#else - MOVQ CX, x+0(FP) - MOVQ DX, y+8(FP) -#endif JMP runtime·goPanicSliceAcapU(SB) TEXT runtime·panicSliceB(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVQ CX, BX -#else - MOVQ AX, x+0(FP) - MOVQ CX, y+8(FP) -#endif JMP runtime·goPanicSliceB(SB) TEXT runtime·panicSliceBU(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVQ CX, BX -#else - MOVQ AX, x+0(FP) - MOVQ CX, y+8(FP) -#endif JMP runtime·goPanicSliceBU(SB) TEXT runtime·panicSlice3Alen(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVQ DX, AX -#else - MOVQ DX, x+0(FP) - MOVQ BX, y+8(FP) -#endif JMP runtime·goPanicSlice3Alen(SB) TEXT runtime·panicSlice3AlenU(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVQ DX, AX -#else - MOVQ DX, x+0(FP) - MOVQ BX, y+8(FP) -#endif JMP runtime·goPanicSlice3AlenU(SB) TEXT runtime·panicSlice3Acap(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVQ DX, AX -#else - MOVQ DX, x+0(FP) - MOVQ BX, y+8(FP) -#endif JMP runtime·goPanicSlice3Acap(SB) TEXT runtime·panicSlice3AcapU(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVQ DX, AX -#else - MOVQ DX, x+0(FP) - MOVQ BX, y+8(FP) -#endif JMP runtime·goPanicSlice3AcapU(SB) TEXT runtime·panicSlice3B(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVQ CX, AX MOVQ DX, BX -#else - MOVQ CX, x+0(FP) - MOVQ DX, y+8(FP) -#endif JMP runtime·goPanicSlice3B(SB) TEXT runtime·panicSlice3BU(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVQ CX, AX MOVQ DX, BX -#else - MOVQ CX, x+0(FP) - MOVQ DX, y+8(FP) -#endif JMP runtime·goPanicSlice3BU(SB) TEXT runtime·panicSlice3C(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVQ CX, BX -#else - MOVQ AX, x+0(FP) - MOVQ CX, y+8(FP) -#endif JMP runtime·goPanicSlice3C(SB) TEXT runtime·panicSlice3CU(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVQ CX, BX -#else - MOVQ AX, x+0(FP) - MOVQ CX, y+8(FP) -#endif JMP runtime·goPanicSlice3CU(SB) TEXT runtime·panicSliceConvert(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVQ DX, AX -#else - MOVQ DX, x+0(FP) - MOVQ BX, y+8(FP) -#endif JMP runtime·goPanicSliceConvert(SB) #ifdef GOOS_android diff --git a/src/runtime/memclr_amd64.s b/src/runtime/memclr_amd64.s index 6c78869f4c6..918a4b9e0e4 100644 --- a/src/runtime/memclr_amd64.s +++ b/src/runtime/memclr_amd64.s @@ -13,14 +13,9 @@ // func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr) // ABIInternal for performance. TEXT runtime·memclrNoHeapPointers(SB), NOSPLIT, $0-16 -#ifdef GOEXPERIMENT_regabiargs // AX = ptr // BX = n MOVQ AX, DI // DI = ptr -#else - MOVQ ptr+0(FP), DI - MOVQ n+8(FP), BX -#endif XORQ AX, AX // MOVOU seems always faster than REP STOSQ. diff --git a/src/runtime/memmove_amd64.s b/src/runtime/memmove_amd64.s index af538d4bced..fa0c0e414f4 100644 --- a/src/runtime/memmove_amd64.s +++ b/src/runtime/memmove_amd64.s @@ -34,18 +34,12 @@ // func memmove(to, from unsafe.Pointer, n uintptr) // ABIInternal for performance. TEXT runtime·memmove(SB), NOSPLIT, $0-24 -#ifdef GOEXPERIMENT_regabiargs // AX = to // BX = from // CX = n MOVQ AX, DI MOVQ BX, SI MOVQ CX, BX -#else - MOVQ to+0(FP), DI - MOVQ from+8(FP), SI - MOVQ n+16(FP), BX -#endif // REP instructions have a high startup cost, so we handle small sizes // with some straightline code. The REP MOVSQ instruction is really fast diff --git a/src/runtime/race_amd64.s b/src/runtime/race_amd64.s index 8a171132328..d42e415dca5 100644 --- a/src/runtime/race_amd64.s +++ b/src/runtime/race_amd64.s @@ -46,11 +46,7 @@ // Defined as ABIInternal so as to avoid introducing a wrapper, // which would render runtime.getcallerpc ineffective. TEXT runtime·raceread(SB), NOSPLIT, $0-8 -#ifdef GOEXPERIMENT_regabiargs MOVQ AX, RARG1 -#else - MOVQ addr+0(FP), RARG1 -#endif MOVQ (SP), RARG2 // void __tsan_read(ThreadState *thr, void *addr, void *pc); MOVQ $__tsan_read(SB), AX @@ -76,11 +72,7 @@ TEXT runtime·racereadpc(SB), NOSPLIT, $0-24 // Defined as ABIInternal so as to avoid introducing a wrapper, // which would render runtime.getcallerpc ineffective. TEXT runtime·racewrite(SB), NOSPLIT, $0-8 -#ifdef GOEXPERIMENT_regabiargs MOVQ AX, RARG1 -#else - MOVQ addr+0(FP), RARG1 -#endif MOVQ (SP), RARG2 // void __tsan_write(ThreadState *thr, void *addr, void *pc); MOVQ $__tsan_write(SB), AX @@ -131,13 +123,8 @@ TEXT runtime·racereadrangepc1(SB), NOSPLIT, $0-24 // Defined as ABIInternal so as to avoid introducing a wrapper, // which would render runtime.getcallerpc ineffective. TEXT runtime·racewriterange(SB), NOSPLIT, $0-16 -#ifdef GOEXPERIMENT_regabiargs MOVQ AX, RARG1 MOVQ BX, RARG2 -#else - MOVQ addr+0(FP), RARG1 - MOVQ size+8(FP), RARG2 -#endif MOVQ (SP), RARG3 // void __tsan_write_range(ThreadState *thr, void *addr, uintptr size, void *pc); MOVQ $__tsan_write_range(SB), AX From 8ab59d812a222773c0a848aaa532630423eecc98 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Tue, 10 Aug 2021 12:49:21 -0700 Subject: [PATCH 907/940] [dev.typeparams] cmd/compile: change export version to 1.17 for testing This is a temporary change. We will revert this back before the 1.18 release. We make this change now to simplify testing, since a lot of tools will break on the new export version. Updates #47654. Change-Id: I0650fa753bb11229c71254d779dd61b5c1af9cdf Reviewed-on: https://go-review.googlesource.com/c/go/+/341211 Trust: Dan Scales Reviewed-by: Robert Griesemer Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/importer/iimport.go | 12 ++++++------ src/cmd/compile/internal/typecheck/iexport.go | 11 ++++++----- src/cmd/compile/internal/typecheck/iimport.go | 2 +- src/go/internal/gcimporter/iimport.go | 12 ++++++------ 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/cmd/compile/internal/importer/iimport.go b/src/cmd/compile/internal/importer/iimport.go index 6051cdaf231..a317dfc34ad 100644 --- a/src/cmd/compile/internal/importer/iimport.go +++ b/src/cmd/compile/internal/importer/iimport.go @@ -43,12 +43,12 @@ func (r *intReader) uint64() uint64 { // Keep this in sync with constants in iexport.go. const ( - iexportVersionGo1_11 = 0 - iexportVersionPosCol = 1 - iexportVersionGenerics = 2 + iexportVersionGo1_11 = 0 + iexportVersionPosCol = 1 + // TODO: before release, change this back to 2. + iexportVersionGenerics = iexportVersionPosCol - // Start of the unstable series of versions, remove "+ n" before release. - iexportVersionCurrent = iexportVersionGenerics + 1 + iexportVersionCurrent = iexportVersionGenerics ) type ident struct { @@ -99,7 +99,7 @@ func ImportData(imports map[string]*types2.Package, data, path string) (pkg *typ version = int64(r.uint64()) switch version { - case currentVersion, iexportVersionPosCol, iexportVersionGo1_11: + case /* iexportVersionGenerics, */ iexportVersionPosCol, iexportVersionGo1_11: default: if version > iexportVersionGenerics { errorf("unstable iexport format version %d, just rebuild compiler and std library", version) diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index 5f510a0a250..75b4931c310 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -226,12 +226,13 @@ import ( // 1: added column details to Pos // 2: added information for generic function/types (currently unstable) const ( - iexportVersionGo1_11 = 0 - iexportVersionPosCol = 1 - iexportVersionGenerics = 2 + iexportVersionGo1_11 = 0 + iexportVersionPosCol = 1 + // TODO: before release, change this back to 2. Kept at previous version + // for now (for testing). + iexportVersionGenerics = iexportVersionPosCol - // Start of the unstable series of versions, remove "+ n" before release. - iexportVersionCurrent = iexportVersionGenerics + 1 + iexportVersionCurrent = iexportVersionGenerics ) // predeclReserved is the number of type offsets reserved for types diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 83974b6d567..2e3fdbc1bc9 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -119,7 +119,7 @@ func ReadImports(pkg *types.Pkg, data string) { version := ird.uint64() switch version { - case iexportVersionCurrent, iexportVersionPosCol, iexportVersionGo1_11: + case /* iexportVersionGenerics, */ iexportVersionPosCol, iexportVersionGo1_11: default: if version > iexportVersionGenerics { base.Errorf("import %q: unstable export format version %d, just recompile", pkg.Path, version) diff --git a/src/go/internal/gcimporter/iimport.go b/src/go/internal/gcimporter/iimport.go index d4778d3a745..dbc9b3a83e8 100644 --- a/src/go/internal/gcimporter/iimport.go +++ b/src/go/internal/gcimporter/iimport.go @@ -43,12 +43,12 @@ func (r *intReader) uint64() uint64 { // Keep this in sync with constants in iexport.go. const ( - iexportVersionGo1_11 = 0 - iexportVersionPosCol = 1 - iexportVersionGenerics = 2 + iexportVersionGo1_11 = 0 + iexportVersionPosCol = 1 + // TODO: before release, change this back to 2. + iexportVersionGenerics = iexportVersionPosCol - // Start of the unstable series of versions, remove "+ n" before release. - iexportVersionCurrent = iexportVersionGenerics + 1 + iexportVersionCurrent = iexportVersionGenerics ) const predeclReserved = 32 @@ -91,7 +91,7 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, dataRea version = int64(r.uint64()) switch version { - case currentVersion, iexportVersionPosCol, iexportVersionGo1_11: + case /* iexportVersionGenerics, */ iexportVersionPosCol, iexportVersionGo1_11: default: if version > iexportVersionGenerics { errorf("unstable iexport format version %d, just rebuild compiler and std library", version) From dea23e9ca80dd629041cba03ae2544dad19948ee Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 11 Aug 2021 12:40:12 -0700 Subject: [PATCH 908/940] src/make.*: make --no-clean flag a no-op that prints a warning This flag is undocumented and is no longer useful. Users who want to install additional toolchains without cleaning the installed packages should just use `go install`. This CL changes cmd/dist to print a warning that --no-clean is deprecated and to advise users to use `go install std cmd` instead, and then otherwise ignores it: ``` $ ./make.bash --no-clean Building Go cmd/dist using $GOROOT_BOOTSTRAP. (devel +b7a85e0003 linux/amd64) warning: --no-clean is deprecated and has no effect; use 'go install std cmd' instead Building Go toolchain1 using $GOROOT_BOOTSTRAP. ``` Fixes #47204. Change-Id: I275031832098401a49e491e324e8de3427973630 Reviewed-on: https://go-review.googlesource.com/c/go/+/341392 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/cmd/dist/build.go | 7 ++++++- src/make.bash | 8 +------- src/make.bat | 20 ++++++++++---------- src/make.rc | 7 +------ 4 files changed, 18 insertions(+), 24 deletions(-) diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index 1abb03bcc56..bec17696f30 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -1263,14 +1263,19 @@ func cmdbootstrap() { timelog("start", "dist bootstrap") defer timelog("end", "dist bootstrap") - var noBanner bool + var noBanner, noClean bool var debug bool flag.BoolVar(&rebuildall, "a", rebuildall, "rebuild all") flag.BoolVar(&debug, "d", debug, "enable debugging of bootstrap process") flag.BoolVar(&noBanner, "no-banner", noBanner, "do not print banner") + flag.BoolVar(&noClean, "no-clean", noClean, "print deprecation warning") xflagparse(0) + if noClean { + xprintf("warning: --no-clean is deprecated and has no effect; use 'go install std cmd' instead\n") + } + // Set GOPATH to an internal directory. We shouldn't actually // need to store files here, since the toolchain won't // depend on modules outside of vendor directories, but if diff --git a/src/make.bash b/src/make.bash index f5e1b60bd5f..7986125a06f 100755 --- a/src/make.bash +++ b/src/make.bash @@ -203,16 +203,10 @@ if [ "$1" = "--dist-tool" ]; then exit 0 fi -buildall="-a" -if [ "$1" = "--no-clean" ]; then - buildall="" - shift -fi - # Run dist bootstrap to complete make.bash. # Bootstrap installs a proper cmd/dist, built with the new toolchain. # Throw ours, built with Go 1.4, away after bootstrap. -./cmd/dist/dist bootstrap $buildall $vflag $GO_DISTFLAGS "$@" +./cmd/dist/dist bootstrap -a $vflag $GO_DISTFLAGS "$@" rm -f ./cmd/dist/dist # DO NOT ADD ANY NEW CODE HERE. diff --git a/src/make.bat b/src/make.bat index b4a8e708490..8f2825b09a9 100644 --- a/src/make.bat +++ b/src/make.bat @@ -112,20 +112,20 @@ if x%2==x--dist-tool goto copydist if x%3==x--dist-tool goto copydist if x%4==x--dist-tool goto copydist -set buildall=-a -if x%1==x--no-clean set buildall= -if x%2==x--no-clean set buildall= -if x%3==x--no-clean set buildall= -if x%4==x--no-clean set buildall= -if x%1==x--no-banner set buildall=%buildall% --no-banner -if x%2==x--no-banner set buildall=%buildall% --no-banner -if x%3==x--no-banner set buildall=%buildall% --no-banner -if x%4==x--no-banner set buildall=%buildall% --no-banner +set bootstrapflags= +if x%1==x--no-clean set bootstrapflags=--no-clean +if x%2==x--no-clean set bootstrapflags=--no-clean +if x%3==x--no-clean set bootstrapflags=--no-clean +if x%4==x--no-clean set bootstrapflags=--no-clean +if x%1==x--no-banner set bootstrapflags=%bootstrapflags% --no-banner +if x%2==x--no-banner set bootstrapflags=%bootstrapflags% --no-banner +if x%3==x--no-banner set bootstrapflags=%bootstrapflags% --no-banner +if x%4==x--no-banner set bootstrapflags=%bootstrapflags% --no-banner :: Run dist bootstrap to complete make.bash. :: Bootstrap installs a proper cmd/dist, built with the new toolchain. :: Throw ours, built with Go 1.4, away after bootstrap. -.\cmd\dist\dist.exe bootstrap %vflag% %buildall% +.\cmd\dist\dist.exe bootstrap -a %vflag% %bootstrapflags% if errorlevel 1 goto fail del .\cmd\dist\dist.exe goto end diff --git a/src/make.rc b/src/make.rc index f5e57e97556..7bdc7dea1c1 100755 --- a/src/make.rc +++ b/src/make.rc @@ -92,15 +92,10 @@ if(~ $1 --dist-tool){ exit } -buildall = -a -if(~ $1 --no-clean) { - buildall = () - shift -} # Run dist bootstrap to complete make.bash. # Bootstrap installs a proper cmd/dist, built with the new toolchain. # Throw ours, built with Go 1.4, away after bootstrap. -./cmd/dist/dist bootstrap $vflag $buildall $* +./cmd/dist/dist bootstrap -a $vflag $* rm -f ./cmd/dist/dist # DO NOT ADD ANY NEW CODE HERE. From 677dfe5ad677d7072ffd69963c407a8945e94ec5 Mon Sep 17 00:00:00 2001 From: zikaeroh Date: Tue, 3 Aug 2021 13:41:49 -0700 Subject: [PATCH 909/940] [dev.typeparams] cmd/compile: don't print out node pointer in ir.Dump This has been a part of the node dumping since the very beginning, but this makes diffing -W output pretty annoying. -d=dumpptrs already prints these out if needed. Change-Id: I9524a7f7b44ec780ae42a8a2a9588f11ab3950f9 Reviewed-on: https://go-review.googlesource.com/c/go/+/340253 Reviewed-by: Dan Scales Reviewed-by: Matthew Dempsky Trust: Dan Scales Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot --- src/cmd/compile/internal/ir/fmt.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/ir/fmt.go b/src/cmd/compile/internal/ir/fmt.go index 3c5a928590f..d19fe453efc 100644 --- a/src/cmd/compile/internal/ir/fmt.go +++ b/src/cmd/compile/internal/ir/fmt.go @@ -1006,7 +1006,7 @@ func (l Nodes) Format(s fmt.State, verb rune) { // Dump prints the message s followed by a debug dump of n. func Dump(s string, n Node) { - fmt.Printf("%s [%p]%+v\n", s, n, n) + fmt.Printf("%s%+v\n", s, n) } // DumpList prints the message s followed by a debug dump of each node in the list. From 095bb790e132a498ba191ad6d27f89c1fc4c0232 Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Wed, 11 Aug 2021 22:02:59 -0400 Subject: [PATCH 910/940] os/exec: re-enable LookPathTest/16 This failure was confirmed to be due to a bug in prerelease versions of Windows, and has been fixed by now. Remove the skip for this test. Fixes #44379. Change-Id: Idfb92ffd6b9d416d4c78ef3800a5ffdda06c6562 Reviewed-on: https://go-review.googlesource.com/c/go/+/341455 Trust: Dmitri Shuralyov Run-TryBot: Dmitri Shuralyov TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/os/exec/lp_windows_test.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/os/exec/lp_windows_test.go b/src/os/exec/lp_windows_test.go index f834ffede03..bbf6a9b7f13 100644 --- a/src/os/exec/lp_windows_test.go +++ b/src/os/exec/lp_windows_test.go @@ -312,9 +312,6 @@ func TestLookPath(t *testing.T) { // Run all tests. for i, test := range lookPathTests { t.Run(fmt.Sprint(i), func(t *testing.T) { - if i == 16 { - t.Skip("golang.org/issue/44379") - } dir := filepath.Join(tmp, "d"+strconv.Itoa(i)) err := os.Mkdir(dir, 0700) if err != nil { From 39634e7daee29a0c7d29ca74e32668d04c842758 Mon Sep 17 00:00:00 2001 From: Carlos Amedee Date: Thu, 12 Aug 2021 12:10:47 -0400 Subject: [PATCH 911/940] CONTRIBUTORS: update for the Go 1.17 release This update was created using the updatecontrib command: go get golang.org/x/build/cmd/updatecontrib cd gotip GO111MODULE=off updatecontrib With manual changes based on publicly available information to canonicalize letter case and formatting for a few names. For #12042. Change-Id: I96718c0fe438cd97b62499a027252748a1fa0779 Reviewed-on: https://go-review.googlesource.com/c/go/+/341709 Trust: Carlos Amedee Run-TryBot: Carlos Amedee Reviewed-by: Dmitri Shuralyov TryBot-Result: Go Bot --- CONTRIBUTORS | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 135 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index ee50a4c049a..1984d44c537 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -33,6 +33,7 @@ Aaron Jacobs Aaron Jensen Aaron Kemp Aaron Patterson +Aaron Sheah Aaron Stein Aaron Torres Aaron Zinman @@ -47,6 +48,7 @@ Adam Harvey Adam Kisala Adam Langley Adam Medzinski +Adam Mitha Adam Shannon Adam Shelton Adam Sindelar @@ -54,6 +56,8 @@ Adam Thomason Adam Williams Adam Woodbeck Adarsh Ravichandran +Adel Rodríguez +Adin Scannell Aditya Harindar Aditya Mukerjee Adrian Hesketh @@ -68,6 +72,7 @@ Afanasev Stanislav Agis Anastasopoulos Agniva De Sarker Ahmed W. Mones +Ahmet Aktürk Ahmet Alp Balkan Ahmet Soormally Ahmy Yulrizka @@ -92,11 +97,13 @@ Alberto Bertogli Alberto Donizetti Alberto García Hierro Alec Benzer +Alejandro García Montoro Aleksa Sarai Aleksandar Dezelin Aleksandr Lukinykh Aleksandr Razumov Alekseev Artem +Aleksei Tirman Alessandro Arzilli Alessandro Baffa Alex A Skinner @@ -165,6 +172,7 @@ Ali Rizvi-Santiago Aliaksandr Valialkin Alice Merrick Alif Rachmawadi +Allan Guwatudde Allan Simon Allen Li Alok Menghrajani @@ -172,6 +180,7 @@ Alwin Doss Aman Gupta Amarjeet Anand Amir Mohammad Saied +Amit Kumar Amr Mohammed Amrut Joshi An Long @@ -185,6 +194,7 @@ André Carvalho André Martins Andre Nathan Andrea Nodari +Andrea Simonini Andrea Spadaccini Andreas Auernhammer Andreas Jellinghaus @@ -244,6 +254,7 @@ Andy Pan Andy Walker Andy Wang Andy Williams +Andy Zhao Andzej Maciusovic Anfernee Yongkun Gui Angelo Bulfone @@ -269,6 +280,7 @@ Anton Kuklin Antonin Amand Antonio Antelo Antonio Bibiano +Antonio Garcia Antonio Huete Jimenez Antonio Murdaca Antonio Troina @@ -292,8 +304,10 @@ Artem Khvastunov Artem Kolin Arthur Fabre Arthur Khashaev +Artur M. Wolff Artyom Pervukhin Arvindh Rajesh Tamilmani +Ashish Bhate Ashish Gandhi Asim Shankar Assel Meher @@ -325,6 +339,7 @@ Baokun Lee Barnaby Keene Bartosz Grzybowski Bartosz Oler +Bassam Ojeil Bastian Ike Ben Burkert Ben Cartwright-Cox @@ -332,6 +347,7 @@ Ben Eitzen Ben Fried Ben Haines Ben Hoyt +Ben Hutchings Ben Kraft Ben Laurie Ben Lubar @@ -430,6 +446,7 @@ Carl Henrik Lunde Carl Jackson Carl Johnson Carl Mastrangelo +Carl Menezes Carl Shapiro Carlisia Campos Carlo Alberto Ferraris @@ -443,6 +460,7 @@ Carlos Iriarte Carlos Souza Carolyn Van Slyck Carrie Bynon +Carson Hoffman Cary Hull Case Nelson Casey Callendrello @@ -462,6 +480,7 @@ Charles Kenney Charles L. Dorian Charles Lee Charles Weill +Charlie Moog Charlotte Brandhorst-Satzkorn Chauncy Cullitan Chen Zhidong @@ -516,6 +535,7 @@ Christopher Nelson Christopher Nielsen Christopher Redden Christopher Swenson +Christopher Thomas <53317512+chrisssthomas@users.noreply.github.com> Christopher Wedgwood Christos Zoulas Christy Perez @@ -541,6 +561,8 @@ Cosmos Nicolaou Costin Chirvasuta Craig Citro Cristian Staretu +Cristo García +cui fliter Cuihtlauac ALVARADO Cuong Manh Le Curtis La Graff @@ -560,6 +582,7 @@ Dan Callahan Dan Harrington Dan Jacques Dan Johnson +Dan McArdle Dan Peterson Dan Pupius Dan Scales @@ -611,6 +634,7 @@ Dave Russell David Anderson David Barnett David Benjamin +David Black David Bond David Brophy David Bürgin <676c7473@gmail.com> @@ -654,6 +678,7 @@ Davor Kapsa Dean Eigenmann <7621705+decanus@users.noreply.github.com> Dean Prichard Deepak Jois +Deepak S Denis Bernard Denis Brandolini Denis Isaev @@ -676,8 +701,10 @@ Dhiru Kholia Dhruvdutt Jadhav Di Xiao Didier Spezia +Diego Medina Diego Siqueira Dieter Plaetinck +Dilyn Corner Dimitri Sokolyuk Dimitri Tcaciuc Dina Garmash @@ -714,6 +741,7 @@ Doug Fawley Douglas Danger Manley Drew Flower Drew Hintz +Drew Richardson Duco van Amstel Duncan Holm Dustin Carlino @@ -735,6 +763,7 @@ Egon Elbre Ehren Kret Eitan Adler Eivind Uggedal +El Mostafa Idrassi Elbert Fliek Eldar Rakhimberdin Elena Grahovac @@ -742,6 +771,7 @@ Eli Bendersky Elias Naur Elliot Morrison-Reed Ellison Leão +Elvina Yakubova Emerson Lin Emil Bektimirov Emil Hessman @@ -767,6 +797,7 @@ Eric Rescorla Eric Roshan-Eisner Eric Rutherford Eric Rykwalder +Eric Wang Erick Tryzelaar Erik Aigner Erik Dubbelboer @@ -778,6 +809,7 @@ Ernest Chiang Erwin Oegema Esko Luontola Ethan Burns +Ethan Hur Ethan Miller Euan Kemp Eugene Formanenko @@ -818,6 +850,7 @@ Felix Cornelius <9767036+fcornelius@users.noreply.github.com> Felix Geisendörfer Felix Kollmann Ferenc Szabo +Fernandez Ludovic Filip Gruszczyński Filip Haglund Filip Stanis @@ -858,6 +891,7 @@ Gabriel Nelle Gabriel Nicolas Avellaneda Gabriel Rosenhouse Gabriel Russell +Gabriel Vasile Gareth Paul Jones Garret Kelly Garrick Evans @@ -891,6 +925,8 @@ Gianguido Sora` Gideon Jan-Wessel Redelinghuys Giles Lean Giovanni Bajo +GitHub User @180909 (70465953) <734461790@qq.com> +GitHub User @6543 (24977596) <6543@obermui.de> GitHub User @aca (50316549) GitHub User @ajnirp (1688456) GitHub User @ajz01 (4744634) @@ -904,10 +940,12 @@ GitHub User @bontequero (2674999) GitHub User @cch123 (384546) GitHub User @chainhelen (7046329) GitHub User @chanxuehong (3416908) +GitHub User @Cluas (10056928) GitHub User @cncal (23520240) GitHub User @DQNEO (188741) GitHub User @Dreamacro (8615343) GitHub User @dupoxy (1143957) +GitHub User @EndlessCheng (7086966) GitHub User @erifan (31343225) GitHub User @esell (9735165) GitHub User @fatedier (7346661) @@ -916,12 +954,15 @@ GitHub User @geedchin (11672310) GitHub User @GrigoriyMikhalkin (3637857) GitHub User @hengwu0 (41297446) <41297446+hengwu0@users.noreply.github.com> GitHub User @hitzhangjie (3725760) +GitHub User @hqpko (13887251) GitHub User @itchyny (375258) GitHub User @jinmiaoluo (39730824) GitHub User @jopbrown (6345470) GitHub User @kazyshr (30496953) GitHub User @kc1212 (1093806) +GitHub User @komisan19 (18901496) GitHub User @Kropekk (13366453) +GitHub User @lhl2617 (33488131) GitHub User @linguohua (3434367) GitHub User @LotusFenn (13775899) GitHub User @ly303550688 (11519839) @@ -936,10 +977,14 @@ GitHub User @OlgaVlPetrova (44112727) GitHub User @pityonline (438222) GitHub User @po3rin (29445112) GitHub User @pokutuna (57545) +GitHub User @povsister (11040951) GitHub User @pytimer (17105586) +GitHub User @qcrao (7698088) GitHub User @ramenjuniti (32011829) GitHub User @saitarunreddy (21041941) +GitHub User @SataQiu (9354727) GitHub User @shogo-ma (9860598) +GitHub User @sivchari (55221074) GitHub User @skanehira (7888591) GitHub User @soolaugust (10558124) GitHub User @surechen (7249331) @@ -947,9 +992,12 @@ GitHub User @tatsumack (4510569) GitHub User @tell-k (26263) GitHub User @tennashi (10219626) GitHub User @uhei (2116845) +GitHub User @uji (49834542) +GitHub User @unbyte (5772358) GitHub User @uropek (39370426) GitHub User @utkarsh-extc (53217283) GitHub User @witchard (4994659) +GitHub User @wolf1996 (5901874) GitHub User @yah01 (12216890) GitHub User @yuanhh (1298735) GitHub User @zikaeroh (48577114) @@ -962,6 +1010,7 @@ Glenn Brown Glenn Lewis Gordon Klaus Gordon Tyler +Grace Han Graham King Graham Miller Grant Griffiths @@ -977,10 +1026,12 @@ Guilherme Caruso Guilherme Garnier Guilherme Goncalves Guilherme Rezende +Guilherme Souza <32180229+gqgs@users.noreply.github.com> Guillaume J. Charmes Guillaume Sottas Günther Noack Guobiao Mei +Guodong Li Guoliang Wang Gustav Paul Gustav Westling @@ -995,6 +1046,7 @@ HAMANO Tsukasa Han-Wen Nienhuys Hang Qian Hanjun Kim +Hanlin He Hanlin Shi Haoran Luo Haosdent Huang @@ -1026,18 +1078,19 @@ Herbie Ong Heschi Kreinick Hidetatsu Yaginuma Hilko Bengen +Himanshu Kishna Srivastava <28himanshu@gmail.com> Hiroaki Nakamura Hiromichi Ema Hironao OTSUBO Hiroshi Ioka Hitoshi Mitake Holden Huang -Songlin Jiang Hong Ruiqi Hongfei Tan Horacio Duran Horst Rutter Hossein Sheikh Attar +Hossein Zolfi Howard Zhang Hsin Tsao Hsin-Ho Yeh @@ -1054,11 +1107,14 @@ Ian Haken Ian Kent Ian Lance Taylor Ian Leue +Ian Mckay Ian Tay +Ian Woolf Ian Zapolsky Ibrahim AshShohail Icarus Sparry Iccha Sethi +Ichinose Shogo Idora Shinatose Ignacio Hagopian Igor Bernstein @@ -1068,6 +1124,7 @@ Igor Vashyst Igor Zhilianin Ikko Ashimine Illya Yalovyy +Ilya Chukov <56119080+Elias506@users.noreply.github.com> Ilya Sinelnikov Ilya Tocar INADA Naoki @@ -1122,6 +1179,7 @@ James Cowgill James Craig Burley James David Chalfant James Eady +James Fennell James Fysh James Gray James Hartig @@ -1178,6 +1236,7 @@ Jason Wangsadinata Javier Kohen Javier Revillas Javier Segura +Jay Chen Jay Conrod Jay Lee Jay Taylor @@ -1200,6 +1259,7 @@ Jeff Johnson Jeff R. Allen Jeff Sickel Jeff Wendling +Jeff Widman Jeffrey H Jelte Fennema Jens Frederich @@ -1210,6 +1270,7 @@ Jeremy Faller Jeremy Jackins Jeremy Jay Jeremy Schlatter +Jero Bado Jeroen Bobbeldijk Jeroen Simonetti Jérôme Doucet @@ -1251,6 +1312,8 @@ Joe Richey Joe Shaw Joe Sylve Joe Tsai +Joel Courtney +Joel Ferrier Joel Sing Joël Stemmer Joel Stemmer @@ -1260,7 +1323,9 @@ Johan Euphrosine Johan Jansson Johan Knutzen Johan Sageryd +Johannes Huning John Asmuth +John Bampton John Beisley John C Barstow John DeNero @@ -1269,6 +1334,7 @@ John Gibb John Gilik John Graham-Cumming John Howard Palevich +John Jago John Jeffery John Jenkins John Leidegren @@ -1320,6 +1386,7 @@ Josa Gesell Jose Luis Vázquez González Joseph Bonneau Joseph Holsten +Joseph Morag Josh Baum Josh Bleecher Snyder Josh Chorlton @@ -1327,12 +1394,14 @@ Josh Deprez Josh Goebel Josh Hoak Josh Holland +Josh Rickmar Josh Roppo Josh Varga Joshua Bezaleel Abednego Joshua Boelter Joshua Chase Joshua Crowgey +Joshua Harshman Joshua M. Clulow Joshua Rubin Josselin Costanzi @@ -1353,6 +1422,7 @@ Julie Qiu Julien Kauffmann Julien Salleyron Julien Schmidt +Julien Tant Julio Montes Jun Zhang Junchen Li @@ -1419,10 +1489,12 @@ Kenta Mori Kerollos Magdy Ketan Parmar Kevan Swanberg +Kevin Albertson Kevin Ballard Kevin Burke Kévin Dunglas Kevin Gillette +Kevin Herro Kevin Kirsche Kevin Klues Kevin Malachowski @@ -1457,6 +1529,7 @@ Koya IWAMURA Kris Kwiatkowski Kris Nova Kris Rousey +Krishna Birla Kristopher Watts Krzysztof Dąbrowski Kshitij Saraogi @@ -1480,6 +1553,7 @@ Lajos Papp Lakshay Garg Lann Martin Lanre Adelowo +Lapo Luchini Larry Clapp Larry Hosken Lars Jeppesen @@ -1496,6 +1570,7 @@ Leigh McCulloch Leo Antunes Leo Rudberg Leon Klingele +Leonard Wang Leonardo Comelli Leonel Quinteros Lev Shamardin @@ -1506,7 +1581,9 @@ Lily Chung Lingchao Xin Lion Yang Liz Rice +Lize Cai Lloyd Dewolf +Lluís Batlle i Rossell Lorenz Bauer Lorenz Brun Lorenz Nickel @@ -1531,6 +1608,7 @@ Lukasz Milewski Luke Champine Luke Curley Luke Granger-Brown +Luke Shumaker Luke Young Luna Duclos Luuk van Dijk @@ -1550,6 +1628,7 @@ Mal Curtis Manfred Touron Manigandan Dharmalingam Manish Goregaokar +Manlio Perillo Manoj Dayaram Mansour Rahimi Manu Garg @@ -1646,6 +1725,8 @@ Matt Joiner Matt Jones Matt Juran Matt Layher +Matt Masurka +Matt Pearring Matt Reiferson Matt Robenolt Matt Strong @@ -1659,9 +1740,12 @@ Matthew Denton Matthew Holt Matthew Horsnell Matthew Waters +Matthias Frei Matthieu Hauglustaine Matthieu Olivier Matthijs Kooijman +Mattias Appelgren +Mauricio Alvarado Max Drosdo.www Max Riveiro Max Schmitt @@ -1677,9 +1761,11 @@ Máximo Cuadros Ortiz Maxwell Krohn Maya Rashish Mayank Kumar +Mehrad Sadeghi <2012.linkinpark@gmail.com> Meir Fischer Meng Zhuo Mhd Sulhan +Mia Zhu Micah Stetson Michael Anthony Knyszek Michael Brandenburg @@ -1730,8 +1816,10 @@ Michal Franc Michał Łowicki Michal Pristas Michal Rostecki +Michal Stokluska Michalis Kargakis Michel Lespinasse +Michel Levieux Michele Di Pede Mickael Kerjean Mickey Reiss @@ -1790,7 +1878,9 @@ Muir Manders Mukesh Sharma Mura Li Mykhailo Lesyk +Nahum Shalman Naman Aggarwal +Naman Gera Nan Deng Nao Yonashiro Naoki Kanatani @@ -1818,6 +1908,7 @@ Neven Sajko Nevins Bartolomeo Niall Sheridan Nic Day +Nicholas Asimov Nicholas Katsaros Nicholas Maniscalco Nicholas Ng @@ -1847,6 +1938,7 @@ Nik Nyby Nikhil Benesch Nikita Gillmann Nikita Kryuchkov +Nikita Melekhin Nikita Vanyasin Niklas Schnelle Niko Dziemba @@ -1858,6 +1950,7 @@ Niranjan Godbole Nishanth Shanmugham Noah Campbell Noah Goldman +Noah Santschi-Cooney Noble Johnson Nodir Turakulov Noel Georgi @@ -1894,6 +1987,7 @@ Pablo Rozas Larraondo Pablo Santiago Blum de Aguiar Padraig Kitterick Pallat Anchaleechamaikorn +Pan Chenglong <1004907659@qq.com> Panos Georgiadis Pantelis Sampaziotis Paolo Giarrusso @@ -1947,6 +2041,7 @@ Paulo Casaretto Paulo Flabiano Smorigo Paulo Gomes Pavel Paulau +Pavel Watson Pavel Zinovkin Pavlo Sumkin Pawel Knap @@ -1954,6 +2049,8 @@ Pawel Szczur Paweł Szulik Pei Xian Chee Pei-Ming Wu +Pen Tree +Peng Gao Percy Wegmann Perry Abbott Petar Dambovaliev @@ -1992,6 +2089,7 @@ Philip Brown Philip Hofer Philip K. Warren Philip Nelson +Philipp Sauter Philipp Stephani Phillip Campbell <15082+phillc@users.noreply.github.com> Pierre Carru @@ -2007,6 +2105,7 @@ Poh Zi How Polina Osadcha Pontus Leitzler Povilas Versockas +Prajwal Koirala <16564273+Prajwal-Koirala@users.noreply.github.com> Prasanga Siripala Prasanna Swaminathan Prashant Agrawal @@ -2027,11 +2126,13 @@ Quim Muntal Quinn Slack Quinten Yearsley Quoc-Viet Nguyen +Rabin Gaire Radek Simko Radek Sohlich Radu Berinde Rafal Jeczalik Raghavendra Nagaraj +Rahul Bajaj Rahul Chaudhry Rahul Wadhwani Raif S. Naffah @@ -2041,12 +2142,14 @@ Rajender Reddy Kompally Ralph Corderoy Ramazan AYYILDIZ Ramesh Dharan +Randy Reddig Raph Levien Raphael Geronimi Raul Silvera Ravil Bikbulatov RaviTeja Pothana Ray Tung +Ray Wu Raymond Kazlauskas Rebecca Stambler Reilly Watson @@ -2066,6 +2169,7 @@ Richard Eric Gavaletz Richard Gibson Richard Miller Richard Musiol +Richard Pickering Richard Ulmer Richard Wilkes Rick Arnold @@ -2124,6 +2228,7 @@ Rowan Worth Rudi Kramer Rui Ueyama Ruixin Bao +Ruslan Andreev Ruslan Nigmatullin Russ Cox Russell Haering @@ -2141,6 +2246,7 @@ Ryan Seys Ryan Slade Ryan Zhang Ryoichi KATO +Ryoya Sekino Ryuji Iwata Ryuma Yoshida Ryuzo Yamamoto @@ -2176,8 +2282,10 @@ Sardorbek Pulatov Sascha Brawer Sasha Lionheart Sasha Sobol +Satoru Kitaguchi Scott Barron Scott Bell +Scott Cotton Scott Crunkleton Scott Ferguson Scott Lawrence @@ -2191,6 +2299,7 @@ Sean Chittenden Sean Christopherson Sean Dolphin Sean Harger +Sean Harrington Sean Hildebrand Sean Liao Sean Rees @@ -2212,6 +2321,7 @@ Sergey Dobrodey Sergey Frolov Sergey Glushchenko Sergey Ivanov +Sergey Kacheev Sergey Lukjanov Sergey Mishin Sergey Mudrik @@ -2223,6 +2333,7 @@ Serhat Giydiren Serhii Aheienko Seth Hoenig Seth Vargo +Shaba Abhiram Shahar Kohanim Shailesh Suryawanshi Shamil Garatuev @@ -2250,9 +2361,13 @@ Shivakumar GN Shivani Singhal Shivansh Rai Shivashis Padhi +Shoshin Nikita +Shota Sugiura Shubham Sharma +Shuhei Takahashi Shun Fan Silvan Jegen +Simão Gomes Viana Simarpreet Singh Simon Drake Simon Ferquel @@ -2267,13 +2382,16 @@ Sina Siadat Sjoerd Siebinga Sokolov Yura Song Gao +Song Lim Songjiayang +Songlin Jiang Soojin Nam Søren L. Hansen Sparrow Li Spencer Kocot Spencer Nelson Spencer Tung +Spenser Black Spring Mc Srdjan Petrovic Sridhar Venkatakrishnan @@ -2324,6 +2442,7 @@ Suyash Suzy Mueller Sven Almgren Sven Blumenstein +Sven Lee Sven Taute Sylvain Zimmer Syohei YOSHIDA @@ -2406,12 +2525,14 @@ Tiwei Bie Tobias Assarsson Tobias Columbus Tobias Klauser +Tobias Kohlbau Toby Burress Todd Kulesza Todd Neal Todd Wang Tom Anthony Tom Bergan +Tom Freudenberg Tom Heng Tom Lanyon Tom Levy @@ -2440,6 +2561,7 @@ Toshiki Shima Totoro W Travis Bischel Travis Cline +Trevor Dixon Trevor Strohman Trey Lawrence Trey Roessig @@ -2463,6 +2585,7 @@ Tzach Shabtay Tzu-Chiao Yeh Tzu-Jung Lee Udalov Max +Uddeshya Singh Ugorji Nwoke Ulf Holm Nielsen Ulrich Kunitz @@ -2475,6 +2598,7 @@ Vadim Grek Vadim Vygonets Val Polouchkine Valentin Vidic +Vaughn Iverson Vee Zhang Vega Garcia Luis Alfonso Venil Noronha @@ -2491,6 +2615,7 @@ Vincent Batts Vincent Vanackere Vinu Rajashekhar Vish Subramanian +Vishal Dalwadi Vishvananda Ishaya Visweswara R Vitaly Zdanevich @@ -2542,6 +2667,7 @@ Willem van der Schyff William Chan William Chang William Josephson +William Langford William Orr William Poussier Wisdom Omuya @@ -2550,6 +2676,7 @@ Xi Ruoyao Xia Bin Xiangdong Ji Xiaodong Liu +Xing Gao <18340825824@163.com> Xing Xing Xingqang Bai Xu Fei @@ -2571,6 +2698,7 @@ Yasha Bubnov Yasser Abdolmaleki Yasuharu Goto Yasuhiro Matsumoto +Yasutaka Shinzaki Yasuyuki Oka Yazen Shunnar Yestin Sun @@ -2583,14 +2711,18 @@ Yorman Arias Yoshiyuki Kanno Yoshiyuki Mineo Yosuke Akatsuka +Youfu Zhang Yu Heng Zhang Yu Xuan Zhang +Yu, Li-Yu Yuichi Kishimoto Yuichi Nishiwaki Yuji Yaginuma +Yuki Ito Yuki OKUSHI Yuki Yugui Sonoda Yukihiro Nishinaka <6elpinal@gmail.com> +YunQiang Su Yury Smolsky Yusuke Kagiwada Yuusei Kuwana @@ -2599,6 +2731,7 @@ Yves Junqueira Zac Bergquist Zach Bintliff Zach Gershman +Zach Hoffman Zach Jones Zachary Amsden Zachary Gershman @@ -2617,6 +2750,7 @@ Zhou Peng Ziad Hatahet Ziheng Liu Zorion Arrizabalaga +Zvonimir Pavlinovic Zyad A. Ali Максадбек Ахмедов Максим Федосеев From 5805efc78e11e54c2c887ae10f277b09bbf81cf4 Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Thu, 12 Aug 2021 12:12:56 -0400 Subject: [PATCH 912/940] doc/go1.17: remove draft notice Fixes #44513. Change-Id: I82c44a681b1fa67df123af86ee02a980b13acdc8 Reviewed-on: https://go-review.googlesource.com/c/go/+/341673 Trust: Dmitri Shuralyov Trust: Carlos Amedee Reviewed-by: Carlos Amedee Run-TryBot: Carlos Amedee TryBot-Result: Go Bot --- doc/go1.17.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 972f9c35594..b65d13a0403 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -14,13 +14,13 @@ Do not send CLs removing the interior tags from such phrases. main ul li { margin: 0.5em 0; } -

    DRAFT RELEASE NOTES — Introduction to Go 1.17

    +

    Introduction to Go 1.17

    - - Go 1.17 is not yet released. These are work-in-progress - release notes. Go 1.17 is expected to be released in August 2021. - + The latest Go release, version 1.17, arrives six months after Go 1.16. + Most of its changes are in the implementation of the toolchain, runtime, and libraries. + As always, the release maintains the Go 1 promise of compatibility. + We expect almost all Go programs to continue to compile and run as before.

    Changes to the language

    From 46fd547d899286982971474b329d7a95da4f2a6b Mon Sep 17 00:00:00 2001 From: Carlos Amedee Date: Wed, 11 Aug 2021 17:19:21 -0400 Subject: [PATCH 913/940] internal/goversion: update Version to 1.18 This is the start of the Go 1.18 development cycle, so update the Version value accordingly. It represents the Go 1.x version that will soon open up for development (and eventually become released). Updates #40705 Updates #47351 Change-Id: Icfb99e28529a3c9fb7394e114a34586f613dfcbf Reviewed-on: https://go-review.googlesource.com/c/go/+/341590 Trust: Carlos Amedee Run-TryBot: Carlos Amedee TryBot-Result: Go Bot Reviewed-by: Dmitri Shuralyov Reviewed-by: Matthew Dempsky Reviewed-by: Alexander Rakoczy --- src/internal/goversion/goversion.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/goversion/goversion.go b/src/internal/goversion/goversion.go index 4cc15688c0b..8fcea100dc6 100644 --- a/src/internal/goversion/goversion.go +++ b/src/internal/goversion/goversion.go @@ -9,4 +9,4 @@ package goversion // // It should be updated at the start of each development cycle to be // the version of the next Go 1.x release. See golang.org/issue/40705. -const Version = 17 +const Version = 18 From 7e9f911ec4fd08ce9b4296f0aea4864b53064573 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Thu, 12 Aug 2021 09:58:54 -0700 Subject: [PATCH 914/940] [dev.typeparams] cmd/compile: remove some shape checks in type substituter, other cleanups The type substituter (typecheck.Typ()) was temporarily substituting from shapes back to concrete types, but doesn't need to anymore. So, remove two shape checks, so the type substituter is now only for substituting type params again. Several other cleanups: - renamed makeGenericName() to makeInstName1(), since that function is a helper to MakeInstName() and MakeDictName() that definitely makes instantiated names, not generic names. - removed the logic in makeInstName1() that adds the ".inst." prefix for concrete type args. We are only specifying concrete type args (as opposed to shape args) when we are calling from MakeDictName, and then we immediately strip of the .inst prefix anyway. - Added a comment on types.Identical that a shape type is considered identicall to another type if their underlying types are the same, or they are both pointers. Change-Id: I3e0206dbd403897797ae7bec3c527ae16b0b930a Reviewed-on: https://go-review.googlesource.com/c/go/+/341729 Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall Trust: Dan Scales --- src/cmd/compile/internal/typecheck/subr.go | 40 ++++++---------------- src/cmd/compile/internal/types/identity.go | 7 ++-- 2 files changed, 15 insertions(+), 32 deletions(-) diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index e86c4c6bca7..c7a3718b31c 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -900,31 +900,11 @@ func TypesOf(x []ir.Node) []*types.Type { return r } -// makeGenericName returns the name of the generic function instantiated -// with the given types. -// name is the name of the generic function or method. -func makeGenericName(name string, targs []*types.Type, hasBrackets bool) string { +// makeInstName1 returns the name of the generic function instantiated with the +// given types, which can have type params or shapes, or be concrete types. name is +// the name of the generic function or method. +func makeInstName1(name string, targs []*types.Type, hasBrackets bool) string { b := bytes.NewBufferString("") - - // Determine if the type args are concrete types or new typeparams. - hasTParam := false - for _, targ := range targs { - if hasTParam { - assert(targ.HasTParam() || targ.HasShape()) - } else if targ.HasTParam() || targ.HasShape() { - hasTParam = true - } - } - - // Marker to distinguish generic instantiations from fully stenciled wrapper functions. - // Once we move to GC shape implementations, this prefix will not be necessary as the - // GC shape naming will distinguish them. - // e.g. f[8bytenonpointer] vs. f[int]. - // For now, we use .inst.f[int] vs. f[int]. - if !hasTParam { - b.WriteString(".inst.") - } - i := strings.Index(name, "[") assert(hasBrackets == (i >= 0)) if i >= 0 { @@ -963,7 +943,7 @@ func makeGenericName(name string, targs []*types.Type, hasBrackets bool) string // MakeInstName makes the unique name for a stenciled generic function or method, // based on the name of the function fnsym and the targs. It replaces any -// existing bracket type list in the name. makeInstName asserts that fnsym has +// existing bracket type list in the name. MakeInstName asserts that fnsym has // brackets in its name if and only if hasBrackets is true. // // Names of declared generic functions have no brackets originally, so hasBrackets @@ -974,7 +954,7 @@ func makeGenericName(name string, targs []*types.Type, hasBrackets bool) string // The standard naming is something like: 'genFn[int,bool]' for functions and // '(*genType[int,bool]).methodName' for methods func MakeInstName(gf *types.Sym, targs []*types.Type, hasBrackets bool) *types.Sym { - return gf.Pkg.Lookup(makeGenericName(gf.Name, targs, hasBrackets)) + return gf.Pkg.Lookup(makeInstName1(gf.Name, targs, hasBrackets)) } func MakeDictName(gf *types.Sym, targs []*types.Type, hasBrackets bool) *types.Sym { @@ -987,8 +967,8 @@ func MakeDictName(gf *types.Sym, targs []*types.Type, hasBrackets bool) *types.S panic("dictionary should always have concrete type args") } } - name := makeGenericName(gf.Name, targs, hasBrackets) - name = ".dict." + name[6:] + name := makeInstName1(gf.Name, targs, hasBrackets) + name = ".dict." + name return gf.Pkg.Lookup(name) } @@ -1014,14 +994,14 @@ type Tsubster struct { // result is t; otherwise the result is a new type. It deals with recursive types // by using TFORW types and finding partially or fully created types via sym.Def. func (ts *Tsubster) Typ(t *types.Type) *types.Type { - if !t.HasTParam() && !t.HasShape() && t.Kind() != types.TFUNC { + if !t.HasTParam() && t.Kind() != types.TFUNC { // Note: function types need to be copied regardless, as the // types of closures may contain declarations that need // to be copied. See #45738. return t } - if t.IsTypeParam() || t.IsShape() { + if t.IsTypeParam() { for i, tp := range ts.Tparams { if tp == t { return ts.Targs[i] diff --git a/src/cmd/compile/internal/types/identity.go b/src/cmd/compile/internal/types/identity.go index dc39acced86..2e9e2f4fd84 100644 --- a/src/cmd/compile/internal/types/identity.go +++ b/src/cmd/compile/internal/types/identity.go @@ -4,8 +4,11 @@ package types -// Identical reports whether t1 and t2 are identical types, following -// the spec rules. Receiver parameter types are ignored. +// Identical reports whether t1 and t2 are identical types, following the spec rules. +// Receiver parameter types are ignored. Named (defined) types are only equal if they +// are pointer-equal - i.e. there must be a unique types.Type for each specific named +// type. Also, a type containing a shape type is considered identical to another type +// (shape or not) if their underlying types are the same, or they are both pointers. func Identical(t1, t2 *Type) bool { return identical(t1, t2, true, nil) } From 044ec4fa9818d785e2b0d4064514abcf4f252fcb Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 6 Aug 2021 13:21:25 -0400 Subject: [PATCH 915/940] time: fix docs for new comma layouts The current text is slightly inaccurate. Make it more correct. Change-Id: Iebe0051b74649d13982d7eefe3697f9e69c9b75d Reviewed-on: https://go-review.googlesource.com/c/go/+/340449 Trust: Russ Cox Run-TryBot: Russ Cox Reviewed-by: Jay Conrod Reviewed-by: Damien Neil Reviewed-by: Ian Lance Taylor TryBot-Result: Go Bot --- doc/go1.17.html | 14 +++++++------- src/time/format.go | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index b65d13a0403..c1b5ab3f6fb 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -753,9 +753,9 @@ func Foo() bool {

    The new - NullInt16 - and - NullByte + NullInt16 + and + NullByte structs represent the int16 and byte values that may be null. These can be used as destinations of the Scan method, similar to NullString. @@ -1205,11 +1205,11 @@ func Foo() bool {

    The package now accepts comma "," as a separator for fractional seconds when parsing and formatting time. - The following time formats are now accepted: + For example, the following time layouts are now accepted:

      -
    • 2006-01-02 14:06:03,999999999 -0700 MST
    • -
    • Mon Jan _2 14:06:03,120007 2006
    • -
    • Mon Jan 2 14:06:03,120007 2006
    • +
    • 2006-01-02 15:04:05,999999999 -0700 MST
    • +
    • Mon Jan _2 15:04:05,000000 2006
    • +
    • Monday, January 2 15:04:05,000 2006

    diff --git a/src/time/format.go b/src/time/format.go index bb173a21c2d..f4b4f48142f 100644 --- a/src/time/format.go +++ b/src/time/format.go @@ -77,9 +77,9 @@ import "errors" // The formats and 002 are space-padded and zero-padded // three-character day of year; there is no unpadded day of year format. // -// A decimal point followed by one or more zeros represents a fractional -// second, printed to the given number of decimal places. -// Either a comma or decimal point followed by one or more nines represents +// A comma or decimal point followed by one or more zeros represents +// a fractional second, printed to the given number of decimal places. +// A comma or decimal point followed by one or more nines represents // a fractional second, printed to the given number of decimal places, with // trailing zeros removed. // For example "15:04:05,000" or "15:04:05.000" formats or parses with From 1fffeddfe9c977510d855277da57e0564700d6c3 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Tue, 20 Jul 2021 14:37:53 -0700 Subject: [PATCH 916/940] cmd/go: add -testsum flag to update go.sum in script tests -testsum may be set to "tidy", "listm", or "listall". When set, TestScript runs 'go mod tidy', 'go list -m -mod=mod all', or 'go list -mod=mod all' at the beginning of each test that has a go.mod file in its root directory. If the test passes and go.mod or go.sum was updated, TestScript will rewrite the test file with the initial content of go.mod and go.sum (after the above command). This is useful for writing tests that need a working go.sum and for fixing tests that rely on -mod=mod. For golang/go#41302 Change-Id: I63a5667621a5082ccedfc1bff33c3969c29e8b3d Reviewed-on: https://go-review.googlesource.com/c/go/+/336150 Run-TryBot: Jay Conrod TryBot-Result: Go Bot Trust: Jay Conrod Reviewed-by: Michael Matloob Reviewed-on: https://go-review.googlesource.com/c/go/+/341932 Reviewed-by: Bryan C. Mills --- src/cmd/go/script_test.go | 81 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/src/cmd/go/script_test.go b/src/cmd/go/script_test.go index 639e907db07..9ca297e89b4 100644 --- a/src/cmd/go/script_test.go +++ b/src/cmd/go/script_test.go @@ -11,6 +11,7 @@ import ( "bytes" "context" "errors" + "flag" "fmt" "go/build" "internal/testenv" @@ -35,6 +36,8 @@ import ( "cmd/internal/sys" ) +var testSum = flag.String("testsum", "", `may be tidy, listm, or listall. If set, TestScript generates a go.sum file at the beginning of each test and updates test files if they pass.`) + // TestScript runs the tests in testdata/script/*.txt. func TestScript(t *testing.T) { testenv.MustHaveGoBuild(t) @@ -269,6 +272,22 @@ func (ts *testScript) run() { ts.mark = ts.log.Len() } + // With -testsum, if a go.mod file is present in the test's initial + // working directory, run 'go mod tidy'. + if *testSum != "" { + if ts.updateSum(a) { + defer func() { + if ts.t.Failed() { + return + } + data := txtar.Format(a) + if err := os.WriteFile(ts.file, data, 0666); err != nil { + ts.t.Errorf("rewriting test file: %v", err) + } + }() + } + } + // Run script. // See testdata/script/README for documentation of script form. script := string(a.Comment) @@ -1341,6 +1360,68 @@ func (ts *testScript) parse(line string) command { return cmd } +// updateSum runs 'go mod tidy', 'go list -mod=mod -m all', or +// 'go list -mod=mod all' in the test's current directory if a file named +// "go.mod" is present after the archive has been extracted. updateSum modifies +// archive and returns true if go.mod or go.sum were changed. +func (ts *testScript) updateSum(archive *txtar.Archive) (rewrite bool) { + gomodIdx, gosumIdx := -1, -1 + for i := range archive.Files { + switch archive.Files[i].Name { + case "go.mod": + gomodIdx = i + case "go.sum": + gosumIdx = i + } + } + if gomodIdx < 0 { + return false + } + + switch *testSum { + case "tidy": + ts.cmdGo(success, []string{"mod", "tidy"}) + case "listm": + ts.cmdGo(success, []string{"list", "-m", "-mod=mod", "all"}) + case "listall": + ts.cmdGo(success, []string{"list", "-mod=mod", "all"}) + default: + ts.t.Fatalf(`unknown value for -testsum %q; may be "tidy", "listm", or "listall"`, *testSum) + } + + newGomodData, err := os.ReadFile(filepath.Join(ts.cd, "go.mod")) + if err != nil { + ts.t.Fatalf("reading go.mod after -testsum: %v", err) + } + if !bytes.Equal(newGomodData, archive.Files[gomodIdx].Data) { + archive.Files[gomodIdx].Data = newGomodData + rewrite = true + } + + newGosumData, err := os.ReadFile(filepath.Join(ts.cd, "go.sum")) + if err != nil && !os.IsNotExist(err) { + ts.t.Fatalf("reading go.sum after -testsum: %v", err) + } + switch { + case os.IsNotExist(err) && gosumIdx >= 0: + // go.sum was deleted. + rewrite = true + archive.Files = append(archive.Files[:gosumIdx], archive.Files[gosumIdx+1:]...) + case err == nil && gosumIdx < 0: + // go.sum was created. + rewrite = true + gosumIdx = gomodIdx + 1 + archive.Files = append(archive.Files, txtar.File{}) + copy(archive.Files[gosumIdx+1:], archive.Files[gosumIdx:]) + archive.Files[gosumIdx] = txtar.File{Name: "go.sum", Data: newGosumData} + case err == nil && gosumIdx >= 0 && !bytes.Equal(newGosumData, archive.Files[gosumIdx].Data): + // go.sum was changed. + rewrite = true + archive.Files[gosumIdx].Data = newGosumData + } + return rewrite +} + // diff returns a formatted diff of the two texts, // showing the entire text and the minimum line-level // additions and removals to turn text1 into text2. From 4be75faa3ee79a273ff82d4f5b7f838ef3642f9d Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Tue, 20 Jul 2021 14:46:40 -0700 Subject: [PATCH 917/940] cmd/go: make fewer 'go mod' commands update go.mod 'go mod graph', 'go mod vendor', 'go mod verify', and 'go mod why' will no longer edit go.mod or go.sum. 'go mod graph', 'go mod verify', and 'go mod why' may still fetch files and look up packages as if they were able to update go.mod. They're useful for debugging and should still work when go.mod is a little broken. This is implemented in modload.setDefaultBuildMod based on command name for now. Super gross. Sorry. This should be fixed with a larger refactoring for #40775. Fixes golang/go#45551 Change-Id: If5f225937180d32e9a5dd252c78d988042bbdedf Reviewed-on: https://go-review.googlesource.com/c/go/+/336151 Trust: Jay Conrod Run-TryBot: Jay Conrod TryBot-Result: Go Bot Reviewed-by: Michael Matloob Reviewed-on: https://go-review.googlesource.com/c/go/+/341933 Reviewed-by: Bryan C. Mills --- src/cmd/go/internal/modload/init.go | 21 +++++++++++++---- src/cmd/go/testdata/script/mod_all.txt | 2 +- src/cmd/go/testdata/script/mod_e.txt | 23 ++++++++++++------- src/cmd/go/testdata/script/mod_get_commit.txt | 2 +- .../go/testdata/script/mod_getmode_vendor.txt | 1 + .../go/testdata/script/mod_list_retract.txt | 4 +++- src/cmd/go/testdata/script/mod_retention.txt | 8 ++++--- src/cmd/go/testdata/script/mod_tidy_error.txt | 4 ++-- .../go/testdata/script/mod_vendor_replace.txt | 5 +++- .../testdata/script/mod_vendor_trimpath.txt | 6 ++++- .../script/mod_vendor_unused_only.txt | 2 ++ src/cmd/go/testdata/script/mod_verify.txt | 5 ---- src/cmd/go/testdata/script/modfile_flag.txt | 5 ++++ 13 files changed, 61 insertions(+), 27 deletions(-) diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go index 45f724d5e36..d5f9d104223 100644 --- a/src/cmd/go/internal/modload/init.go +++ b/src/cmd/go/internal/modload/init.go @@ -686,12 +686,25 @@ func setDefaultBuildMod() { return } - if cfg.CmdName == "get" || strings.HasPrefix(cfg.CmdName, "mod ") { - // 'get' and 'go mod' commands may update go.mod automatically. - // TODO(jayconrod): should this narrower? Should 'go mod download' or - // 'go mod graph' update go.mod by default? + // TODO(#40775): commands should pass in the module mode as an option + // to modload functions instead of relying on an implicit setting + // based on command name. + switch cfg.CmdName { + case "get", "mod download", "mod init", "mod tidy": + // These commands are intended to update go.mod and go.sum. cfg.BuildMod = "mod" return + case "mod graph", "mod verify", "mod why": + // These commands should not update go.mod or go.sum, but they should be + // able to fetch modules not in go.sum and should not report errors if + // go.mod is inconsistent. They're useful for debugging, and they need + // to work in buggy situations. + cfg.BuildMod = "mod" + allowWriteGoMod = false + return + case "mod vendor": + cfg.BuildMod = "readonly" + return } if modRoot == "" { if allowMissingModuleImports { diff --git a/src/cmd/go/testdata/script/mod_all.txt b/src/cmd/go/testdata/script/mod_all.txt index 090eeee22df..6fa2d832396 100644 --- a/src/cmd/go/testdata/script/mod_all.txt +++ b/src/cmd/go/testdata/script/mod_all.txt @@ -315,7 +315,7 @@ go 1.15 require ( example.com/a v0.1.0 - example.com/b v0.1.0 + example.com/b v0.1.0 // indirect example.com/q v0.1.0 example.com/r v0.1.0 // indirect example.com/t v0.1.0 diff --git a/src/cmd/go/testdata/script/mod_e.txt b/src/cmd/go/testdata/script/mod_e.txt index 3a0d18dabc2..3cffaf6ef1c 100644 --- a/src/cmd/go/testdata/script/mod_e.txt +++ b/src/cmd/go/testdata/script/mod_e.txt @@ -24,11 +24,11 @@ cmp go.mod.orig go.mod ! go mod vendor -stderr '^example.com/untidy imports\n\texample.net/directnotfound: cannot find module providing package example.net/directnotfound: module example.net/directnotfound: reading http://.*: 404 Not Found$' +stderr '^example.com/untidy imports\n\texample.net/directnotfound: no required module provides package example.net/directnotfound; to add it:\n\tgo get example.net/directnotfound$' -stderr '^example.com/untidy imports\n\texample.net/m imports\n\texample.net/indirectnotfound: cannot find module providing package example.net/indirectnotfound: module example.net/indirectnotfound: reading http://.*: 404 Not Found$' +stderr '^example.com/untidy imports\n\texample.net/m: module example.net/m provides package example.net/m and is replaced but not required; to add it:\n\tgo get example.net/m@v0.1.0$' -stderr '^example.com/untidy tested by\n\texample.com/untidy.test imports\n\texample.net/directtestnotfound: cannot find module providing package example.net/directtestnotfound: module example.net/directtestnotfound: reading http://.*: 404 Not Found$' +stderr '^example.com/untidy tested by\n\texample.com/untidy.test imports\n\texample.net/directtestnotfound: no required module provides package example.net/directtestnotfound; to add it:\n\tgo get example.net/directtestnotfound$' ! stderr 'indirecttestnotfound' # Vendor prunes test dependencies. @@ -43,16 +43,23 @@ stderr -count=4 'cannot find module providing package' cmp go.mod.final go.mod -# 'go mod vendor -e' still logs the errors, but succeeds and updates go.mod. - +# 'go mod vendor -e' still logs the errors, but creates a vendor directory +# and exits with status 0. +# 'go mod vendor -e' does not update go.mod and will not vendor packages that +# would require changing go.mod, for example, by adding a requirement. cp go.mod.orig go.mod go mod vendor -e -stderr -count=3 'cannot find module providing package' -cmp go.mod.final go.mod +stderr -count=2 'no required module provides package' +stderr '^example.com/untidy imports\n\texample.net/m: module example.net/m provides package example.net/m and is replaced but not required; to add it:\n\tgo get example.net/m@v0.1.0$' +exists vendor/modules.txt +! exists vendor/example.net + +go mod edit -require example.net/m@v0.1.0 +go mod vendor -e +stderr -count=3 'no required module provides package' exists vendor/modules.txt exists vendor/example.net/m/m.go - -- go.mod -- module example.com/untidy go 1.16 diff --git a/src/cmd/go/testdata/script/mod_get_commit.txt b/src/cmd/go/testdata/script/mod_get_commit.txt index 4649491a532..0cf94ae1821 100644 --- a/src/cmd/go/testdata/script/mod_get_commit.txt +++ b/src/cmd/go/testdata/script/mod_get_commit.txt @@ -44,7 +44,7 @@ go mod edit -require rsc.io/quote@23179ee grep 'rsc.io/quote 23179ee' go.mod # but other commands fix them -go mod graph +go list -m -mod=mod all grep 'rsc.io/quote v1.5.1' go.mod -- go.mod -- diff --git a/src/cmd/go/testdata/script/mod_getmode_vendor.txt b/src/cmd/go/testdata/script/mod_getmode_vendor.txt index d3df2078b07..00070c03b53 100644 --- a/src/cmd/go/testdata/script/mod_getmode_vendor.txt +++ b/src/cmd/go/testdata/script/mod_getmode_vendor.txt @@ -25,6 +25,7 @@ stderr 'go list -m: can''t match module patterns using the vendor directory\n\t\ -- go.mod -- module x +go 1.16 -- x.go -- package x import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_list_retract.txt b/src/cmd/go/testdata/script/mod_list_retract.txt index 4b133485152..b7147aa1824 100644 --- a/src/cmd/go/testdata/script/mod_list_retract.txt +++ b/src/cmd/go/testdata/script/mod_list_retract.txt @@ -101,7 +101,9 @@ module example.com/use go 1.15 require example.com/retract v1.0.0-bad - +-- go.sum -- +example.com/retract v1.0.0-bad h1:liAW69rbtjY67x2CcNzat668L/w+YGgNX3lhJsWIJis= +example.com/retract v1.0.0-bad/go.mod h1:0DvGGofJ9hr1q63cBrOY/jSY52OwhRGA0K47NE80I5Y= -- use.go -- package use diff --git a/src/cmd/go/testdata/script/mod_retention.txt b/src/cmd/go/testdata/script/mod_retention.txt index 7a371b18068..481c10d2b7d 100644 --- a/src/cmd/go/testdata/script/mod_retention.txt +++ b/src/cmd/go/testdata/script/mod_retention.txt @@ -39,12 +39,14 @@ go list -mod=mod all cmp go.mod go.mod.tidy # "// indirect" comments should be added if appropriate. +# TODO(#42504): add case for 'go list -mod=mod -tags=any all' when -tags=any +# is supported. Only a command that loads "all" without build constraints +# (except "ignore") has enough information to add "// indirect" comments. +# 'go mod tidy' and 'go mod vendor' are the only commands that do that, +# but 'go mod vendor' cannot write go.mod. cp go.mod.toodirect go.mod go list all cmp go.mod go.mod.toodirect -go mod vendor # loads everything, so adds "// indirect" comments. -cmp go.mod go.mod.tidy -rm -r vendor # Redundant requirements should be preserved... diff --git a/src/cmd/go/testdata/script/mod_tidy_error.txt b/src/cmd/go/testdata/script/mod_tidy_error.txt index 395537b1a71..51fc65fa7a8 100644 --- a/src/cmd/go/testdata/script/mod_tidy_error.txt +++ b/src/cmd/go/testdata/script/mod_tidy_error.txt @@ -10,8 +10,8 @@ stderr '^issue27063 imports\n\tissue27063/other imports\n\tother.example.com/non ! go mod vendor ! stderr 'package nonexist is not in GOROOT' -stderr '^issue27063 imports\n\tnonexist.example.com: cannot find module providing package nonexist.example.com' -stderr '^issue27063 imports\n\tissue27063/other imports\n\tother.example.com/nonexist: cannot find module providing package other.example.com/nonexist' +stderr '^issue27063 imports\n\tnonexist.example.com: no required module provides package nonexist.example.com; to add it:\n\tgo get nonexist.example.com$' +stderr '^issue27063 imports\n\tissue27063/other imports\n\tother.example.com/nonexist: no required module provides package other.example.com/nonexist; to add it:\n\tgo get other.example.com/nonexist$' -- go.mod -- module issue27063 diff --git a/src/cmd/go/testdata/script/mod_vendor_replace.txt b/src/cmd/go/testdata/script/mod_vendor_replace.txt index 0c1c1d22f5b..1820af62ad8 100644 --- a/src/cmd/go/testdata/script/mod_vendor_replace.txt +++ b/src/cmd/go/testdata/script/mod_vendor_replace.txt @@ -36,7 +36,6 @@ module example.com/replace require rsc.io/quote/v3 v3.0.0 replace rsc.io/quote/v3 => ./local/not-rsc.io/quote/v3 - -- imports.go -- package replace @@ -64,3 +63,7 @@ require ( not-rsc.io/quote/v3 v3.0.0 ) replace not-rsc.io/quote/v3 => rsc.io/quote/v3 v3.0.0 +-- multiple-paths/go.sum -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote/v3 v3.0.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/src/cmd/go/testdata/script/mod_vendor_trimpath.txt b/src/cmd/go/testdata/script/mod_vendor_trimpath.txt index 5451aa773c8..d9d9d988974 100644 --- a/src/cmd/go/testdata/script/mod_vendor_trimpath.txt +++ b/src/cmd/go/testdata/script/mod_vendor_trimpath.txt @@ -29,8 +29,12 @@ stdout '^example.com/stack@v1.0.0/stack.go$' -- go.mod -- module example.com/main -require example.com/stack v1.0.0 +go 1.17 +require example.com/stack v1.0.0 +-- go.sum -- +example.com/stack v1.0.0 h1:IEDLeew5NytZ8vrgCF/QVem3H3SR3QMttdu9HfJvk9I= +example.com/stack v1.0.0/go.mod h1:7wFEbaV5e5O7wJ8aBdqQOR//UXppm/pwnwziMKViuI4= -- main.go -- package main diff --git a/src/cmd/go/testdata/script/mod_vendor_unused_only.txt b/src/cmd/go/testdata/script/mod_vendor_unused_only.txt index 839c6453cf8..accd9f373de 100644 --- a/src/cmd/go/testdata/script/mod_vendor_unused_only.txt +++ b/src/cmd/go/testdata/script/mod_vendor_unused_only.txt @@ -12,6 +12,8 @@ module example.com/m go 1.14 require example.com v1.0.0 // indirect +-- go.sum -- +example.com v1.0.0/go.mod h1:WRiieAqDBb1hVdDXLLdxNtCDWNfehn7FWyPC5Oz2vB4= -- go1.14-modules.txt -- # example.com v1.0.0 ## explicit diff --git a/src/cmd/go/testdata/script/mod_verify.txt b/src/cmd/go/testdata/script/mod_verify.txt index b5106659a9a..f02d15aa289 100644 --- a/src/cmd/go/testdata/script/mod_verify.txt +++ b/src/cmd/go/testdata/script/mod_verify.txt @@ -39,11 +39,6 @@ stderr 'go.mod: checksum mismatch' # go.sum should be created and updated automatically. rm go.sum -go mod graph -exists go.sum -grep '^rsc.io/quote v1.1.0/go.mod ' go.sum -! grep '^rsc.io/quote v1.1.0 ' go.sum - go mod tidy grep '^rsc.io/quote v1.1.0/go.mod ' go.sum grep '^rsc.io/quote v1.1.0 ' go.sum diff --git a/src/cmd/go/testdata/script/modfile_flag.txt b/src/cmd/go/testdata/script/modfile_flag.txt index 0ad08808178..baf25d31b89 100644 --- a/src/cmd/go/testdata/script/modfile_flag.txt +++ b/src/cmd/go/testdata/script/modfile_flag.txt @@ -24,6 +24,11 @@ stdout '^go.alt.mod$' go mod edit -require rsc.io/quote@v1.5.2 grep rsc.io/quote go.alt.mod +# 'go list -m' should add sums to the alternate go.sum. +go list -m -mod=mod all +grep '^rsc.io/quote v1.5.2/go.mod ' go.alt.sum +! grep '^rsc.io/quote v1.5.2 ' go.alt.sum + # other 'go mod' commands should work. 'go mod vendor' is tested later. go mod download rsc.io/quote go mod graph From 4c8ffb3baaabce1aa2139ce7739fec333ab80728 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Wed, 14 Jul 2021 13:52:00 -0700 Subject: [PATCH 918/940] cmd/internal/str: move package from cmd/go/internal/str This will let cmd/cgo and cmd/link use this package for argument parsing. For golang/go#41400 Change-Id: I12ee21151bf3f00f3e8d427faaaab2453c823117 Reviewed-on: https://go-review.googlesource.com/c/go/+/334730 Trust: Jay Conrod Reviewed-by: Michael Matloob Reviewed-on: https://go-review.googlesource.com/c/go/+/341934 Run-TryBot: Jay Conrod Reviewed-by: Bryan C. Mills --- src/cmd/go/internal/base/base.go | 2 +- src/cmd/go/internal/base/flag.go | 2 +- src/cmd/go/internal/fix/fix.go | 2 +- src/cmd/go/internal/fmtcmd/fmt.go | 2 +- src/cmd/go/internal/generate/generate.go | 2 +- src/cmd/go/internal/get/get.go | 2 +- src/cmd/go/internal/list/list.go | 2 +- src/cmd/go/internal/load/flag.go | 2 +- src/cmd/go/internal/load/pkg.go | 2 +- src/cmd/go/internal/load/test.go | 2 +- src/cmd/go/internal/modcmd/vendor.go | 2 +- src/cmd/go/internal/modfetch/codehost/codehost.go | 2 +- src/cmd/go/internal/modfetch/codehost/vcs.go | 2 +- src/cmd/go/internal/modget/query.go | 2 +- src/cmd/go/internal/modload/load.go | 2 +- src/cmd/go/internal/modload/query.go | 2 +- src/cmd/go/internal/run/run.go | 2 +- src/cmd/go/internal/test/test.go | 2 +- src/cmd/go/internal/vcs/vcs.go | 2 +- src/cmd/go/internal/work/buildid.go | 2 +- src/cmd/go/internal/work/exec.go | 2 +- src/cmd/go/internal/work/gc.go | 2 +- src/cmd/go/internal/work/gccgo.go | 2 +- src/cmd/{go => }/internal/str/path.go | 0 src/cmd/{go => }/internal/str/str.go | 0 src/cmd/{go => }/internal/str/str_test.go | 0 26 files changed, 23 insertions(+), 23 deletions(-) rename src/cmd/{go => }/internal/str/path.go (100%) rename src/cmd/{go => }/internal/str/str.go (100%) rename src/cmd/{go => }/internal/str/str_test.go (100%) diff --git a/src/cmd/go/internal/base/base.go b/src/cmd/go/internal/base/base.go index 954ce47a989..0144525e307 100644 --- a/src/cmd/go/internal/base/base.go +++ b/src/cmd/go/internal/base/base.go @@ -17,7 +17,7 @@ import ( "sync" "cmd/go/internal/cfg" - "cmd/go/internal/str" + "cmd/internal/str" ) // A Command is an implementation of a go command diff --git a/src/cmd/go/internal/base/flag.go b/src/cmd/go/internal/base/flag.go index 677f8196827..6914efa0e6f 100644 --- a/src/cmd/go/internal/base/flag.go +++ b/src/cmd/go/internal/base/flag.go @@ -9,7 +9,7 @@ import ( "cmd/go/internal/cfg" "cmd/go/internal/fsys" - "cmd/go/internal/str" + "cmd/internal/str" ) // A StringsFlag is a command-line flag that interprets its argument diff --git a/src/cmd/go/internal/fix/fix.go b/src/cmd/go/internal/fix/fix.go index 988d45e71cc..cc5940fccd8 100644 --- a/src/cmd/go/internal/fix/fix.go +++ b/src/cmd/go/internal/fix/fix.go @@ -10,7 +10,7 @@ import ( "cmd/go/internal/cfg" "cmd/go/internal/load" "cmd/go/internal/modload" - "cmd/go/internal/str" + "cmd/internal/str" "context" "fmt" "os" diff --git a/src/cmd/go/internal/fmtcmd/fmt.go b/src/cmd/go/internal/fmtcmd/fmt.go index 8a040087539..2b89a078acc 100644 --- a/src/cmd/go/internal/fmtcmd/fmt.go +++ b/src/cmd/go/internal/fmtcmd/fmt.go @@ -18,7 +18,7 @@ import ( "cmd/go/internal/cfg" "cmd/go/internal/load" "cmd/go/internal/modload" - "cmd/go/internal/str" + "cmd/internal/str" ) func init() { diff --git a/src/cmd/go/internal/generate/generate.go b/src/cmd/go/internal/generate/generate.go index 80ea32b4284..d7f2eb46107 100644 --- a/src/cmd/go/internal/generate/generate.go +++ b/src/cmd/go/internal/generate/generate.go @@ -25,8 +25,8 @@ import ( "cmd/go/internal/cfg" "cmd/go/internal/load" "cmd/go/internal/modload" - "cmd/go/internal/str" "cmd/go/internal/work" + "cmd/internal/str" ) var CmdGenerate = &base.Command{ diff --git a/src/cmd/go/internal/get/get.go b/src/cmd/go/internal/get/get.go index 3c16dc3040f..836364e39b6 100644 --- a/src/cmd/go/internal/get/get.go +++ b/src/cmd/go/internal/get/get.go @@ -17,10 +17,10 @@ import ( "cmd/go/internal/cfg" "cmd/go/internal/load" "cmd/go/internal/search" - "cmd/go/internal/str" "cmd/go/internal/vcs" "cmd/go/internal/web" "cmd/go/internal/work" + "cmd/internal/str" "golang.org/x/mod/module" ) diff --git a/src/cmd/go/internal/list/list.go b/src/cmd/go/internal/list/list.go index 7cb9ec6d949..4b8c0e9f482 100644 --- a/src/cmd/go/internal/list/list.go +++ b/src/cmd/go/internal/list/list.go @@ -23,8 +23,8 @@ import ( "cmd/go/internal/load" "cmd/go/internal/modinfo" "cmd/go/internal/modload" - "cmd/go/internal/str" "cmd/go/internal/work" + "cmd/internal/str" ) var CmdList = &base.Command{ diff --git a/src/cmd/go/internal/load/flag.go b/src/cmd/go/internal/load/flag.go index 440cb861344..4e0cb5bc19e 100644 --- a/src/cmd/go/internal/load/flag.go +++ b/src/cmd/go/internal/load/flag.go @@ -6,7 +6,7 @@ package load import ( "cmd/go/internal/base" - "cmd/go/internal/str" + "cmd/internal/str" "fmt" "strings" ) diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index a83cc9a812b..e44e71b3660 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -36,8 +36,8 @@ import ( "cmd/go/internal/modload" "cmd/go/internal/par" "cmd/go/internal/search" - "cmd/go/internal/str" "cmd/go/internal/trace" + "cmd/internal/str" "cmd/internal/sys" "golang.org/x/mod/modfile" diff --git a/src/cmd/go/internal/load/test.go b/src/cmd/go/internal/load/test.go index c8282965669..42eefe37ba5 100644 --- a/src/cmd/go/internal/load/test.go +++ b/src/cmd/go/internal/load/test.go @@ -22,8 +22,8 @@ import ( "unicode/utf8" "cmd/go/internal/fsys" - "cmd/go/internal/str" "cmd/go/internal/trace" + "cmd/internal/str" ) var TestMainDeps = []string{ diff --git a/src/cmd/go/internal/modcmd/vendor.go b/src/cmd/go/internal/modcmd/vendor.go index 713d5f9f3fa..b133ba7ea93 100644 --- a/src/cmd/go/internal/modcmd/vendor.go +++ b/src/cmd/go/internal/modcmd/vendor.go @@ -24,7 +24,7 @@ import ( "cmd/go/internal/imports" "cmd/go/internal/load" "cmd/go/internal/modload" - "cmd/go/internal/str" + "cmd/internal/str" "golang.org/x/mod/module" "golang.org/x/mod/semver" diff --git a/src/cmd/go/internal/modfetch/codehost/codehost.go b/src/cmd/go/internal/modfetch/codehost/codehost.go index 378fbae34f9..efb4b1516a2 100644 --- a/src/cmd/go/internal/modfetch/codehost/codehost.go +++ b/src/cmd/go/internal/modfetch/codehost/codehost.go @@ -21,7 +21,7 @@ import ( "cmd/go/internal/cfg" "cmd/go/internal/lockedfile" - "cmd/go/internal/str" + "cmd/internal/str" ) // Downloaded size limits. diff --git a/src/cmd/go/internal/modfetch/codehost/vcs.go b/src/cmd/go/internal/modfetch/codehost/vcs.go index c2cca084e30..5d810d2621c 100644 --- a/src/cmd/go/internal/modfetch/codehost/vcs.go +++ b/src/cmd/go/internal/modfetch/codehost/vcs.go @@ -20,7 +20,7 @@ import ( "cmd/go/internal/lockedfile" "cmd/go/internal/par" - "cmd/go/internal/str" + "cmd/internal/str" ) // A VCSError indicates an error using a version control system. diff --git a/src/cmd/go/internal/modget/query.go b/src/cmd/go/internal/modget/query.go index 1a5a60f7eb9..0a66517a499 100644 --- a/src/cmd/go/internal/modget/query.go +++ b/src/cmd/go/internal/modget/query.go @@ -14,7 +14,7 @@ import ( "cmd/go/internal/base" "cmd/go/internal/modload" "cmd/go/internal/search" - "cmd/go/internal/str" + "cmd/internal/str" "golang.org/x/mod/module" ) diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go index bce9ad85f42..b54f670812f 100644 --- a/src/cmd/go/internal/modload/load.go +++ b/src/cmd/go/internal/modload/load.go @@ -118,7 +118,7 @@ import ( "cmd/go/internal/mvs" "cmd/go/internal/par" "cmd/go/internal/search" - "cmd/go/internal/str" + "cmd/internal/str" "golang.org/x/mod/module" "golang.org/x/mod/semver" diff --git a/src/cmd/go/internal/modload/query.go b/src/cmd/go/internal/modload/query.go index e737ca90fcd..d4c906a8739 100644 --- a/src/cmd/go/internal/modload/query.go +++ b/src/cmd/go/internal/modload/query.go @@ -21,8 +21,8 @@ import ( "cmd/go/internal/imports" "cmd/go/internal/modfetch" "cmd/go/internal/search" - "cmd/go/internal/str" "cmd/go/internal/trace" + "cmd/internal/str" "golang.org/x/mod/module" "golang.org/x/mod/semver" diff --git a/src/cmd/go/internal/run/run.go b/src/cmd/go/internal/run/run.go index 784f7162dfd..9e9e49ec898 100644 --- a/src/cmd/go/internal/run/run.go +++ b/src/cmd/go/internal/run/run.go @@ -18,8 +18,8 @@ import ( "cmd/go/internal/cfg" "cmd/go/internal/load" "cmd/go/internal/modload" - "cmd/go/internal/str" "cmd/go/internal/work" + "cmd/internal/str" ) var CmdRun = &base.Command{ diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go index 59ea1ef5445..aeba80eb680 100644 --- a/src/cmd/go/internal/test/test.go +++ b/src/cmd/go/internal/test/test.go @@ -30,9 +30,9 @@ import ( "cmd/go/internal/load" "cmd/go/internal/lockedfile" "cmd/go/internal/search" - "cmd/go/internal/str" "cmd/go/internal/trace" "cmd/go/internal/work" + "cmd/internal/str" "cmd/internal/test2json" ) diff --git a/src/cmd/go/internal/vcs/vcs.go b/src/cmd/go/internal/vcs/vcs.go index 91485f6f745..97b2a631ae6 100644 --- a/src/cmd/go/internal/vcs/vcs.go +++ b/src/cmd/go/internal/vcs/vcs.go @@ -23,8 +23,8 @@ import ( "cmd/go/internal/base" "cmd/go/internal/cfg" "cmd/go/internal/search" - "cmd/go/internal/str" "cmd/go/internal/web" + "cmd/internal/str" "golang.org/x/mod/module" ) diff --git a/src/cmd/go/internal/work/buildid.go b/src/cmd/go/internal/work/buildid.go index 4e9189a3632..15f944d2af2 100644 --- a/src/cmd/go/internal/work/buildid.go +++ b/src/cmd/go/internal/work/buildid.go @@ -15,8 +15,8 @@ import ( "cmd/go/internal/cache" "cmd/go/internal/cfg" "cmd/go/internal/fsys" - "cmd/go/internal/str" "cmd/internal/buildid" + "cmd/internal/str" ) // Build IDs diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index 5a225fb9f1f..2aa099bf171 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -34,8 +34,8 @@ import ( "cmd/go/internal/fsys" "cmd/go/internal/load" "cmd/go/internal/modload" - "cmd/go/internal/str" "cmd/go/internal/trace" + "cmd/internal/str" ) // actionList returns the list of actions in the dag rooted at root diff --git a/src/cmd/go/internal/work/gc.go b/src/cmd/go/internal/work/gc.go index 2ae908bc8fd..70ca5d69f83 100644 --- a/src/cmd/go/internal/work/gc.go +++ b/src/cmd/go/internal/work/gc.go @@ -20,8 +20,8 @@ import ( "cmd/go/internal/cfg" "cmd/go/internal/fsys" "cmd/go/internal/load" - "cmd/go/internal/str" "cmd/internal/objabi" + "cmd/internal/str" "cmd/internal/sys" "crypto/sha1" ) diff --git a/src/cmd/go/internal/work/gccgo.go b/src/cmd/go/internal/work/gccgo.go index 1499536932d..3cb7b641833 100644 --- a/src/cmd/go/internal/work/gccgo.go +++ b/src/cmd/go/internal/work/gccgo.go @@ -16,8 +16,8 @@ import ( "cmd/go/internal/cfg" "cmd/go/internal/fsys" "cmd/go/internal/load" - "cmd/go/internal/str" "cmd/internal/pkgpath" + "cmd/internal/str" ) // The Gccgo toolchain. diff --git a/src/cmd/go/internal/str/path.go b/src/cmd/internal/str/path.go similarity index 100% rename from src/cmd/go/internal/str/path.go rename to src/cmd/internal/str/path.go diff --git a/src/cmd/go/internal/str/str.go b/src/cmd/internal/str/str.go similarity index 100% rename from src/cmd/go/internal/str/str.go rename to src/cmd/internal/str/str.go diff --git a/src/cmd/go/internal/str/str_test.go b/src/cmd/internal/str/str_test.go similarity index 100% rename from src/cmd/go/internal/str/str_test.go rename to src/cmd/internal/str/str_test.go From 20a620fd9f7bc35739c1af3602d53808d0430814 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Thu, 12 Aug 2021 17:17:51 -0400 Subject: [PATCH 919/940] runtime: drop SIGPROF while in ARM < 7 kernel helpers On Linux ARMv6 and below runtime/internal/atomic.Cas calls into a kernel cas helper at a fixed address. If a SIGPROF arrives while executing the kernel helper, the sigprof lostAtomic logic will miss that we are potentially in the spinlock critical section, which could cause a deadlock when using atomics later in sigprof. Fixes #47505 Change-Id: If8ba0d0fc47e45d4e6c68eca98fac4c6ed4e43c1 Reviewed-on: https://go-review.googlesource.com/c/go/+/341889 Trust: Michael Pratt Run-TryBot: Michael Pratt Reviewed-by: Michael Knyszek Reviewed-by: Cherry Mui TryBot-Result: Go Bot --- src/runtime/proc.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/runtime/proc.go b/src/runtime/proc.go index ec4be31db35..764f12769ed 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -4619,7 +4619,7 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) { return } - // On mips{,le}, 64bit atomics are emulated with spinlocks, in + // On mips{,le}/arm, 64bit atomics are emulated with spinlocks, in // runtime/internal/atomic. If SIGPROF arrives while the program is inside // the critical section, it creates a deadlock (when writing the sample). // As a workaround, create a counter of SIGPROFs while in critical section @@ -4632,6 +4632,13 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) { return } } + if GOARCH == "arm" && goarm < 7 && GOOS == "linux" && pc&0xffff0000 == 0xffff0000 { + // runtime/internal/atomic functions call into kernel + // helpers on arm < 7. See + // runtime/internal/atomic/sys_linux_arm.s. + cpuprof.lostAtomic++ + return + } } // Profiling runs concurrently with GC, so it must not allocate. From 98f3d7fecbb8a9074f5f4ffc50bb016e194940b7 Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Mon, 9 Aug 2021 20:29:14 -0400 Subject: [PATCH 920/940] all: gofmt more (but vendor, testdata, and top-level test directories) CL 294430 made packages in std and cmd modules use Go 1.17 gofmt format, adding //go:build lines. This change applies the same formatting to some more packages that 'go fmt' missed (e.g., syscall/js, runtime/msan), and everything else that is easy and safe to modify in bulk. Consider the top-level test directory, testdata, and vendor directories out of scope, since there are many files that don't follow strict gofmt formatting, often for intentional and legitimate reasons (testing gofmt itself, invalid Go programs that shouldn't crash the compiler, etc.). That makes it easy and safe to gofmt -w the .go files that are found with gofmt -l with aforementioned directories filtered out: $ gofmt -l . 2>/dev/null | \ grep -v '^test/' | \ grep -v '/testdata/' | \ grep -v '/vendor/' | wc -l 51 None of the 51 files are generated. After this change, the same command prints 0. For #41184. Change-Id: Ia96ee2a0f998d6a167d4473bcad17ad09bc1d86e Reviewed-on: https://go-review.googlesource.com/c/go/+/341009 Run-TryBot: Dmitri Shuralyov TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor Trust: Dmitri Shuralyov --- misc/android/go_android_exec.go | 1 + misc/cgo/gmp/fib.go | 1 + misc/cgo/gmp/pi.go | 1 + misc/cgo/test/cgo_thread_lock.go | 1 + misc/cgo/test/cgo_unix_test.go | 1 + misc/cgo/test/issue1435.go | 1 + misc/cgo/test/issue18146.go | 1 + misc/cgo/test/issue21897.go | 1 + misc/cgo/test/issue21897b.go | 1 + misc/cgo/test/issue4029.go | 4 +++- misc/cgo/test/issue4029w.go | 1 + misc/cgo/test/issue6997_linux.go | 1 + misc/cgo/test/issue8517.go | 1 + misc/cgo/test/issue8694.go | 1 + misc/cgo/test/sigaltstack.go | 1 + misc/cgo/test/sigprocmask.go | 1 + misc/cgo/test/test_unix.go | 1 + misc/cgo/testso/noso_test.go | 1 + misc/cgo/testso/so_test.go | 1 + misc/cgo/testsovar/noso_test.go | 1 + misc/cgo/testsovar/so_test.go | 1 + misc/cgo/testtls/tls_test.go | 1 + misc/ios/detect.go | 1 + misc/reboot/experiment_toolid_test.go | 1 + src/cmd/compile/internal/base/bootstrap_false.go | 1 + src/cmd/compile/internal/base/bootstrap_true.go | 1 + src/cmd/compile/internal/noder/frames_go1.go | 1 + src/cmd/compile/internal/noder/frames_go17.go | 1 + src/cmd/compile/internal/ssa/gen/386Ops.go | 1 + src/cmd/compile/internal/ssa/gen/MIPS64Ops.go | 1 + src/cmd/compile/internal/ssa/gen/MIPSOps.go | 1 + src/cmd/compile/internal/ssa/gen/PPC64Ops.go | 1 + src/cmd/compile/internal/ssa/gen/RISCV64Ops.go | 1 + src/cmd/compile/internal/ssa/gen/S390XOps.go | 1 + src/cmd/compile/internal/ssa/gen/WasmOps.go | 1 + src/cmd/compile/internal/ssa/gen/dec64Ops.go | 1 + src/cmd/compile/internal/ssa/gen/decOps.go | 1 + src/internal/syscall/windows/exec_windows_test.go | 1 + src/internal/syscall/windows/mksyscall.go | 1 + src/internal/syscall/windows/registry/export_test.go | 1 + src/internal/syscall/windows/registry/key.go | 1 + src/internal/syscall/windows/registry/mksyscall.go | 1 + src/internal/syscall/windows/registry/registry_test.go | 1 + src/internal/syscall/windows/registry/syscall.go | 1 + src/internal/syscall/windows/registry/value.go | 1 + src/internal/syscall/windows/sysdll/sysdll.go | 1 + src/runtime/msan/msan.go | 4 +++- src/syscall/js/export_test.go | 1 + src/syscall/js/func.go | 1 + src/syscall/js/js.go | 1 + src/syscall/js/js_test.go | 1 + 51 files changed, 55 insertions(+), 2 deletions(-) diff --git a/misc/android/go_android_exec.go b/misc/android/go_android_exec.go index 3af2bee5839..168ebe88a22 100644 --- a/misc/android/go_android_exec.go +++ b/misc/android/go_android_exec.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // This program can be used as go_android_GOARCH_exec by the Go tool. diff --git a/misc/cgo/gmp/fib.go b/misc/cgo/gmp/fib.go index f1091b1c54f..f453fcf1843 100644 --- a/misc/cgo/gmp/fib.go +++ b/misc/cgo/gmp/fib.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // Compute Fibonacci numbers with two goroutines diff --git a/misc/cgo/gmp/pi.go b/misc/cgo/gmp/pi.go index d5851e8e6bd..5ea034900a9 100644 --- a/misc/cgo/gmp/pi.go +++ b/misc/cgo/gmp/pi.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore package main diff --git a/misc/cgo/test/cgo_thread_lock.go b/misc/cgo/test/cgo_thread_lock.go index b1050685182..3b9ac845493 100644 --- a/misc/cgo/test/cgo_thread_lock.go +++ b/misc/cgo/test/cgo_thread_lock.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && freebsd && openbsd // +build linux,freebsd,openbsd package cgotest diff --git a/misc/cgo/test/cgo_unix_test.go b/misc/cgo/test/cgo_unix_test.go index e3d59166498..a324503a22f 100644 --- a/misc/cgo/test/cgo_unix_test.go +++ b/misc/cgo/test/cgo_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !windows // +build !windows package cgotest diff --git a/misc/cgo/test/issue1435.go b/misc/cgo/test/issue1435.go index 92c6b998465..91db155c90b 100644 --- a/misc/cgo/test/issue1435.go +++ b/misc/cgo/test/issue1435.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && cgo // +build linux,cgo package cgotest diff --git a/misc/cgo/test/issue18146.go b/misc/cgo/test/issue18146.go index f92d6c7f939..e50f9ae5301 100644 --- a/misc/cgo/test/issue18146.go +++ b/misc/cgo/test/issue18146.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !windows // +build !windows // Issue 18146: pthread_create failure during syscall.Exec. diff --git a/misc/cgo/test/issue21897.go b/misc/cgo/test/issue21897.go index d13246bd84a..8f39252e688 100644 --- a/misc/cgo/test/issue21897.go +++ b/misc/cgo/test/issue21897.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin && cgo && !internal // +build darwin,cgo,!internal package cgotest diff --git a/misc/cgo/test/issue21897b.go b/misc/cgo/test/issue21897b.go index 08b5f4d808e..50aece35289 100644 --- a/misc/cgo/test/issue21897b.go +++ b/misc/cgo/test/issue21897b.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !darwin || !cgo || internal // +build !darwin !cgo internal package cgotest diff --git a/misc/cgo/test/issue4029.go b/misc/cgo/test/issue4029.go index b2d131833a9..90ca08cbfb7 100644 --- a/misc/cgo/test/issue4029.go +++ b/misc/cgo/test/issue4029.go @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !windows,!static +//go:build !windows && !static && (!darwin || (!internal_pie && !arm64)) +// +build !windows +// +build !static // +build !darwin !internal_pie,!arm64 // Excluded in darwin internal linking PIE mode, as dynamic export is not diff --git a/misc/cgo/test/issue4029w.go b/misc/cgo/test/issue4029w.go index b969bdd0fe8..c2f59485e49 100644 --- a/misc/cgo/test/issue4029w.go +++ b/misc/cgo/test/issue4029w.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build windows || static || (darwin && internal_pie) || (darwin && arm64) // +build windows static darwin,internal_pie darwin,arm64 package cgotest diff --git a/misc/cgo/test/issue6997_linux.go b/misc/cgo/test/issue6997_linux.go index f19afb8b7ad..4acc8c1a070 100644 --- a/misc/cgo/test/issue6997_linux.go +++ b/misc/cgo/test/issue6997_linux.go @@ -2,6 +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 // +build !android // Test that pthread_cancel works as expected diff --git a/misc/cgo/test/issue8517.go b/misc/cgo/test/issue8517.go index 4e431df921d..7316ab0335d 100644 --- a/misc/cgo/test/issue8517.go +++ b/misc/cgo/test/issue8517.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !windows // +build !windows package cgotest diff --git a/misc/cgo/test/issue8694.go b/misc/cgo/test/issue8694.go index 89be7ea0907..19071ce1595 100644 --- a/misc/cgo/test/issue8694.go +++ b/misc/cgo/test/issue8694.go @@ -2,6 +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 // +build !android package cgotest diff --git a/misc/cgo/test/sigaltstack.go b/misc/cgo/test/sigaltstack.go index 034cc4b3719..6b371897a73 100644 --- a/misc/cgo/test/sigaltstack.go +++ b/misc/cgo/test/sigaltstack.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !windows && !android // +build !windows,!android // Test that the Go runtime still works if C code changes the signal stack. diff --git a/misc/cgo/test/sigprocmask.go b/misc/cgo/test/sigprocmask.go index e2b939f05e2..983734cc7b6 100644 --- a/misc/cgo/test/sigprocmask.go +++ b/misc/cgo/test/sigprocmask.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !windows // +build !windows package cgotest diff --git a/misc/cgo/test/test_unix.go b/misc/cgo/test/test_unix.go index 4a234469dbc..831b9ca625a 100644 --- a/misc/cgo/test/test_unix.go +++ b/misc/cgo/test/test_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !windows // +build !windows package cgotest diff --git a/misc/cgo/testso/noso_test.go b/misc/cgo/testso/noso_test.go index c88aebfb02a..1014534d62c 100644 --- a/misc/cgo/testso/noso_test.go +++ b/misc/cgo/testso/noso_test.go @@ -2,6 +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 // +build !cgo package so_test diff --git a/misc/cgo/testso/so_test.go b/misc/cgo/testso/so_test.go index 2023c51f113..6d14e32dc6c 100644 --- a/misc/cgo/testso/so_test.go +++ b/misc/cgo/testso/so_test.go @@ -2,6 +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 // +build cgo package so_test diff --git a/misc/cgo/testsovar/noso_test.go b/misc/cgo/testsovar/noso_test.go index c88aebfb02a..1014534d62c 100644 --- a/misc/cgo/testsovar/noso_test.go +++ b/misc/cgo/testsovar/noso_test.go @@ -2,6 +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 // +build !cgo package so_test diff --git a/misc/cgo/testsovar/so_test.go b/misc/cgo/testsovar/so_test.go index 2023c51f113..6d14e32dc6c 100644 --- a/misc/cgo/testsovar/so_test.go +++ b/misc/cgo/testsovar/so_test.go @@ -2,6 +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 // +build cgo package so_test diff --git a/misc/cgo/testtls/tls_test.go b/misc/cgo/testtls/tls_test.go index 3076c2d5943..a3b67c00441 100644 --- a/misc/cgo/testtls/tls_test.go +++ b/misc/cgo/testtls/tls_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !windows // +build !windows package cgotlstest diff --git a/misc/ios/detect.go b/misc/ios/detect.go index cde57238923..1cb8ae5ff71 100644 --- a/misc/ios/detect.go +++ b/misc/ios/detect.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // detect attempts to autodetect the correct diff --git a/misc/reboot/experiment_toolid_test.go b/misc/reboot/experiment_toolid_test.go index 4f40284d80f..87a828e32f7 100644 --- a/misc/reboot/experiment_toolid_test.go +++ b/misc/reboot/experiment_toolid_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build explicit // +build explicit // Package experiment_toolid_test verifies that GOEXPERIMENT settings built diff --git a/src/cmd/compile/internal/base/bootstrap_false.go b/src/cmd/compile/internal/base/bootstrap_false.go index de86644527d..c77fcd73081 100644 --- a/src/cmd/compile/internal/base/bootstrap_false.go +++ b/src/cmd/compile/internal/base/bootstrap_false.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !compiler_bootstrap // +build !compiler_bootstrap package base diff --git a/src/cmd/compile/internal/base/bootstrap_true.go b/src/cmd/compile/internal/base/bootstrap_true.go index 81a17e1f6e5..1eb58b2f9dc 100644 --- a/src/cmd/compile/internal/base/bootstrap_true.go +++ b/src/cmd/compile/internal/base/bootstrap_true.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build compiler_bootstrap // +build compiler_bootstrap package base diff --git a/src/cmd/compile/internal/noder/frames_go1.go b/src/cmd/compile/internal/noder/frames_go1.go index 2958efd6222..d00e0f51f9f 100644 --- a/src/cmd/compile/internal/noder/frames_go1.go +++ b/src/cmd/compile/internal/noder/frames_go1.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !go1.7 // +build !go1.7 // TODO(mdempsky): Remove after #44505 is resolved diff --git a/src/cmd/compile/internal/noder/frames_go17.go b/src/cmd/compile/internal/noder/frames_go17.go index 273217e39a1..48d77625b41 100644 --- a/src/cmd/compile/internal/noder/frames_go17.go +++ b/src/cmd/compile/internal/noder/frames_go17.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build go1.7 // +build go1.7 package noder diff --git a/src/cmd/compile/internal/ssa/gen/386Ops.go b/src/cmd/compile/internal/ssa/gen/386Ops.go index c4b49fbb230..91f33c83745 100644 --- a/src/cmd/compile/internal/ssa/gen/386Ops.go +++ b/src/cmd/compile/internal/ssa/gen/386Ops.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore package main diff --git a/src/cmd/compile/internal/ssa/gen/MIPS64Ops.go b/src/cmd/compile/internal/ssa/gen/MIPS64Ops.go index 77f251c0d3f..a18cd4289d4 100644 --- a/src/cmd/compile/internal/ssa/gen/MIPS64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/MIPS64Ops.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore package main diff --git a/src/cmd/compile/internal/ssa/gen/MIPSOps.go b/src/cmd/compile/internal/ssa/gen/MIPSOps.go index b92e8cb9f1e..8177c7e2d17 100644 --- a/src/cmd/compile/internal/ssa/gen/MIPSOps.go +++ b/src/cmd/compile/internal/ssa/gen/MIPSOps.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore package main diff --git a/src/cmd/compile/internal/ssa/gen/PPC64Ops.go b/src/cmd/compile/internal/ssa/gen/PPC64Ops.go index f7198b90c32..d7d8a33a0a1 100644 --- a/src/cmd/compile/internal/ssa/gen/PPC64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/PPC64Ops.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore package main diff --git a/src/cmd/compile/internal/ssa/gen/RISCV64Ops.go b/src/cmd/compile/internal/ssa/gen/RISCV64Ops.go index 0ac9c5f62ad..0774d4c654f 100644 --- a/src/cmd/compile/internal/ssa/gen/RISCV64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/RISCV64Ops.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore package main diff --git a/src/cmd/compile/internal/ssa/gen/S390XOps.go b/src/cmd/compile/internal/ssa/gen/S390XOps.go index 5b33ba710e9..00fce8e0e58 100644 --- a/src/cmd/compile/internal/ssa/gen/S390XOps.go +++ b/src/cmd/compile/internal/ssa/gen/S390XOps.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore package main diff --git a/src/cmd/compile/internal/ssa/gen/WasmOps.go b/src/cmd/compile/internal/ssa/gen/WasmOps.go index c92878ca73b..7f7ae5e8370 100644 --- a/src/cmd/compile/internal/ssa/gen/WasmOps.go +++ b/src/cmd/compile/internal/ssa/gen/WasmOps.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore package main diff --git a/src/cmd/compile/internal/ssa/gen/dec64Ops.go b/src/cmd/compile/internal/ssa/gen/dec64Ops.go index 8c5883bc569..78fcea885aa 100644 --- a/src/cmd/compile/internal/ssa/gen/dec64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/dec64Ops.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore package main diff --git a/src/cmd/compile/internal/ssa/gen/decOps.go b/src/cmd/compile/internal/ssa/gen/decOps.go index b826481c9fb..d5cd79378c7 100644 --- a/src/cmd/compile/internal/ssa/gen/decOps.go +++ b/src/cmd/compile/internal/ssa/gen/decOps.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore package main diff --git a/src/internal/syscall/windows/exec_windows_test.go b/src/internal/syscall/windows/exec_windows_test.go index 283d7cea94b..0db626636e9 100644 --- a/src/internal/syscall/windows/exec_windows_test.go +++ b/src/internal/syscall/windows/exec_windows_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build windows // +build windows package windows_test diff --git a/src/internal/syscall/windows/mksyscall.go b/src/internal/syscall/windows/mksyscall.go index 599f07601bd..39f745db7a3 100644 --- a/src/internal/syscall/windows/mksyscall.go +++ b/src/internal/syscall/windows/mksyscall.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build generate // +build generate package windows diff --git a/src/internal/syscall/windows/registry/export_test.go b/src/internal/syscall/windows/registry/export_test.go index 8badf6fdcf1..d02d93f2875 100644 --- a/src/internal/syscall/windows/registry/export_test.go +++ b/src/internal/syscall/windows/registry/export_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build windows // +build windows package registry diff --git a/src/internal/syscall/windows/registry/key.go b/src/internal/syscall/windows/registry/key.go index 612c48f0840..ebe73a2e024 100644 --- a/src/internal/syscall/windows/registry/key.go +++ b/src/internal/syscall/windows/registry/key.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build windows // +build windows // Package registry provides access to the Windows registry. diff --git a/src/internal/syscall/windows/registry/mksyscall.go b/src/internal/syscall/windows/registry/mksyscall.go index 320abf7fc69..0a007df7ccd 100644 --- a/src/internal/syscall/windows/registry/mksyscall.go +++ b/src/internal/syscall/windows/registry/mksyscall.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build generate // +build generate package registry diff --git a/src/internal/syscall/windows/registry/registry_test.go b/src/internal/syscall/windows/registry/registry_test.go index 57971629006..69b84e1c4c5 100644 --- a/src/internal/syscall/windows/registry/registry_test.go +++ b/src/internal/syscall/windows/registry/registry_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build windows // +build windows package registry_test diff --git a/src/internal/syscall/windows/registry/syscall.go b/src/internal/syscall/windows/registry/syscall.go index a6525dac5d9..bb612793613 100644 --- a/src/internal/syscall/windows/registry/syscall.go +++ b/src/internal/syscall/windows/registry/syscall.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build windows // +build windows package registry diff --git a/src/internal/syscall/windows/registry/value.go b/src/internal/syscall/windows/registry/value.go index dc3930a6bc2..e1fc99c40d4 100644 --- a/src/internal/syscall/windows/registry/value.go +++ b/src/internal/syscall/windows/registry/value.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build windows // +build windows package registry diff --git a/src/internal/syscall/windows/sysdll/sysdll.go b/src/internal/syscall/windows/sysdll/sysdll.go index c587c19c77d..61b998e4cfc 100644 --- a/src/internal/syscall/windows/sysdll/sysdll.go +++ b/src/internal/syscall/windows/sysdll/sysdll.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build windows // +build windows // Package sysdll is an internal leaf package that records and reports diff --git a/src/runtime/msan/msan.go b/src/runtime/msan/msan.go index c81577dddac..9908a8ec221 100644 --- a/src/runtime/msan/msan.go +++ b/src/runtime/msan/msan.go @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build msan,linux +//go:build msan && linux && (amd64 || arm64) +// +build msan +// +build linux // +build amd64 arm64 package msan diff --git a/src/syscall/js/export_test.go b/src/syscall/js/export_test.go index 1b5ed3ce849..4bd9c5d595e 100644 --- a/src/syscall/js/export_test.go +++ b/src/syscall/js/export_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package js diff --git a/src/syscall/js/func.go b/src/syscall/js/func.go index da4cf68774d..ab23e5fbfc0 100644 --- a/src/syscall/js/func.go +++ b/src/syscall/js/func.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package js diff --git a/src/syscall/js/js.go b/src/syscall/js/js.go index a48bbd4dd79..d805d691664 100644 --- a/src/syscall/js/js.go +++ b/src/syscall/js/js.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm // Package js gives access to the WebAssembly host environment when using the js/wasm architecture. diff --git a/src/syscall/js/js_test.go b/src/syscall/js/js_test.go index 5fc9107d402..8088a897f60 100644 --- a/src/syscall/js/js_test.go +++ b/src/syscall/js/js_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm // To run these tests: From 641e8bc2c7166135d3a63ed1a71a3aa495bc3c5d Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 16 Jul 2021 12:16:21 -0700 Subject: [PATCH 921/940] test: add test case that caused a gofrontend compiler crash For #47131 Change-Id: Ie2d5a2bd3dceec607544c43e6dc68bd5ea353091 Reviewed-on: https://go-review.googlesource.com/c/go/+/335172 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor Reviewed-by: Cherry Mui Reviewed-by: Than McIntosh TryBot-Result: Go Bot --- test/fixedbugs/issue47131.dir/a.go | 13 +++++++++++++ test/fixedbugs/issue47131.dir/b.go | 12 ++++++++++++ test/fixedbugs/issue47131.go | 7 +++++++ 3 files changed, 32 insertions(+) create mode 100644 test/fixedbugs/issue47131.dir/a.go create mode 100644 test/fixedbugs/issue47131.dir/b.go create mode 100644 test/fixedbugs/issue47131.go diff --git a/test/fixedbugs/issue47131.dir/a.go b/test/fixedbugs/issue47131.dir/a.go new file mode 100644 index 00000000000..6e798d1d0c8 --- /dev/null +++ b/test/fixedbugs/issue47131.dir/a.go @@ -0,0 +1,13 @@ +// Copyright 2021 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 a + +type MyInt int + +type MyIntAlias = MyInt + +func (mia *MyIntAlias) Get() int { + return int(*mia) +} diff --git a/test/fixedbugs/issue47131.dir/b.go b/test/fixedbugs/issue47131.dir/b.go new file mode 100644 index 00000000000..c658127ca9d --- /dev/null +++ b/test/fixedbugs/issue47131.dir/b.go @@ -0,0 +1,12 @@ +// Copyright 2021 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 b + +import "./a" + +func F2() int { + var mia a.MyIntAlias + return mia.Get() +} diff --git a/test/fixedbugs/issue47131.go b/test/fixedbugs/issue47131.go new file mode 100644 index 00000000000..b83fbd7af16 --- /dev/null +++ b/test/fixedbugs/issue47131.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2021 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 ignored From bad1fc126536f14fd6f00a93e1b76320c1510bf2 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 9 Aug 2021 14:59:56 -0700 Subject: [PATCH 922/940] test: add test case for CL 340609 The first version of CL 340609 for gofrontend passed all existing tests, but not this one. For #42076 Change-Id: I6491e2f186091bdae140b7f7befa511806a6478a Reviewed-on: https://go-review.googlesource.com/c/go/+/340950 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Cherry Mui Reviewed-by: Than McIntosh --- test/fixedbugs/bug514.go | 55 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 test/fixedbugs/bug514.go diff --git a/test/fixedbugs/bug514.go b/test/fixedbugs/bug514.go new file mode 100644 index 00000000000..3fb7f32a300 --- /dev/null +++ b/test/fixedbugs/bug514.go @@ -0,0 +1,55 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type iface interface { + Get() int +} + +//go:notinheap +type notInHeap struct { + i int +} + +type myInt struct { + f *notInHeap +} + +func (mi myInt) Get() int { + return int(mi.f.i) +} + +type embed struct { + *myInt +} + +var val = 1234 + +var valNotInHeap = notInHeap{val} + +func main() { + i := val + check(i) + mi := myInt{f: &valNotInHeap} + check(mi.Get()) + ifv := iface(mi) + check(ifv.Get()) + ifv = iface(&mi) + check(ifv.Get()) + em := embed{&mi} + check(em.Get()) + ifv = em + check(ifv.Get()) + ifv = &em + check(ifv.Get()) +} + +func check(v int) { + if v != val { + panic(v) + } +} From 2eb4d68833e28fce2701a9c39755413630921371 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 11 Aug 2021 15:34:29 -0700 Subject: [PATCH 923/940] runtime: don't use systemstack for BeforeFork/AfterFork In https://golang.org/cl/140930043 syscall.BeforeFork was changed to call beforefork via onM. This was done because at the time BeforeFork was written in C but was called from Go. While the runtime was being converted to Go, calls to complex C functions used onM to ensure that enough stack space was available. In https://golang.org/cl/172260043 the syscall.BeforeFork and beforefork functions were rewritten into Go. In this rewrite syscall.BeforeFork continue to call beforefork via onM, although because both functions were now in Go that was no longer necessary. In https://golang.org/cl/174950043 onM was renamed to systemstack, producing essentially the code we have today. Therefore, the use of systemstack in syscall.BeforeFork (and syscall.AfterFork) is a historical relic. Remove it. Change-Id: Ia570f556b20e8405afa6c5e707bd6f4ad18fd7ca Reviewed-on: https://go-review.googlesource.com/c/go/+/341335 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Austin Clements --- src/runtime/proc.go | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 764f12769ed..cde1a115830 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -4104,7 +4104,10 @@ func exitsyscall0(gp *g) { schedule() // Never returns. } -func beforefork() { +// Called from syscall package before fork. +//go:linkname syscall_runtime_BeforeFork syscall.runtime_BeforeFork +//go:nosplit +func syscall_runtime_BeforeFork() { gp := getg().m.curg // Block signals during a fork, so that the child does not run @@ -4121,14 +4124,10 @@ func beforefork() { gp.stackguard0 = stackFork } -// Called from syscall package before fork. -//go:linkname syscall_runtime_BeforeFork syscall.runtime_BeforeFork +// Called from syscall package after fork in parent. +//go:linkname syscall_runtime_AfterFork syscall.runtime_AfterFork //go:nosplit -func syscall_runtime_BeforeFork() { - systemstack(beforefork) -} - -func afterfork() { +func syscall_runtime_AfterFork() { gp := getg().m.curg // See the comments in beforefork. @@ -4139,13 +4138,6 @@ func afterfork() { gp.m.locks-- } -// Called from syscall package after fork in parent. -//go:linkname syscall_runtime_AfterFork syscall.runtime_AfterFork -//go:nosplit -func syscall_runtime_AfterFork() { - systemstack(afterfork) -} - // inForkedChild is true while manipulating signals in the child process. // This is used to avoid calling libc functions in case we are using vfork. var inForkedChild bool From 89a4f996405684c117571e3a0813742b6a8269b7 Mon Sep 17 00:00:00 2001 From: 180909 <734461790@qq.com> Date: Wed, 11 Aug 2021 08:52:31 +0000 Subject: [PATCH 924/940] lib/time: fix tz-link ftp url Change-Id: Id09c01192dea6a6f26cbad7222946266587acfda GitHub-Last-Rev: c4f99aedcdc8316f13e8d9bfe9a00e48443fae9e GitHub-Pull-Request: golang/go#47639 Reviewed-on: https://go-review.googlesource.com/c/go/+/341389 Reviewed-by: Ian Lance Taylor Reviewed-by: Emmanuel Odeke --- lib/time/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/time/README b/lib/time/README index aab4daa7e2d..edb8dccd266 100644 --- a/lib/time/README +++ b/lib/time/README @@ -4,7 +4,7 @@ The IANA asserts that the database is in the public domain. For more information, see https://www.iana.org/time-zones -ftp://ftp.iana.org/tz/code/tz-link.htm +ftp://ftp.iana.org/tz/code/tz-link.html http://tools.ietf.org/html/rfc6557 To rebuild the archive, read and run update.bash. From a95f1b51be6cdf39235dd4a00f03bab9bf17a3f3 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 13 Jul 2021 09:26:28 -0700 Subject: [PATCH 925/940] test: change issue10441.go from "build" to "compile" We use "build" for tests in the main package with a main function. We use "compile" for tests that are not in the main package. Change-Id: I9876b55a9e4672277483fd24e69058d439c66658 Reviewed-on: https://go-review.googlesource.com/c/go/+/334329 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor Reviewed-by: Cherry Mui Reviewed-by: Dmitri Shuralyov TryBot-Result: Go Bot --- test/fixedbugs/issue10441.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fixedbugs/issue10441.go b/test/fixedbugs/issue10441.go index 9bc4948b15b..7cd26d841b6 100644 --- a/test/fixedbugs/issue10441.go +++ b/test/fixedbugs/issue10441.go @@ -1,4 +1,4 @@ -// build +// compile // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style From 58490972c0d5a9dc59450474d38533faf69e4aaf Mon Sep 17 00:00:00 2001 From: korzhao Date: Tue, 10 Aug 2021 22:05:34 +0800 Subject: [PATCH 926/940] cmd/link: fix dead reference link Change-Id: I0f53cc2b845f8a52fece2aaba1445a0ecb9cdc53 Reviewed-on: https://go-review.googlesource.com/c/go/+/341129 Reviewed-by: Ian Lance Taylor Trust: Dmitri Shuralyov --- src/cmd/link/internal/loadelf/ldelf.go | 2 +- src/cmd/link/internal/loadmacho/ldmacho.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/link/internal/loadelf/ldelf.go b/src/cmd/link/internal/loadelf/ldelf.go index c6956297f6c..b4f565a153f 100644 --- a/src/cmd/link/internal/loadelf/ldelf.go +++ b/src/cmd/link/internal/loadelf/ldelf.go @@ -22,7 +22,7 @@ import ( /* Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c -http://code.swtch.com/plan9port/src/tip/src/libmach/ +https://github.com/9fans/plan9port/tree/master/src/libmach/ Copyright © 2004 Russ Cox. Portions Copyright © 2008-2010 Google Inc. diff --git a/src/cmd/link/internal/loadmacho/ldmacho.go b/src/cmd/link/internal/loadmacho/ldmacho.go index e7d9eebc33f..5402ecd7484 100644 --- a/src/cmd/link/internal/loadmacho/ldmacho.go +++ b/src/cmd/link/internal/loadmacho/ldmacho.go @@ -18,7 +18,7 @@ import ( /* Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c -http://code.swtch.com/plan9port/src/tip/src/libmach/ +https://github.com/9fans/plan9port/tree/master/src/libmach/ Copyright © 2004 Russ Cox. Portions Copyright © 2008-2010 Google Inc. From 7eaabae84d8b69216356b84ebc7c86917100f99a Mon Sep 17 00:00:00 2001 From: hitzhangjie Date: Sat, 7 Aug 2021 04:18:37 +0000 Subject: [PATCH 927/940] net: update IP.String doc to reflect RFC 5952 conformance Fixes #44485 Change-Id: I1b1bf14245ef738342ec881ac4c99adbfc9c5b7d GitHub-Last-Rev: ae0242c6d61fc0e80c58113a70db74829f6aa12c GitHub-Pull-Request: golang/go#47394 Reviewed-on: https://go-review.googlesource.com/c/go/+/337409 Trust: Dmitri Shuralyov Trust: Damien Neil Reviewed-by: Damien Neil --- src/net/ip.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net/ip.go b/src/net/ip.go index 38e1aa2247f..b016bef144a 100644 --- a/src/net/ip.go +++ b/src/net/ip.go @@ -308,7 +308,7 @@ func ubtoa(dst []byte, start int, v byte) int { // It returns one of 4 forms: // - "", if ip has length 0 // - dotted decimal ("192.0.2.1"), if ip is an IPv4 or IP4-mapped IPv6 address -// - IPv6 ("2001:db8::1"), if ip is a valid IPv6 address +// - IPv6 conforming to RFC 5952 ("2001:db8::1"), if ip is a valid IPv6 address // - the hexadecimal form of ip, without punctuation, if no other cases apply func (ip IP) String() string { p := ip From fc27eb50ffcada3d4f5e7e00a5c120f474cc0da4 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Tue, 10 Aug 2021 14:00:56 -0400 Subject: [PATCH 928/940] cmd/compile/internal/types2: merge Instantiate and InstantiateLazy Instantiate and InstantiateLazy have the same signature; on first principles, if Instantiate should work for importers it should be possible to consolidate these APIs. This CL does this. In order to make it work, a typMap needs to be threaded through type expansion to prevent infinite recursion in the case that the Checker is nil. Notably, Named types now must be expanded before returning from Underlying(). This makes Underlying generally unsafe to call while type checking a package, so a helper function safeUnderlying is added to provide the previous behavior. This is probably overly conservative at most call sites, but cleanup is deferred to a later CL. Change-Id: I03cfb75bea0750862cd6eea4e3cdc875a7daa989 Reviewed-on: https://go-review.googlesource.com/c/go/+/341855 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/noder/reader2.go | 2 +- src/cmd/compile/internal/types2/api_test.go | 4 +- src/cmd/compile/internal/types2/call.go | 4 +- src/cmd/compile/internal/types2/decl.go | 5 ++- src/cmd/compile/internal/types2/expr.go | 2 +- src/cmd/compile/internal/types2/infer.go | 6 +-- .../compile/internal/types2/instantiate.go | 27 +++++-------- src/cmd/compile/internal/types2/lookup.go | 4 +- src/cmd/compile/internal/types2/named.go | 39 +++++++++++++++---- src/cmd/compile/internal/types2/predicates.go | 4 +- src/cmd/compile/internal/types2/signature.go | 4 +- src/cmd/compile/internal/types2/subst.go | 22 +++++++---- src/cmd/compile/internal/types2/type.go | 2 +- src/cmd/compile/internal/types2/typexpr.go | 14 ++++--- src/cmd/compile/internal/types2/unify.go | 4 +- 15 files changed, 87 insertions(+), 56 deletions(-) diff --git a/src/cmd/compile/internal/noder/reader2.go b/src/cmd/compile/internal/noder/reader2.go index 5637196dc0e..97ea4fcb76d 100644 --- a/src/cmd/compile/internal/noder/reader2.go +++ b/src/cmd/compile/internal/noder/reader2.go @@ -229,7 +229,7 @@ func (r *reader2) doTyp() (res types2.Type) { obj, targs := r.obj() name := obj.(*types2.TypeName) if len(targs) != 0 { - return r.p.check.InstantiateLazy(syntax.Pos{}, name.Type(), targs, nil, false) + return r.p.check.Instantiate(syntax.Pos{}, name.Type(), targs, nil, false) } return name.Type() diff --git a/src/cmd/compile/internal/types2/api_test.go b/src/cmd/compile/internal/types2/api_test.go index d8844956afb..dfa4de11750 100644 --- a/src/cmd/compile/internal/types2/api_test.go +++ b/src/cmd/compile/internal/types2/api_test.go @@ -1875,7 +1875,7 @@ func TestInstantiate(t *testing.T) { res := check.Instantiate(nopos, T, []Type{Typ[Int]}, nil, false) // instantiated type should point to itself - if res.Underlying().(*Pointer).Elem() != res { - t.Fatalf("unexpected result type: %s", res) + if p := res.Underlying().(*Pointer).Elem(); p != res { + t.Fatalf("unexpected result type: %s points to %s", res, p) } } diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index 049d80dd9e7..94bcc4870bb 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -334,7 +334,7 @@ func (check *Checker) arguments(call *syntax.CallExpr, sig *Signature, targs []T // need to compute it from the adjusted list; otherwise we can // simply use the result signature's parameter list. if adjusted { - sigParams = check.subst(call.Pos(), sigParams, makeSubstMap(sig.TParams().list(), targs)).(*Tuple) + sigParams = check.subst(call.Pos(), sigParams, makeSubstMap(sig.TParams().list(), targs), nil).(*Tuple) } else { sigParams = rsig.params } @@ -555,7 +555,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) { // (If we modify m, some tests will fail; possibly because the m is in use.) // TODO(gri) investigate and provide a correct explanation here copy := *m - copy.typ = check.subst(e.Pos(), m.typ, makeSubstMap(sig.RParams().list(), targs)) + copy.typ = check.subst(e.Pos(), m.typ, makeSubstMap(sig.RParams().list(), targs), nil) obj = © } // TODO(gri) we also need to do substitution for parameterized interface methods diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go index bfccbc5dbf2..24ec4cd0294 100644 --- a/src/cmd/compile/internal/types2/decl.go +++ b/src/cmd/compile/internal/types2/decl.go @@ -317,7 +317,7 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo { } case *Named: - t.expand() + t.expand(check.typMap) // don't touch the type if it is from a different package or the Universe scope // (doing so would lead to a race condition - was issue #35049) @@ -650,7 +650,8 @@ func (check *Checker) collectMethods(obj *TypeName) { // and field names must be distinct." base := asNamed(obj.typ) // shouldn't fail but be conservative if base != nil { - if t, _ := base.Underlying().(*Struct); t != nil { + u := safeUnderlying(base) // base should be expanded, but use safeUnderlying to be conservative + if t, _ := u.(*Struct); t != nil { for _, fld := range t.fields { if fld.name != "_" { assert(mset.insert(fld) == nil) diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go index 3c2b10cd7e0..6d8b423714c 100644 --- a/src/cmd/compile/internal/types2/expr.go +++ b/src/cmd/compile/internal/types2/expr.go @@ -661,7 +661,7 @@ func (check *Checker) updateExprVal(x syntax.Expr, val constant.Value) { func (check *Checker) convertUntyped(x *operand, target Type) { newType, val, code := check.implicitTypeAndValue(x, target) if code != 0 { - check.invalidConversion(code, x, target.Underlying()) + check.invalidConversion(code, x, safeUnderlying(target)) x.mode = invalid return } diff --git a/src/cmd/compile/internal/types2/infer.go b/src/cmd/compile/internal/types2/infer.go index ff4bb3ea175..7bf507471d3 100644 --- a/src/cmd/compile/internal/types2/infer.go +++ b/src/cmd/compile/internal/types2/infer.go @@ -87,7 +87,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeName, targs []Type, p // but that doesn't impact the isParameterized check for now). if params.Len() > 0 { smap := makeSubstMap(tparams, targs) - params = check.subst(nopos, params, smap).(*Tuple) + params = check.subst(nopos, params, smap, nil).(*Tuple) } // --- 2 --- @@ -127,7 +127,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeName, targs []Type, p } } smap := makeSubstMap(tparams, targs) - inferred := check.subst(arg.Pos(), tpar, smap) + inferred := check.subst(arg.Pos(), tpar, smap, nil) if inferred != tpar { check.errorf(arg, "%s %s of %s does not match inferred type %s for %s", kind, targ, arg.expr, inferred, tpar) } else { @@ -427,7 +427,7 @@ func (check *Checker) inferB(tparams []*TypeName, targs []Type, report bool) (ty n := 0 for _, index := range dirty { t0 := types[index] - if t1 := check.subst(nopos, t0, smap); t1 != t0 { + if t1 := check.subst(nopos, t0, smap, nil); t1 != t0 { types[index] = t1 dirty[n] = index n++ diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go index 0bb4ac956b2..a648a3c38c8 100644 --- a/src/cmd/compile/internal/types2/instantiate.go +++ b/src/cmd/compile/internal/types2/instantiate.go @@ -29,7 +29,7 @@ func (check *Checker) Instantiate(pos syntax.Pos, typ Type, targs []Type, posLis var tparams []*TypeName switch t := typ.(type) { case *Named: - tparams = t.TParams().list() + return check.instantiateLazy(pos, t, targs, posList, verify) case *Signature: tparams = t.TParams().list() defer func() { @@ -55,14 +55,14 @@ func (check *Checker) Instantiate(pos syntax.Pos, typ Type, targs []Type, posLis panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) } - inst := check.instantiate(pos, typ, tparams, targs, posList) + inst := check.instantiate(pos, typ, tparams, targs, posList, nil) if verify && len(tparams) == len(targs) { check.verify(pos, tparams, targs, posList) } return inst } -func (check *Checker) instantiate(pos syntax.Pos, typ Type, tparams []*TypeName, targs []Type, posList []syntax.Pos) (res Type) { +func (check *Checker) instantiate(pos syntax.Pos, typ Type, tparams []*TypeName, targs []Type, posList []syntax.Pos, typMap map[string]*Named) (res Type) { // the number of supplied types must match the number of type parameters if len(targs) != len(tparams) { // TODO(gri) provide better error message @@ -83,7 +83,7 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, tparams []*TypeName, // Calling under() here may lead to endless instantiations. // Test case: type T[P any] T[P] // TODO(gri) investigate if that's a bug or to be expected. - under = res.Underlying() + under = safeUnderlying(res) } check.trace(pos, "=> %s (under = %s)", res, under) }() @@ -95,21 +95,14 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, tparams []*TypeName, return typ // nothing to do (minor optimization) } - return check.subst(pos, typ, makeSubstMap(tparams, targs)) + return check.subst(pos, typ, makeSubstMap(tparams, targs), typMap) } -// InstantiateLazy is like Instantiate, but avoids actually -// instantiating the type until needed. typ must be a *Named -// type. -func (check *Checker) InstantiateLazy(pos syntax.Pos, typ Type, targs []Type, posList []syntax.Pos, verify bool) Type { - // Don't use asNamed here: we don't want to expand the base during lazy - // instantiation. - base := typ.(*Named) - if base == nil { - panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) - } - +// instantiateLazy avoids actually instantiating the type until needed. typ +// must be a *Named type. +func (check *Checker) instantiateLazy(pos syntax.Pos, base *Named, targs []Type, posList []syntax.Pos, verify bool) Type { if verify && base.TParams().Len() == len(targs) { + // TODO: lift the nil check in verify to here. check.later(func() { check.verify(pos, base.tparams.list(), targs, posList) }) @@ -169,7 +162,7 @@ func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap // as the instantiated type; before we can use it for bounds checking we // need to instantiate it with the type arguments with which we instantiate // the parameterized type. - iface = check.subst(pos, iface, smap).(*Interface) + iface = check.subst(pos, iface, smap, nil).(*Interface) // if iface is comparable, targ must be comparable // TODO(gri) the error messages needs to be better, here diff --git a/src/cmd/compile/internal/types2/lookup.go b/src/cmd/compile/internal/types2/lookup.go index 0363008ad9a..3779d17b3db 100644 --- a/src/cmd/compile/internal/types2/lookup.go +++ b/src/cmd/compile/internal/types2/lookup.go @@ -46,7 +46,7 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o // pointer type but discard the result if it is a method since we would // not have found it for T (see also issue 8590). if t := asNamed(T); t != nil { - if p, _ := t.Underlying().(*Pointer); p != nil { + if p, _ := safeUnderlying(t).(*Pointer); p != nil { obj, index, indirect = lookupFieldOrMethod(p, false, pkg, name) if _, ok := obj.(*Func); ok { return nil, nil, false @@ -394,7 +394,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, if len(ftyp.RParams().list()) != len(Vn.targs) { return } - ftyp = check.subst(nopos, ftyp, makeSubstMap(ftyp.RParams().list(), Vn.targs)).(*Signature) + ftyp = check.subst(nopos, ftyp, makeSubstMap(ftyp.RParams().list(), Vn.targs), nil).(*Signature) } // If the methods have type parameters we don't care whether they diff --git a/src/cmd/compile/internal/types2/named.go b/src/cmd/compile/internal/types2/named.go index adf3eb38229..b12e59b586d 100644 --- a/src/cmd/compile/internal/types2/named.go +++ b/src/cmd/compile/internal/types2/named.go @@ -153,7 +153,7 @@ func (t *Named) AddMethod(m *Func) { } } -func (t *Named) Underlying() Type { return t.load().underlying } +func (t *Named) Underlying() Type { return t.load().expand(nil).underlying } func (t *Named) String() string { return TypeString(t, nil) } // ---------------------------------------------------------------------------- @@ -166,9 +166,9 @@ func (t *Named) String() string { return TypeString(t, nil) } // is detected, the result is Typ[Invalid]. If a cycle is detected and // n0.check != nil, the cycle is reported. func (n0 *Named) under() Type { - n0.expand() + n0.expand(nil) - u := n0.Underlying() + u := n0.load().underlying if u == Typ[Invalid] { return u @@ -206,7 +206,7 @@ func (n0 *Named) under() Type { seen := map[*Named]int{n0: 0} path := []Object{n0.obj} for { - u = n.Underlying() + u = n.load().underlying if u == nil { u = Typ[Invalid] break @@ -214,7 +214,7 @@ func (n0 *Named) under() Type { var n1 *Named switch u1 := u.(type) { case *Named: - u1.expand() + u1.expand(nil) n1 = u1 } if n1 == nil { @@ -264,15 +264,40 @@ type instance struct { // expand ensures that the underlying type of n is instantiated. // The underlying type will be Typ[Invalid] if there was an error. -func (n *Named) expand() { +func (n *Named) expand(typMap map[string]*Named) *Named { if n.instance != nil { // n must be loaded before instantiation, in order to have accurate // tparams. This is done implicitly by the call to n.TParams, but making it // explicit is harmless: load is idempotent. n.load() - inst := n.check.instantiate(n.instance.pos, n.orig.underlying, n.TParams().list(), n.targs, n.instance.posList) + if typMap == nil { + if n.check != nil { + typMap = n.check.typMap + } else { + // If we're instantiating lazily, we might be outside the scope of a + // type-checking pass. In that case we won't have a pre-existing + // typMap, but don't want to create a duplicate of the current instance + // in the process of expansion. + h := instantiatedHash(n.orig, n.targs) + typMap = map[string]*Named{h: n} + } + } + + inst := n.check.instantiate(n.instance.pos, n.orig.underlying, n.TParams().list(), n.targs, n.instance.posList, typMap) n.underlying = inst n.fromRHS = inst n.instance = nil } + return n +} + +// safeUnderlying returns the underlying of typ without expanding instances, to +// avoid infinite recursion. +// +// TODO(rfindley): eliminate this function or give it a better name. +func safeUnderlying(typ Type) Type { + if t, _ := typ.(*Named); t != nil { + return t.load().underlying + } + return typ.Underlying() } diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go index 1541b3f416d..070a0b39320 100644 --- a/src/cmd/compile/internal/types2/predicates.go +++ b/src/cmd/compile/internal/types2/predicates.go @@ -302,8 +302,8 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { // Two named types are identical if their type names originate // in the same type declaration. if y, ok := y.(*Named); ok { - x.expand() - y.expand() + x.expand(nil) + y.expand(nil) // TODO(gri) Why is x == y not sufficient? And if it is, // we can just return false here because x == y // is caught in the very beginning of this function. diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go index 48b11b289cd..c4c209b3574 100644 --- a/src/cmd/compile/internal/types2/signature.go +++ b/src/cmd/compile/internal/types2/signature.go @@ -153,7 +153,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams [] // TODO(gri) should we assume now that bounds always exist? // (no bound == empty interface) if bound != nil { - bound = check.subst(tname.pos, bound, smap) + bound = check.subst(tname.pos, bound, smap, nil) tname.typ.(*TypeParam).bound = bound } } @@ -215,7 +215,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams [] var err string switch T := rtyp.(type) { case *Named: - T.expand() + T.expand(nil) // spec: "The type denoted by T is called the receiver base type; it must not // be a pointer or interface type and it must be declared in the same package // as the method." diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index 26796fc604d..044544f1f9d 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -51,7 +51,9 @@ func (m *substMap) lookup(tpar *TypeParam) Type { // subst is functional in the sense that it doesn't modify the incoming // type. If a substitution took place, the result type is different from // from the incoming type. -func (check *Checker) subst(pos syntax.Pos, typ Type, smap *substMap) Type { +// +// If the given typMap is nil and check is non-nil, check.typMap is used. +func (check *Checker) subst(pos syntax.Pos, typ Type, smap *substMap, typMap map[string]*Named) Type { if smap.empty() { return typ } @@ -68,16 +70,21 @@ func (check *Checker) subst(pos syntax.Pos, typ Type, smap *substMap) Type { var subst subster subst.pos = pos subst.smap = smap + if check != nil { subst.check = check - subst.typMap = check.typMap - } else { + if typMap == nil { + typMap = check.typMap + } + } + if typMap == nil { // If we don't have a *Checker and its global type map, // use a local version. Besides avoiding duplicate work, // the type map prevents infinite recursive substitution // for recursive types (example: type T[P any] *T[P]). - subst.typMap = make(map[string]*Named) + typMap = make(map[string]*Named) } + subst.typMap = typMap return subst.typ(typ) } @@ -234,14 +241,15 @@ func (subst *subster) typ(typ Type) Type { // create a new named type and populate typMap to avoid endless recursion tname := NewTypeName(subst.pos, t.obj.pkg, t.obj.name, nil) - named := subst.check.newNamed(tname, t, t.Underlying(), t.TParams(), t.methods) // method signatures are updated lazily + t.load() + named := subst.check.newNamed(tname, t.orig, t.underlying, t.TParams(), t.methods) // method signatures are updated lazily named.targs = new_targs subst.typMap[h] = named - t.expand() // must happen after typMap update to avoid infinite recursion + t.expand(subst.typMap) // must happen after typMap update to avoid infinite recursion // do the substitution dump(">>> subst %s with %s (new: %s)", t.underlying, subst.smap, new_targs) - named.underlying = subst.typOrNil(t.Underlying()) + named.underlying = subst.typOrNil(t.underlying) dump(">>> underlying: %v", named.underlying) assert(named.underlying != nil) named.fromRHS = named.underlying // for cycle detection (Checker.validType) diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index 637829613b1..4b8642aa962 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -116,7 +116,7 @@ func asInterface(t Type) *Interface { func asNamed(t Type) *Named { e, _ := t.(*Named) if e != nil { - e.expand() + e.expand(nil) } return e } diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index 6a9eacd31df..a53319c1539 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -225,7 +225,7 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) { // Test case: type T[P any] *T[P] // TODO(gri) investigate if that's a bug or to be expected // (see also analogous comment in Checker.instantiate). - under = T.Underlying() + under = safeUnderlying(T) } if T == under { check.trace(e0.Pos(), "=> %s // %s", T, goTypeName(T)) @@ -422,9 +422,13 @@ func (check *Checker) typOrNil(e syntax.Expr) Type { } func (check *Checker) instantiatedType(x syntax.Expr, targsx []syntax.Expr, def *Named) Type { - base := check.genericType(x, true) - if base == Typ[Invalid] { - return base // error already reported + gtyp := check.genericType(x, true) + if gtyp == Typ[Invalid] { + return gtyp // error already reported + } + base, _ := gtyp.(*Named) + if base == nil { + panic(fmt.Sprintf("%v: cannot instantiate %v", x.Pos(), gtyp)) } // evaluate arguments @@ -440,7 +444,7 @@ func (check *Checker) instantiatedType(x syntax.Expr, targsx []syntax.Expr, def posList[i] = syntax.StartPos(arg) } - typ := check.InstantiateLazy(x.Pos(), base, targs, posList, true) + typ := check.instantiateLazy(x.Pos(), base, targs, posList, true) def.setUnderlying(typ) // make sure we check instantiation works at least once diff --git a/src/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go index ae81382fb0e..28f9cf751c0 100644 --- a/src/cmd/compile/internal/types2/unify.go +++ b/src/cmd/compile/internal/types2/unify.go @@ -432,8 +432,8 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool { // return x.obj == y.obj // } if y, ok := y.(*Named); ok { - x.expand() - y.expand() + x.expand(nil) + y.expand(nil) // TODO(gri) This is not always correct: two types may have the same names // in the same package if one of them is nested in a function. // Extremely unlikely but we need an always correct solution. From 50f4ebbdd30f53272b5f42ab66c50939eade0a0e Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Wed, 11 Aug 2021 11:45:11 -0400 Subject: [PATCH 929/940] cmd/compile/internal/types2: define Identical for instances Instantiation of parameterized types may occur in other packages, so we need an intrinsic notion of type identity for instances. Add the natural definition: two instances are identical if their bases and type arguments are identical. Type unification was already considering type arguments, but has some inaccurate logic with respect to objects. This will be addressed in a follow-up CL. Change-Id: Ib2ce67c05de65eb302ee588cc40c89c60018da50 Reviewed-on: https://go-review.googlesource.com/c/go/+/341856 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types2/api_test.go | 25 +++++++++++++++++++ src/cmd/compile/internal/types2/predicates.go | 22 ++++++++++++++++ src/cmd/compile/internal/types2/unify.go | 5 ---- 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/cmd/compile/internal/types2/api_test.go b/src/cmd/compile/internal/types2/api_test.go index dfa4de11750..be05d06fd0a 100644 --- a/src/cmd/compile/internal/types2/api_test.go +++ b/src/cmd/compile/internal/types2/api_test.go @@ -1879,3 +1879,28 @@ func TestInstantiate(t *testing.T) { t.Fatalf("unexpected result type: %s points to %s", res, p) } } + +func TestInstanceIdentity(t *testing.T) { + imports := make(testImporter) + conf := Config{Importer: imports} + makePkg := func(src string) { + f, err := parseSrc("", src) + if err != nil { + t.Fatal(err) + } + name := f.PkgName.Value + pkg, err := conf.Check(name, []*syntax.File{f}, nil) + if err != nil { + t.Fatal(err) + } + imports[name] = pkg + } + makePkg(genericPkg + `lib; type T[P any] struct{}`) + makePkg(genericPkg + `a; import "generic_lib"; var A generic_lib.T[int]`) + makePkg(genericPkg + `b; import "generic_lib"; var B generic_lib.T[int]`) + a := imports["generic_a"].Scope().Lookup("A") + b := imports["generic_b"].Scope().Lookup("B") + if !Identical(a.Type(), b.Type()) { + t.Errorf("mismatching types: a.A: %s, b.B: %s", a.Type(), b.Type()) + } +} diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go index 070a0b39320..3c883e1ab5c 100644 --- a/src/cmd/compile/internal/types2/predicates.go +++ b/src/cmd/compile/internal/types2/predicates.go @@ -304,6 +304,28 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { if y, ok := y.(*Named); ok { x.expand(nil) y.expand(nil) + + xargs := x.TArgs() + yargs := y.TArgs() + + if len(xargs) != len(yargs) { + return false + } + + if len(xargs) > 0 { + // Instances are identical if their original type and type arguments + // are identical. + if !Identical(x.orig, y.orig) { + return false + } + for i, xa := range xargs { + if !Identical(xa, yargs[i]) { + return false + } + } + return true + } + // TODO(gri) Why is x == y not sufficient? And if it is, // we can just return false here because x == y // is caught in the very beginning of this function. diff --git a/src/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go index 28f9cf751c0..710fc51b53f 100644 --- a/src/cmd/compile/internal/types2/unify.go +++ b/src/cmd/compile/internal/types2/unify.go @@ -426,11 +426,6 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool { } case *Named: - // Two named types are identical if their type names originate - // in the same type declaration. - // if y, ok := y.(*Named); ok { - // return x.obj == y.obj - // } if y, ok := y.(*Named); ok { x.expand(nil) y.expand(nil) From 2d250043b4c5095f326ab72741d557fe74e4e3a6 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Wed, 11 Aug 2021 13:36:26 -0400 Subject: [PATCH 930/940] cmd/compile/internal/types2: simplify Named.under Remove some unnecessary logic from Named.under: - no need to have special handling for Typ[Invalid]: this is the same as other cases where the underlying type is resolved. - use Underlying() to get the loaded and expanded underlying - no need for special handling of the first iteration Change-Id: I2029711f51fa9eaaee11debadd55974a1376a980 Reviewed-on: https://go-review.googlesource.com/c/go/+/341857 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types2/named.go | 52 +++++++++--------------- 1 file changed, 19 insertions(+), 33 deletions(-) diff --git a/src/cmd/compile/internal/types2/named.go b/src/cmd/compile/internal/types2/named.go index b12e59b586d..59671726753 100644 --- a/src/cmd/compile/internal/types2/named.go +++ b/src/cmd/compile/internal/types2/named.go @@ -166,18 +166,13 @@ func (t *Named) String() string { return TypeString(t, nil) } // is detected, the result is Typ[Invalid]. If a cycle is detected and // n0.check != nil, the cycle is reported. func (n0 *Named) under() Type { - n0.expand(nil) - - u := n0.load().underlying - - if u == Typ[Invalid] { - return u - } + u := n0.Underlying() // If the underlying type of a defined type is not a defined // (incl. instance) type, then that is the desired underlying // type. - switch u.(type) { + var n1 *Named + switch u1 := u.(type) { case nil: return Typ[Invalid] default: @@ -185,6 +180,7 @@ func (n0 *Named) under() Type { return u case *Named: // handled below + n1 = u1 } if n0.check == nil { @@ -194,43 +190,33 @@ func (n0 *Named) under() Type { // Invariant: after this point n0 as well as any named types in its // underlying chain should be set up when this function exits. check := n0.check + n := n0 - // If we can't expand u at this point, it is invalid. - n := asNamed(u) - if n == nil { - n0.underlying = Typ[Invalid] - return n0.underlying - } + seen := make(map[*Named]int) // types that need their underlying resolved + var path []Object // objects encountered, for cycle reporting - // Otherwise, follow the forward chain. - seen := map[*Named]int{n0: 0} - path := []Object{n0.obj} +loop: for { - u = n.load().underlying - if u == nil { - u = Typ[Invalid] - break - } - var n1 *Named - switch u1 := u.(type) { - case *Named: - u1.expand(nil) - n1 = u1 - } - if n1 == nil { - break // end of chain - } - seen[n] = len(seen) path = append(path, n.obj) n = n1 - if i, ok := seen[n]; ok { // cycle check.cycleError(path[i:]) u = Typ[Invalid] break } + u = n.Underlying() + switch u1 := u.(type) { + case nil: + u = Typ[Invalid] + break loop + default: + break loop + case *Named: + // Continue collecting *Named types in the chain. + n1 = u1 + } } for n := range seen { From 456759b24682a41e282f73855377ac4f341da191 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Wed, 11 Aug 2021 12:43:27 -0400 Subject: [PATCH 931/940] cmd/compile/internal/types2: use the orig object for Named.Obj Exposing a synthetic type name for instantiated types is problematic: there is no way to ensure that type instances are first created in the same type checking pass, and therefore no guarantee that their instantiation positions are the same. Even type checking a given package with different file ordering could result in different positions being associated with type instances. This is therefore an implementation detail that we should not expose. Keep the synthetic type name for accurate error reporting, but hide it in the API. Change-Id: I61f0e3ed322e97b157eb1ca316480f5719dcc174 Reviewed-on: https://go-review.googlesource.com/c/go/+/341858 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types2/named.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/cmd/compile/internal/types2/named.go b/src/cmd/compile/internal/types2/named.go index 59671726753..ad29886f7d6 100644 --- a/src/cmd/compile/internal/types2/named.go +++ b/src/cmd/compile/internal/types2/named.go @@ -15,7 +15,7 @@ import ( type Named struct { check *Checker info typeInfo // for cycle detection - obj *TypeName // corresponding declared object + obj *TypeName // corresponding declared object for declared types; placeholder for instantiated types orig *Named // original, uninstantiated type fromRHS Type // type (on RHS of declaration) this *Named type is derived from (for cycle reporting) underlying Type // possibly a *Named during setup; never a *Named once set up completely @@ -108,8 +108,11 @@ func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tpar return typ } -// Obj returns the type name for the named type t. -func (t *Named) Obj() *TypeName { return t.obj } +// Obj returns the type name for the declaration defining the named type t. For +// instantiated types, this is the type name of the base type. +func (t *Named) Obj() *TypeName { + return t.orig.obj // for non-instances this is the same as t.obj +} // Orig returns the original generic type an instantiated type is derived from. // If t is not an instantiated type, the result is t. From b2253c8041511fad5fdcf7514131f972f63a01a0 Mon Sep 17 00:00:00 2001 From: Robert Findley Date: Thu, 12 Aug 2021 15:03:45 -0400 Subject: [PATCH 932/940] cmd/compile/internal/types2: remove targs from substMap Now that we always capture targs when constructing an instance, we no longer need to pass them via the substMap. This simplifies the code and resolves a TODO. Change-Id: I592dccaeb89c7cc31ac037d919137bb762820365 Reviewed-on: https://go-review.googlesource.com/c/go/+/341859 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- .../compile/internal/types2/instantiate.go | 2 +- src/cmd/compile/internal/types2/subst.go | 83 ++++++++----------- 2 files changed, 34 insertions(+), 51 deletions(-) diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go index a648a3c38c8..fff26354560 100644 --- a/src/cmd/compile/internal/types2/instantiate.go +++ b/src/cmd/compile/internal/types2/instantiate.go @@ -152,7 +152,7 @@ func (check *Checker) verify(pos syntax.Pos, tparams []*TypeName, targs []Type, // parameter tpar (after any of its type parameters have been substituted through smap). // A suitable error is reported if the result is false. // TODO(gri) This should be a method of interfaces or type sets. -func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap *substMap) bool { +func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap substMap) bool { iface := tpar.iface() if iface.Empty() { return true // no type bound diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index 044544f1f9d..ed3fd654a0e 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -9,38 +9,27 @@ package types2 import ( "bytes" "cmd/compile/internal/syntax" - "fmt" ) -type substMap struct { - // The targs field is currently needed for *Named type substitution. - // TODO(gri) rewrite that code, get rid of this field, and make this - // struct just the map (proj) - targs []Type - proj map[*TypeParam]Type -} +type substMap map[*TypeParam]Type // makeSubstMap creates a new substitution map mapping tpars[i] to targs[i]. // If targs[i] is nil, tpars[i] is not substituted. -func makeSubstMap(tpars []*TypeName, targs []Type) *substMap { +func makeSubstMap(tpars []*TypeName, targs []Type) substMap { assert(len(tpars) == len(targs)) - proj := make(map[*TypeParam]Type, len(tpars)) + proj := make(substMap, len(tpars)) for i, tpar := range tpars { proj[tpar.typ.(*TypeParam)] = targs[i] } - return &substMap{targs, proj} + return proj } -func (m *substMap) String() string { - return fmt.Sprintf("%s", m.proj) +func (m substMap) empty() bool { + return len(m) == 0 } -func (m *substMap) empty() bool { - return len(m.proj) == 0 -} - -func (m *substMap) lookup(tpar *TypeParam) Type { - if t := m.proj[tpar]; t != nil { +func (m substMap) lookup(tpar *TypeParam) Type { + if t := m[tpar]; t != nil { return t } return tpar @@ -53,7 +42,7 @@ func (m *substMap) lookup(tpar *TypeParam) Type { // from the incoming type. // // If the given typMap is nil and check is non-nil, check.typMap is used. -func (check *Checker) subst(pos syntax.Pos, typ Type, smap *substMap, typMap map[string]*Named) Type { +func (check *Checker) subst(pos syntax.Pos, typ Type, smap substMap, typMap map[string]*Named) Type { if smap.empty() { return typ } @@ -91,7 +80,7 @@ func (check *Checker) subst(pos syntax.Pos, typ Type, smap *substMap, typMap map type subster struct { pos syntax.Pos - smap *substMap + smap substMap check *Checker // nil if called via Instantiate typMap map[string]*Named } @@ -199,40 +188,34 @@ func (subst *subster) typ(typ Type) Type { return t // type is not parameterized } - var new_targs []Type + var newTArgs []Type + assert(len(t.targs) == t.TParams().Len()) - if len(t.targs) > 0 { - // already instantiated - dump(">>> %s already instantiated", t) - assert(len(t.targs) == t.TParams().Len()) - // For each (existing) type argument targ, determine if it needs - // to be substituted; i.e., if it is or contains a type parameter - // that has a type argument for it. - for i, targ := range t.targs { - dump(">>> %d targ = %s", i, targ) - new_targ := subst.typ(targ) - if new_targ != targ { - dump(">>> substituted %d targ %s => %s", i, targ, new_targ) - if new_targs == nil { - new_targs = make([]Type, t.TParams().Len()) - copy(new_targs, t.targs) - } - new_targs[i] = new_targ + // already instantiated + dump(">>> %s already instantiated", t) + // For each (existing) type argument targ, determine if it needs + // to be substituted; i.e., if it is or contains a type parameter + // that has a type argument for it. + for i, targ := range t.targs { + dump(">>> %d targ = %s", i, targ) + new_targ := subst.typ(targ) + if new_targ != targ { + dump(">>> substituted %d targ %s => %s", i, targ, new_targ) + if newTArgs == nil { + newTArgs = make([]Type, t.TParams().Len()) + copy(newTArgs, t.targs) } + newTArgs[i] = new_targ } + } - if new_targs == nil { - dump(">>> nothing to substitute in %s", t) - return t // nothing to substitute - } - } else { - // not yet instantiated - dump(">>> first instantiation of %s", t) - new_targs = subst.smap.targs + if newTArgs == nil { + dump(">>> nothing to substitute in %s", t) + return t // nothing to substitute } // before creating a new named type, check if we have this one already - h := instantiatedHash(t, new_targs) + h := instantiatedHash(t, newTArgs) dump(">>> new type hash: %s", h) if named, found := subst.typMap[h]; found { dump(">>> found %s", named) @@ -243,12 +226,12 @@ func (subst *subster) typ(typ Type) Type { tname := NewTypeName(subst.pos, t.obj.pkg, t.obj.name, nil) t.load() named := subst.check.newNamed(tname, t.orig, t.underlying, t.TParams(), t.methods) // method signatures are updated lazily - named.targs = new_targs + named.targs = newTArgs subst.typMap[h] = named t.expand(subst.typMap) // must happen after typMap update to avoid infinite recursion // do the substitution - dump(">>> subst %s with %s (new: %s)", t.underlying, subst.smap, new_targs) + dump(">>> subst %s with %s (new: %s)", t.underlying, subst.smap, newTArgs) named.underlying = subst.typOrNil(t.underlying) dump(">>> underlying: %v", named.underlying) assert(named.underlying != nil) From 49c688e45c9bb8782b3db4df9dcaf163a4965f6d Mon Sep 17 00:00:00 2001 From: Robert Findley Date: Fri, 13 Aug 2021 11:16:50 -0400 Subject: [PATCH 933/940] cmd/compile/internal/types2: rename TypeParams to TParamList The 'TypeParams' name is too easily confused with the singular 'TypeParam', and does not say anything about what type of collection it is. We decided that TTuple was not great. TParamList seems OK for now, though perhaps a better name will emerge. Change-Id: I5eabdc91b1f666bb4c7ea8acdbebf7c372d19227 Reviewed-on: https://go-review.googlesource.com/c/go/+/341861 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/noder/writer.go | 4 ++-- src/cmd/compile/internal/types2/decl.go | 2 +- src/cmd/compile/internal/types2/named.go | 6 +++--- src/cmd/compile/internal/types2/signature.go | 8 ++++---- src/cmd/compile/internal/types2/typeparam.go | 14 +++++++------- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go index b5028e7f695..d971bd0d164 100644 --- a/src/cmd/compile/internal/noder/writer.go +++ b/src/cmd/compile/internal/noder/writer.go @@ -646,7 +646,7 @@ func (w *writer) objDict(obj types2.Object, dict *writerDict) { assert(len(dict.funcs) == nfuncs) } -func (w *writer) typeParamNames(tparams *types2.TypeParams) { +func (w *writer) typeParamNames(tparams *types2.TParamList) { w.sync(syncTypeParamNames) ntparams := tparams.Len() @@ -1861,7 +1861,7 @@ func fieldIndex(info *types2.Info, str *types2.Struct, key *syntax.Name) int { } // objTypeParams returns the type parameters on the given object. -func objTypeParams(obj types2.Object) *types2.TypeParams { +func objTypeParams(obj types2.Object) *types2.TParamList { switch obj := obj.(type) { case *types2.Func: sig := obj.Type().(*types2.Signature) diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go index 24ec4cd0294..aa9710788ad 100644 --- a/src/cmd/compile/internal/types2/decl.go +++ b/src/cmd/compile/internal/types2/decl.go @@ -581,7 +581,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named } } -func (check *Checker) collectTypeParams(list []*syntax.Field) *TypeParams { +func (check *Checker) collectTypeParams(list []*syntax.Field) *TParamList { tparams := make([]*TypeName, len(list)) // Declare type parameters up-front. diff --git a/src/cmd/compile/internal/types2/named.go b/src/cmd/compile/internal/types2/named.go index ad29886f7d6..3ce9c5b0c79 100644 --- a/src/cmd/compile/internal/types2/named.go +++ b/src/cmd/compile/internal/types2/named.go @@ -20,7 +20,7 @@ type Named struct { fromRHS Type // type (on RHS of declaration) this *Named type is derived from (for cycle reporting) underlying Type // possibly a *Named during setup; never a *Named once set up completely instance *instance // position information for lazy instantiation, or nil - tparams *TypeParams // type parameters, or nil + tparams *TParamList // type parameters, or nil targs []Type // type arguments (after instantiation), or nil methods []*Func // methods declared for this type (not the method set of this type); signatures are type-checked lazily @@ -80,7 +80,7 @@ func (t *Named) load() *Named { } // newNamed is like NewNamed but with a *Checker receiver and additional orig argument. -func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams *TypeParams, methods []*Func) *Named { +func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams *TParamList, methods []*Func) *Named { typ := &Named{check: check, obj: obj, orig: orig, fromRHS: underlying, underlying: underlying, tparams: tparams, methods: methods} if typ.orig == nil { typ.orig = typ @@ -123,7 +123,7 @@ func (t *Named) Orig() *Named { return t.orig } // TParams returns the type parameters of the named type t, or nil. // The result is non-nil for an (originally) parameterized type even if it is instantiated. -func (t *Named) TParams() *TypeParams { return t.load().tparams } +func (t *Named) TParams() *TParamList { return t.load().tparams } // SetTParams sets the type parameters of the named type t. func (t *Named) SetTParams(tparams []*TypeName) { t.load().tparams = bindTParams(tparams) } diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go index c4c209b3574..e319e652112 100644 --- a/src/cmd/compile/internal/types2/signature.go +++ b/src/cmd/compile/internal/types2/signature.go @@ -19,8 +19,8 @@ type Signature struct { // and store it in the Func Object) because when type-checking a function // literal we call the general type checker which returns a general Type. // We then unpack the *Signature and use the scope for the literal body. - rparams *TypeParams // receiver type parameters from left to right, or nil - tparams *TypeParams // type parameters from left to right, or nil + rparams *TParamList // receiver type parameters from left to right, or nil + tparams *TParamList // type parameters from left to right, or nil scope *Scope // function scope, present for package-local signatures recv *Var // nil if not a method params *Tuple // (incoming) parameters from left to right; or nil @@ -54,13 +54,13 @@ func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature { func (s *Signature) Recv() *Var { return s.recv } // TParams returns the type parameters of signature s, or nil. -func (s *Signature) TParams() *TypeParams { return s.tparams } +func (s *Signature) TParams() *TParamList { return s.tparams } // SetTParams sets the type parameters of signature s. func (s *Signature) SetTParams(tparams []*TypeName) { s.tparams = bindTParams(tparams) } // RParams returns the receiver type parameters of signature s, or nil. -func (s *Signature) RParams() *TypeParams { return s.rparams } +func (s *Signature) RParams() *TParamList { return s.rparams } // SetRParams sets the receiver type params of signature s. func (s *Signature) SetRParams(rparams []*TypeName) { s.rparams = bindTParams(rparams) } diff --git a/src/cmd/compile/internal/types2/typeparam.go b/src/cmd/compile/internal/types2/typeparam.go index 4b4282efe0b..f666fae7ede 100644 --- a/src/cmd/compile/internal/types2/typeparam.go +++ b/src/cmd/compile/internal/types2/typeparam.go @@ -83,28 +83,28 @@ func (t *TypeParam) SetConstraint(bound Type) { func (t *TypeParam) Underlying() Type { return t } func (t *TypeParam) String() string { return TypeString(t, nil) } -// TypeParams holds a list of type parameters bound to a type. -type TypeParams struct{ tparams []*TypeName } +// TParamList holds a list of type parameters bound to a type. +type TParamList struct{ tparams []*TypeName } // Len returns the number of type parameters in the list. // It is safe to call on a nil receiver. -func (tps *TypeParams) Len() int { +func (tps *TParamList) Len() int { return len(tps.list()) } // At returns the i'th type parameter in the list. -func (tps *TypeParams) At(i int) *TypeName { +func (tps *TParamList) At(i int) *TypeName { return tps.list()[i] } -func (tps *TypeParams) list() []*TypeName { +func (tps *TParamList) list() []*TypeName { if tps == nil { return nil } return tps.tparams } -func bindTParams(list []*TypeName) *TypeParams { +func bindTParams(list []*TypeName) *TParamList { if len(list) == 0 { return nil } @@ -115,7 +115,7 @@ func bindTParams(list []*TypeName) *TypeParams { } typ.index = i } - return &TypeParams{tparams: list} + return &TParamList{tparams: list} } // ---------------------------------------------------------------------------- From 0a0a160d4df488939892a1adaca6c530fb784cc8 Mon Sep 17 00:00:00 2001 From: Jeff Wentworth Date: Sat, 14 Aug 2021 09:46:32 +0000 Subject: [PATCH 934/940] sync/atomic: fix documentation for CompareAndSwap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #47699 The documentation for CompareAndSwap atomic/value incorrectly labelled the function as CompareAndSwapPointer. This PR fixes that. Change-Id: I6db08fdfe166570b775248fd24550f5d28e3434e GitHub-Last-Rev: 41f78707928f48c9cdac26b6a4f618d4284e1ca1 GitHub-Pull-Request: golang/go#47700 Reviewed-on: https://go-review.googlesource.com/c/go/+/342210 Reviewed-by: Keith Randall Reviewed-by: Daniel Martí Trust: Daniel Martí Run-TryBot: Daniel Martí TryBot-Result: Go Bot --- src/sync/atomic/value.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sync/atomic/value.go b/src/sync/atomic/value.go index 61f81d8fd37..3500cd22f4e 100644 --- a/src/sync/atomic/value.go +++ b/src/sync/atomic/value.go @@ -126,7 +126,7 @@ func (v *Value) Swap(new interface{}) (old interface{}) { } } -// CompareAndSwapPointer executes the compare-and-swap operation for the Value. +// CompareAndSwap executes the compare-and-swap operation for the Value. // // All calls to CompareAndSwap for a given Value must use values of the same // concrete type. CompareAndSwap of an inconsistent type panics, as does From ff3469b1c21e241a8319f9e79412849819d7ecab Mon Sep 17 00:00:00 2001 From: Robert Findley Date: Sat, 14 Aug 2021 00:03:09 -0400 Subject: [PATCH 935/940] cmd/dist: remove tests using the typeparams build tag This stanza is no longer necessary now that the typeparams build tag is not used. Change-Id: I7bcc4a01e354e5130d50b00895a5b96c25c71502 Reviewed-on: https://go-review.googlesource.com/c/go/+/342153 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/dist/test.go | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index f40fa926dfd..a104b5c8f31 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -491,19 +491,6 @@ func (t *tester) registerTests() { }) } - // Test go/... cmd/gofmt with type parameters enabled. - if !t.compileOnly { - t.tests = append(t.tests, distTest{ - name: "tyepparams", - heading: "go/... and cmd/gofmt tests with tag typeparams", - fn: func(dt *distTest) error { - t.addCmd(dt, "src", t.goTest(), t.timeout(300), "-tags=typeparams", "go/...") - t.addCmd(dt, "src", t.goTest(), t.timeout(300), "-tags=typeparams", "cmd/gofmt") - return nil - }, - }) - } - if t.iOS() && !t.compileOnly { t.tests = append(t.tests, distTest{ name: "x509omitbundledroots", From 1162aae0ad7d7fefeebd1c8537c457eae76d43ec Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 13 Aug 2021 13:58:23 -0700 Subject: [PATCH 936/940] time/tzdata: update links in comment Change-Id: I141d29bb4adc957de5de1f8ed8867980fd3c8386 Reviewed-on: https://go-review.googlesource.com/c/go/+/342071 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Emmanuel Odeke --- src/time/tzdata/generate_zipdata.go | 4 ++-- src/time/tzdata/zipdata.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/time/tzdata/generate_zipdata.go b/src/time/tzdata/generate_zipdata.go index 64b5b1b22c2..0869c8458c6 100644 --- a/src/time/tzdata/generate_zipdata.go +++ b/src/time/tzdata/generate_zipdata.go @@ -31,8 +31,8 @@ const header = `// Copyright 2020 The Go Authors. All rights reserved. // For more information, see // https://www.iana.org/time-zones -// ftp://ftp.iana.org/tz/code/tz-link.htm -// http://tools.ietf.org/html/rfc6557 +// ftp://ftp.iana.org/tz/code/tz-link.html +// https://datatracker.ietf.org/doc/html/rfc6557 package tzdata diff --git a/src/time/tzdata/zipdata.go b/src/time/tzdata/zipdata.go index 03b59720e27..60c07840082 100644 --- a/src/time/tzdata/zipdata.go +++ b/src/time/tzdata/zipdata.go @@ -11,8 +11,8 @@ // For more information, see // https://www.iana.org/time-zones -// ftp://ftp.iana.org/tz/code/tz-link.htm -// http://tools.ietf.org/html/rfc6557 +// ftp://ftp.iana.org/tz/code/tz-link.html +// https://datatracker.ietf.org/doc/html/rfc6557 package tzdata From 48dfddbab3569798267798a5d8828bf35355eb9d Mon Sep 17 00:00:00 2001 From: 180909 <734461790@qq.com> Date: Sun, 15 Aug 2021 01:57:33 +0000 Subject: [PATCH 937/940] lib/time: fix RFC 6557 url Change-Id: I59406ee7dbab7b2a0404b62061af552b6b4ecf5f GitHub-Last-Rev: 7cad5ae9bac19fdffb072413095fe5b223c95eca GitHub-Pull-Request: golang/go#47696 Reviewed-on: https://go-review.googlesource.com/c/go/+/342209 Reviewed-by: Emmanuel Odeke Reviewed-by: Ian Lance Taylor Run-TryBot: Emmanuel Odeke TryBot-Result: Go Bot --- lib/time/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/time/README b/lib/time/README index edb8dccd266..0de06df13b9 100644 --- a/lib/time/README +++ b/lib/time/README @@ -5,6 +5,6 @@ The IANA asserts that the database is in the public domain. For more information, see https://www.iana.org/time-zones ftp://ftp.iana.org/tz/code/tz-link.html -http://tools.ietf.org/html/rfc6557 +https://datatracker.ietf.org/doc/html/rfc6557 To rebuild the archive, read and run update.bash. From 6ed9463133daabcf11b259155c3f3348ae5a06af Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Sun, 15 Aug 2021 11:46:33 -0700 Subject: [PATCH 938/940] cmd/compile/internal/syntax: better error message for index syntax error Fixes #47704. Change-Id: I1de9fd00baaa4b534c23f011ade54120f5153a9d Reviewed-on: https://go-review.googlesource.com/c/go/+/342369 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/syntax/parser.go | 6 +++++- .../internal/syntax/testdata/issue47704.src | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/cmd/compile/internal/syntax/testdata/issue47704.src diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go index acffd848855..29f5c88d0f2 100644 --- a/src/cmd/compile/internal/syntax/parser.go +++ b/src/cmd/compile/internal/syntax/parser.go @@ -1049,7 +1049,11 @@ loop: } // x[i:... - p.want(_Colon) + // For better error message, don't use p.want(_Colon) here (issue #47704). + if !p.got(_Colon) { + p.syntaxError("expecting : or ]") + p.advance(_Colon, _Rbrack) + } p.xnest++ t := new(SliceExpr) t.pos = pos diff --git a/src/cmd/compile/internal/syntax/testdata/issue47704.src b/src/cmd/compile/internal/syntax/testdata/issue47704.src new file mode 100644 index 00000000000..0156af7d8d1 --- /dev/null +++ b/src/cmd/compile/internal/syntax/testdata/issue47704.src @@ -0,0 +1,18 @@ +// Copyright 2021 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 + +// error messages for parser in non-generic mode +func _() { + _ = m[] // ERROR expecting operand + _ = m[x,] // ERROR unexpected comma, expecting \: or \] + _ = m[x /* ERROR unexpected a */ a b c d] +} + +// test case from the issue +func f(m map[int]int) int { + return m[0 // ERROR expecting \: or \] + ] +} From 717894cf8024cfaad629f0e66a4b9bc123676be5 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Sun, 15 Aug 2021 12:34:59 -0700 Subject: [PATCH 939/940] cmd/compile/internal/types2: better error message for index syntax error (follow-up) For #47704. Change-Id: I09e6f638df0cd456a20a3b68ab55c47bb5b1f555 Reviewed-on: https://go-review.googlesource.com/c/go/+/342370 Trust: Robert Griesemer Run-TryBot: Robert Griesemer Reviewed-by: Robert Findley TryBot-Result: Go Bot --- src/cmd/compile/internal/syntax/parser.go | 11 ++++++++--- .../internal/syntax/testdata/issue47704.go2 | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 src/cmd/compile/internal/syntax/testdata/issue47704.go2 diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go index 29f5c88d0f2..4fb6de10a82 100644 --- a/src/cmd/compile/internal/syntax/parser.go +++ b/src/cmd/compile/internal/syntax/parser.go @@ -1049,10 +1049,15 @@ loop: } // x[i:... - // For better error message, don't use p.want(_Colon) here (issue #47704). + // For better error message, don't simply use p.want(_Colon) here (issue #47704). if !p.got(_Colon) { - p.syntaxError("expecting : or ]") - p.advance(_Colon, _Rbrack) + if p.mode&AllowGenerics == 0 { + p.syntaxError("expecting : or ]") + p.advance(_Colon, _Rbrack) + } else { + p.syntaxError("expecting comma, : or ]") + p.advance(_Comma, _Colon, _Rbrack) + } } p.xnest++ t := new(SliceExpr) diff --git a/src/cmd/compile/internal/syntax/testdata/issue47704.go2 b/src/cmd/compile/internal/syntax/testdata/issue47704.go2 new file mode 100644 index 00000000000..4e65857f3b1 --- /dev/null +++ b/src/cmd/compile/internal/syntax/testdata/issue47704.go2 @@ -0,0 +1,18 @@ +// Copyright 2021 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 + +// error messages for parser in generic mode +func _() { + _ = m[] // ERROR expecting operand + _ = m[x,] + _ = m[x /* ERROR unexpected a */ a b c d] +} + +// test case from the issue +func f(m map[int]int) int { + return m[0 // ERROR expecting comma, \: or \] + ] +} From 57c115e1f68a997ba8978d4a5abd6ccc954ae3dd Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 24 May 2021 10:06:36 -0700 Subject: [PATCH 940/940] crypto/sha{256,512}: unname result parameters for consistency Sum224 and Sum256 didn't look the same at: https://golang.org/pkg/crypto/sha256/ Now they match. Likewise with sha512's funcs. Per: https://github.com/golang/go/wiki/CodeReviewComments#named-result-parameters Change-Id: I6b88c8ef15141c78a6cddeb0960b3ad52db34244 Reviewed-on: https://go-review.googlesource.com/c/go/+/322329 Run-TryBot: Brad Fitzpatrick TryBot-Result: Go Bot Trust: Brad Fitzpatrick Trust: Katie Hockman Reviewed-by: Katie Hockman Reviewed-by: Ian Lance Taylor --- src/crypto/sha256/sha256.go | 6 +++--- src/crypto/sha512/sha512.go | 18 +++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/crypto/sha256/sha256.go b/src/crypto/sha256/sha256.go index e1cccf65a60..659531dc716 100644 --- a/src/crypto/sha256/sha256.go +++ b/src/crypto/sha256/sha256.go @@ -259,12 +259,12 @@ func Sum256(data []byte) [Size]byte { } // Sum224 returns the SHA224 checksum of the data. -func Sum224(data []byte) (sum224 [Size224]byte) { +func Sum224(data []byte) [Size224]byte { var d digest d.is224 = true d.Reset() d.Write(data) sum := d.checkSum() - copy(sum224[:], sum[:Size224]) - return + ap := (*[Size224]byte)(sum[:]) + return *ap } diff --git a/src/crypto/sha512/sha512.go b/src/crypto/sha512/sha512.go index 9c143a2a281..d5715558c04 100644 --- a/src/crypto/sha512/sha512.go +++ b/src/crypto/sha512/sha512.go @@ -337,31 +337,31 @@ func Sum512(data []byte) [Size]byte { } // Sum384 returns the SHA384 checksum of the data. -func Sum384(data []byte) (sum384 [Size384]byte) { +func Sum384(data []byte) [Size384]byte { d := digest{function: crypto.SHA384} d.Reset() d.Write(data) sum := d.checkSum() - copy(sum384[:], sum[:Size384]) - return + ap := (*[Size384]byte)(sum[:]) + return *ap } // Sum512_224 returns the Sum512/224 checksum of the data. -func Sum512_224(data []byte) (sum224 [Size224]byte) { +func Sum512_224(data []byte) [Size224]byte { d := digest{function: crypto.SHA512_224} d.Reset() d.Write(data) sum := d.checkSum() - copy(sum224[:], sum[:Size224]) - return + ap := (*[Size224]byte)(sum[:]) + return *ap } // Sum512_256 returns the Sum512/256 checksum of the data. -func Sum512_256(data []byte) (sum256 [Size256]byte) { +func Sum512_256(data []byte) [Size256]byte { d := digest{function: crypto.SHA512_256} d.Reset() d.Write(data) sum := d.checkSum() - copy(sum256[:], sum[:Size256]) - return + ap := (*[Size256]byte)(sum[:]) + return *ap }